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