"Fossies" - the Fresh Open Source Software Archive 
Member "which-2.21/bash.c" (19 Mar 2015, 13140 Bytes) of package /linux/privat/which-2.21.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "bash.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
2.20_vs_2.21.
1 /*
2 * Copyright (C) 1987 - 2002 Free Software Foundation, Inc.
3 *
4 * This file is based on stuff from GNU Bash 1.14.7, the Bourne Again SHell.
5 * Everything that was changed is marked with the word `CHANGED'.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02110-1301, USA.
20 */
21
22 #include "sys.h"
23 #include "posixstat.h"
24 #include <pwd.h>
25 #include <unistd.h>
26 #include "bash.h"
27
28 /* Use the type that was determined by configure. */
29 #define GID_T GETGROUPS_T
30
31 /*
32 * CHANGED:
33 * Perhaps these need new configure.in entries.
34 * The following macro's are used in bash, and below:
35 */
36 #undef SHELL
37 #undef AFS
38 #undef NOGROUP
39
40 /*
41 * CHANGED:
42 * - Added prototypes,
43 * - used ANSI function arguments,
44 * - made all functions static and
45 * - changed all occurences of 'char *' into 'char const*' where possible.
46 * - changed all occurences of 'gid_t' into 'GID_T'.
47 * - exported functions needed in which.c
48 */
49 static char* extract_colon_unit (char const* string, int* p_index);
50
51 /*===========================================================================
52 *
53 * Everything below is from bash-4.3.
54 *
55 */
56
57 /* From bash-4.3 / shell.h / line 113 */
58 /* Information about the current user. */
59 struct user_info {
60 uid_t uid, euid;
61 GID_T gid, egid;
62 char *user_name;
63 char *shell; /* shell from the password file */
64 char *home_dir;
65 };
66
67 /* From bash-4.3 / shell.c / line 116 */
68 /* Information about the current user. */
69 struct user_info current_user =
70 {
71 (uid_t)-1, (uid_t)-1, (GID_T)-1, (GID_T)-1,
72 (char *)NULL, (char *)NULL, (char *)NULL
73 };
74
75 /* From bash-4.3 / general.h / line 153 */
76 #define FREE(s) do { if (s) free (s); } while (0)
77
78 /* From bash-4.3 / shell.c / line 1201 */
79 /* Fetch the current set of uids and gids and return 1 if we're running
80 setuid or setgid. */
81 int
82 uidget ()
83 {
84 uid_t u;
85
86 u = getuid ();
87 if (current_user.uid != u)
88 {
89 FREE (current_user.user_name);
90 FREE (current_user.shell);
91 FREE (current_user.home_dir);
92 current_user.user_name = current_user.shell = current_user.home_dir = (char *)NULL;
93 }
94 current_user.uid = u;
95 current_user.gid = getgid ();
96 current_user.euid = geteuid ();
97 current_user.egid = getegid ();
98
99 /* See whether or not we are running setuid or setgid. */
100 return (current_user.uid != current_user.euid) ||
101 (current_user.gid != current_user.egid);
102 }
103
104 /* From bash-4.3 / general.c / line 1018 */
105 static int ngroups, maxgroups;
106
107 /* From bash-4.3 / general.c / line 1020 */
108 /* The set of groups that this user is a member of. */
109 static GETGROUPS_T *group_array = (GETGROUPS_T *)NULL;
110
111 /* From bash-4.3 / general.c / line 1023 */
112 #if !defined (NOGROUP)
113 # define NOGROUP (GID_T) -1
114 #endif
115
116 /* From bash-4.3 / lib/sh/oslib.c / line 250 */
117 #define DEFAULT_MAXGROUPS 64
118
119 /* From bash-4.3 / lib/sh/oslib.c / line 252 */
120 int
121 getmaxgroups ()
122 {
123 static int maxgroups = -1;
124
125 if (maxgroups > 0)
126 return maxgroups;
127
128 #if defined (HAVE_SYSCONF) && defined (_SC_NGROUPS_MAX)
129 maxgroups = sysconf (_SC_NGROUPS_MAX);
130 #else
131 # if defined (NGROUPS_MAX)
132 maxgroups = NGROUPS_MAX;
133 # else /* !NGROUPS_MAX */
134 # if defined (NGROUPS)
135 maxgroups = NGROUPS;
136 # else /* !NGROUPS */
137 maxgroups = DEFAULT_MAXGROUPS;
138 # endif /* !NGROUPS */
139 # endif /* !NGROUPS_MAX */
140 #endif /* !HAVE_SYSCONF || !SC_NGROUPS_MAX */
141
142 if (maxgroups <= 0)
143 maxgroups = DEFAULT_MAXGROUPS;
144
145 return maxgroups;
146 }
147
148 /* From bash-4.3 / general.c / line 1027 */
149 static void
150 initialize_group_array ()
151 {
152 register int i;
153
154 if (maxgroups == 0)
155 maxgroups = getmaxgroups ();
156
157 ngroups = 0;
158 group_array = (GETGROUPS_T *)xrealloc (group_array, maxgroups * sizeof (GETGROUPS_T));
159
160 #if defined (HAVE_GETGROUPS)
161 ngroups = getgroups (maxgroups, group_array);
162 #endif
163
164 /* If getgroups returns nothing, or the OS does not support getgroups(),
165 make sure the groups array includes at least the current gid. */
166 if (ngroups == 0)
167 {
168 group_array[0] = current_user.gid;
169 ngroups = 1;
170 }
171
172 /* If the primary group is not in the groups array, add it as group_array[0]
173 and shuffle everything else up 1, if there's room. */
174 for (i = 0; i < ngroups; i++)
175 if (current_user.gid == (GID_T)group_array[i])
176 break;
177 if (i == ngroups && ngroups < maxgroups)
178 {
179 for (i = ngroups; i > 0; i--)
180 group_array[i] = group_array[i - 1];
181 group_array[0] = current_user.gid;
182 ngroups++;
183 }
184
185 /* If the primary group is not group_array[0], swap group_array[0] and
186 whatever the current group is. The vast majority of systems should
187 not need this; a notable exception is Linux. */
188 if (group_array[0] != current_user.gid)
189 {
190 for (i = 0; i < ngroups; i++)
191 if (group_array[i] == current_user.gid)
192 break;
193 if (i < ngroups)
194 {
195 group_array[i] = group_array[0];
196 group_array[0] = current_user.gid;
197 }
198 }
199 }
200
201 /* From bash-4.3 / general.c / line 1079 */
202 /* Return non-zero if GID is one that we have in our groups list. */
203 int
204 #if defined (__STDC__) || defined ( _MINIX)
205 group_member (GID_T gid)
206 #else
207 group_member (gid)
208 GID_T gid;
209 #endif /* !__STDC__ && !_MINIX */
210 {
211 #if defined (HAVE_GETGROUPS)
212 register int i;
213 #endif
214
215 /* Short-circuit if possible, maybe saving a call to getgroups(). */
216 if (gid == current_user.gid || gid == current_user.egid)
217 return (1);
218
219 #if defined (HAVE_GETGROUPS)
220 if (ngroups == 0)
221 initialize_group_array ();
222
223 /* In case of error, the user loses. */
224 if (ngroups <= 0)
225 return (0);
226
227 /* Search through the list looking for GID. */
228 for (i = 0; i < ngroups; i++)
229 if (gid == (GID_T)group_array[i])
230 return (1);
231 #endif
232
233 return (0);
234 }
235
236 /* From bash-4.3 / findcmd.c / line 80 */
237 /* Return some flags based on information about this file.
238 The EXISTS bit is non-zero if the file is found.
239 The EXECABLE bit is non-zero the file is executble.
240 Zero is returned if the file is not found. */
241 int
242 file_status (char const* name)
243 {
244 struct stat finfo;
245 int r;
246
247 /* Determine whether this file exists or not. */
248 if (stat (name, &finfo) < 0)
249 return (0);
250
251 /* If the file is a directory, then it is not "executable" in the
252 sense of the shell. */
253 if (S_ISDIR (finfo.st_mode))
254 return (FS_EXISTS|FS_DIRECTORY);
255
256 r = FS_EXISTS;
257
258 #if defined (HAVE_EACCESS)
259 /* Use eaccess(2) if we have it to take things like ACLs and other
260 file access mechanisms into account. eaccess uses the effective
261 user and group IDs, not the real ones. We could use sh_eaccess,
262 but we don't want any special treatment for /dev/fd. */
263 if (eaccess (name, X_OK) == 0)
264 r |= FS_EXECABLE;
265 if (eaccess (name, R_OK) == 0)
266 r |= FS_READABLE;
267
268 return r;
269 #elif defined (AFS)
270 /* We have to use access(2) to determine access because AFS does not
271 support Unix file system semantics. This may produce wrong
272 answers for non-AFS files when ruid != euid. I hate AFS. */
273 if (access (name, X_OK) == 0)
274 r |= FS_EXECABLE;
275 if (access (name, R_OK) == 0)
276 r |= FS_READABLE;
277
278 return r;
279 #else /* !AFS */
280
281 /* Find out if the file is actually executable. By definition, the
282 only other criteria is that the file has an execute bit set that
283 we can use. The same with whether or not a file is readable. */
284
285 /* Root only requires execute permission for any of owner, group or
286 others to be able to exec a file, and can read any file. */
287 if (current_user.euid == (uid_t)0)
288 {
289 r |= FS_READABLE;
290 if (finfo.st_mode & S_IXUGO)
291 r |= FS_EXECABLE;
292 return r;
293 }
294
295 /* If we are the owner of the file, the owner bits apply. */
296 if (current_user.euid == finfo.st_uid)
297 {
298 if (finfo.st_mode & S_IXUSR)
299 r |= FS_EXECABLE;
300 if (finfo.st_mode & S_IRUSR)
301 r |= FS_READABLE;
302 }
303
304 /* If we are in the owning group, the group permissions apply. */
305 else if (group_member (finfo.st_gid))
306 {
307 if (finfo.st_mode & S_IXGRP)
308 r |= FS_EXECABLE;
309 if (finfo.st_mode & S_IRGRP)
310 r |= FS_READABLE;
311 }
312
313 /* Else we check whether `others' have permission to execute the file */
314 else
315 {
316 if (finfo.st_mode & S_IXOTH)
317 r |= FS_EXECABLE;
318 if (finfo.st_mode & S_IROTH)
319 r |= FS_READABLE;
320 }
321
322 return r;
323 #endif /* !AFS */
324 }
325
326 /* From bash-4.3 / general.c / line 604 ; Changes: Using 'strchr' instead of 'mbschr'. */
327 /* Return 1 if STRING is an absolute program name; it is absolute if it
328 contains any slashes. This is used to decide whether or not to look
329 up through $PATH. */
330 int
331 absolute_program (char const* string)
332 {
333 return ((char *)strchr (string, '/') != (char *)NULL);
334 }
335
336 /* From bash-4.3 / stringlib.c / line 124 */
337 /* Cons a new string from STRING starting at START and ending at END,
338 not including END. */
339 char *
340 substring (char const* string, int start, int end)
341 {
342 register int len;
343 register char *result;
344
345 len = end - start;
346 result = (char *)xmalloc (len + 1);
347 memcpy (result, string + start, len);
348 result[len] = '\0';
349 return (result);
350 }
351
352 /* From bash-4.3 / general.c / line 780 ; changes: Return NULL instead of 'string' when string == 0. */
353 /* Given a string containing units of information separated by colons,
354 return the next one pointed to by (P_INDEX), or NULL if there are no more.
355 Advance (P_INDEX) to the character after the colon. */
356 char*
357 extract_colon_unit (char const* string, int* p_index)
358 {
359 int i, start, len;
360 char *value;
361
362 if (string == 0)
363 return NULL;
364
365 len = strlen (string);
366 if (*p_index >= len)
367 return ((char *)NULL);
368
369 i = *p_index;
370
371 /* Each call to this routine leaves the index pointing at a colon if
372 there is more to the path. If I is > 0, then increment past the
373 `:'. If I is 0, then the path has a leading colon. Trailing colons
374 are handled OK by the `else' part of the if statement; an empty
375 string is returned in that case. */
376 if (i && string[i] == ':')
377 i++;
378
379 for (start = i; string[i] && string[i] != ':'; i++)
380 ;
381
382 *p_index = i;
383
384 if (i == start)
385 {
386 if (string[i])
387 (*p_index)++;
388 /* Return "" in the case of a trailing `:'. */
389 value = (char *)xmalloc (1);
390 value[0] = '\0';
391 }
392 else
393 value = substring (string, start, i);
394
395 return (value);
396 }
397
398 /* From bash-4.3 / findcmd.c / line 273 */
399 /* Return the next element from PATH_LIST, a colon separated list of
400 paths. PATH_INDEX_POINTER is the address of an index into PATH_LIST;
401 the index is modified by this function.
402 Return the next element of PATH_LIST or NULL if there are no more. */
403 char*
404 get_next_path_element (char const* path_list, int* path_index_pointer)
405 {
406 char* path;
407
408 path = extract_colon_unit (path_list, path_index_pointer);
409
410 if (path == 0)
411 return (path);
412
413 if (*path == '\0')
414 {
415 free (path);
416 path = savestring (".");
417 }
418
419 return (path);
420 }
421
422 /* From bash-1.14.7 */
423 /* Turn PATH, a directory, and NAME, a filename, into a full pathname.
424 This allocates new memory and returns it. */
425 char *
426 make_full_pathname (const char *path, const char *name, int name_len)
427 {
428 char *full_path;
429 int path_len;
430
431 path_len = strlen (path);
432 full_path = (char *) xmalloc (2 + path_len + name_len);
433 strcpy (full_path, path);
434 full_path[path_len] = '/';
435 strcpy (full_path + path_len + 1, name);
436 return (full_path);
437 }
438
439 /* From bash-4.3 / shell.c / line 1659 */
440 void
441 get_current_user_info ()
442 {
443 struct passwd *entry;
444
445 /* Don't fetch this more than once. */
446 if (current_user.user_name == 0)
447 {
448 #if defined (__TANDEM)
449 entry = getpwnam (getlogin ());
450 #else
451 entry = getpwuid (current_user.uid);
452 #endif
453 if (entry)
454 {
455 current_user.user_name = savestring (entry->pw_name);
456 current_user.shell = (entry->pw_shell && entry->pw_shell[0])
457 ? savestring (entry->pw_shell)
458 : savestring ("/bin/sh");
459 current_user.home_dir = savestring (entry->pw_dir);
460 }
461 else
462 {
463 current_user.user_name = "I have no name!";
464 current_user.user_name = savestring (current_user.user_name);
465 current_user.shell = savestring ("/bin/sh");
466 current_user.home_dir = savestring ("/");
467 }
468 endpwent ();
469 }
470 }
471
472 /* This is present for use by the tilde library. */
473 char* sh_get_env_value (const char* v)
474 {
475 return getenv(v);
476 }
477
478 char* sh_get_home_dir(void)
479 {
480 if (current_user.home_dir == NULL)
481 get_current_user_info();
482 return current_user.home_dir;
483 }
484