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