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