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 strncpy (tdir + 1, name + l, sizeof(tdir) - 2);
849 tdir[sizeof(tdir) - 1] = '\0';
856 /* Given a string containing units of information separated by colons,
857 return the next one pointed to by (P_INDEX), or NULL if there are no more.
858 Advance (P_INDEX) to the character after the colon. */
860 extract_colon_unit (string, p_index)
870 len = strlen (string);
872 return ((char *)NULL);
876 /* Each call to this routine leaves the index pointing at a colon if
877 there is more to the path. If I is > 0, then increment past the
878 `:'. If I is 0, then the path has a leading colon. Trailing colons
879 are handled OK by the `else' part of the if statement; an empty
880 string is returned in that case. */
881 if (i && string[i] == ':')
884 for (start = i; string[i] && string[i] != ':'; i++)
893 /* Return "" in the case of a trailing `:'. */
900 value = xmalloc (1 + len);
901 strncpy (value, string + start, len);
908 /* **************************************************************** */
910 /* Tilde Initialization and Expansion */
912 /* **************************************************************** */
914 /* If tilde_expand hasn't been able to expand the text, perhaps it
915 is a special shell expansion. This function is installed as the
916 tilde_expansion_preexpansion_hook. It knows how to expand ~- and ~+. */
918 bash_special_tilde_expansions (text)
923 result = (char *)NULL;
927 result = get_string_value ("PWD");
928 else if (*text == '-')
929 result = get_string_value ("OLDPWD");
932 return (result ? savestring (result) : (char *)NULL);
935 /* Initialize the tilde expander. In Bash, we handle `~-' and `~+', as
936 well as handling special tilde prefixes; `:~" and `=~' are indications
937 that we should do tilde expansion. */
941 static int times_called = 0;
943 /* Tell the tilde expander that we want a crack first. */
944 tilde_expansion_preexpansion_hook = (CPFunction *)bash_special_tilde_expansions;
946 /* Tell the tilde expander about special strings which start a tilde
947 expansion, and the special strings that end one. Only do this once.
948 tilde_initialize () is called from within bashline_reinitialize (). */
949 if (times_called == 0)
951 tilde_additional_prefixes = (char **)xmalloc (3 * sizeof (char *));
952 tilde_additional_prefixes[0] = "=~";
953 tilde_additional_prefixes[1] = ":~";
954 tilde_additional_prefixes[2] = (char *)NULL;
956 tilde_additional_suffixes = (char **)xmalloc (3 * sizeof (char *));
957 tilde_additional_suffixes[0] = ":";
958 tilde_additional_suffixes[1] = "=~";
959 tilde_additional_suffixes[2] = (char *)NULL;
965 bash_tilde_expand (s)
971 old_immed = interrupt_immediately;
972 interrupt_immediately = 1;
973 ret = tilde_expand (s);
974 interrupt_immediately = old_immed;
978 /* **************************************************************** */
980 /* Functions to manipulate and search the group list */
982 /* **************************************************************** */
984 static int ngroups, maxgroups;
986 /* The set of groups that this user is a member of. */
987 static GETGROUPS_T *group_array = (GETGROUPS_T *)NULL;
989 #if !defined (NOGROUP)
990 # define NOGROUP (gid_t) -1
993 #if defined (HAVE_SYSCONF) && defined (_SC_NGROUPS_MAX)
994 # define getmaxgroups() sysconf(_SC_NGROUPS_MAX)
996 # if defined (NGROUPS_MAX)
997 # define getmaxgroups() NGROUPS_MAX
998 # else /* !NGROUPS_MAX */
999 # if defined (NGROUPS)
1000 # define getmaxgroups() NGROUPS
1001 # else /* !NGROUPS */
1002 # define getmaxgroups() 64
1003 # endif /* !NGROUPS */
1004 # endif /* !NGROUPS_MAX */
1005 #endif /* !HAVE_SYSCONF || !SC_NGROUPS_MAX */
1008 initialize_group_array ()
1013 maxgroups = getmaxgroups ();
1016 group_array = (GETGROUPS_T *)xrealloc (group_array, maxgroups * sizeof (GETGROUPS_T));
1018 #if defined (HAVE_GETGROUPS)
1019 ngroups = getgroups (maxgroups, group_array);
1022 /* If getgroups returns nothing, or the OS does not support getgroups(),
1023 make sure the groups array includes at least the current gid. */
1026 group_array[0] = current_user.gid;
1030 /* If the primary group is not in the groups array, add it as group_array[0]
1031 and shuffle everything else up 1, if there's room. */
1032 for (i = 0; i < ngroups; i++)
1033 if (current_user.gid == (gid_t)group_array[i])
1035 if (i == ngroups && ngroups < maxgroups)
1037 for (i = ngroups; i > 0; i--)
1038 group_array[i] = group_array[i - 1];
1039 group_array[0] = current_user.gid;
1044 /* Return non-zero if GID is one that we have in our groups list. */
1049 #if defined (HAVE_GETGROUPS)
1053 /* Short-circuit if possible, maybe saving a call to getgroups(). */
1054 if (gid == current_user.gid || gid == current_user.egid)
1057 #if defined (HAVE_GETGROUPS)
1059 initialize_group_array ();
1061 /* In case of error, the user loses. */
1065 /* Search through the list looking for GID. */
1066 for (i = 0; i < ngroups; i++)
1067 if (gid == (gid_t)group_array[i])
1075 get_group_list (ngp)
1078 static char **group_vector = (char **)NULL;
1086 return group_vector;
1090 initialize_group_array ();
1096 return (char **)NULL;
1099 group_vector = (char **)xmalloc (ngroups * sizeof (char *));
1100 for (i = 0; i < ngroups; i++)
1102 nbuf = itos ((int)group_array[i]);
1103 group_vector[i] = nbuf;
1107 return group_vector;