xref: /illumos-gate/usr/src/lib/libc/port/gen/isaexec.c (revision 711890bc9379ceea66272dc8d4981812224ea86e)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #pragma weak isaexec = _isaexec
30 #include "synonyms.h"
31 
32 #include <sys/types.h>
33 #include <sys/systeminfo.h>
34 #include <unistd.h>
35 #include <string.h>
36 #include <errno.h>
37 #include <limits.h>
38 #include <stdarg.h>
39 #include <stdlib.h>
40 
41 /*
42  * This is a utility routine to allow wrapper programs to simply
43  * implement the isalist exec algorithms.  See PSARC/1997/220.
44  */
45 int
46 isaexec(const char *execname, char *const *argv, char *const *envp)
47 {
48 	const char *fname;
49 	char *isalist;
50 	char *pathname;
51 	char *str;
52 	char *lasts;
53 	size_t isalen = 255;		/* wild guess */
54 	size_t len;
55 	int saved_errno;
56 
57 	/*
58 	 * Extract the isalist(5) for userland from the kernel.
59 	 */
60 	isalist = malloc(isalen);
61 	do {
62 		long ret = sysinfo(SI_ISALIST, isalist, isalen);
63 		if (ret == -1l) {
64 			free(isalist);
65 			errno = ENOENT;
66 			return (-1);
67 		}
68 		if (ret > isalen) {
69 			isalen = ret;
70 			isalist = realloc(isalist, isalen);
71 		} else
72 			break;
73 	} while (isalist != NULL);
74 
75 	if (isalist == NULL) {
76 		/*
77 		 * Then either a malloc or a realloc failed.
78 		 */
79 		errno = EAGAIN;
80 		return (-1);
81 	}
82 
83 	/*
84 	 * Allocate a full pathname buffer.  The sum of the lengths of the
85 	 * 'path' and isalist strings is guaranteed to be big enough.
86 	 */
87 	len = strlen(execname) + isalen;
88 	if ((pathname = malloc(len)) == NULL) {
89 		free(isalist);
90 		errno = EAGAIN;
91 		return (-1);
92 	}
93 
94 	/*
95 	 * Break the exec name into directory and file name components.
96 	 */
97 	(void) strcpy(pathname, execname);
98 	if ((str = strrchr(pathname, '/')) != NULL) {
99 		*++str = '\0';
100 		fname = execname + (str - pathname);
101 	} else {
102 		fname = execname;
103 		*pathname = '\0';
104 	}
105 	len = strlen(pathname);
106 
107 	/*
108 	 * For each name in the isa list, look for an executable file
109 	 * with the given file name in the corresponding subdirectory.
110 	 * If it's there, exec it.  If it's not there, or the exec
111 	 * fails, then run the next version ..
112 	 */
113 	str = strtok_r(isalist, " ", &lasts);
114 	saved_errno = ENOENT;
115 	do {
116 		(void) strcpy(pathname + len, str);
117 		(void) strcat(pathname + len, "/");
118 		(void) strcat(pathname + len, fname);
119 		if (access(pathname, X_OK) == 0) {
120 			/*
121 			 * File exists and is marked executable.  Attempt
122 			 * to execute the file from the subdirectory,
123 			 * using the user-supplied argv and envp.
124 			 */
125 			(void) execve(pathname, argv, envp);
126 
127 			/*
128 			 * If we failed to exec because of a temporary
129 			 * resource shortage, it's better to let our
130 			 * caller handle it (free memory, sleep for a while,
131 			 * or whatever before retrying) rather than drive
132 			 * on to run the "less capable" version.
133 			 */
134 			if (errno == EAGAIN) {
135 				saved_errno = errno;
136 				break;
137 			}
138 		}
139 	} while ((str = strtok_r(NULL, " ", &lasts)) != NULL);
140 
141 	free(pathname);
142 	free(isalist);
143 
144 	errno = saved_errno;
145 	return (-1);
146 }
147