blob: 5b978dcf82fc565fc9fd03795c53d53045850541 [file] [log] [blame]
Jari Aalto726f6381996-08-26 18:22:31 +00001/* general.c -- Stuff that is used by all files. */
2
3/* Copyright (C) 1987, 1988, 1989, 1990, 1991, 1992
4 Free Software Foundation, Inc.
5
6 This file is part of GNU Bash, the Bourne Again SHell.
7
8 Bash is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
11 version.
12
13 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License along
19 with Bash; see the file COPYING. If not, write to the Free Software
20 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
21
Jari Aaltoccc6cda1996-12-23 17:02:34 +000022#include "config.h"
23
24#include "bashtypes.h"
Jari Aaltocce855b1998-04-17 19:52:44 +000025#ifndef _MINIX
26# include <sys/param.h>
27#endif
Jari Aaltoccc6cda1996-12-23 17:02:34 +000028#include "posixstat.h"
29
30#if defined (HAVE_UNISTD_H)
31# include <unistd.h>
32#endif
33
34#include "filecntl.h"
35#include "bashansi.h"
Jari Aalto726f6381996-08-26 18:22:31 +000036#include <stdio.h>
37#include <ctype.h>
38#include <errno.h>
Jari Aaltoccc6cda1996-12-23 17:02:34 +000039
Jari Aalto726f6381996-08-26 18:22:31 +000040#include "shell.h"
41#include <tilde/tilde.h>
42
Jari Aaltoccc6cda1996-12-23 17:02:34 +000043#if defined (TIME_WITH_SYS_TIME)
Jari Aalto726f6381996-08-26 18:22:31 +000044# include <sys/time.h>
Jari Aaltoccc6cda1996-12-23 17:02:34 +000045# include <time.h>
46#else
47# if defined (HAVE_SYS_TIME_H)
48# include <sys/time.h>
49# else
50# include <time.h>
51# endif
Jari Aalto726f6381996-08-26 18:22:31 +000052#endif
53
54#include <sys/times.h>
55#include "maxpath.h"
56
57#if !defined (errno)
58extern int errno;
59#endif /* !errno */
60
Jari Aaltoccc6cda1996-12-23 17:02:34 +000061#ifndef to_upper
62# define to_upper(c) (islower(c) ? toupper(c) : (c))
63# define to_lower(c) (isupper(c) ? tolower(c) : (c))
64#endif
Jari Aalto726f6381996-08-26 18:22:31 +000065
Jari Aaltoccc6cda1996-12-23 17:02:34 +000066extern int interrupt_immediately;
67extern int interactive_comments;
Jari Aaltocce855b1998-04-17 19:52:44 +000068
69/* A standard error message to use when getcwd() returns NULL. */
70char *bash_getcwd_errstr = "getcwd: cannot access parent directories";
Jari Aalto726f6381996-08-26 18:22:31 +000071
Jari Aaltoccc6cda1996-12-23 17:02:34 +000072/* Do whatever is necessary to initialize `Posix mode'. */
Jari Aalto726f6381996-08-26 18:22:31 +000073void
Jari Aaltoccc6cda1996-12-23 17:02:34 +000074posix_initialize (on)
75 int on;
Jari Aalto726f6381996-08-26 18:22:31 +000076{
Jari Aaltoccc6cda1996-12-23 17:02:34 +000077 interactive_comments = on != 0;
Jari Aalto726f6381996-08-26 18:22:31 +000078}
79
80/* **************************************************************** */
81/* */
Jari Aaltoccc6cda1996-12-23 17:02:34 +000082/* Functions to convert to and from and display non-standard types */
83/* */
84/* **************************************************************** */
85
Jari Aalto726f6381996-08-26 18:22:31 +000086#if defined (RLIMTYPE)
87RLIMTYPE
88string_to_rlimtype (s)
89 char *s;
90{
Jari Aaltocce855b1998-04-17 19:52:44 +000091 RLIMTYPE ret;
92 int neg;
Jari Aalto726f6381996-08-26 18:22:31 +000093
Jari Aaltocce855b1998-04-17 19:52:44 +000094 ret = 0;
95 neg = 0;
Jari Aalto726f6381996-08-26 18:22:31 +000096 while (s && *s && whitespace (*s))
97 s++;
98 if (*s == '-' || *s == '+')
99 {
100 neg = *s == '-';
101 s++;
102 }
103 for ( ; s && *s && digit (*s); s++)
104 ret = (ret * 10) + digit_value (*s);
105 return (neg ? -ret : ret);
106}
107
108void
109print_rlimtype (n, addnl)
110 RLIMTYPE n;
111 int addnl;
112{
113 char s[sizeof (RLIMTYPE) * 3 + 1];
Jari Aaltocce855b1998-04-17 19:52:44 +0000114 int len;
Jari Aalto726f6381996-08-26 18:22:31 +0000115
116 if (n == 0)
117 {
118 printf ("0%s", addnl ? "\n" : "");
119 return;
120 }
121
122 if (n < 0)
123 {
124 putchar ('-');
125 n = -n;
126 }
127
Jari Aaltocce855b1998-04-17 19:52:44 +0000128 len = sizeof (RLIMTYPE) * 3 + 1;
Jari Aalto726f6381996-08-26 18:22:31 +0000129 s[--len] = '\0';
130 for ( ; n != 0; n /= 10)
131 s[--len] = n % 10 + '0';
132 printf ("%s%s", s + len, addnl ? "\n" : "");
133}
134#endif /* RLIMTYPE */
135
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000136#if defined (HAVE_TIMEVAL)
137/* Convert a pointer to a struct timeval to seconds and thousandths of a
138 second, returning the values in *SP and *SFP, respectively. This does
139 rounding on the fractional part, not just truncation to three places. */
140void
141timeval_to_secs (tvp, sp, sfp)
142 struct timeval *tvp;
143 long *sp;
144 int *sfp;
145{
146 int rest;
147
148 *sp = tvp->tv_sec;
149
150 *sfp = tvp->tv_usec % 1000000; /* pretty much a no-op */
151 rest = *sfp % 1000;
152 *sfp = (*sfp * 1000) / 1000000;
153 if (rest >= 500)
154 *sfp += 1;
Jari Aaltob72432f1999-02-19 17:11:39 +0000155
156 /* Sanity check */
157 if (*sfp >= 1000)
158 {
159 *sp += 1;
160 *sfp -= 1000;
161 }
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000162}
163
164/* Print the contents of a struct timeval * in a standard way to stdio
165 stream FP. */
166void
167print_timeval (fp, tvp)
168 FILE *fp;
169 struct timeval *tvp;
170{
171 int minutes, seconds_fraction;
172 long seconds;
173
174 timeval_to_secs (tvp, &seconds, &seconds_fraction);
175
176 minutes = seconds / 60;
177 seconds %= 60;
178
179 fprintf (fp, "%0dm%0ld.%03ds", minutes, seconds, seconds_fraction);
180}
181#endif /* HAVE_TIMEVAL */
182
183#if defined (HAVE_TIMES)
184void
185clock_t_to_secs (t, sp, sfp)
186 clock_t t;
187 long *sp;
188 int *sfp;
189{
190 static long clk_tck = 0;
191
192 if (clk_tck == 0)
193 clk_tck = get_clk_tck ();
194
195 *sfp = t % clk_tck;
196 *sfp = (*sfp * 1000) / clk_tck;
197
198 *sp = t / clk_tck;
Jari Aaltob72432f1999-02-19 17:11:39 +0000199
200 /* Sanity check */
201 if (*sfp >= 1000)
202 {
203 *sp += 1;
204 *sfp -= 1000;
205 }
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000206}
207
208/* Print the time defined by a time_t (returned by the `times' and `time'
209 system calls) in a standard way to stdion stream FP. This is scaled in
210 terms of HZ, which is what is returned by the `times' call. */
211void
212print_time_in_hz (fp, t)
213 FILE *fp;
214 clock_t t;
215{
216 int minutes, seconds_fraction;
217 long seconds;
218
219 clock_t_to_secs (t, &seconds, &seconds_fraction);
220
221 minutes = seconds / 60;
222 seconds %= 60;
223
224 fprintf (fp, "%0dm%0ld.%03ds", minutes, seconds, seconds_fraction);
225}
226#endif /* HAVE_TIMES */
227
228/* **************************************************************** */
229/* */
230/* Input Validation Functions */
231/* */
232/* **************************************************************** */
233
234/* Return non-zero if all of the characters in STRING are digits. */
235int
236all_digits (string)
237 char *string;
238{
239 while (*string)
240 {
241 if (!digit (*string))
242 return (0);
243 else
244 string++;
245 }
246 return (1);
247}
248
249/* Return non-zero if the characters pointed to by STRING constitute a
250 valid number. Stuff the converted number into RESULT if RESULT is
251 a non-null pointer to a long. */
252int
253legal_number (string, result)
254 char *string;
255 long *result;
256{
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000257 long value;
Jari Aaltocce855b1998-04-17 19:52:44 +0000258 char *ep;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000259
260 if (result)
261 *result = 0;
262
Jari Aaltocce855b1998-04-17 19:52:44 +0000263 value = strtol (string, &ep, 10);
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000264
Jari Aaltocce855b1998-04-17 19:52:44 +0000265 /* If *string is not '\0' but *ep is '\0' on return, the entire string
266 is valid. */
267 if (string && *string && *ep == '\0')
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000268 {
269 if (result)
Jari Aaltocce855b1998-04-17 19:52:44 +0000270 *result = value;
271 /* The SunOS4 implementation of strtol() will happily ignore
272 overflow conditions, so this cannot do overflow correctly
273 on those systems. */
274 return 1;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000275 }
Jari Aaltocce855b1998-04-17 19:52:44 +0000276
277 return (0);
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000278}
279
Jari Aalto726f6381996-08-26 18:22:31 +0000280/* Return 1 if this token is a legal shell `identifier'; that is, it consists
281 solely of letters, digits, and underscores, and does not begin with a
282 digit. */
283int
284legal_identifier (name)
285 char *name;
286{
287 register char *s;
288
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000289 if (!name || !*name || (legal_variable_starter (*name) == 0))
Jari Aalto726f6381996-08-26 18:22:31 +0000290 return (0);
291
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000292 for (s = name + 1; *s; s++)
Jari Aalto726f6381996-08-26 18:22:31 +0000293 {
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000294 if (legal_variable_char (*s) == 0)
Jari Aalto726f6381996-08-26 18:22:31 +0000295 return (0);
296 }
297 return (1);
298}
299
300/* Make sure that WORD is a valid shell identifier, i.e.
301 does not contain a dollar sign, nor is quoted in any way. Nor
302 does it consist of all digits. If CHECK_WORD is non-zero,
303 the word is checked to ensure that it consists of only letters,
304 digits, and underscores. */
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000305int
Jari Aalto726f6381996-08-26 18:22:31 +0000306check_identifier (word, check_word)
307 WORD_DESC *word;
308 int check_word;
309{
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000310 if ((word->flags & (W_HASDOLLAR|W_QUOTED)) || all_digits (word->word))
Jari Aalto726f6381996-08-26 18:22:31 +0000311 {
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000312 internal_error ("`%s': not a valid identifier", word->word);
Jari Aalto726f6381996-08-26 18:22:31 +0000313 return (0);
314 }
315 else if (check_word && legal_identifier (word->word) == 0)
316 {
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000317 internal_error ("`%s': not a valid identifier", word->word);
Jari Aalto726f6381996-08-26 18:22:31 +0000318 return (0);
319 }
320 else
321 return (1);
322}
323
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000324/* **************************************************************** */
325/* */
326/* Functions to manage files and file descriptors */
327/* */
328/* **************************************************************** */
329
Jari Aalto726f6381996-08-26 18:22:31 +0000330/* A function to unset no-delay mode on a file descriptor. Used in shell.c
331 to unset it on the fd passed as stdin. Should be called on stdin if
332 readline gets an EAGAIN or EWOULDBLOCK when trying to read input. */
333
334#if !defined (O_NDELAY)
335# if defined (FNDELAY)
336# define O_NDELAY FNDELAY
337# endif
338#endif /* O_NDELAY */
339
340/* Make sure no-delay mode is not set on file descriptor FD. */
341void
342unset_nodelay_mode (fd)
343 int fd;
344{
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000345 int flags, set;
Jari Aalto726f6381996-08-26 18:22:31 +0000346
347 if ((flags = fcntl (fd, F_GETFL, 0)) < 0)
348 return;
349
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000350 set = 0;
351
352 /* This is defined to O_NDELAY in filecntl.h if O_NONBLOCK is not present
353 and O_NDELAY is defined. */
Jari Aalto726f6381996-08-26 18:22:31 +0000354 if (flags & O_NONBLOCK)
355 {
356 flags &= ~O_NONBLOCK;
357 set++;
358 }
Jari Aalto726f6381996-08-26 18:22:31 +0000359
360 if (set)
361 fcntl (fd, F_SETFL, flags);
362}
363
Jari Aaltob72432f1999-02-19 17:11:39 +0000364/* There is a bug in the NeXT 2.1 rlogind that causes opens
365 of /dev/tty to fail. */
366
367#if defined (__BEOS__)
368/* On BeOS, opening in non-blocking mode exposes a bug in BeOS, so turn it
369 into a no-op. This should probably go away in the future. */
370# undef O_NONBLOCK
371# define O_NONBLOCK 0
372#endif /* __BEOS__ */
373
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000374void
375check_dev_tty ()
376{
377 int tty_fd;
378 char *tty;
379
Jari Aaltod166f041997-06-05 14:59:13 +0000380 tty_fd = open ("/dev/tty", O_RDWR|O_NONBLOCK);
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000381
382 if (tty_fd < 0)
383 {
384 tty = (char *)ttyname (fileno (stdin));
385 if (tty == 0)
386 return;
Jari Aaltod166f041997-06-05 14:59:13 +0000387 tty_fd = open (tty, O_RDWR|O_NONBLOCK);
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000388 }
389 close (tty_fd);
390}
391
392/* Return 1 if PATH1 and PATH2 are the same file. This is kind of
393 expensive. If non-NULL STP1 and STP2 point to stat structures
394 corresponding to PATH1 and PATH2, respectively. */
395int
396same_file (path1, path2, stp1, stp2)
397 char *path1, *path2;
398 struct stat *stp1, *stp2;
399{
400 struct stat st1, st2;
401
402 if (stp1 == NULL)
403 {
404 if (stat (path1, &st1) != 0)
405 return (0);
406 stp1 = &st1;
407 }
408
409 if (stp2 == NULL)
410 {
411 if (stat (path2, &st2) != 0)
412 return (0);
413 stp2 = &st2;
414 }
415
416 return ((stp1->st_dev == stp2->st_dev) && (stp1->st_ino == stp2->st_ino));
417}
418
419/* Move FD to a number close to the maximum number of file descriptors
420 allowed in the shell process, to avoid the user stepping on it with
421 redirection and causing us extra work. If CHECK_NEW is non-zero,
422 we check whether or not the file descriptors are in use before
Jari Aaltod166f041997-06-05 14:59:13 +0000423 duplicating FD onto them. MAXFD says where to start checking the
424 file descriptors. If it's less than 20, we get the maximum value
425 available from getdtablesize(2). */
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000426int
Jari Aaltod166f041997-06-05 14:59:13 +0000427move_to_high_fd (fd, check_new, maxfd)
428 int fd, check_new, maxfd;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000429{
430 int script_fd, nfds, ignore;
431
Jari Aaltod166f041997-06-05 14:59:13 +0000432 if (maxfd < 20)
433 {
434 nfds = getdtablesize ();
435 if (nfds <= 0)
436 nfds = 20;
437 if (nfds > 256)
438 nfds = 256;
439 }
440 else
441 nfds = maxfd;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000442
443 for (nfds--; check_new && nfds > 3; nfds--)
444 if (fcntl (nfds, F_GETFD, &ignore) == -1)
445 break;
446
447 if (nfds && fd != nfds && (script_fd = dup2 (fd, nfds)) != -1)
448 {
449 if (check_new == 0 || fd != fileno (stderr)) /* don't close stderr */
450 close (fd);
451 return (script_fd);
452 }
453
454 return (fd);
455}
456
457/* Return non-zero if the characters from SAMPLE are not all valid
458 characters to be found in the first line of a shell script. We
459 check up to the first newline, or SAMPLE_LEN, whichever comes first.
460 All of the characters must be printable or whitespace. */
461
462#if !defined (isspace)
463#define isspace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\f')
464#endif
465
466#if !defined (isprint)
467#define isprint(c) (isletter(c) || digit(c) || ispunct(c))
468#endif
469
470int
471check_binary_file (sample, sample_len)
472 unsigned char *sample;
473 int sample_len;
474{
475 register int i;
476
477 for (i = 0; i < sample_len; i++)
478 {
479 if (sample[i] == '\n')
480 return (0);
481
482 if (isspace (sample[i]) == 0 && isprint (sample[i]) == 0)
483 return (1);
484 }
485
486 return (0);
487}
Jari Aalto726f6381996-08-26 18:22:31 +0000488
489/* **************************************************************** */
490/* */
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000491/* Functions to manipulate pathnames */
Jari Aalto726f6381996-08-26 18:22:31 +0000492/* */
493/* **************************************************************** */
494
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000495/* Return 1 if PATH corresponds to a directory. */
496static int
497canon_stat (path)
498 char *path;
Jari Aalto726f6381996-08-26 18:22:31 +0000499{
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000500 int l;
501 char *s;
502 struct stat sb;
Jari Aalto726f6381996-08-26 18:22:31 +0000503
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000504 l = strlen (path);
505 s = xmalloc (l + 3);
506 strcpy (s, path);
507 s[l] = '/';
508 s[l+1] = '.';
509 s[l+2] = '\0';
510 l = stat (s, &sb) == 0 && S_ISDIR (sb.st_mode);
511 free (s);
512 return l;
Jari Aalto726f6381996-08-26 18:22:31 +0000513}
514
515/* Canonicalize PATH, and return a new path. The new path differs from PATH
516 in that:
517 Multple `/'s are collapsed to a single `/'.
518 Leading `./'s and trailing `/.'s are removed.
519 Trailing `/'s are removed.
520 Non-leading `../'s and trailing `..'s are handled by removing
521 portions of the path. */
522char *
523canonicalize_pathname (path)
524 char *path;
525{
526 register int i, start;
527 char stub_char;
528 char *result;
529
530 /* The result cannot be larger than the input PATH. */
531 result = savestring (path);
532
533 stub_char = (*path == '/') ? '/' : '.';
534
535 /* Walk along RESULT looking for things to compact. */
536 i = 0;
537 while (1)
538 {
539 if (!result[i])
540 break;
541
542 while (result[i] && result[i] != '/')
543 i++;
544
545 start = i++;
546
547 /* If we didn't find any slashes, then there is nothing left to do. */
548 if (!result[start])
549 break;
550
551 /* Handle multiple `/'s in a row. */
552 while (result[i] == '/')
553 i++;
554
Jari Aaltod166f041997-06-05 14:59:13 +0000555#if 0
Jari Aalto726f6381996-08-26 18:22:31 +0000556 if ((start + 1) != i)
557#else
Jari Aaltod166f041997-06-05 14:59:13 +0000558 /* Leave a leading `//' alone, as POSIX requires. */
Jari Aalto726f6381996-08-26 18:22:31 +0000559 if ((start + 1) != i && (start != 0 || i != 2))
Jari Aaltod166f041997-06-05 14:59:13 +0000560#endif
Jari Aalto726f6381996-08-26 18:22:31 +0000561 {
562 strcpy (result + start + 1, result + i);
563 i = start + 1;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000564 /* Make sure that what we have so far corresponds to a directory.
565 If it does not, just punt. */
566 if (*result)
567 {
568 char c;
569 c = result[start];
570 result[start] = '\0';
571 if (canon_stat (result) == 0)
572 {
573 free (result);
574 return ((char *)NULL);
575 }
576 result[start] = c;
577 }
Jari Aalto726f6381996-08-26 18:22:31 +0000578 }
Jari Aalto726f6381996-08-26 18:22:31 +0000579#if 0
580 /* Handle backslash-quoted `/'. */
581 if (start > 0 && result[start - 1] == '\\')
582 continue;
583#endif
584
585 /* Check for trailing `/'. */
586 if (start && !result[i])
587 {
588 zero_last:
589 result[--i] = '\0';
590 break;
591 }
592
593 /* Check for `../', `./' or trailing `.' by itself. */
594 if (result[i] == '.')
595 {
596 /* Handle trailing `.' by itself. */
597 if (!result[i + 1])
598 goto zero_last;
599
600 /* Handle `./'. */
601 if (result[i + 1] == '/')
602 {
603 strcpy (result + i, result + i + 1);
604 i = (start < 0) ? 0 : start;
605 continue;
606 }
607
608 /* Handle `../' or trailing `..' by itself. */
609 if (result[i + 1] == '.' &&
610 (result[i + 2] == '/' || !result[i + 2]))
611 {
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000612 /* Make sure that the last component corresponds to a directory
613 before blindly chopping it off. */
614 if (i)
615 {
616 result[i] = '\0';
617 if (canon_stat (result) == 0)
618 {
619 free (result);
620 return ((char *)NULL);
621 }
622 result[i] = '.';
623 }
Jari Aalto726f6381996-08-26 18:22:31 +0000624 while (--start > -1 && result[start] != '/');
625 strcpy (result + start + 1, result + i + 2);
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000626#if 0 /* Unnecessary */
627 if (*result && canon_stat (result) == 0)
628 {
629 free (result);
630 return ((char *)NULL);
631 }
632#endif
Jari Aalto726f6381996-08-26 18:22:31 +0000633 i = (start < 0) ? 0 : start;
634 continue;
635 }
636 }
637 }
638
639 if (!*result)
640 {
641 *result = stub_char;
642 result[1] = '\0';
643 }
Jari Aaltocce855b1998-04-17 19:52:44 +0000644
Jari Aaltob72432f1999-02-19 17:11:39 +0000645 /* If the result starts with `//', but the original path does not, we
646 can turn the // into /. */
647 if ((result[0] == '/' && result[1] == '/' && result[2] != '/') &&
648 (path[0] != '/' || path[1] != '/' || path[2] == '/'))
649 {
650 char *r2;
651 if (result[2] == '\0') /* short-circuit for bare `//' */
652 result[1] = '\0';
653 else
654 {
655 r2 = savestring (result + 1);
656 free (result);
657 result = r2;
658 }
659 }
Jari Aaltocce855b1998-04-17 19:52:44 +0000660
Jari Aalto726f6381996-08-26 18:22:31 +0000661 return (result);
662}
663
664/* Turn STRING (a pathname) into an absolute pathname, assuming that
665 DOT_PATH contains the symbolic location of `.'. This always
666 returns a new string, even if STRING was an absolute pathname to
667 begin with. */
668char *
669make_absolute (string, dot_path)
670 char *string, *dot_path;
671{
672 char *result;
673 int result_len;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000674
Jari Aaltod166f041997-06-05 14:59:13 +0000675 if (dot_path == 0 || *string == '/')
Jari Aalto726f6381996-08-26 18:22:31 +0000676 result = savestring (string);
677 else
678 {
Jari Aaltod166f041997-06-05 14:59:13 +0000679 if (dot_path[0])
Jari Aalto726f6381996-08-26 18:22:31 +0000680 {
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000681 result_len = strlen (dot_path);
682 result = xmalloc (2 + result_len + strlen (string));
Jari Aalto726f6381996-08-26 18:22:31 +0000683 strcpy (result, dot_path);
Jari Aalto726f6381996-08-26 18:22:31 +0000684 if (result[result_len - 1] != '/')
685 {
686 result[result_len++] = '/';
687 result[result_len] = '\0';
688 }
689 }
690 else
691 {
692 result = xmalloc (3 + strlen (string));
693 result[0] = '.'; result[1] = '/'; result[2] = '\0';
694 result_len = 2;
695 }
696
697 strcpy (result + result_len, string);
698 }
699
700 return (result);
701}
702
703/* Return 1 if STRING contains an absolute pathname, else 0. */
704int
705absolute_pathname (string)
706 char *string;
707{
708 if (!string || !*string)
709 return (0);
710
711 if (*string == '/')
712 return (1);
713
714 if (*string++ == '.')
715 {
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000716 if (!*string || *string == '/' ||
717 (*string == '.' && (string[1] == '\0' || string[1] == '/')))
Jari Aalto726f6381996-08-26 18:22:31 +0000718 return (1);
719 }
720 return (0);
721}
722
723/* Return 1 if STRING is an absolute program name; it is absolute if it
724 contains any slashes. This is used to decide whether or not to look
725 up through $PATH. */
726int
727absolute_program (string)
728 char *string;
729{
730 return ((char *)strchr (string, '/') != (char *)NULL);
731}
732
733/* Return the `basename' of the pathname in STRING (the stuff after the
734 last '/'). If STRING is not a full pathname, simply return it. */
735char *
736base_pathname (string)
737 char *string;
738{
739 char *p;
740
741 if (!absolute_pathname (string))
742 return (string);
743
744 p = (char *)strrchr (string, '/');
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000745 return (p ? ++p : string);
Jari Aalto726f6381996-08-26 18:22:31 +0000746}
747
748/* Return the full pathname of FILE. Easy. Filenames that begin
749 with a '/' are returned as themselves. Other filenames have
750 the current working directory prepended. A new string is
751 returned in either case. */
752char *
753full_pathname (file)
754 char *file;
755{
756 char *disposer;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000757 char *current_dir;
758 int dlen;
Jari Aalto726f6381996-08-26 18:22:31 +0000759
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000760 file = (*file == '~') ? bash_tilde_expand (file) : savestring (file);
Jari Aalto726f6381996-08-26 18:22:31 +0000761
762 if ((*file == '/') && absolute_pathname (file))
763 return (file);
764
765 disposer = file;
766
Jari Aaltod166f041997-06-05 14:59:13 +0000767 /* XXX - this should probably be just PATH_MAX or PATH_MAX + 1 */
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000768 current_dir = xmalloc (2 + PATH_MAX + strlen (file));
769 if (getcwd (current_dir, PATH_MAX) == 0)
Jari Aalto726f6381996-08-26 18:22:31 +0000770 {
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000771 sys_error (bash_getcwd_errstr);
772 free (disposer);
773 free (current_dir);
774 return ((char *)NULL);
Jari Aalto726f6381996-08-26 18:22:31 +0000775 }
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000776 dlen = strlen (current_dir);
Jari Aaltob72432f1999-02-19 17:11:39 +0000777 if (current_dir[0] == '/' && dlen > 1)
778 current_dir[dlen++] = '/';
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000779
780 /* Turn /foo/./bar into /foo/bar. */
781 if (file[0] == '.' && file[1] == '/')
782 file += 2;
783
784 strcpy (current_dir + dlen, file);
785 free (disposer);
786 return (current_dir);
Jari Aalto726f6381996-08-26 18:22:31 +0000787}
788
Jari Aalto726f6381996-08-26 18:22:31 +0000789/* A slightly related function. Get the prettiest name of this
790 directory possible. */
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000791static char tdir[PATH_MAX];
Jari Aalto726f6381996-08-26 18:22:31 +0000792
793/* Return a pretty pathname. If the first part of the pathname is
794 the same as $HOME, then replace that with `~'. */
795char *
796polite_directory_format (name)
797 char *name;
798{
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000799 char *home;
800 int l;
Jari Aalto726f6381996-08-26 18:22:31 +0000801
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000802 home = get_string_value ("HOME");
803 l = home ? strlen (home) : 0;
Jari Aalto726f6381996-08-26 18:22:31 +0000804 if (l > 1 && strncmp (home, name, l) == 0 && (!name[l] || name[l] == '/'))
805 {
Jari Aaltoe8ce7751997-09-22 20:22:27 +0000806 strncpy (tdir + 1, name + l, sizeof(tdir) - 2);
Jari Aalto726f6381996-08-26 18:22:31 +0000807 tdir[0] = '~';
Jari Aaltoe8ce7751997-09-22 20:22:27 +0000808 tdir[sizeof(tdir) - 1] = '\0';
Jari Aalto726f6381996-08-26 18:22:31 +0000809 return (tdir);
810 }
811 else
812 return (name);
813}
814
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000815/* Given a string containing units of information separated by colons,
816 return the next one pointed to by (P_INDEX), or NULL if there are no more.
817 Advance (P_INDEX) to the character after the colon. */
818char *
819extract_colon_unit (string, p_index)
820 char *string;
821 int *p_index;
Jari Aalto726f6381996-08-26 18:22:31 +0000822{
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000823 int i, start, len;
824 char *value;
825
826 if (string == 0)
827 return (string);
828
829 len = strlen (string);
830 if (*p_index >= len)
831 return ((char *)NULL);
832
833 i = *p_index;
834
835 /* Each call to this routine leaves the index pointing at a colon if
836 there is more to the path. If I is > 0, then increment past the
837 `:'. If I is 0, then the path has a leading colon. Trailing colons
838 are handled OK by the `else' part of the if statement; an empty
839 string is returned in that case. */
840 if (i && string[i] == ':')
841 i++;
842
843 for (start = i; string[i] && string[i] != ':'; i++)
844 ;
845
846 *p_index = i;
847
848 if (i == start)
Jari Aalto726f6381996-08-26 18:22:31 +0000849 {
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000850 if (string[i])
851 (*p_index)++;
852 /* Return "" in the case of a trailing `:'. */
853 value = xmalloc (1);
854 value[0] = '\0';
Jari Aalto726f6381996-08-26 18:22:31 +0000855 }
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000856 else
857 {
858 len = i - start;
859 value = xmalloc (1 + len);
860 strncpy (value, string + start, len);
861 value [len] = '\0';
862 }
863
864 return (value);
Jari Aalto726f6381996-08-26 18:22:31 +0000865}
866
Jari Aalto726f6381996-08-26 18:22:31 +0000867/* **************************************************************** */
868/* */
869/* Tilde Initialization and Expansion */
870/* */
871/* **************************************************************** */
872
Jari Aaltocce855b1998-04-17 19:52:44 +0000873#if defined (PUSHD_AND_POPD)
874extern char *get_dirstack_from_string __P((char *));
875#endif
876
Jari Aalto726f6381996-08-26 18:22:31 +0000877/* If tilde_expand hasn't been able to expand the text, perhaps it
878 is a special shell expansion. This function is installed as the
Jari Aaltocce855b1998-04-17 19:52:44 +0000879 tilde_expansion_preexpansion_hook. It knows how to expand ~- and ~+.
880 If PUSHD_AND_POPD is defined, ~[+-]N expands to directories from the
881 directory stack. */
Jari Aalto726f6381996-08-26 18:22:31 +0000882static char *
Jari Aaltod166f041997-06-05 14:59:13 +0000883bash_special_tilde_expansions (text)
Jari Aalto726f6381996-08-26 18:22:31 +0000884 char *text;
885{
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000886 char *result;
Jari Aalto726f6381996-08-26 18:22:31 +0000887
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000888 result = (char *)NULL;
Jari Aaltocce855b1998-04-17 19:52:44 +0000889
890 if (text[0] == '+' && text[1] == '\0')
891 result = get_string_value ("PWD");
892 else if (text[0] == '-' && text[1] == '\0')
893 result = get_string_value ("OLDPWD");
894#if defined (PUSHD_AND_POPD)
895 else if (isdigit (*text) || ((*text == '+' || *text == '-') && isdigit (text[1])))
896 result = get_dirstack_from_string (text);
897#endif
Jari Aalto726f6381996-08-26 18:22:31 +0000898
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000899 return (result ? savestring (result) : (char *)NULL);
Jari Aalto726f6381996-08-26 18:22:31 +0000900}
901
902/* Initialize the tilde expander. In Bash, we handle `~-' and `~+', as
903 well as handling special tilde prefixes; `:~" and `=~' are indications
904 that we should do tilde expansion. */
905void
906tilde_initialize ()
907{
908 static int times_called = 0;
909
Jari Aaltod166f041997-06-05 14:59:13 +0000910 /* Tell the tilde expander that we want a crack first. */
911 tilde_expansion_preexpansion_hook = (CPFunction *)bash_special_tilde_expansions;
Jari Aalto726f6381996-08-26 18:22:31 +0000912
913 /* Tell the tilde expander about special strings which start a tilde
914 expansion, and the special strings that end one. Only do this once.
915 tilde_initialize () is called from within bashline_reinitialize (). */
Jari Aaltocce855b1998-04-17 19:52:44 +0000916 if (times_called++ == 0)
Jari Aalto726f6381996-08-26 18:22:31 +0000917 {
918 tilde_additional_prefixes = (char **)xmalloc (3 * sizeof (char *));
919 tilde_additional_prefixes[0] = "=~";
920 tilde_additional_prefixes[1] = ":~";
921 tilde_additional_prefixes[2] = (char *)NULL;
922
923 tilde_additional_suffixes = (char **)xmalloc (3 * sizeof (char *));
924 tilde_additional_suffixes[0] = ":";
925 tilde_additional_suffixes[1] = "=~";
926 tilde_additional_suffixes[2] = (char *)NULL;
927 }
Jari Aalto726f6381996-08-26 18:22:31 +0000928}
929
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000930char *
931bash_tilde_expand (s)
932 char *s;
Jari Aalto726f6381996-08-26 18:22:31 +0000933{
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000934 int old_immed;
935 char *ret;
Jari Aalto726f6381996-08-26 18:22:31 +0000936
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000937 old_immed = interrupt_immediately;
938 interrupt_immediately = 1;
939 ret = tilde_expand (s);
940 interrupt_immediately = old_immed;
941 return (ret);
Jari Aalto726f6381996-08-26 18:22:31 +0000942}
Jari Aaltod166f041997-06-05 14:59:13 +0000943
944/* **************************************************************** */
945/* */
946/* Functions to manipulate and search the group list */
947/* */
948/* **************************************************************** */
949
950static int ngroups, maxgroups;
951
952/* The set of groups that this user is a member of. */
953static GETGROUPS_T *group_array = (GETGROUPS_T *)NULL;
954
955#if !defined (NOGROUP)
956# define NOGROUP (gid_t) -1
957#endif
958
959#if defined (HAVE_SYSCONF) && defined (_SC_NGROUPS_MAX)
960# define getmaxgroups() sysconf(_SC_NGROUPS_MAX)
961#else
962# if defined (NGROUPS_MAX)
963# define getmaxgroups() NGROUPS_MAX
964# else /* !NGROUPS_MAX */
965# if defined (NGROUPS)
966# define getmaxgroups() NGROUPS
967# else /* !NGROUPS */
968# define getmaxgroups() 64
969# endif /* !NGROUPS */
970# endif /* !NGROUPS_MAX */
971#endif /* !HAVE_SYSCONF || !SC_NGROUPS_MAX */
972
973static void
974initialize_group_array ()
975{
976 register int i;
977
978 if (maxgroups == 0)
979 maxgroups = getmaxgroups ();
980
981 ngroups = 0;
982 group_array = (GETGROUPS_T *)xrealloc (group_array, maxgroups * sizeof (GETGROUPS_T));
983
984#if defined (HAVE_GETGROUPS)
985 ngroups = getgroups (maxgroups, group_array);
986#endif
987
988 /* If getgroups returns nothing, or the OS does not support getgroups(),
989 make sure the groups array includes at least the current gid. */
990 if (ngroups == 0)
991 {
992 group_array[0] = current_user.gid;
993 ngroups = 1;
994 }
995
996 /* If the primary group is not in the groups array, add it as group_array[0]
997 and shuffle everything else up 1, if there's room. */
998 for (i = 0; i < ngroups; i++)
999 if (current_user.gid == (gid_t)group_array[i])
1000 break;
1001 if (i == ngroups && ngroups < maxgroups)
1002 {
1003 for (i = ngroups; i > 0; i--)
1004 group_array[i] = group_array[i - 1];
1005 group_array[0] = current_user.gid;
1006 ngroups++;
1007 }
Jari Aaltocce855b1998-04-17 19:52:44 +00001008
1009 /* If the primary group is not group_array[0], swap group_array[0] and
1010 whatever the current group is. The vast majority of systems should
1011 not need this; a notable exception is Linux. */
1012 if (group_array[0] != current_user.gid)
1013 {
1014 for (i = 0; i < ngroups; i++)
1015 if (group_array[i] == current_user.gid)
1016 break;
1017 if (i < ngroups)
1018 {
1019 group_array[i] = group_array[0];
1020 group_array[0] = current_user.gid;
1021 }
1022 }
Jari Aaltod166f041997-06-05 14:59:13 +00001023}
1024
1025/* Return non-zero if GID is one that we have in our groups list. */
1026int
Jari Aaltocce855b1998-04-17 19:52:44 +00001027#if defined (__STDC__) || defined ( _MINIX)
1028group_member (gid_t gid)
1029#else
Jari Aaltod166f041997-06-05 14:59:13 +00001030group_member (gid)
1031 gid_t gid;
Jari Aaltocce855b1998-04-17 19:52:44 +00001032#endif /* !__STDC__ && !_MINIX */
Jari Aaltod166f041997-06-05 14:59:13 +00001033{
1034#if defined (HAVE_GETGROUPS)
1035 register int i;
1036#endif
1037
1038 /* Short-circuit if possible, maybe saving a call to getgroups(). */
1039 if (gid == current_user.gid || gid == current_user.egid)
1040 return (1);
1041
1042#if defined (HAVE_GETGROUPS)
1043 if (ngroups == 0)
1044 initialize_group_array ();
1045
1046 /* In case of error, the user loses. */
1047 if (ngroups <= 0)
1048 return (0);
1049
1050 /* Search through the list looking for GID. */
1051 for (i = 0; i < ngroups; i++)
1052 if (gid == (gid_t)group_array[i])
1053 return (1);
1054#endif
1055
1056 return (0);
1057}
1058
1059char **
1060get_group_list (ngp)
1061 int *ngp;
1062{
1063 static char **group_vector = (char **)NULL;
1064 register int i;
1065 char *nbuf;
1066
1067 if (group_vector)
1068 {
1069 if (ngp)
1070 *ngp = ngroups;
1071 return group_vector;
1072 }
1073
1074 if (ngroups == 0)
1075 initialize_group_array ();
1076
1077 if (ngroups <= 0)
1078 {
1079 if (ngp)
1080 *ngp = 0;
1081 return (char **)NULL;
1082 }
1083
1084 group_vector = (char **)xmalloc (ngroups * sizeof (char *));
1085 for (i = 0; i < ngroups; i++)
1086 {
1087 nbuf = itos ((int)group_array[i]);
1088 group_vector[i] = nbuf;
1089 }
Jari Aaltob72432f1999-02-19 17:11:39 +00001090
Jari Aaltod166f041997-06-05 14:59:13 +00001091 if (ngp)
1092 *ngp = ngroups;
1093 return group_vector;
1094}
Jari Aaltob72432f1999-02-19 17:11:39 +00001095
1096int *
1097get_group_array (ngp)
1098 int *ngp;
1099{
1100 int i;
1101 static int *group_iarray = (int *)NULL;
1102
1103 if (group_iarray)
1104 {
1105 if (ngp)
1106 *ngp = ngroups;
1107 return (group_iarray);
1108 }
1109
1110 if (ngroups == 0)
1111 initialize_group_array ();
1112
1113 if (ngroups <= 0)
1114 {
1115 if (ngp)
1116 *ngp = 0;
1117 return (int *)NULL;
1118 }
1119
1120 group_iarray = (int *)xmalloc (ngroups * sizeof (int));
1121 for (i = 0; i < ngroups; i++)
1122 group_iarray[i] = (int)group_array[i];
1123
1124 if (ngp)
1125 *ngp = ngroups;
1126 return group_iarray;
1127}