blob: b17a7311488999529ff55506b290bbd0c2c365c1 [file] [log] [blame]
Jari Aaltoccc6cda1996-12-23 17:02:34 +00001/* oslib.c - functions present only in some unix versions. */
2
3/* Copyright (C) 1995 Free Software Foundation, Inc.
4
5 This file is part of GNU Bash, the Bourne Again SHell.
6
7 Bash is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with Bash; see the file COPYING. If not, write to the Free Software
19 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
20
21#include "config.h"
22
23#include "bashtypes.h"
24#include <sys/param.h>
25
26#if defined (HAVE_UNISTD_H)
27# include <unistd.h>
28#endif
29
30#include "posixstat.h"
31#include "filecntl.h"
32#include "bashansi.h"
33
34#include <stdio.h>
35#include <errno.h>
36#include <ctype.h>
37
38#include "shell.h"
39#include "maxpath.h"
40
41#if !defined (errno)
42extern int errno;
43#endif /* !errno */
44
45/* A standard error message to use when getcwd() returns NULL. */
46char *bash_getcwd_errstr = "getcwd: cannot access parent directories";
47
48#if !defined (HAVE_SYSCONF) || !defined (_SC_CLK_TCK)
49# if !defined (CLK_TCK)
50# if defined (HZ)
51# define CLK_TCK HZ
52# else
53# define CLK_TCK 60
54# endif
55# endif /* !CLK_TCK */
56#endif /* !HAVE_SYSCONF && !_SC_CLK_TCK */
57
58long
59get_clk_tck ()
60{
61 static long retval = 0;
62
63 if (retval != 0)
64 return (retval);
65
66#if defined (HAVE_SYSCONF) && defined (_SC_CLK_TCK)
67 retval = sysconf (_SC_CLK_TCK);
68#else /* !SYSCONF || !_SC_CLK_TCK */
69 retval = CLK_TCK;
70#endif /* !SYSCONF || !_SC_CLK_TCK */
71
72 return (retval);
73}
74
75/* Make the functions strchr and strrchr if they do not exist. */
76#if !defined (HAVE_STRCHR)
77char *
78strchr (string, c)
79 char *string;
80 int c;
81{
82 register char *s;
83
84 for (s = string; s && *s; s++)
85 if (*s == c)
86 return (s);
87
88 return ((char *) NULL);
89}
90
91char *
92strrchr (string, c)
93 char *string;
94 int c;
95{
96 register char *s, *t;
97
98 for (s = string, t = (char *)NULL; s && *s; s++)
99 if (*s == c)
100 t = s;
101 return (t);
102}
103#endif /* !HAVE_STRCHR */
104
105#if !defined (HAVE_STRCASECMP)
106
107#if !defined (to_lower)
Jari Aaltod166f041997-06-05 14:59:13 +0000108# define to_lower(c) (islower(c) ? (c) : tolower(c))
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000109#endif /* to_lower */
110
111/* Compare at most COUNT characters from string1 to string2. Case
112 doesn't matter. */
113int
114strncasecmp (string1, string2, count)
115 char *string1, *string2;
116 int count;
117{
118 register char *s1, *s2;
119 register int r;
120
121 if (count > 0)
122 {
123 s1 = string1;
124 s2 = string2;
125 do
126 {
127 if ((r = to_lower (*s1) - to_lower (*s2)) != 0)
128 return r;
129 if (*s1++ == '\0')
130 break;
131 s2++;
132 }
133 while (--count != 0);
134 }
135 return (0);
136}
137
138/* strcmp (), but caseless. */
139int
140strcasecmp (string1, string2)
141 char *string1, *string2;
142{
143 register char *s1, *s2;
144 register int r;
145
146 s1 = string1;
147 s2 = string2;
148
149 while ((r = to_lower (*s1) - to_lower (*s2)) == 0)
150 {
151 if (*s1++ == '\0')
152 return 0;
153 s2++;
154 }
155 return (r);
156}
157#endif /* !HAVE_STRCASECMP */
158
159/* Return a string corresponding to the error number E. From
160 the ANSI C spec. */
161#if defined (strerror)
162# undef strerror
163#endif
164
165#if !defined (HAVE_STRERROR)
166char *
167strerror (e)
168 int e;
169{
170 static char emsg[40];
171#if defined (HAVE_SYS_ERRLIST)
172 extern int sys_nerr;
173 extern char *sys_errlist[];
174
175 if (e > 0 && e < sys_nerr)
176 return (sys_errlist[e]);
177 else
178#endif /* HAVE_SYS_ERRLIST */
179 {
180 sprintf (emsg, "Unknown error %d", e);
181 return (&emsg[0]);
182 }
183}
184#endif /* HAVE_STRERROR */
185
186#if !defined (HAVE_DUP2) || defined (DUP2_BROKEN)
187/* Replacement for dup2 (), for those systems which either don't have it,
188 or supply one with broken behaviour. */
189int
190dup2 (fd1, fd2)
191 int fd1, fd2;
192{
193 int saved_errno, r;
194
195 /* If FD1 is not a valid file descriptor, then return immediately with
196 an error. */
197 if (fcntl (fd1, F_GETFL, 0) == -1)
198 return (-1);
199
200 if (fd2 < 0 || fd2 >= getdtablesize ())
201 {
202 errno = EBADF;
203 return (-1);
204 }
205
206 if (fd1 == fd2)
207 return (0);
208
209 saved_errno = errno;
210
211 (void) close (fd2);
212 r = fcntl (fd1, F_DUPFD, fd2);
213
214 if (r >= 0)
215 errno = saved_errno;
216 else
217 if (errno == EINVAL)
218 errno = EBADF;
219
220 /* Force the new file descriptor to remain open across exec () calls. */
221 SET_OPEN_ON_EXEC (fd2);
222 return (r);
223}
224#endif /* !HAVE_DUP2 */
225
226/*
227 * Return the total number of available file descriptors.
228 *
229 * On some systems, like 4.2BSD and its descendents, there is a system call
230 * that returns the size of the descriptor table: getdtablesize(). There are
231 * lots of ways to emulate this on non-BSD systems.
232 *
233 * On System V.3, this can be obtained via a call to ulimit:
234 * return (ulimit(4, 0L));
235 *
236 * On other System V systems, NOFILE is defined in /usr/include/sys/param.h
237 * (this is what we assume below), so we can simply use it:
238 * return (NOFILE);
239 *
240 * On POSIX systems, there are specific functions for retrieving various
241 * configuration parameters:
242 * return (sysconf(_SC_OPEN_MAX));
243 *
244 */
245
246#if !defined (HAVE_GETDTABLESIZE)
247int
248getdtablesize ()
249{
250# if defined (_POSIX_VERSION) && defined (HAVE_SYSCONF) && defined (_SC_OPEN_MAX)
251 return (sysconf(_SC_OPEN_MAX)); /* Posix systems use sysconf */
252# else /* ! (_POSIX_VERSION && HAVE_SYSCONF && _SC_OPEN_MAX) */
253# if defined (ULIMIT_MAXFDS)
254 return (ulimit (4, 0L)); /* System V.3 systems use ulimit(4, 0L) */
255# else /* !ULIMIT_MAXFDS */
256# if defined (NOFILE) /* Other systems use NOFILE */
257 return (NOFILE);
258# else /* !NOFILE */
259 return (20); /* XXX - traditional value is 20 */
260# endif /* !NOFILE */
261# endif /* !ULIMIT_MAXFDS */
262# endif /* ! (_POSIX_VERSION && _SC_OPEN_MAX) */
263}
264#endif /* !HAVE_GETDTABLESIZE */
265
266#if !defined (HAVE_BCOPY)
267void
268bcopy (s,d,n)
269 char *d, *s;
270 int n;
271{
272 FASTCOPY (s, d, n);
273}
274#endif /* !HAVE_BCOPY */
275
276#if !defined (HAVE_BZERO)
277void
278bzero (s, n)
279 char *s;
280 int n;
281{
282 register int i;
Jari Aaltod166f041997-06-05 14:59:13 +0000283 register char *r;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000284
Jari Aaltod166f041997-06-05 14:59:13 +0000285 for (i = 0, r = s; i < n; i++)
286 *r++ = '\0';
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000287}
288#endif
289
290#if !defined (HAVE_GETHOSTNAME)
291# if defined (HAVE_UNAME)
292# include <sys/utsname.h>
293int
294gethostname (name, namelen)
295 char *name;
296 int namelen;
297{
298 int i;
299 struct utsname ut;
300
301 --namelen;
302
303 uname (&ut);
304 i = strlen (ut.nodename) + 1;
305 strncpy (name, ut.nodename, i < namelen ? i : namelen);
306 name[namelen] = '\0';
307 return (0);
308}
309# else /* !HAVE_UNAME */
310int
311gethostname (name, namelen)
312 int name, namelen;
313{
314 strncpy (name, "unknown", namelen);
315 name[namelen] = '\0';
316 return 0;
317}
318# endif /* !HAVE_UNAME */
319#endif /* !HAVE_GETHOSTNAME */
320
321#if !defined (HAVE_KILLPG)
322int
323killpg (pgrp, sig)
324 pid_t pgrp;
325 int sig;
326{
327 return (kill (-pgrp, sig));
328}
329#endif /* !HAVE_KILLPG */
330
331
332/* We supply our own version of getenv () because we want library
333 routines to get the changed values of exported variables. */
334
335/* The NeXT C library has getenv () defined and used in the same file.
336 This screws our scheme. However, Bash will run on the NeXT using
337 the C library getenv (), since right now the only environment variable
338 that we care about is HOME, and that is already defined. */
339#if defined (CAN_REDEFINE_GETENV)
340static char *last_tempenv_value = (char *)NULL;
341extern char **environ;
342
343char *
344getenv (name)
345#if defined (__linux__) || defined (__bsdi__) || defined (convex)
346 const char *name;
347#else
348 char const *name;
349#endif /* !__linux__ && !__bsdi__ && !convex */
350{
351 SHELL_VAR *var;
352
353 var = find_tempenv_variable ((char *)name);
354 if (var)
355 {
356 FREE (last_tempenv_value);
357
358 last_tempenv_value = savestring (value_cell (var));
359 dispose_variable (var);
360 return (last_tempenv_value);
361 }
362 else if (shell_variables)
363 {
364 var = find_variable ((char *)name);
365 if (var && exported_p (var))
366 return (value_cell (var));
367 }
368 else
369 {
370 register int i, len;
371
372 /* In some cases, s5r3 invokes getenv() before main(); BSD systems
373 using gprof also exhibit this behavior. This means that
374 shell_variables will be 0 when this is invoked. We look up the
375 variable in the real environment in that case. */
376
377 for (i = 0, len = strlen (name); environ[i]; i++)
378 {
379 if ((STREQN (environ[i], name, len)) && (environ[i][len] == '='))
380 return (environ[i] + len + 1);
381 }
382 }
383
384 return ((char *)NULL);
385}
386
387/* Some versions of Unix use _getenv instead. */
388char *
389_getenv (name)
390#if defined (__linux__) || defined (__bsdi__) || defined (convex)
391 const char *name;
392#else
393 char const *name;
394#endif /* !__linux__ && !__bsdi__ && !convex */
395{
396 return (getenv (name));
397}
398
399#endif /* CAN_REDEFINE_GETENV */
400
401#if !defined (HAVE_MKFIFO) && defined (PROCESS_SUBSTITUTION)
402int
403mkfifo (path, mode)
404 char *path;
405 int mode;
406{
407#if defined (S_IFIFO)
408 return (mknod (path, (mode | S_IFIFO), 0));
409#else /* !S_IFIFO */
410 return (-1);
411#endif /* !S_IFIFO */
412}
413#endif
414
415#if !defined (HAVE_SETLINEBUF)
416/* Cause STREAM to buffer lines as opposed to characters or blocks. */
417int
418setlinebuf (stream)
419 FILE *stream;
420{
421#if defined (_IOLBF)
422# if defined (SETVBUF_REVERSED)
423 setvbuf (stream, _IOLBF, (char *)NULL, BUFSIZ);
424# else /* !SETVBUF_REVERSED */
425 setvbuf (stream, (char *)NULL, _IOLBF, BUFSIZ);
426# endif /* !SETVBUF_REVERSED */
427#endif /* _IOLBF */
428 return (0);
429}
430#endif /* !HAVE_SETLINEBUF */