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