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