]> git.ipfire.org Git - thirdparty/bash.git/blame - general.c
Imported from ../bash-2.05b.tar.gz.
[thirdparty/bash.git] / general.c
CommitLineData
726f6388
JA
1/* general.c -- Stuff that is used by all files. */
2
7117c2d2 3/* Copyright (C) 1987-2002 Free Software Foundation, Inc.
726f6388
JA
4
5 This file is part of GNU Bash, the Bourne Again SHell.
6
7 Bash is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with Bash; see the file COPYING. If not, write to the Free Software
bb70624e 19 Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
726f6388 20
ccc6cda3
JA
21#include "config.h"
22
726f6388 23#include "bashtypes.h"
cce855bc
JA
24#ifndef _MINIX
25# include <sys/param.h>
26#endif
ccc6cda3
JA
27#include "posixstat.h"
28
29#if defined (HAVE_UNISTD_H)
30# include <unistd.h>
31#endif
32
726f6388
JA
33#include "filecntl.h"
34#include "bashansi.h"
ccc6cda3 35#include <stdio.h>
f73dda09 36#include "chartypes.h"
ccc6cda3
JA
37#include <errno.h>
38
726f6388
JA
39#include "shell.h"
40#include <tilde/tilde.h>
41
726f6388
JA
42#if !defined (errno)
43extern int errno;
44#endif /* !errno */
45
f73dda09 46extern int expand_aliases;
ccc6cda3
JA
47extern int interrupt_immediately;
48extern int interactive_comments;
28ef6c31
JA
49extern int check_hashed_filenames;
50extern int source_uses_path;
51extern int source_searches_cwd;
cce855bc 52
7117c2d2
JA
53static char *bash_special_tilde_expansions __P((char *));
54static int unquoted_tilde_word __P((const char *));
55static void initialize_group_array __P((void));
56
cce855bc
JA
57/* A standard error message to use when getcwd() returns NULL. */
58char *bash_getcwd_errstr = "getcwd: cannot access parent directories";
726f6388 59
ccc6cda3 60/* Do whatever is necessary to initialize `Posix mode'. */
726f6388 61void
ccc6cda3
JA
62posix_initialize (on)
63 int on;
726f6388 64{
28ef6c31
JA
65 /* Things that should be turned on when posix mode is enabled. */
66 if (on != 0)
67 {
68 interactive_comments = source_uses_path = expand_aliases = 1;
69 }
70
71 /* Things that should be turned on when posix mode is disabled. */
72 if (on == 0)
73 {
74 source_searches_cwd = 1;
75 expand_aliases = interactive_shell;
76 }
726f6388
JA
77}
78
ccc6cda3
JA
79/* **************************************************************** */
80/* */
81/* Functions to convert to and from and display non-standard types */
82/* */
83/* **************************************************************** */
84
726f6388
JA
85#if defined (RLIMTYPE)
86RLIMTYPE
87string_to_rlimtype (s)
88 char *s;
89{
cce855bc
JA
90 RLIMTYPE ret;
91 int neg;
726f6388 92
cce855bc
JA
93 ret = 0;
94 neg = 0;
726f6388
JA
95 while (s && *s && whitespace (*s))
96 s++;
97 if (*s == '-' || *s == '+')
98 {
99 neg = *s == '-';
100 s++;
101 }
f73dda09
JA
102 for ( ; s && *s && DIGIT (*s); s++)
103 ret = (ret * 10) + TODIGIT (*s);
726f6388
JA
104 return (neg ? -ret : ret);
105}
106
107void
108print_rlimtype (n, addnl)
109 RLIMTYPE n;
110 int addnl;
111{
f73dda09 112 char s[INT_STRLEN_BOUND (RLIMTYPE) + 1], *p;
726f6388 113
f73dda09
JA
114 p = s + sizeof(s);
115 *--p = '\0';
726f6388
JA
116
117 if (n < 0)
118 {
f73dda09
JA
119 do
120 *--p = '0' - n % 10;
121 while ((n /= 10) != 0);
122
123 *--p = '-';
124 }
125 else
126 {
127 do
128 *--p = '0' + n % 10;
129 while ((n /= 10) != 0);
726f6388
JA
130 }
131
f73dda09 132 printf ("%s%s", p, addnl ? "\n" : "");
726f6388
JA
133}
134#endif /* RLIMTYPE */
135
ccc6cda3
JA
136/* **************************************************************** */
137/* */
138/* Input Validation Functions */
139/* */
140/* **************************************************************** */
141
142/* Return non-zero if all of the characters in STRING are digits. */
143int
144all_digits (string)
145 char *string;
146{
28ef6c31
JA
147 register char *s;
148
149 for (s = string; *s; s++)
f73dda09 150 if (DIGIT (*s) == 0)
28ef6c31
JA
151 return (0);
152
ccc6cda3
JA
153 return (1);
154}
155
156/* Return non-zero if the characters pointed to by STRING constitute a
157 valid number. Stuff the converted number into RESULT if RESULT is
f73dda09 158 not null. */
ccc6cda3
JA
159int
160legal_number (string, result)
161 char *string;
7117c2d2 162 intmax_t *result;
ccc6cda3 163{
7117c2d2 164 intmax_t value;
cce855bc 165 char *ep;
ccc6cda3
JA
166
167 if (result)
168 *result = 0;
169
f73dda09 170 errno = 0;
7117c2d2 171 value = strtoimax (string, &ep, 10);
f73dda09
JA
172 if (errno)
173 return 0; /* errno is set on overflow or underflow */
ccc6cda3 174
7117c2d2 175 /* Skip any trailing whitespace, since strtoimax does not. */
28ef6c31
JA
176 while (whitespace (*ep))
177 ep++;
178
cce855bc
JA
179 /* If *string is not '\0' but *ep is '\0' on return, the entire string
180 is valid. */
181 if (string && *string && *ep == '\0')
ccc6cda3
JA
182 {
183 if (result)
cce855bc
JA
184 *result = value;
185 /* The SunOS4 implementation of strtol() will happily ignore
186 overflow conditions, so this cannot do overflow correctly
187 on those systems. */
188 return 1;
ccc6cda3 189 }
cce855bc
JA
190
191 return (0);
ccc6cda3
JA
192}
193
726f6388
JA
194/* Return 1 if this token is a legal shell `identifier'; that is, it consists
195 solely of letters, digits, and underscores, and does not begin with a
196 digit. */
197int
198legal_identifier (name)
199 char *name;
200{
201 register char *s;
f73dda09 202 unsigned char c;
726f6388 203
f73dda09 204 if (!name || !(c = *name) || (legal_variable_starter (c) == 0))
726f6388
JA
205 return (0);
206
f73dda09 207 for (s = name + 1; (c = *s) != 0; s++)
726f6388 208 {
f73dda09 209 if (legal_variable_char (c) == 0)
28ef6c31 210 return (0);
726f6388
JA
211 }
212 return (1);
213}
214
215/* Make sure that WORD is a valid shell identifier, i.e.
216 does not contain a dollar sign, nor is quoted in any way. Nor
217 does it consist of all digits. If CHECK_WORD is non-zero,
218 the word is checked to ensure that it consists of only letters,
219 digits, and underscores. */
ccc6cda3 220int
726f6388
JA
221check_identifier (word, check_word)
222 WORD_DESC *word;
223 int check_word;
224{
ccc6cda3 225 if ((word->flags & (W_HASDOLLAR|W_QUOTED)) || all_digits (word->word))
726f6388 226 {
ccc6cda3 227 internal_error ("`%s': not a valid identifier", word->word);
726f6388
JA
228 return (0);
229 }
230 else if (check_word && legal_identifier (word->word) == 0)
231 {
ccc6cda3 232 internal_error ("`%s': not a valid identifier", word->word);
726f6388
JA
233 return (0);
234 }
235 else
236 return (1);
237}
238
7117c2d2
JA
239/* Returns non-zero if STRING is an assignment statement. The returned value
240 is the index of the `=' sign. */
241int
242assignment (string)
243 const char *string;
244{
245 register unsigned char c;
246 register int newi, indx;
247
248 c = string[indx = 0];
249
250 if (legal_variable_starter (c) == 0)
251 return (0);
252
253 while (c = string[indx])
254 {
255 /* The following is safe. Note that '=' at the start of a word
256 is not an assignment statement. */
257 if (c == '=')
258 return (indx);
259
260#if defined (ARRAY_VARS)
261 if (c == '[')
262 {
263 newi = skipsubscript (string, indx);
264 if (string[newi++] != ']')
265 return (0);
266 return ((string[newi] == '=') ? newi : 0);
267 }
268#endif /* ARRAY_VARS */
269
270 /* Variable names in assignment statements may contain only letters,
271 digits, and `_'. */
272 if (legal_variable_char (c) == 0)
273 return (0);
274
275 indx++;
276 }
277 return (0);
278}
279
ccc6cda3
JA
280/* **************************************************************** */
281/* */
282/* Functions to manage files and file descriptors */
283/* */
284/* **************************************************************** */
285
726f6388
JA
286/* A function to unset no-delay mode on a file descriptor. Used in shell.c
287 to unset it on the fd passed as stdin. Should be called on stdin if
288 readline gets an EAGAIN or EWOULDBLOCK when trying to read input. */
289
290#if !defined (O_NDELAY)
291# if defined (FNDELAY)
292# define O_NDELAY FNDELAY
293# endif
294#endif /* O_NDELAY */
295
296/* Make sure no-delay mode is not set on file descriptor FD. */
bb70624e 297int
28ef6c31 298sh_unset_nodelay_mode (fd)
726f6388
JA
299 int fd;
300{
bb70624e 301 int flags, bflags;
726f6388
JA
302
303 if ((flags = fcntl (fd, F_GETFL, 0)) < 0)
bb70624e 304 return -1;
726f6388 305
bb70624e 306 bflags = 0;
ccc6cda3
JA
307
308 /* This is defined to O_NDELAY in filecntl.h if O_NONBLOCK is not present
309 and O_NDELAY is defined. */
bb70624e
JA
310#ifdef O_NONBLOCK
311 bflags |= O_NONBLOCK;
312#endif
313
314#ifdef O_NDELAY
315 bflags |= O_NDELAY;
316#endif
317
318 if (flags & bflags)
726f6388 319 {
bb70624e
JA
320 flags &= ~bflags;
321 return (fcntl (fd, F_SETFL, flags));
726f6388 322 }
726f6388 323
bb70624e 324 return 0;
726f6388
JA
325}
326
7117c2d2
JA
327/* Return 1 if file descriptor FD is valid; 0 otherwise. */
328int
329sh_validfd (fd)
330 int fd;
331{
332 return (fcntl (fd, F_GETFD, 0) >= 0);
333}
334
b72432fd
JA
335/* There is a bug in the NeXT 2.1 rlogind that causes opens
336 of /dev/tty to fail. */
337
338#if defined (__BEOS__)
339/* On BeOS, opening in non-blocking mode exposes a bug in BeOS, so turn it
340 into a no-op. This should probably go away in the future. */
341# undef O_NONBLOCK
342# define O_NONBLOCK 0
343#endif /* __BEOS__ */
344
726f6388 345void
ccc6cda3 346check_dev_tty ()
726f6388 347{
ccc6cda3
JA
348 int tty_fd;
349 char *tty;
726f6388 350
d166f048 351 tty_fd = open ("/dev/tty", O_RDWR|O_NONBLOCK);
726f6388 352
ccc6cda3 353 if (tty_fd < 0)
726f6388 354 {
ccc6cda3
JA
355 tty = (char *)ttyname (fileno (stdin));
356 if (tty == 0)
357 return;
d166f048 358 tty_fd = open (tty, O_RDWR|O_NONBLOCK);
726f6388 359 }
ccc6cda3 360 close (tty_fd);
726f6388
JA
361}
362
ccc6cda3
JA
363/* Return 1 if PATH1 and PATH2 are the same file. This is kind of
364 expensive. If non-NULL STP1 and STP2 point to stat structures
365 corresponding to PATH1 and PATH2, respectively. */
726f6388 366int
ccc6cda3
JA
367same_file (path1, path2, stp1, stp2)
368 char *path1, *path2;
369 struct stat *stp1, *stp2;
726f6388 370{
ccc6cda3 371 struct stat st1, st2;
726f6388 372
ccc6cda3 373 if (stp1 == NULL)
726f6388 374 {
ccc6cda3
JA
375 if (stat (path1, &st1) != 0)
376 return (0);
377 stp1 = &st1;
726f6388 378 }
726f6388 379
ccc6cda3
JA
380 if (stp2 == NULL)
381 {
382 if (stat (path2, &st2) != 0)
383 return (0);
384 stp2 = &st2;
385 }
726f6388 386
ccc6cda3 387 return ((stp1->st_dev == stp2->st_dev) && (stp1->st_ino == stp2->st_ino));
726f6388
JA
388}
389
ccc6cda3
JA
390/* Move FD to a number close to the maximum number of file descriptors
391 allowed in the shell process, to avoid the user stepping on it with
392 redirection and causing us extra work. If CHECK_NEW is non-zero,
393 we check whether or not the file descriptors are in use before
d166f048
JA
394 duplicating FD onto them. MAXFD says where to start checking the
395 file descriptors. If it's less than 20, we get the maximum value
396 available from getdtablesize(2). */
726f6388 397int
d166f048
JA
398move_to_high_fd (fd, check_new, maxfd)
399 int fd, check_new, maxfd;
726f6388 400{
ccc6cda3 401 int script_fd, nfds, ignore;
726f6388 402
d166f048
JA
403 if (maxfd < 20)
404 {
405 nfds = getdtablesize ();
406 if (nfds <= 0)
407 nfds = 20;
7117c2d2
JA
408 if (nfds > HIGH_FD_MAX)
409 nfds = HIGH_FD_MAX; /* reasonable maximum */
d166f048
JA
410 }
411 else
412 nfds = maxfd;
726f6388 413
ccc6cda3
JA
414 for (nfds--; check_new && nfds > 3; nfds--)
415 if (fcntl (nfds, F_GETFD, &ignore) == -1)
416 break;
726f6388 417
7117c2d2 418 if (nfds > 3 && fd != nfds && (script_fd = dup2 (fd, nfds)) != -1)
ccc6cda3
JA
419 {
420 if (check_new == 0 || fd != fileno (stderr)) /* don't close stderr */
421 close (fd);
422 return (script_fd);
423 }
726f6388 424
7117c2d2
JA
425 /* OK, we didn't find one less than our artificial maximum; return the
426 original file descriptor. */
ccc6cda3
JA
427 return (fd);
428}
429
430/* Return non-zero if the characters from SAMPLE are not all valid
431 characters to be found in the first line of a shell script. We
432 check up to the first newline, or SAMPLE_LEN, whichever comes first.
433 All of the characters must be printable or whitespace. */
726f6388 434
726f6388 435int
ccc6cda3 436check_binary_file (sample, sample_len)
f73dda09 437 char *sample;
ccc6cda3 438 int sample_len;
726f6388 439{
ccc6cda3 440 register int i;
f73dda09 441 unsigned char c;
726f6388 442
ccc6cda3
JA
443 for (i = 0; i < sample_len; i++)
444 {
f73dda09
JA
445 c = sample[i];
446 if (c == '\n')
ccc6cda3 447 return (0);
726f6388 448
f73dda09 449 if (ISSPACE (c) == 0 && ISPRINT (c) == 0)
ccc6cda3
JA
450 return (1);
451 }
726f6388 452
ccc6cda3 453 return (0);
726f6388
JA
454}
455
ccc6cda3
JA
456/* **************************************************************** */
457/* */
458/* Functions to manipulate pathnames */
459/* */
460/* **************************************************************** */
726f6388 461
726f6388
JA
462/* Turn STRING (a pathname) into an absolute pathname, assuming that
463 DOT_PATH contains the symbolic location of `.'. This always
464 returns a new string, even if STRING was an absolute pathname to
465 begin with. */
466char *
467make_absolute (string, dot_path)
468 char *string, *dot_path;
469{
470 char *result;
ccc6cda3 471
28ef6c31 472 if (dot_path == 0 || ABSPATH(string))
726f6388
JA
473 result = savestring (string);
474 else
bb70624e 475 result = sh_makepath (dot_path, string, 0);
726f6388
JA
476
477 return (result);
478}
479
28ef6c31
JA
480/* Return 1 if STRING contains an absolute pathname, else 0. Used by `cd'
481 to decide whether or not to look up a directory name in $CDPATH. */
726f6388
JA
482int
483absolute_pathname (string)
f73dda09 484 const char *string;
726f6388 485{
28ef6c31 486 if (string == 0 || *string == '\0')
726f6388
JA
487 return (0);
488
28ef6c31
JA
489 if (ABSPATH(string))
490 return (1);
491
492 if (string[0] == '.' && PATHSEP(string[1])) /* . and ./ */
493 return (1);
494
495 if (string[0] == '.' && string[1] == '.' && PATHSEP(string[2])) /* .. and ../ */
726f6388
JA
496 return (1);
497
726f6388
JA
498 return (0);
499}
500
501/* Return 1 if STRING is an absolute program name; it is absolute if it
502 contains any slashes. This is used to decide whether or not to look
503 up through $PATH. */
504int
505absolute_program (string)
f73dda09 506 const char *string;
726f6388 507{
7117c2d2 508 return ((char *)xstrchr (string, '/') != (char *)NULL);
726f6388
JA
509}
510
511/* Return the `basename' of the pathname in STRING (the stuff after the
512 last '/'). If STRING is not a full pathname, simply return it. */
513char *
514base_pathname (string)
515 char *string;
516{
517 char *p;
518
28ef6c31 519 if (absolute_pathname (string) == 0)
726f6388
JA
520 return (string);
521
522 p = (char *)strrchr (string, '/');
ccc6cda3 523 return (p ? ++p : string);
726f6388
JA
524}
525
526/* Return the full pathname of FILE. Easy. Filenames that begin
527 with a '/' are returned as themselves. Other filenames have
528 the current working directory prepended. A new string is
529 returned in either case. */
530char *
531full_pathname (file)
532 char *file;
533{
bb70624e 534 char *ret;
726f6388 535
7117c2d2 536 file = (*file == '~') ? bash_tilde_expand (file, 0) : savestring (file);
726f6388 537
28ef6c31 538 if (ABSPATH(file))
726f6388
JA
539 return (file);
540
bb70624e
JA
541 ret = sh_makepath ((char *)NULL, file, (MP_DOCWD|MP_RMDOT));
542 free (file);
726f6388 543
bb70624e 544 return (ret);
726f6388 545}
726f6388
JA
546
547/* A slightly related function. Get the prettiest name of this
548 directory possible. */
ccc6cda3 549static char tdir[PATH_MAX];
726f6388
JA
550
551/* Return a pretty pathname. If the first part of the pathname is
552 the same as $HOME, then replace that with `~'. */
553char *
554polite_directory_format (name)
555 char *name;
556{
ccc6cda3
JA
557 char *home;
558 int l;
726f6388 559
ccc6cda3
JA
560 home = get_string_value ("HOME");
561 l = home ? strlen (home) : 0;
726f6388
JA
562 if (l > 1 && strncmp (home, name, l) == 0 && (!name[l] || name[l] == '/'))
563 {
e8ce775d 564 strncpy (tdir + 1, name + l, sizeof(tdir) - 2);
726f6388 565 tdir[0] = '~';
e8ce775d 566 tdir[sizeof(tdir) - 1] = '\0';
726f6388
JA
567 return (tdir);
568 }
569 else
570 return (name);
571}
572
ccc6cda3
JA
573/* Given a string containing units of information separated by colons,
574 return the next one pointed to by (P_INDEX), or NULL if there are no more.
575 Advance (P_INDEX) to the character after the colon. */
576char *
577extract_colon_unit (string, p_index)
578 char *string;
579 int *p_index;
726f6388 580{
ccc6cda3
JA
581 int i, start, len;
582 char *value;
726f6388 583
ccc6cda3
JA
584 if (string == 0)
585 return (string);
726f6388 586
ccc6cda3
JA
587 len = strlen (string);
588 if (*p_index >= len)
589 return ((char *)NULL);
726f6388 590
ccc6cda3 591 i = *p_index;
726f6388 592
ccc6cda3
JA
593 /* Each call to this routine leaves the index pointing at a colon if
594 there is more to the path. If I is > 0, then increment past the
595 `:'. If I is 0, then the path has a leading colon. Trailing colons
596 are handled OK by the `else' part of the if statement; an empty
597 string is returned in that case. */
598 if (i && string[i] == ':')
599 i++;
600
601 for (start = i; string[i] && string[i] != ':'; i++)
602 ;
603
604 *p_index = i;
605
606 if (i == start)
607 {
608 if (string[i])
609 (*p_index)++;
610 /* Return "" in the case of a trailing `:'. */
f73dda09 611 value = (char *)xmalloc (1);
ccc6cda3
JA
612 value[0] = '\0';
613 }
614 else
bb70624e 615 value = substring (string, start, i);
ccc6cda3
JA
616
617 return (value);
726f6388 618}
726f6388
JA
619
620/* **************************************************************** */
621/* */
622/* Tilde Initialization and Expansion */
623/* */
624/* **************************************************************** */
625
cce855bc
JA
626#if defined (PUSHD_AND_POPD)
627extern char *get_dirstack_from_string __P((char *));
628#endif
629
f73dda09
JA
630static char **bash_tilde_prefixes;
631static char **bash_tilde_suffixes;
632
726f6388
JA
633/* If tilde_expand hasn't been able to expand the text, perhaps it
634 is a special shell expansion. This function is installed as the
cce855bc
JA
635 tilde_expansion_preexpansion_hook. It knows how to expand ~- and ~+.
636 If PUSHD_AND_POPD is defined, ~[+-]N expands to directories from the
637 directory stack. */
726f6388 638static char *
d166f048 639bash_special_tilde_expansions (text)
726f6388
JA
640 char *text;
641{
ccc6cda3 642 char *result;
726f6388 643
ccc6cda3 644 result = (char *)NULL;
cce855bc
JA
645
646 if (text[0] == '+' && text[1] == '\0')
647 result = get_string_value ("PWD");
648 else if (text[0] == '-' && text[1] == '\0')
649 result = get_string_value ("OLDPWD");
650#if defined (PUSHD_AND_POPD)
f73dda09 651 else if (DIGIT (*text) || ((*text == '+' || *text == '-') && DIGIT (text[1])))
cce855bc
JA
652 result = get_dirstack_from_string (text);
653#endif
726f6388 654
ccc6cda3 655 return (result ? savestring (result) : (char *)NULL);
726f6388
JA
656}
657
658/* Initialize the tilde expander. In Bash, we handle `~-' and `~+', as
659 well as handling special tilde prefixes; `:~" and `=~' are indications
660 that we should do tilde expansion. */
661void
662tilde_initialize ()
663{
664 static int times_called = 0;
665
d166f048 666 /* Tell the tilde expander that we want a crack first. */
f73dda09 667 tilde_expansion_preexpansion_hook = bash_special_tilde_expansions;
726f6388
JA
668
669 /* Tell the tilde expander about special strings which start a tilde
670 expansion, and the special strings that end one. Only do this once.
671 tilde_initialize () is called from within bashline_reinitialize (). */
cce855bc 672 if (times_called++ == 0)
726f6388 673 {
7117c2d2 674 bash_tilde_prefixes = strvec_create (3);
f73dda09
JA
675 bash_tilde_prefixes[0] = "=~";
676 bash_tilde_prefixes[1] = ":~";
677 bash_tilde_prefixes[2] = (char *)NULL;
678
679 tilde_additional_prefixes = bash_tilde_prefixes;
680
7117c2d2 681 bash_tilde_suffixes = strvec_create (3);
f73dda09
JA
682 bash_tilde_suffixes[0] = ":";
683 bash_tilde_suffixes[1] = "=~"; /* XXX - ?? */
684 bash_tilde_suffixes[2] = (char *)NULL;
685
686 tilde_additional_suffixes = bash_tilde_suffixes;
726f6388 687 }
726f6388
JA
688}
689
f73dda09
JA
690/* POSIX.2, 3.6.1: A tilde-prefix consists of an unquoted tilde character
691 at the beginning of the word, followed by all of the characters preceding
692 the first unquoted slash in the word, or all the characters in the word
693 if there is no slash...If none of the characters in the tilde-prefix are
694 quoted, the characters in the tilde-prefix following the tilde shell be
695 treated as a possible login name. */
696
697#define TILDE_END(c) ((c) == '\0' || (c) == '/' || (c) == ':')
698
699static int
700unquoted_tilde_word (s)
701 const char *s;
702{
703 const char *r;
704
705 for (r = s; TILDE_END(*r) == 0; r++)
706 {
707 switch (*r)
708 {
709 case '\\':
710 case '\'':
711 case '"':
712 return 0;
713 }
714 }
715 return 1;
716}
717
7117c2d2
JA
718/* Tilde-expand S by running it through the tilde expansion library.
719 ASSIGN_P is 1 if this is a variable assignment, so the alternate
720 tilde prefixes should be enabled (`=~' and `:~', see above). */
ccc6cda3 721char *
7117c2d2 722bash_tilde_expand (s, assign_p)
f73dda09 723 const char *s;
7117c2d2 724 int assign_p;
726f6388 725{
f73dda09 726 int old_immed, r;
ccc6cda3 727 char *ret;
726f6388 728
ccc6cda3
JA
729 old_immed = interrupt_immediately;
730 interrupt_immediately = 1;
7117c2d2 731 tilde_additional_prefixes = assign_p ? bash_tilde_prefixes : (char **)0;
f73dda09
JA
732 r = (*s == '~') ? unquoted_tilde_word (s) : 1;
733 ret = r ? tilde_expand (s) : savestring (s);
ccc6cda3
JA
734 interrupt_immediately = old_immed;
735 return (ret);
726f6388 736}
d166f048
JA
737
738/* **************************************************************** */
739/* */
740/* Functions to manipulate and search the group list */
741/* */
742/* **************************************************************** */
743
744static int ngroups, maxgroups;
745
746/* The set of groups that this user is a member of. */
747static GETGROUPS_T *group_array = (GETGROUPS_T *)NULL;
748
749#if !defined (NOGROUP)
750# define NOGROUP (gid_t) -1
751#endif
752
d166f048
JA
753static void
754initialize_group_array ()
755{
756 register int i;
757
758 if (maxgroups == 0)
759 maxgroups = getmaxgroups ();
760
761 ngroups = 0;
762 group_array = (GETGROUPS_T *)xrealloc (group_array, maxgroups * sizeof (GETGROUPS_T));
763
764#if defined (HAVE_GETGROUPS)
765 ngroups = getgroups (maxgroups, group_array);
766#endif
767
768 /* If getgroups returns nothing, or the OS does not support getgroups(),
769 make sure the groups array includes at least the current gid. */
770 if (ngroups == 0)
771 {
772 group_array[0] = current_user.gid;
773 ngroups = 1;
774 }
775
776 /* If the primary group is not in the groups array, add it as group_array[0]
777 and shuffle everything else up 1, if there's room. */
778 for (i = 0; i < ngroups; i++)
779 if (current_user.gid == (gid_t)group_array[i])
780 break;
781 if (i == ngroups && ngroups < maxgroups)
782 {
783 for (i = ngroups; i > 0; i--)
28ef6c31 784 group_array[i] = group_array[i - 1];
d166f048
JA
785 group_array[0] = current_user.gid;
786 ngroups++;
787 }
cce855bc
JA
788
789 /* If the primary group is not group_array[0], swap group_array[0] and
790 whatever the current group is. The vast majority of systems should
791 not need this; a notable exception is Linux. */
792 if (group_array[0] != current_user.gid)
793 {
794 for (i = 0; i < ngroups; i++)
28ef6c31
JA
795 if (group_array[i] == current_user.gid)
796 break;
cce855bc
JA
797 if (i < ngroups)
798 {
799 group_array[i] = group_array[0];
800 group_array[0] = current_user.gid;
801 }
802 }
d166f048
JA
803}
804
805/* Return non-zero if GID is one that we have in our groups list. */
806int
cce855bc
JA
807#if defined (__STDC__) || defined ( _MINIX)
808group_member (gid_t gid)
809#else
d166f048
JA
810group_member (gid)
811 gid_t gid;
cce855bc 812#endif /* !__STDC__ && !_MINIX */
d166f048
JA
813{
814#if defined (HAVE_GETGROUPS)
815 register int i;
816#endif
817
818 /* Short-circuit if possible, maybe saving a call to getgroups(). */
819 if (gid == current_user.gid || gid == current_user.egid)
820 return (1);
821
822#if defined (HAVE_GETGROUPS)
823 if (ngroups == 0)
824 initialize_group_array ();
825
826 /* In case of error, the user loses. */
827 if (ngroups <= 0)
828 return (0);
829
830 /* Search through the list looking for GID. */
831 for (i = 0; i < ngroups; i++)
832 if (gid == (gid_t)group_array[i])
833 return (1);
834#endif
835
836 return (0);
837}
838
839char **
840get_group_list (ngp)
841 int *ngp;
842{
843 static char **group_vector = (char **)NULL;
844 register int i;
d166f048
JA
845
846 if (group_vector)
847 {
848 if (ngp)
849 *ngp = ngroups;
850 return group_vector;
851 }
852
853 if (ngroups == 0)
854 initialize_group_array ();
855
856 if (ngroups <= 0)
857 {
858 if (ngp)
859 *ngp = 0;
860 return (char **)NULL;
861 }
862
7117c2d2 863 group_vector = strvec_create (ngroups);
d166f048 864 for (i = 0; i < ngroups; i++)
7117c2d2 865 group_vector[i] = itos (group_array[i]);
b72432fd 866
d166f048
JA
867 if (ngp)
868 *ngp = ngroups;
869 return group_vector;
870}
b72432fd
JA
871
872int *
873get_group_array (ngp)
874 int *ngp;
875{
876 int i;
877 static int *group_iarray = (int *)NULL;
878
879 if (group_iarray)
880 {
881 if (ngp)
882 *ngp = ngroups;
883 return (group_iarray);
884 }
885
886 if (ngroups == 0)
887 initialize_group_array ();
888
889 if (ngroups <= 0)
890 {
891 if (ngp)
892 *ngp = 0;
893 return (int *)NULL;
894 }
895
896 group_iarray = (int *)xmalloc (ngroups * sizeof (int));
897 for (i = 0; i < ngroups; i++)
898 group_iarray[i] = (int)group_array[i];
899
900 if (ngp)
901 *ngp = ngroups;
902 return group_iarray;
903}