]> git.ipfire.org Git - thirdparty/bash.git/blame - general.c
Initial devel branch import from bash-3.0-alpha
[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))
d3a24ed2
CR
473#ifdef __CYGWIN__
474 {
475 char pathbuf[PATH_MAX + 1];
476
477 cygwin_conv_to_full_posix_path (string, pathbuf);
478 result = savestring (pathbuf);
479 }
480#else
726f6388 481 result = savestring (string);
d3a24ed2 482#endif
726f6388 483 else
bb70624e 484 result = sh_makepath (dot_path, string, 0);
726f6388
JA
485
486 return (result);
487}
488
28ef6c31
JA
489/* Return 1 if STRING contains an absolute pathname, else 0. Used by `cd'
490 to decide whether or not to look up a directory name in $CDPATH. */
726f6388
JA
491int
492absolute_pathname (string)
f73dda09 493 const char *string;
726f6388 494{
28ef6c31 495 if (string == 0 || *string == '\0')
726f6388
JA
496 return (0);
497
28ef6c31
JA
498 if (ABSPATH(string))
499 return (1);
500
501 if (string[0] == '.' && PATHSEP(string[1])) /* . and ./ */
502 return (1);
503
504 if (string[0] == '.' && string[1] == '.' && PATHSEP(string[2])) /* .. and ../ */
726f6388
JA
505 return (1);
506
726f6388
JA
507 return (0);
508}
509
510/* Return 1 if STRING is an absolute program name; it is absolute if it
511 contains any slashes. This is used to decide whether or not to look
512 up through $PATH. */
513int
514absolute_program (string)
f73dda09 515 const char *string;
726f6388 516{
7117c2d2 517 return ((char *)xstrchr (string, '/') != (char *)NULL);
726f6388
JA
518}
519
520/* Return the `basename' of the pathname in STRING (the stuff after the
521 last '/'). If STRING is not a full pathname, simply return it. */
522char *
523base_pathname (string)
524 char *string;
525{
526 char *p;
527
28ef6c31 528 if (absolute_pathname (string) == 0)
726f6388
JA
529 return (string);
530
531 p = (char *)strrchr (string, '/');
ccc6cda3 532 return (p ? ++p : string);
726f6388
JA
533}
534
535/* Return the full pathname of FILE. Easy. Filenames that begin
536 with a '/' are returned as themselves. Other filenames have
537 the current working directory prepended. A new string is
538 returned in either case. */
539char *
540full_pathname (file)
541 char *file;
542{
bb70624e 543 char *ret;
726f6388 544
7117c2d2 545 file = (*file == '~') ? bash_tilde_expand (file, 0) : savestring (file);
726f6388 546
28ef6c31 547 if (ABSPATH(file))
726f6388
JA
548 return (file);
549
bb70624e
JA
550 ret = sh_makepath ((char *)NULL, file, (MP_DOCWD|MP_RMDOT));
551 free (file);
726f6388 552
bb70624e 553 return (ret);
726f6388 554}
726f6388
JA
555
556/* A slightly related function. Get the prettiest name of this
557 directory possible. */
ccc6cda3 558static char tdir[PATH_MAX];
726f6388
JA
559
560/* Return a pretty pathname. If the first part of the pathname is
561 the same as $HOME, then replace that with `~'. */
562char *
563polite_directory_format (name)
564 char *name;
565{
ccc6cda3
JA
566 char *home;
567 int l;
726f6388 568
ccc6cda3
JA
569 home = get_string_value ("HOME");
570 l = home ? strlen (home) : 0;
726f6388
JA
571 if (l > 1 && strncmp (home, name, l) == 0 && (!name[l] || name[l] == '/'))
572 {
e8ce775d 573 strncpy (tdir + 1, name + l, sizeof(tdir) - 2);
726f6388 574 tdir[0] = '~';
e8ce775d 575 tdir[sizeof(tdir) - 1] = '\0';
726f6388
JA
576 return (tdir);
577 }
578 else
579 return (name);
580}
581
ccc6cda3
JA
582/* Given a string containing units of information separated by colons,
583 return the next one pointed to by (P_INDEX), or NULL if there are no more.
584 Advance (P_INDEX) to the character after the colon. */
585char *
586extract_colon_unit (string, p_index)
587 char *string;
588 int *p_index;
726f6388 589{
ccc6cda3
JA
590 int i, start, len;
591 char *value;
726f6388 592
ccc6cda3
JA
593 if (string == 0)
594 return (string);
726f6388 595
ccc6cda3
JA
596 len = strlen (string);
597 if (*p_index >= len)
598 return ((char *)NULL);
726f6388 599
ccc6cda3 600 i = *p_index;
726f6388 601
ccc6cda3
JA
602 /* Each call to this routine leaves the index pointing at a colon if
603 there is more to the path. If I is > 0, then increment past the
604 `:'. If I is 0, then the path has a leading colon. Trailing colons
605 are handled OK by the `else' part of the if statement; an empty
606 string is returned in that case. */
607 if (i && string[i] == ':')
608 i++;
609
610 for (start = i; string[i] && string[i] != ':'; i++)
611 ;
612
613 *p_index = i;
614
615 if (i == start)
616 {
617 if (string[i])
618 (*p_index)++;
619 /* Return "" in the case of a trailing `:'. */
f73dda09 620 value = (char *)xmalloc (1);
ccc6cda3
JA
621 value[0] = '\0';
622 }
623 else
bb70624e 624 value = substring (string, start, i);
ccc6cda3
JA
625
626 return (value);
726f6388 627}
726f6388
JA
628
629/* **************************************************************** */
630/* */
631/* Tilde Initialization and Expansion */
632/* */
633/* **************************************************************** */
634
cce855bc
JA
635#if defined (PUSHD_AND_POPD)
636extern char *get_dirstack_from_string __P((char *));
637#endif
638
f73dda09
JA
639static char **bash_tilde_prefixes;
640static char **bash_tilde_suffixes;
641
726f6388
JA
642/* If tilde_expand hasn't been able to expand the text, perhaps it
643 is a special shell expansion. This function is installed as the
cce855bc
JA
644 tilde_expansion_preexpansion_hook. It knows how to expand ~- and ~+.
645 If PUSHD_AND_POPD is defined, ~[+-]N expands to directories from the
646 directory stack. */
726f6388 647static char *
d166f048 648bash_special_tilde_expansions (text)
726f6388
JA
649 char *text;
650{
ccc6cda3 651 char *result;
726f6388 652
ccc6cda3 653 result = (char *)NULL;
cce855bc
JA
654
655 if (text[0] == '+' && text[1] == '\0')
656 result = get_string_value ("PWD");
657 else if (text[0] == '-' && text[1] == '\0')
658 result = get_string_value ("OLDPWD");
659#if defined (PUSHD_AND_POPD)
f73dda09 660 else if (DIGIT (*text) || ((*text == '+' || *text == '-') && DIGIT (text[1])))
cce855bc
JA
661 result = get_dirstack_from_string (text);
662#endif
726f6388 663
ccc6cda3 664 return (result ? savestring (result) : (char *)NULL);
726f6388
JA
665}
666
667/* Initialize the tilde expander. In Bash, we handle `~-' and `~+', as
668 well as handling special tilde prefixes; `:~" and `=~' are indications
669 that we should do tilde expansion. */
670void
671tilde_initialize ()
672{
673 static int times_called = 0;
674
d166f048 675 /* Tell the tilde expander that we want a crack first. */
f73dda09 676 tilde_expansion_preexpansion_hook = bash_special_tilde_expansions;
726f6388
JA
677
678 /* Tell the tilde expander about special strings which start a tilde
679 expansion, and the special strings that end one. Only do this once.
680 tilde_initialize () is called from within bashline_reinitialize (). */
cce855bc 681 if (times_called++ == 0)
726f6388 682 {
7117c2d2 683 bash_tilde_prefixes = strvec_create (3);
f73dda09
JA
684 bash_tilde_prefixes[0] = "=~";
685 bash_tilde_prefixes[1] = ":~";
686 bash_tilde_prefixes[2] = (char *)NULL;
687
688 tilde_additional_prefixes = bash_tilde_prefixes;
689
7117c2d2 690 bash_tilde_suffixes = strvec_create (3);
f73dda09
JA
691 bash_tilde_suffixes[0] = ":";
692 bash_tilde_suffixes[1] = "=~"; /* XXX - ?? */
693 bash_tilde_suffixes[2] = (char *)NULL;
694
695 tilde_additional_suffixes = bash_tilde_suffixes;
726f6388 696 }
726f6388
JA
697}
698
f73dda09
JA
699/* POSIX.2, 3.6.1: A tilde-prefix consists of an unquoted tilde character
700 at the beginning of the word, followed by all of the characters preceding
701 the first unquoted slash in the word, or all the characters in the word
702 if there is no slash...If none of the characters in the tilde-prefix are
703 quoted, the characters in the tilde-prefix following the tilde shell be
704 treated as a possible login name. */
705
706#define TILDE_END(c) ((c) == '\0' || (c) == '/' || (c) == ':')
707
708static int
709unquoted_tilde_word (s)
710 const char *s;
711{
712 const char *r;
713
714 for (r = s; TILDE_END(*r) == 0; r++)
715 {
716 switch (*r)
717 {
718 case '\\':
719 case '\'':
720 case '"':
721 return 0;
722 }
723 }
724 return 1;
725}
726
7117c2d2
JA
727/* Tilde-expand S by running it through the tilde expansion library.
728 ASSIGN_P is 1 if this is a variable assignment, so the alternate
729 tilde prefixes should be enabled (`=~' and `:~', see above). */
ccc6cda3 730char *
7117c2d2 731bash_tilde_expand (s, assign_p)
f73dda09 732 const char *s;
7117c2d2 733 int assign_p;
726f6388 734{
f73dda09 735 int old_immed, r;
ccc6cda3 736 char *ret;
726f6388 737
ccc6cda3
JA
738 old_immed = interrupt_immediately;
739 interrupt_immediately = 1;
7117c2d2 740 tilde_additional_prefixes = assign_p ? bash_tilde_prefixes : (char **)0;
f73dda09
JA
741 r = (*s == '~') ? unquoted_tilde_word (s) : 1;
742 ret = r ? tilde_expand (s) : savestring (s);
ccc6cda3
JA
743 interrupt_immediately = old_immed;
744 return (ret);
726f6388 745}
d166f048
JA
746
747/* **************************************************************** */
748/* */
749/* Functions to manipulate and search the group list */
750/* */
751/* **************************************************************** */
752
753static int ngroups, maxgroups;
754
755/* The set of groups that this user is a member of. */
756static GETGROUPS_T *group_array = (GETGROUPS_T *)NULL;
757
758#if !defined (NOGROUP)
759# define NOGROUP (gid_t) -1
760#endif
761
d166f048
JA
762static void
763initialize_group_array ()
764{
765 register int i;
766
767 if (maxgroups == 0)
768 maxgroups = getmaxgroups ();
769
770 ngroups = 0;
771 group_array = (GETGROUPS_T *)xrealloc (group_array, maxgroups * sizeof (GETGROUPS_T));
772
773#if defined (HAVE_GETGROUPS)
774 ngroups = getgroups (maxgroups, group_array);
775#endif
776
777 /* If getgroups returns nothing, or the OS does not support getgroups(),
778 make sure the groups array includes at least the current gid. */
779 if (ngroups == 0)
780 {
781 group_array[0] = current_user.gid;
782 ngroups = 1;
783 }
784
785 /* If the primary group is not in the groups array, add it as group_array[0]
786 and shuffle everything else up 1, if there's room. */
787 for (i = 0; i < ngroups; i++)
788 if (current_user.gid == (gid_t)group_array[i])
789 break;
790 if (i == ngroups && ngroups < maxgroups)
791 {
792 for (i = ngroups; i > 0; i--)
28ef6c31 793 group_array[i] = group_array[i - 1];
d166f048
JA
794 group_array[0] = current_user.gid;
795 ngroups++;
796 }
cce855bc
JA
797
798 /* If the primary group is not group_array[0], swap group_array[0] and
799 whatever the current group is. The vast majority of systems should
800 not need this; a notable exception is Linux. */
801 if (group_array[0] != current_user.gid)
802 {
803 for (i = 0; i < ngroups; i++)
28ef6c31
JA
804 if (group_array[i] == current_user.gid)
805 break;
cce855bc
JA
806 if (i < ngroups)
807 {
808 group_array[i] = group_array[0];
809 group_array[0] = current_user.gid;
810 }
811 }
d166f048
JA
812}
813
814/* Return non-zero if GID is one that we have in our groups list. */
815int
cce855bc
JA
816#if defined (__STDC__) || defined ( _MINIX)
817group_member (gid_t gid)
818#else
d166f048
JA
819group_member (gid)
820 gid_t gid;
cce855bc 821#endif /* !__STDC__ && !_MINIX */
d166f048
JA
822{
823#if defined (HAVE_GETGROUPS)
824 register int i;
825#endif
826
827 /* Short-circuit if possible, maybe saving a call to getgroups(). */
828 if (gid == current_user.gid || gid == current_user.egid)
829 return (1);
830
831#if defined (HAVE_GETGROUPS)
832 if (ngroups == 0)
833 initialize_group_array ();
834
835 /* In case of error, the user loses. */
836 if (ngroups <= 0)
837 return (0);
838
839 /* Search through the list looking for GID. */
840 for (i = 0; i < ngroups; i++)
841 if (gid == (gid_t)group_array[i])
842 return (1);
843#endif
844
845 return (0);
846}
847
848char **
849get_group_list (ngp)
850 int *ngp;
851{
852 static char **group_vector = (char **)NULL;
853 register int i;
d166f048
JA
854
855 if (group_vector)
856 {
857 if (ngp)
858 *ngp = ngroups;
859 return group_vector;
860 }
861
862 if (ngroups == 0)
863 initialize_group_array ();
864
865 if (ngroups <= 0)
866 {
867 if (ngp)
868 *ngp = 0;
869 return (char **)NULL;
870 }
871
7117c2d2 872 group_vector = strvec_create (ngroups);
d166f048 873 for (i = 0; i < ngroups; i++)
7117c2d2 874 group_vector[i] = itos (group_array[i]);
b72432fd 875
d166f048
JA
876 if (ngp)
877 *ngp = ngroups;
878 return group_vector;
879}
b72432fd
JA
880
881int *
882get_group_array (ngp)
883 int *ngp;
884{
885 int i;
886 static int *group_iarray = (int *)NULL;
887
888 if (group_iarray)
889 {
890 if (ngp)
891 *ngp = ngroups;
892 return (group_iarray);
893 }
894
895 if (ngroups == 0)
896 initialize_group_array ();
897
898 if (ngroups <= 0)
899 {
900 if (ngp)
901 *ngp = 0;
902 return (int *)NULL;
903 }
904
905 group_iarray = (int *)xmalloc (ngroups * sizeof (int));
906 for (i = 0; i < ngroups; i++)
907 group_iarray[i] = (int)group_array[i];
908
909 if (ngp)
910 *ngp = ngroups;
911 return group_iarray;
912}