1 /* general.c -- Stuff that is used by all files. */
3 /* Copyright (C) 1987, 1988, 1989, 1990, 1991, 1992
4 Free Software Foundation, Inc.
6 This file is part of GNU Bash, the Bourne Again SHell.
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
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
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. */
24 #include "bashtypes.h"
25 #include <sys/param.h>
26 #include "posixstat.h"
28 #if defined (HAVE_UNISTD_H)
39 #include <tilde/tilde.h>
41 #if defined (TIME_WITH_SYS_TIME)
42 # include <sys/time.h>
45 # if defined (HAVE_SYS_TIME_H)
46 # include <sys/time.h>
52 #include <sys/times.h>
60 # define to_upper(c) (islower(c) ? toupper(c) : (c))
61 # define to_lower(c) (isupper(c) ? tolower(c) : (c))
64 extern int interrupt_immediately;
65 extern int interactive_comments;
66 extern char *bash_getcwd_errstr;
68 /* Do whatever is necessary to initialize `Posix mode'. */
73 interactive_comments = on != 0;
76 /* **************************************************************** */
78 /* Integer to String Conversion */
80 /* **************************************************************** */
82 /* Number of characters that can appear in a string representation
83 of an integer. 32 is larger than the string rep of 2^^31 - 1. */
84 #define MAX_INT_LEN 32
86 /* Integer to string conversion. This conses the string; the
87 caller should free it. */
92 char buf[MAX_INT_LEN], *p, *ret;
102 ui = (unsigned int) i;
104 p = buf + MAX_INT_LEN - 2;
108 *p-- = (ui % 10) + '0';
114 ret = savestring (p + 1);
118 /* atol(3) is not universal */
126 while (s && *s && whitespace (*s))
128 if (*s == '-' || *s == '+')
133 for ( ; s && *s && digit (*s); s++)
134 ret = (ret * 10) + digit_value (*s);
135 return (neg ? -ret : ret);
138 /* **************************************************************** */
140 /* Functions to convert to and from and display non-standard types */
142 /* **************************************************************** */
144 #if defined (RLIMTYPE)
146 string_to_rlimtype (s)
152 while (s && *s && whitespace (*s))
154 if (*s == '-' || *s == '+')
159 for ( ; s && *s && digit (*s); s++)
160 ret = (ret * 10) + digit_value (*s);
161 return (neg ? -ret : ret);
165 print_rlimtype (n, addnl)
169 char s[sizeof (RLIMTYPE) * 3 + 1];
170 int len = sizeof (RLIMTYPE) * 3 + 1;
174 printf ("0%s", addnl ? "\n" : "");
185 for ( ; n != 0; n /= 10)
186 s[--len] = n % 10 + '0';
187 printf ("%s%s", s + len, addnl ? "\n" : "");
189 #endif /* RLIMTYPE */
191 #if defined (HAVE_TIMEVAL)
192 /* Convert a pointer to a struct timeval to seconds and thousandths of a
193 second, returning the values in *SP and *SFP, respectively. This does
194 rounding on the fractional part, not just truncation to three places. */
196 timeval_to_secs (tvp, sp, sfp)
205 *sfp = tvp->tv_usec % 1000000; /* pretty much a no-op */
207 *sfp = (*sfp * 1000) / 1000000;
212 /* Print the contents of a struct timeval * in a standard way to stdio
215 print_timeval (fp, tvp)
219 int minutes, seconds_fraction;
222 timeval_to_secs (tvp, &seconds, &seconds_fraction);
224 minutes = seconds / 60;
227 fprintf (fp, "%0dm%0ld.%03ds", minutes, seconds, seconds_fraction);
229 #endif /* HAVE_TIMEVAL */
231 #if defined (HAVE_TIMES)
233 clock_t_to_secs (t, sp, sfp)
238 static long clk_tck = 0;
241 clk_tck = get_clk_tck ();
244 *sfp = (*sfp * 1000) / clk_tck;
249 /* Print the time defined by a time_t (returned by the `times' and `time'
250 system calls) in a standard way to stdion stream FP. This is scaled in
251 terms of HZ, which is what is returned by the `times' call. */
253 print_time_in_hz (fp, t)
257 int minutes, seconds_fraction;
260 clock_t_to_secs (t, &seconds, &seconds_fraction);
262 minutes = seconds / 60;
265 fprintf (fp, "%0dm%0ld.%03ds", minutes, seconds, seconds_fraction);
267 #endif /* HAVE_TIMES */
269 /* **************************************************************** */
271 /* Input Validation Functions */
273 /* **************************************************************** */
275 /* Return non-zero if all of the characters in STRING are digits. */
282 if (!digit (*string))
290 /* Return non-zero if the characters pointed to by STRING constitute a
291 valid number. Stuff the converted number into RESULT if RESULT is
292 a non-null pointer to a long. */
294 legal_number (string, result)
307 /* Skip leading whitespace characters. */
308 while (whitespace (*string))
314 /* We allow leading `-' or `+'. */
315 if (*string == '-' || *string == '+')
317 if (!digit (string[1]))
326 while (digit (*string))
329 value = (value * 10) + digit_value (*string);
333 /* Skip trailing whitespace, if any. */
334 while (whitespace (*string))
337 /* Error if not at end of string. */
342 *result = value * sign;
347 /* Return 1 if this token is a legal shell `identifier'; that is, it consists
348 solely of letters, digits, and underscores, and does not begin with a
351 legal_identifier (name)
356 if (!name || !*name || (legal_variable_starter (*name) == 0))
359 for (s = name + 1; *s; s++)
361 if (legal_variable_char (*s) == 0)
367 /* Make sure that WORD is a valid shell identifier, i.e.
368 does not contain a dollar sign, nor is quoted in any way. Nor
369 does it consist of all digits. If CHECK_WORD is non-zero,
370 the word is checked to ensure that it consists of only letters,
371 digits, and underscores. */
373 check_identifier (word, check_word)
377 if ((word->flags & (W_HASDOLLAR|W_QUOTED)) || all_digits (word->word))
379 internal_error ("`%s': not a valid identifier", word->word);
382 else if (check_word && legal_identifier (word->word) == 0)
384 internal_error ("`%s': not a valid identifier", word->word);
391 /* **************************************************************** */
393 /* Functions to manage files and file descriptors */
395 /* **************************************************************** */
397 /* A function to unset no-delay mode on a file descriptor. Used in shell.c
398 to unset it on the fd passed as stdin. Should be called on stdin if
399 readline gets an EAGAIN or EWOULDBLOCK when trying to read input. */
401 #if !defined (O_NDELAY)
402 # if defined (FNDELAY)
403 # define O_NDELAY FNDELAY
405 #endif /* O_NDELAY */
407 /* Make sure no-delay mode is not set on file descriptor FD. */
409 unset_nodelay_mode (fd)
414 if ((flags = fcntl (fd, F_GETFL, 0)) < 0)
419 /* This is defined to O_NDELAY in filecntl.h if O_NONBLOCK is not present
420 and O_NDELAY is defined. */
421 if (flags & O_NONBLOCK)
423 flags &= ~O_NONBLOCK;
428 fcntl (fd, F_SETFL, flags);
431 /* There is a bug in the NeXT 2.1 rlogind that causes opens
432 of /dev/tty to fail. */
439 tty_fd = open ("/dev/tty", O_RDWR|O_NONBLOCK);
443 tty = (char *)ttyname (fileno (stdin));
446 tty_fd = open (tty, O_RDWR|O_NONBLOCK);
451 /* Return 1 if PATH1 and PATH2 are the same file. This is kind of
452 expensive. If non-NULL STP1 and STP2 point to stat structures
453 corresponding to PATH1 and PATH2, respectively. */
455 same_file (path1, path2, stp1, stp2)
457 struct stat *stp1, *stp2;
459 struct stat st1, st2;
463 if (stat (path1, &st1) != 0)
470 if (stat (path2, &st2) != 0)
475 return ((stp1->st_dev == stp2->st_dev) && (stp1->st_ino == stp2->st_ino));
478 /* Move FD to a number close to the maximum number of file descriptors
479 allowed in the shell process, to avoid the user stepping on it with
480 redirection and causing us extra work. If CHECK_NEW is non-zero,
481 we check whether or not the file descriptors are in use before
482 duplicating FD onto them. MAXFD says where to start checking the
483 file descriptors. If it's less than 20, we get the maximum value
484 available from getdtablesize(2). */
486 move_to_high_fd (fd, check_new, maxfd)
487 int fd, check_new, maxfd;
489 int script_fd, nfds, ignore;
493 nfds = getdtablesize ();
502 for (nfds--; check_new && nfds > 3; nfds--)
503 if (fcntl (nfds, F_GETFD, &ignore) == -1)
506 if (nfds && fd != nfds && (script_fd = dup2 (fd, nfds)) != -1)
508 if (check_new == 0 || fd != fileno (stderr)) /* don't close stderr */
516 /* Return non-zero if the characters from SAMPLE are not all valid
517 characters to be found in the first line of a shell script. We
518 check up to the first newline, or SAMPLE_LEN, whichever comes first.
519 All of the characters must be printable or whitespace. */
521 #if !defined (isspace)
522 #define isspace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\f')
525 #if !defined (isprint)
526 #define isprint(c) (isletter(c) || digit(c) || ispunct(c))
530 check_binary_file (sample, sample_len)
531 unsigned char *sample;
536 for (i = 0; i < sample_len; i++)
538 if (sample[i] == '\n')
541 if (isspace (sample[i]) == 0 && isprint (sample[i]) == 0)
548 /* **************************************************************** */
550 /* Functions to manipulate pathnames */
552 /* **************************************************************** */
554 /* Return 1 if PATH corresponds to a directory. */
569 l = stat (s, &sb) == 0 && S_ISDIR (sb.st_mode);
574 /* Canonicalize PATH, and return a new path. The new path differs from PATH
576 Multple `/'s are collapsed to a single `/'.
577 Leading `./'s and trailing `/.'s are removed.
578 Trailing `/'s are removed.
579 Non-leading `../'s and trailing `..'s are handled by removing
580 portions of the path. */
582 canonicalize_pathname (path)
585 register int i, start;
589 /* The result cannot be larger than the input PATH. */
590 result = savestring (path);
592 stub_char = (*path == '/') ? '/' : '.';
594 /* Walk along RESULT looking for things to compact. */
601 while (result[i] && result[i] != '/')
606 /* If we didn't find any slashes, then there is nothing left to do. */
610 /* Handle multiple `/'s in a row. */
611 while (result[i] == '/')
615 if ((start + 1) != i)
617 /* Leave a leading `//' alone, as POSIX requires. */
618 if ((start + 1) != i && (start != 0 || i != 2))
621 strcpy (result + start + 1, result + i);
623 /* Make sure that what we have so far corresponds to a directory.
624 If it does not, just punt. */
629 result[start] = '\0';
630 if (canon_stat (result) == 0)
633 return ((char *)NULL);
639 /* Handle backslash-quoted `/'. */
640 if (start > 0 && result[start - 1] == '\\')
644 /* Check for trailing `/'. */
645 if (start && !result[i])
652 /* Check for `../', `./' or trailing `.' by itself. */
653 if (result[i] == '.')
655 /* Handle trailing `.' by itself. */
660 if (result[i + 1] == '/')
662 strcpy (result + i, result + i + 1);
663 i = (start < 0) ? 0 : start;
667 /* Handle `../' or trailing `..' by itself. */
668 if (result[i + 1] == '.' &&
669 (result[i + 2] == '/' || !result[i + 2]))
671 /* Make sure that the last component corresponds to a directory
672 before blindly chopping it off. */
676 if (canon_stat (result) == 0)
679 return ((char *)NULL);
683 while (--start > -1 && result[start] != '/');
684 strcpy (result + start + 1, result + i + 2);
685 #if 0 /* Unnecessary */
686 if (*result && canon_stat (result) == 0)
689 return ((char *)NULL);
692 i = (start < 0) ? 0 : start;
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
711 make_absolute (string, dot_path)
712 char *string, *dot_path;
717 if (dot_path == 0 || *string == '/')
718 result = savestring (string);
723 result_len = strlen (dot_path);
724 result = xmalloc (2 + result_len + strlen (string));
725 strcpy (result, dot_path);
726 if (result[result_len - 1] != '/')
728 result[result_len++] = '/';
729 result[result_len] = '\0';
734 result = xmalloc (3 + strlen (string));
735 result[0] = '.'; result[1] = '/'; result[2] = '\0';
739 strcpy (result + result_len, string);
745 /* Return 1 if STRING contains an absolute pathname, else 0. */
747 absolute_pathname (string)
750 if (!string || !*string)
756 if (*string++ == '.')
758 if (!*string || *string == '/' ||
759 (*string == '.' && (string[1] == '\0' || string[1] == '/')))
765 /* Return 1 if STRING is an absolute program name; it is absolute if it
766 contains any slashes. This is used to decide whether or not to look
769 absolute_program (string)
772 return ((char *)strchr (string, '/') != (char *)NULL);
775 /* Return the `basename' of the pathname in STRING (the stuff after the
776 last '/'). If STRING is not a full pathname, simply return it. */
778 base_pathname (string)
783 if (!absolute_pathname (string))
786 p = (char *)strrchr (string, '/');
787 return (p ? ++p : string);
790 /* Return the full pathname of FILE. Easy. Filenames that begin
791 with a '/' are returned as themselves. Other filenames have
792 the current working directory prepended. A new string is
793 returned in either case. */
802 file = (*file == '~') ? bash_tilde_expand (file) : savestring (file);
804 if ((*file == '/') && absolute_pathname (file))
809 /* XXX - this should probably be just PATH_MAX or PATH_MAX + 1 */
810 current_dir = xmalloc (2 + PATH_MAX + strlen (file));
811 if (getcwd (current_dir, PATH_MAX) == 0)
813 sys_error (bash_getcwd_errstr);
816 return ((char *)NULL);
818 dlen = strlen (current_dir);
819 current_dir[dlen++] = '/';
821 /* Turn /foo/./bar into /foo/bar. */
822 if (file[0] == '.' && file[1] == '/')
825 strcpy (current_dir + dlen, file);
827 return (current_dir);
830 /* A slightly related function. Get the prettiest name of this
831 directory possible. */
832 static char tdir[PATH_MAX];
834 /* Return a pretty pathname. If the first part of the pathname is
835 the same as $HOME, then replace that with `~'. */
837 polite_directory_format (name)
843 home = get_string_value ("HOME");
844 l = home ? strlen (home) : 0;
845 if (l > 1 && strncmp (home, name, l) == 0 && (!name[l] || name[l] == '/'))
847 strcpy (tdir + 1, name + l);
855 /* Given a string containing units of information separated by colons,
856 return the next one pointed to by (P_INDEX), or NULL if there are no more.
857 Advance (P_INDEX) to the character after the colon. */
859 extract_colon_unit (string, p_index)
869 len = strlen (string);
871 return ((char *)NULL);
875 /* Each call to this routine leaves the index pointing at a colon if
876 there is more to the path. If I is > 0, then increment past the
877 `:'. If I is 0, then the path has a leading colon. Trailing colons
878 are handled OK by the `else' part of the if statement; an empty
879 string is returned in that case. */
880 if (i && string[i] == ':')
883 for (start = i; string[i] && string[i] != ':'; i++)
892 /* Return "" in the case of a trailing `:'. */
899 value = xmalloc (1 + len);
900 strncpy (value, string + start, len);
907 /* **************************************************************** */
909 /* Tilde Initialization and Expansion */
911 /* **************************************************************** */
913 /* If tilde_expand hasn't been able to expand the text, perhaps it
914 is a special shell expansion. This function is installed as the
915 tilde_expansion_preexpansion_hook. It knows how to expand ~- and ~+. */
917 bash_special_tilde_expansions (text)
922 result = (char *)NULL;
926 result = get_string_value ("PWD");
927 else if (*text == '-')
928 result = get_string_value ("OLDPWD");
931 return (result ? savestring (result) : (char *)NULL);
934 /* Initialize the tilde expander. In Bash, we handle `~-' and `~+', as
935 well as handling special tilde prefixes; `:~" and `=~' are indications
936 that we should do tilde expansion. */
940 static int times_called = 0;
942 /* Tell the tilde expander that we want a crack first. */
943 tilde_expansion_preexpansion_hook = (CPFunction *)bash_special_tilde_expansions;
945 /* Tell the tilde expander about special strings which start a tilde
946 expansion, and the special strings that end one. Only do this once.
947 tilde_initialize () is called from within bashline_reinitialize (). */
948 if (times_called == 0)
950 tilde_additional_prefixes = (char **)xmalloc (3 * sizeof (char *));
951 tilde_additional_prefixes[0] = "=~";
952 tilde_additional_prefixes[1] = ":~";
953 tilde_additional_prefixes[2] = (char *)NULL;
955 tilde_additional_suffixes = (char **)xmalloc (3 * sizeof (char *));
956 tilde_additional_suffixes[0] = ":";
957 tilde_additional_suffixes[1] = "=~";
958 tilde_additional_suffixes[2] = (char *)NULL;
964 bash_tilde_expand (s)
970 old_immed = interrupt_immediately;
971 interrupt_immediately = 1;
972 ret = tilde_expand (s);
973 interrupt_immediately = old_immed;
977 /* **************************************************************** */
979 /* Functions to manipulate and search the group list */
981 /* **************************************************************** */
983 static int ngroups, maxgroups;
985 /* The set of groups that this user is a member of. */
986 static GETGROUPS_T *group_array = (GETGROUPS_T *)NULL;
988 #if !defined (NOGROUP)
989 # define NOGROUP (gid_t) -1
992 #if defined (HAVE_SYSCONF) && defined (_SC_NGROUPS_MAX)
993 # define getmaxgroups() sysconf(_SC_NGROUPS_MAX)
995 # if defined (NGROUPS_MAX)
996 # define getmaxgroups() NGROUPS_MAX
997 # else /* !NGROUPS_MAX */
998 # if defined (NGROUPS)
999 # define getmaxgroups() NGROUPS
1000 # else /* !NGROUPS */
1001 # define getmaxgroups() 64
1002 # endif /* !NGROUPS */
1003 # endif /* !NGROUPS_MAX */
1004 #endif /* !HAVE_SYSCONF || !SC_NGROUPS_MAX */
1007 initialize_group_array ()
1012 maxgroups = getmaxgroups ();
1015 group_array = (GETGROUPS_T *)xrealloc (group_array, maxgroups * sizeof (GETGROUPS_T));
1017 #if defined (HAVE_GETGROUPS)
1018 ngroups = getgroups (maxgroups, group_array);
1021 /* If getgroups returns nothing, or the OS does not support getgroups(),
1022 make sure the groups array includes at least the current gid. */
1025 group_array[0] = current_user.gid;
1029 /* If the primary group is not in the groups array, add it as group_array[0]
1030 and shuffle everything else up 1, if there's room. */
1031 for (i = 0; i < ngroups; i++)
1032 if (current_user.gid == (gid_t)group_array[i])
1034 if (i == ngroups && ngroups < maxgroups)
1036 for (i = ngroups; i > 0; i--)
1037 group_array[i] = group_array[i - 1];
1038 group_array[0] = current_user.gid;
1043 /* Return non-zero if GID is one that we have in our groups list. */
1048 #if defined (HAVE_GETGROUPS)
1052 /* Short-circuit if possible, maybe saving a call to getgroups(). */
1053 if (gid == current_user.gid || gid == current_user.egid)
1056 #if defined (HAVE_GETGROUPS)
1058 initialize_group_array ();
1060 /* In case of error, the user loses. */
1064 /* Search through the list looking for GID. */
1065 for (i = 0; i < ngroups; i++)
1066 if (gid == (gid_t)group_array[i])
1074 get_group_list (ngp)
1077 static char **group_vector = (char **)NULL;
1085 return group_vector;
1089 initialize_group_array ();
1095 return (char **)NULL;
1098 group_vector = (char **)xmalloc (ngroups * sizeof (char *));
1099 for (i = 0; i < ngroups; i++)
1101 nbuf = itos ((int)group_array[i]);
1102 group_vector[i] = nbuf;
1106 return group_vector;