386BSD 0.1 development
[unix-history] / usr / src / libexec / uucp / sys1.unx
CommitLineData
32c0721d
WJ
1/* sys1.unx
2 The basic system dependent routines for UNIX.
3
4 Copyright (C) 1991, 1992 Ian Lance Taylor
5
6 This file is part of the Taylor UUCP package.
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the
11 License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 The author of the program may be contacted at ian@airs.com or
23 c/o AIRS, P.O. Box 520, Waltham, MA 02254.
24
25 $Log: sys1.unx,v $
26# Revision 1.2 92/05/13 05:42:07 rich
27# ported to 386bsd
28#
29# Revision 1.1 1992/05/10 17:36:33 rich
30# Initial revision
31#
32 Revision 1.68 1992/04/03 05:37:11 ian
33 Minor cleanups for gcc 2.1
34
35 Revision 1.67 1992/03/31 23:53:34 ian
36 Use $PWD to get the current directory if it's defined and correct
37
38 Revision 1.66 1992/03/31 23:42:59 ian
39 Brian W. Antoine: use name from getpwnam rather than getlogin
40
41 Revision 1.65 1992/03/26 17:17:25 ian
42 Gerben Wierda: various cleanups
43
44 Revision 1.64 1992/03/18 06:00:25 ian
45 Open the controlling terminal in non delay mode
46
47 Revision 1.63 1992/03/17 15:35:28 ian
48 Log signals when they happen, even if we continue looping
49
50 Revision 1.62 1992/03/17 01:28:18 ian
51 Undefine remove in uucp.h if ! HAVE_REMOVE
52
53 Revision 1.61 1992/03/16 22:40:01 ian
54 Undefine remove before function definition
55
56 Revision 1.60 1992/03/16 22:22:35 ian
57 Adjusted external declarations
58
59 Revision 1.59 1992/03/16 22:01:58 ian
60 Don't declare sigemptyset
61
62 Revision 1.58 1992/03/16 01:23:08 ian
63 Make blocking writes optional
64
65 Revision 1.57 1992/03/15 04:51:17 ian
66 Keep an array of signals we've received rather than a single variable
67
68 Revision 1.56 1992/03/15 01:54:46 ian
69 All execs are now done in isspawn, all waits are done in iswait
70
71 Revision 1.55 1992/03/12 19:54:43 ian
72 Debugging based on types rather than number
73
74 Revision 1.54 1992/03/11 02:09:57 ian
75 Franc,ois Pinard: retry fork several times before giving up
76
77 Revision 1.53 1992/03/11 00:18:50 ian
78 Save temporary file if file send fails
79
80 Revision 1.52 1992/03/08 02:06:28 ian
81 Let setpgrp fail silently
82
83 Revision 1.51 1992/03/04 01:40:51 ian
84 Thomas Fischer: tweaked a bit for the NeXT
85
86 Revision 1.50 1992/03/03 21:01:20 ian
87 Use strict timeout in fsserial_read, eliminate all race conditions
88
89 Revision 1.49 1992/02/29 01:06:59 ian
90 Chip Salzenberg: recheck file permissions before sending
91
92 Revision 1.48 1992/02/28 05:06:15 ian
93 T. William Wells: fsysdep_catch must be a macro
94
95 Revision 1.47 1992/02/27 19:51:09 ian
96 Added some new extern definitions
97
98 Revision 1.46 1992/02/27 05:40:54 ian
99 T. William Wells: detach from controlling terminal, handle signals safely
100
101 Revision 1.45 1992/02/24 20:07:43 ian
102 John Theus: some systems don't have <fcntl.h>
103
104 Revision 1.44 1992/02/24 04:58:47 ian
105 Only permit files to be received into directories that are world-writeable
106
107 Revision 1.43 1992/02/23 03:26:51 ian
108 Overhaul to use automatic configure shell script
109
110 Revision 1.42 1992/02/19 19:36:07 ian
111 Rearranged time functions
112
113 Revision 1.41 1992/02/09 05:10:50 ian
114 Added HAVE_MKDIR configuration parameter and mkdir emulation
115
116 Revision 1.40 1992/02/09 03:14:48 ian
117 Added HAVE_OLD_DIRECTORIES for systems without readdir routines
118
119 Revision 1.39 1992/02/09 02:41:58 ian
120 Added HAVE_DUP2 configuration parameter and dup2 emulation function
121
122 Revision 1.38 1992/02/08 23:38:17 ian
123 Put utsname on stack rather than making it static
124
125 Revision 1.37 1992/02/08 23:34:41 ian
126 If we have neither getcwd nor getwd, fork /bin/pwd to get the cwd
127
128 Revision 1.36 1992/02/08 22:33:32 ian
129 Only get the current working directory if it's going to be needed
130
131 Revision 1.35 1992/02/08 03:54:18 ian
132 Include <string.h> only in <uucp.h>, added 1992 copyright
133
134 Revision 1.34 1992/01/29 04:27:11 ian
135 Jay Vassos-Libove: removed some conflicting declarations
136
137 Revision 1.33 1992/01/22 05:08:21 ian
138 Call execl with correct first argument
139
140 Revision 1.32 1992/01/21 19:39:12 ian
141 Chip Salzenberg: uucp and uux start uucico for right system, not any
142
143 Revision 1.31 1992/01/21 00:30:48 ian
144 Don't try to create a directory with no name
145
146 Revision 1.30 1992/01/16 03:38:20 ian
147 Put \n at end of fsysdep_run error message
148
149 Revision 1.29 1992/01/15 21:06:11 ian
150 Mike Park: some systems can't include <sys/time.h> and <time.h> together
151
152 Revision 1.28 1992/01/13 19:38:16 ian
153 Chip Salzenberg: can't declare execl, since it is varadic
154
155 Revision 1.27 1992/01/13 06:11:39 ian
156 David Nugent: can't declare open or fcntl
157
158 Revision 1.26 1992/01/11 17:30:10 ian
159 John Antypas: use memcpy instead of relying on structure assignment
160
161 Revision 1.25 1992/01/04 23:23:57 ian
162 usysdep_localtime can't use usysdep_full_time if HAVE_TIMES
163
164 Revision 1.24 1992/01/04 22:56:22 ian
165 Added extern definition
166
167 Revision 1.23 1991/12/29 15:45:46 ian
168 Don't take the address of a cast value
169
170 Revision 1.22 1991/12/29 04:04:18 ian
171 Added a bunch of extern definitions
172
173 Revision 1.21 1991/12/29 02:59:50 ian
174 Lele Gaifax: put full year in log file
175
176 Revision 1.20 1991/12/28 17:08:47 ian
177 John Theus: offer HAVE_GETWD as an alternative to using getcwd
178
179 Revision 1.19 1991/12/28 07:01:15 ian
180 Added HAVE_FTIME configuration option
181
182 Revision 1.18 1991/12/22 22:14:19 ian
183 Monty Solomon: added HAVE_UNISTD_H configuration parameter
184
185 Revision 1.17 1991/12/21 21:34:14 ian
186 Moved fsysdep_file_exists from sys5.unx to sys1.unx
187
188 Revision 1.16 1991/12/21 21:04:42 ian
189 Use real program name in fsysdep_run error messages
190
191 Revision 1.15 1991/12/17 07:09:58 ian
192 Record statistics in fractions of a second
193
194 Revision 1.14 1991/12/12 18:35:47 ian
195 Do locking with link to avoid races and to permit running as root
196
197 Revision 1.13 1991/12/12 17:39:40 ian
198 Set the GID as well as the UID for extra safety
199
200 Revision 1.12 1991/12/11 03:59:19 ian
201 Create directories when necessary; don't just assume they exist
202
203 Revision 1.11 1991/12/06 22:50:01 ian
204 Franc,ois Pinard: getcwd may legitimately fail in usysdep_initialize
205
206 Revision 1.10 1991/12/01 02:23:12 ian
207 Niels Baggesen: don't multiply include <unistd.h>
208
209 Revision 1.9 1991/11/21 20:59:32 ian
210 Brian Campbell: ttyname takes an argument
211
212 Revision 1.8 1991/11/14 19:11:25 ian
213 Add extern for ttyname
214
215 Revision 1.7 1991/11/14 03:40:10 ian
216 Try to figure out whether stdin is a TCP port
217
218 Revision 1.6 1991/11/11 18:55:52 ian
219 Get protocol parameters from port and dialer for incoming calls
220
221 Revision 1.5 1991/09/19 17:49:39 ian
222 Chip Salzenberg: the log file has been closed before calling fsysdep_run
223
224 Revision 1.4 1991/09/19 15:46:48 ian
225 Chip Salzenberg: Make sure getlogin () uid matches process uid
226
227 Revision 1.3 1991/09/19 03:23:34 ian
228 Chip Salzenberg: append to private debugging file, don't overwrite it
229
230 Revision 1.2 1991/09/11 02:33:14 ian
231 Added ffork argument to fsysdep_run
232
233 Revision 1.1 1991/09/10 19:45:50 ian
234 Initial revision
235
236 */
237
238#include "uucp.h"
239
240#if USE_RCS_ID
241char sys1_unx_rcsid[] = "$Id: sys1.unx,v 1.2 92/05/13 05:42:07 rich Exp Locker: root $";
242#endif
243
244#include <errno.h>
245
246#if USE_STDIO && HAVE_UNISTD_H
247#include <unistd.h>
248#endif
249
250#include "system.h"
251#include "sysdep.h"
252
253#include <pwd.h>
254
255#if HAVE_GETGRENT
256#include <grp.h>
257extern struct group *getgrent ();
258#endif
259
260#if HAVE_LIMITS_H
261#include <limits.h>
262#endif
263
264#if HAVE_SYS_PARAM_H
265#include <sys/param.h>
266#endif
267
268#if HAVE_FCNTL_H
269#include <fcntl.h>
270#else
271#if HAVE_SYS_FILE_H
272#include <sys/file.h>
273#endif
274#endif
275
276#ifndef O_RDONLY
277#define O_RDONLY 0
278#define O_WRONLY 1
279#define O_RDWR 2
280#endif
281
282#ifndef O_APPEND
283#ifdef FAPPEND
284#define O_APPEND FAPPEND
285#endif
286#endif
287
288#ifndef O_NOCTTY
289#define O_NOCTTY 0
290#endif
291
292#if ! HAVE_GETHOSTNAME && HAVE_UNAME
293#include <sys/utsname.h>
294extern int uname ();
295#endif
296
297#if HAVE_TIME_H && (HAVE_SYS_TIME_AND_TIME_H || ! HAVE_GETTIMEOFDAY)
298#include <time.h>
299#endif
300
301#if HAVE_SYS_IOCTL_H
302#include <sys/ioctl.h>
303#endif
304
305/* If we have getcwd, forget about getwd. */
306
307#if HAVE_GETCWD
308#undef HAVE_GETWD
309#define HAVE_GETWD 0
310#endif
311
312#if HAVE_GETWD
313/* If we didn't get MAXPATHLEN, make it up. */
314#ifndef MAXPATHLEN
315#define MAXPATHLEN 1024
316#endif
317extern char *getwd ();
318#endif /* HAVE_GETWD */
319
320/* Prefer gettimeofday to ftime to times. */
321
322#if HAVE_GETTIMEOFDAY || HAVE_FTIME
323#undef HAVE_TIMES
324#define HAVE_TIMES 0
325#endif
326
327#if HAVE_GETTIMEOFDAY
328#undef HAVE_FTIME
329#define HAVE_FTIME 0
330#endif
331
332#if HAVE_GETTIMEOFDAY
333#include <sys/time.h>
334extern int gettimeofday ();
335#endif
336
337#if HAVE_FTIME
338#include <sys/timeb.h>
339extern int ftime ();
340#endif
341
342#if HAVE_TIMES
343#include <sys/times.h>
344#if TIMES_DECLARATION_OK
345/* We use a macro to protect this because times really returns clock_t
346 and on some systems, such as Ultrix 4.0, clock_t is int. We don't
347 leave it out entirely because on some systems, such as System III,
348 the declaration is necessary for correct compilation. */
349extern long times ();
350#endif
351
352#if TIMES_TICK == 0
353/* We don't have a value for TIMES_TICK. Look for one. */
354#ifdef CLK_TCK
355#undef TIMES_TICK
356#define TIMES_TICK CLK_TCK
357#else /* ! defined (CLK_TCK) */
358#ifdef HZ
359#undef TIMES_TICK
360#define TIMES_TICK HZ
361#endif /* defined (HZ) */
362#endif /* ! defined (CLK_TCK) */
363#endif /* TIMES_TICK == 0 */
364
365#endif /* HAVE_TIMES */
366
367/* We need the access macros. */
368
369#ifndef R_OK
370#define R_OK 4
371#define W_OK 2
372#define X_OK 1
373#define F_OK 0
374#endif /* ! defined (R_OK) */
375
376/* We need wait status information. */
377
378#if HAVE_SYS_WAIT_H
379#include <sys/wait.h>
380#endif
381
382/* We use a typedef wait_status for wait and related functions to put
383 results into. We define the POSIX examination functions we need if
384 they are not already defined (if they aren't defined, I assume that
385 we have a standard wait status). */
386
387#if HAVE_UNION_WAIT
388typedef union wait wait_status;
389#ifndef WIFEXITED
390#define WIFEXITED(u) ((u).w_termsig == 0)
391#endif
392#ifndef WEXITSTATUS
393#define WEXITSTATUS(u) ((u).w_retcode)
394#endif
395#ifndef WTERMSIG
396#define WTERMSIG(u) ((u).w_termsig)
397#endif
398#else /* ! HAVE_UNION_WAIT */
399typedef int wait_status;
400#ifndef WIFEXITED
401#define WIFEXITED(i) (((i) & 0xff) == 0)
402#endif
403#ifndef WEXITSTATUS
404#define WEXITSTATUS(i) (((i) >> 8) & 0xff)
405#endif
406#ifndef WTERMSIG
407#define WTERMSIG(i) ((i) & 0x7f)
408#endif
409#endif /* ! HAVE_UNION_WAIT */
410
411/* External variables. */
412extern char **environ;
413
414/* External functions. */
415#ifndef __386BSD__
416extern int kill ();
417#endif __386BSD__
418extern int chdir (), access (), stat (), unlink (), execve ();
419extern int close (), pipe (), dup2 ();
420extern int fputs ();
421extern void _exit ();
422extern time_t time ();
423extern char *getlogin (), *ttyname ();
424extern pid_t getpid (), getppid (), fork (), getpgrp ();
425extern uid_t getuid (), geteuid (), getgid (), getegid ();
426extern struct tm *localtime ();
427#ifndef __386BSD__
428extern struct passwd *getpwuid ();
429#endif __386BSD__
430extern struct passwd *getpwnam ();
431#if HAVE_GETHOSTNAME
432extern int gethostname ();
433#endif
434#if HAVE_GETCWD
435extern char *getcwd ();
436#else
437#if ! HAVE_GETWD
438static char *getcwd P((char *zbuf, int cbuf));
439#endif /* ! HAVE_GETWD */
440#endif /* ! HAVE_GETCWD */
441#if HAVE_GETDTABLESIZE
442extern int getdtablesize ();
443#endif
444#if HAVE_SYSCONF
445extern long sysconf ();
446#endif
447#if HAVE_SETPGRP
448#ifndef __386BSD__
449extern int setpgrp ();
450#endif __386BSD__
451#endif
452#if HAVE_SETSID
453#ifndef __386BSD__
454extern int setsid ();
455#endif __386BSD__
456#endif
457#if HAVE_SIGACTION
458extern int sigaction ();
459#endif
460#if HAVE_SIGVEC
461extern int sigvec ();
462#endif
463#if HAVE_TCP
464extern int getsockname ();
465#endif
466\f
467/* Initialize the system dependent routines. We will probably be running
468 suid to uucp, so we make sure that nothing is obviously wrong. We
469 save the login name since we will be losing the real uid. */
470static char *zSlogin;
471
472/* We save the current directory since we will do a chdir to the
473 spool directory. */
474char *zScwd;
475
476/* The maximum length of a system name is controlled by the type of spool
477 directory we use. */
478
479#if SPOOLDIR_V2 | SPOOLDIR_BSD42 | SPOOLDIR_BSD43 | SPOOLDIR_ULTRIX
480int cSysdep_max_name_len = 7;
481#endif /* SPOOLDIR_V2 | SPOOLDIR_BSD42 | SPOOLDIR_BSD43 | SPOOLDIR_ULTRIX */
482#if SPOOLDIR_BNU
483int cSysdep_max_name_len = 14;
484#endif /* SPOOLDIR_BNU */
485#if SPOOLDIR_TAYLOR
486#if HAVE_LONG_NAMES
487int cSysdep_max_name_len = 255;
488#else /* ! HAVE_LONG_NAMES */
489int cSysdep_max_name_len = 14;
490#endif /* ! HAVE_LONG_NAMES */
491#endif /* SPOOLDIR_TAYLOR */
492
493/* The number of available file descriptors. */
494
495static int cSdescriptors;
496
497/* Local functions. */
498
499static void xmkdir P((const char *zdir));
500static void usmake_spool_dir P((void));
501\f
502void
503usysdep_initialize (fdaemon, fgetcwd)
504 boolean fdaemon;
505 boolean fgetcwd;
506{
507 int o;
508 char *z;
509 struct passwd *q;
510
511 ulog_id (getpid ());
512
513#if HAVE_GETDTABLESIZE
514 cSdescriptors = getdtablesize ();
515#else
516#if HAVE_SYSCONF
517 cSdescriptors = sysconf (_SC_OPEN_MAX);
518#else
519#ifdef OPEN_MAX
520 cSdescriptors = OPEN_MAX;
521#else
522#ifdef NOFILE
523 cSdescriptors = NOFILE;
524#else
525 cSdescriptors = 20;
526#endif /* ! defined (NOFILE) */
527#endif /* ! defined (OPEN_MAX) */
528#endif /* ! HAVE_SYSCONF */
529#endif /* ! HAVE_GETDTABLESIZE */
530
531 /* Close everything but stdin, stdout and stderr. */
532
533 for (o = 3; o < cSdescriptors; o++)
534 (void) close (o);
535
536 /* Make sure stdin, stdout and stderr are open. Otherwise, newly
537 opened files will appear to be them and confusion will result. */
538 if (fcntl (0, F_GETFD, 0) == -1
539 && open ("/dev/null", O_RDONLY, 0) != 0)
540 exit (EXIT_FAILURE);
541 if (fcntl (1, F_GETFD, 0) == -1
542 && open ("/dev/null", O_WRONLY, 0) != 1)
543 exit (EXIT_FAILURE);
544 if (fcntl (2, F_GETFD, 0) == -1
545 && open ("/dev/null", O_WRONLY, 0) != 2)
546 exit (EXIT_FAILURE);
547
548 /* We always set our file modes to exactly what we want. */
549 umask (0);
550
551 /* Get the login name, making sure that it matches the uid. Many
552 systems truncate the getlogin return value to 8 characters, but
553 keep the full name in the password file, so we prefer the name in
554 the password file. */
555 z = getlogin ();
556 if (z == NULL)
557 q = NULL;
558 else
559 {
560 q = getpwnam (z);
561 if (q != NULL)
562 z = q->pw_name;
563 }
564 if (q == NULL || q->pw_uid != getuid ())
565 {
566 q = getpwuid (getuid ());
567 if (q == NULL)
568 ulog (LOG_FATAL, "Can't get login name");
569 z = q->pw_name;
570 }
571 zSlogin = xstrdup (z);
572
573 if (fdaemon)
574 {
575 /* Set our uid to our effective uid. There is no point in
576 remembering who originally ran the program. This won't work
577 on System V, but there's nothing to be done about that and it
578 doesn't make all that much difference. */
579 (void) setuid (geteuid ());
580 (void) setgid (getegid ());
581 }
582
583 if (fgetcwd)
584 {
585 const char *zenv;
586 struct stat senv, sdot;
587
588 /* Get the current working directory. We have to get it now,
589 since we're about to do a chdir. We use PWD if it's defined
590 and if it really names the working directory, since if it's
591 not the same as whatever getcwd returns it's probably more
592 appropriate. */
593 zenv = getenv ("PWD");
594 if (zenv != NULL
595 && stat (zenv, &senv) == 0
596 && stat (".", &sdot) == 0
597 && senv.st_ino == sdot.st_ino
598 && senv.st_dev == sdot.st_dev)
599 zScwd = xstrdup (zenv);
600 else
601 {
602
603#if HAVE_GETCWD || ! HAVE_GETWD
604 {
605 int c;
606
607 c = 128;
608 while (TRUE)
609 {
610 zScwd = (char *) xmalloc (c);
611 if (getcwd (zScwd, c) != NULL)
612 break;
613 if (errno != ERANGE)
614 ulog (LOG_FATAL, "getcwd: %s", strerror (errno));
615 xfree ((pointer) zScwd);
616 c <<= 1;
617 }
618 }
619#endif /* HAVE_GETCWD */
620
621#if HAVE_GETWD
622 zScwd = (char *) xmalloc (MAXPATHLEN);
623 /* The getwd function puts in an error message in the
624 buffer, rather than setting errno. */
625 if (getwd (zScwd) == NULL)
626 ulog (LOG_FATAL, "getwd: %s", zScwd);
627#endif /* HAVE_GETWD */
628
629 zScwd = (char *) xrealloc ((pointer) zScwd, strlen (zScwd) + 1);
630 }
631 }
632
633 /* Connect to the spool directory, and create it if is doesn't
634 exist. */
635 if (chdir (zSpooldir) < 0)
636 {
637 if (errno != ENOENT)
638 ulog (LOG_FATAL, "chdir (%s): %s", zSpooldir,
639 strerror (errno));
640 usmake_spool_dir ();
641 }
642}
643
644/* Exit the program. */
645
646void
647usysdep_exit (fsuccess)
648 boolean fsuccess;
649{
650 exit (fsuccess ? EXIT_SUCCESS : EXIT_FAILURE);
651}
652
653/* This is called when a non-standard configuration file is used, to
654 make sure the program doesn't hand out privileged file access.
655 This means that to test non-standard configuration files, you
656 should be logged in as uucp. This is called before
657 usysdep_initialize. It ensures that someone can't simply use an
658 alternate configuration file to steal UUCP transfers from other
659 systems. This will still permit people to set up their own
660 configuration file and pretend to be whatever system they choose.
661 The only real security is to use a high level of protection on the
662 modem ports. */
663
664/*ARGSUSED*/
665boolean fsysdep_other_config (z)
666 const char *z;
667{
668 (void) setuid (getuid ());
669 (void) setgid (getgid ());
670 return TRUE;
671}
672\f
673/* Detach from the controlling terminal. This is called by uucico if
674 it is calling out to another system, so that it can receive SIGHUP
675 signals from the port it calls out on. It is also called by uucico
676 just before it starts uuxqt, so that uuxqt is completely
677 independent of the terminal. */
678
679#ifdef TIOCNOTTY
680#define HAVE_TIOCNOTTY 1
681#else
682#define HAVE_TIOCNOTTY 0
683#endif
684
685void
686usysdep_detach ()
687{
688 int o;
689
690#if ! HAVE_BSD_PGRP || ! HAVE_TIOCNOTTY
691
692 pid_t igrp;
693
694 /* First make sure we are not a process group leader. If we have
695 TIOCNOTTY, this doesn't matter, since TIOCNOTTY sets our process
696 group to 0 anyhow. */
697
698#if HAVE_BSD_PGRP
699 igrp = getpgrp (0);
700#else
701 igrp = getpgrp ();
702#endif
703
704 if (igrp == getpid ())
705 {
706 boolean fignored;
707 pid_t ipid;
708
709 /* Ignore SIGHUP, since our process group leader is about to
710 die. */
711 usset_signal (SIGHUP, SIG_IGN, FALSE, &fignored);
712
713 ipid = isfork ();
714 if (ipid < 0)
715 ulog (LOG_FATAL, "fork: %s", strerror (errno));
716
717 if (ipid != 0)
718 _exit (EXIT_SUCCESS);
719
720 /* We'll always wind up as a child of process number 1, right?
721 Right? We have to wait for our parent to die before
722 reenabling SIGHUP. */
723 while (getppid () != 1)
724 sleep (1);
725
726 /* Restore SIGHUP catcher if it wasn't being ignored. */
727 if (! fignored)
728 usset_signal (SIGHUP, ussignal, TRUE, (boolean *) NULL);
729 }
730
731#endif /* ! HAVE_BSD_PGRP || ! HAVE_TIOCNOTTY */
732
733 /* Close all open files. */
734
735 ulog_close ();
736
737 for (o = 0; o < cSdescriptors; o++)
738 (void) close (o);
739
740 /* Reopen stdin, stdout and stderr. */
741
742 if (open ("/dev/null", O_RDONLY) != 0
743 || open ("/dev/null", O_WRONLY) != 1
744 || open ("/dev/null", O_WRONLY) != 2)
745 ulog (LOG_FATAL, "open (/dev/null): %s", strerror (errno));
746
747#if HAVE_BSD_PGRP
748
749#if HAVE_TIOCNOTTY
750 /* Lose our controlling terminal. */
751
752#ifndef O_NDELAY
753#define O_NDELAY FNDELAY
754#endif
755
756 o = open ("/dev/tty", O_RDWR | O_NDELAY, 0);
757 if (o >= 0)
758 {
759 (void) ioctl (o, TIOCNOTTY, (char *) NULL);
760 (void) close (o);
761 }
762#endif /* HAVE_TIOCNOTTY */
763
764 /* Make sure our process group ID is set to 0. On BSD TIOCNOTTY
765 should already have set it 0, so this will do no harm. On System
766 V we presumably did not execute the TIOCNOTTY call, but the
767 System V setpgrp will detach the controlling terminal anyhow.
768 This lets us use the same code on both BSD and System V, provided
769 it compiles correctly, which life easier for the configure
770 script. We don't output an error if we got EPERM because some
771 BSD variants don't permit this usage of setpgrp (which means they
772 don't provide any way to pick up a new controlling terminal). */
773
774 if (setpgrp (0, 0) < 0)
775 {
776 if (errno != EPERM)
777 ulog (LOG_ERROR, "setpgrp: %s", strerror (errno));
778 }
779
780#else /* ! HAVE_BSD_PGRP */
781
782#if HAVE_SETSID
783
784 /* Under POSIX the setsid call creates a new session for which we
785 are the process group leader. It also detaches us from our
786 controlling terminal. I'm using the BSD setpgrp call first
787 because they should be equivalent for my purposes, but it turns
788 out that on Ultrix 4.0 setsid prevents us from ever acquiring
789 another controlling terminal (it does not change our process
790 group, and Ultrix 4.0 prevents us from setting our process group
791 to 0). */
792
793 if (setsid () < 0)
794 ulog (LOG_ERROR, "setsid: %s", strerror (errno));
795
796#else /* ! HAVE_SETSID */
797
798#if HAVE_SETPGRP
799
800 /* Now we assume we have the System V setpgrp, which takes no
801 arguments, and we couldn't compile the HAVE_BSD_PGRP code above
802 because there was a prototype somewhere in scope. On System V
803 setpgrp makes us the leader of a new process group and also
804 detaches the controlling terminal. */
805
806 if (setpgrp () < 0)
807 ulog (LOG_ERROR, "setpgrp: %s", strerror (errno));
808
809#else /* ! HAVE_SETPGRP */
810
811 #error Must detach from controlling terminal
812
813#endif /* HAVE_SETPGRP */
814#endif /* ! HAVE_SETSID */
815#endif /* ! HAVE_BSD_PGRP */
816
817 /* At this point we have completely detached from our controlling
818 terminal. The next terminal device we open will probably become
819 our controlling terminal. */
820}
821\f
822/* Get the node name to use if it was not specified in the configuration
823 file. */
824
825const char *
826zsysdep_local_name ()
827{
828#if HAVE_GETHOSTNAME
829 char ab[256];
830
831 if (gethostname (ab, sizeof ab) < 0)
832 {
833 ulog (LOG_ERROR, "gethostname: %s", strerror (errno));
834 return NULL;
835 }
836 ab[sizeof ab - 1] = '\0';
837 ab[strcspn (ab, ".")] = '\0';
838 return xstrdup (ab);
839#else /* ! HAVE_GETHOSTNAME */
840#if HAVE_UNAME
841 struct utsname s;
842
843 if (uname (&s) < 0)
844 {
845 ulog (LOG_ERROR, "uname: %s", strerror (errno));
846 return NULL;
847 }
848 return xstrdup (s.nodename);
849#else /* ! HAVE_UNAME */
850 return NULL;
851#endif /* ! HAVE_UNAME */
852#endif /* ! HAVE_GETHOSTNAME */
853}
854\f
855/* Get the login name. We actually get the login name in
856 usysdep_initialize, because after that we will lost the real uid. */
857
858const char *
859zsysdep_login_name ()
860{
861 return zSlogin;
862}
863
864/* Get the port name of standard input. I assume that Unix systems
865 generally support ttyname. If they don't, this function can just
866 return NULL. It uses getsockname to see whether standard input is
867 a TCP connection. */
868
869const char *
870zsysdep_port_name (ftcp_port)
871 boolean *ftcp_port;
872{
873 const char *z;
874
875 *ftcp_port = FALSE;
876
877#if HAVE_TCP
878 {
879 int clen;
880
881 clen = 0;
882 if (getsockname (0, (struct sockaddr *) NULL, &clen) == 0)
883 *ftcp_port = TRUE;
884 }
885#endif /* HAVE_TCP */
886
887 z = ttyname (0);
888 if (z == NULL)
889 return NULL;
890 if (strncmp (z, "/dev/", 5) == 0)
891 return z + 5;
892 else
893 return z;
894}
895\f
896/* Signal handling routines. When we catch a signal, we want to set
897 the appropriate elements of afSignal and afLog_signal to TRUE. If
898 we are on a system which restarts system calls, we may also want to
899 longjmp out. On a system which does not restart system calls,
900 these signal handling routines are well-defined by ANSI C. */
901
902#if HAVE_RESTARTABLE_SYSCALLS
903volatile sig_atomic_t fSjmp;
904volatile jmp_buf sSjmp_buf;
905#endif /* HAVE_RESTARTABLE_SYSCALLS */
906
907/* The SVR3 sigset function can be called just like signal, unless
908 system calls are restarted which is extremely unlikely; we prevent
909 this case in sysh.unx. */
910#if HAVE_SIGSET && ! HAVE_SIGACTION && ! HAVE_SIGVEC
911#define signal sigset
912#endif
913
914/* Catch a signal. Reinstall the signal handler if necessary, set the
915 appropriate variables, and do a longjmp if necessary. */
916
917SIGtype
918ussignal (isig)
919 int isig;
920{
921 int iindex;
922
923#if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET
924 (void) signal (isig, ussignal);
925#endif
926
927 switch (isig)
928 {
929 default: iindex = INDEXSIG_SIGHUP; break;
930#ifdef SIGINT
931 case SIGINT: iindex = INDEXSIG_SIGINT; break;
932#endif
933#ifdef SIGQUIT
934 case SIGQUIT: iindex = INDEXSIG_SIGQUIT; break;
935#endif
936#ifdef SIGTERM
937 case SIGTERM: iindex = INDEXSIG_SIGTERM; break;
938#endif
939#ifdef SIGPIPE
940 case SIGPIPE: iindex = INDEXSIG_SIGPIPE; break;
941#endif
942 }
943
944 afSignal[iindex] = TRUE;
945 afLog_signal[iindex] = TRUE;
946
947#if HAVE_RESTARTABLE_SYSCALLS
948 if (fSjmp)
949 longjmp (sSjmp_buf, 1);
950#endif /* HAVE_RESTARTABLE_SYSCALLS */
951}
952
953/* Prepare to catch a signal. This is basically the ANSI C routine
954 signal, but it uses sigaction or sigvec instead if they are
955 available. If fforce is FALSE, we do not set the signal if it is
956 currently being ignored. If pfignored is not NULL and fforce is
957 FALSE, then *pfignored will be set to TRUE if the signal was
958 previously being ignored (if fforce is TRUE the value of *pfignored
959 is meaningless). If we can't change the signal handler we give a
960 fatal error. */
961
962void
963usset_signal (isig, pfn, fforce, pfignored)
964 int isig;
965 SIGtype (*pfn) P((int));
966 boolean fforce;
967 boolean *pfignored;
968{
969#if HAVE_SIGACTION
970
971 struct sigaction s;
972
973 if (! fforce)
974 {
975 sigemptyset (&s.sa_mask);
976 if (sigaction (isig, (struct sigaction *) NULL, &s) != 0)
977 ulog (LOG_FATAL, "sigaction (%d): %s", isig, strerror (errno));
978
979 if (s.sa_handler == SIG_IGN)
980 {
981 if (pfignored != NULL)
982 *pfignored = TRUE;
983 return;
984 }
985
986 if (pfignored != NULL)
987 *pfignored = FALSE;
988 }
989
990 s.sa_handler = pfn;
991 sigemptyset (&s.sa_mask);
992 s.sa_flags = 0;
993
994 if (sigaction (isig, &s, (struct sigaction *) NULL) != 0)
995 ulog (LOG_FATAL, "sigaction (%d): %s", isig, strerror (errno));
996
997#else /* ! HAVE_SIGACTION */
998#if HAVE_SIGVEC
999
1000 struct sigvec s;
1001
1002 if (! fforce)
1003 {
1004 if (sigvec (isig, (struct sigvec *) NULL, &s) != 0)
1005 ulog (LOG_FATAL, "sigvec (%d): %s", isig, strerror (errno));
1006
1007 if (s.sv_handler == SIG_IGN)
1008 {
1009 if (pfignored != NULL)
1010 *pfignored = TRUE;
1011 return;
1012 }
1013
1014 if (pfignored != NULL)
1015 *pfignored = FALSE;
1016 }
1017
1018 s.sv_handler = pfn;
1019 s.sv_mask = 0;
1020#ifdef SV_INTERRUPT
1021 s.sv_flags = SV_INTERRUPT;
1022#else
1023 s.sv_flags = 0;
1024#endif
1025
1026 if (sigvec (isig, &s, (struct sigvec *) NULL) != 0)
1027 ulog (LOG_FATAL, "sigvec (%d): %s", isig, strerror (errno));
1028
1029#else /* ! HAVE_SIGVEC */
1030
1031 if (! fforce)
1032 {
1033 if (signal (isig, SIG_IGN) == SIG_IGN)
1034 {
1035 if (pfignored != NULL)
1036 *pfignored = TRUE;
1037 return;
1038 }
1039
1040 if (pfignored != NULL)
1041 *pfignored = FALSE;
1042 }
1043
1044 (void) signal (isig, pfn);
1045
1046#endif /* ! HAVE_SIGVEC */
1047#endif /* ! HAVE_SIGACTION */
1048}
1049
1050/* The routine called by the system independent code, which always
1051 uses the same signal handler. */
1052
1053void
1054usysdep_signal (isig)
1055 int isig;
1056{
1057 usset_signal (isig, ussignal, FALSE, (boolean *) NULL);
1058}
1059\f
1060/* Get the time in seconds since the epoch, with optional
1061 microseconds. We use usysdep_process_time to get the microseconds
1062 if it will work (it won't is it uses times, since that returns a
1063 time based only on the process). */
1064
1065long
1066isysdep_time (pimicros)
1067 long *pimicros;
1068{
1069#if HAVE_GETTIMEOFDAY || HAVE_FTIME
1070 return isysdep_process_time (pimicros);
1071#else
1072 if (pimicros != NULL)
1073 *pimicros = 0;
1074 return time ((time_t *) NULL);
1075#endif
1076}
1077
1078/* Get the time in seconds and microseconds; this need only work
1079 within the process when called from the system independent code.
1080 It is also called by isysdep_time, above. */
1081
1082long
1083isysdep_process_time (pimicros)
1084 long *pimicros;
1085{
1086#if HAVE_GETTIMEOFDAY
1087 struct timeval stime;
1088 struct timezone stz;
1089
1090 (void) gettimeofday (&stime, &stz);
1091 if (pimicros != NULL)
1092 *pimicros = stime.tv_usec;
1093 return stime.tv_sec;
1094#endif /* HAVE_GETTIMEOFDAY */
1095
1096#if HAVE_FTIME
1097 struct timeb stime;
1098
1099 (void) ftime (&stime);
1100 if (pimicros != NULL)
1101 *pimicros = stime.millitm * 1000;
1102 return stime.time;
1103#endif /* HAVE_FTIME */
1104
1105#if HAVE_TIMES
1106 struct tms s;
1107 long i;
1108 static int itick;
1109
1110 if (itick == 0)
1111 {
1112#if TIMES_TICK != 0
1113 itick = TIMES_TICK;
1114#else /* TIMES_TICK == 0 */
1115 const char *z;
1116
1117 z = getenv ("HZ");
1118 if (z != NULL)
1119 itick = atoi (z);
1120
1121 /* If we really couldn't get anything, just use 60. */
1122 if (itick == 0)
1123 itick = 60;
1124#endif /* TIMES_TICK == 0 */
1125 }
1126
1127 i = (long) times (&s);
1128 if (pimicros != NULL)
1129 *pimicros = (i % (long) itick) * ((long) 1000000 / (long) itick);
1130 return i / (long) itick;
1131#endif /* HAVE_TIMES */
1132
1133#if ! HAVE_GETTIMEOFDAY && ! HAVE_FTIME && ! HAVE_TIMES
1134 if (pimicros != NULL)
1135 *pimicros = 0;
1136 return time ((time_t *) NULL);
1137#endif /* ! HAVE_GETTIMEOFDAY && ! HAVE_FTIME && ! HAVE_TIMES */
1138}
1139
1140/* Fill in a struct tm. */
1141
1142void
1143usysdep_localtime (itime, q)
1144 long itime;
1145 struct tm *q;
1146{
1147 time_t i;
1148
1149 i = (time_t) itime;
1150 memcpy (q, localtime (&i), sizeof (struct tm));
1151}
1152
1153/* Sleep for a number of seconds. */
1154
1155void
1156usysdep_sleep (c)
1157 int c;
1158{
1159 sleep (c);
1160}
1161\f
1162/* Check whether a file exists. */
1163
1164boolean
1165fsysdep_file_exists (zfile)
1166 const char *zfile;
1167{
1168 struct stat s;
1169
1170 return stat (zfile, &s) == 0;
1171}
1172\f
1173/* Open a stdio file with appropriate permissions. */
1174
1175FILE *
1176esysdep_fopen (zfile, fpublic, fappend, fmkdirs)
1177 const char *zfile;
1178 boolean fpublic;
1179 boolean fappend;
1180 boolean fmkdirs;
1181{
1182 int imode;
1183 int o;
1184 FILE *e;
1185
1186 if (fpublic)
1187 imode = IPUBLIC_FILE_MODE;
1188 else
1189 imode = IPRIVATE_FILE_MODE;
1190
1191 if (! fappend)
1192 o = creat (zfile, imode);
1193 else
1194 {
1195#ifdef O_CREAT
1196 o = open (zfile, O_WRONLY | O_APPEND | O_CREAT | O_NOCTTY, imode);
1197#else
1198 o = open (zfile, O_WRONLY | O_NOCTTY);
1199 if (o < 0 && errno == ENOENT)
1200 o = creat (zfile, imode);
1201#endif /* ! defined (O_CREAT) */
1202 }
1203
1204 if (o < 0)
1205 {
1206 if (errno == ENOENT && fmkdirs)
1207 {
1208 if (! fsysdep_make_dirs (zfile, fpublic))
1209 return NULL;
1210 if (! fappend)
1211 o = creat (zfile, imode);
1212 else
1213 {
1214#ifdef O_CREAT
1215 o = open (zfile, O_WRONLY | O_APPEND | O_CREAT, imode);
1216#else
1217 o = creat (zfile, imode);
1218#endif
1219 }
1220 }
1221 if (o < 0)
1222 {
1223 ulog (LOG_ERROR, "open (%s): %s", zfile, strerror (errno));
1224 return NULL;
1225 }
1226 }
1227
1228#ifndef O_CREAT
1229#ifdef O_APPEND
1230 if (fappend)
1231 {
1232 if (fcntl (o, F_SETFL, O_APPEND) != 0)
1233 {
1234 ulog (LOG_ERROR, "fcntl (%s, O_APPEND): %s", zfile,
1235 strerror (errno));
1236 (void) close (o);
1237 return NULL;
1238 }
1239 }
1240#endif /* defined (O_APPEND) */
1241#endif /* ! defined (O_CREAT) */
1242
1243 if (fappend)
1244 e = fdopen (o, (char *) "a");
1245 else
1246 e = fdopen (o, (char *) "w");
1247
1248 if (e == NULL)
1249 {
1250 ulog (LOG_ERROR, "fdopen: %s", strerror (errno));
1251 (void) close (o);
1252 }
1253
1254 return e;
1255}
1256\f
1257/* See whether a directory exists. */
1258
1259boolean
1260fsdirectory_exists (z)
1261 const char *z;
1262{
1263 struct stat s;
1264
1265 if (stat (z, &s) < 0)
1266 return FALSE;
1267 return S_ISDIR (s.st_mode);
1268}
1269
1270/* Create any directories needed for a file name. */
1271
1272boolean
1273fsysdep_make_dirs (zfile, fpublic)
1274 const char *zfile;
1275 boolean fpublic;
1276{
1277 char *zcopy, *z;
1278 int imode;
1279
1280 zcopy = (char *) alloca (strlen (zfile) + 1);
1281 strcpy (zcopy, zfile);
1282
1283 if (fpublic)
1284 imode = IPUBLIC_DIRECTORY_MODE;
1285 else
1286 imode = IDIRECTORY_MODE;
1287
1288 for (z = zcopy; *z != '\0'; z++)
1289 {
1290 if (*z == '/' && z != zcopy)
1291 {
1292 *z = '\0';
1293 if (! fsdirectory_exists (zcopy))
1294 {
1295 if (mkdir (zcopy, imode) != 0)
1296 {
1297 ulog (LOG_ERROR, "mkdir (%s): %s", zcopy,
1298 strerror (errno));
1299 return FALSE;
1300 }
1301 }
1302 *z = '/';
1303 }
1304 }
1305
1306 return TRUE;
1307}
1308\f
1309/* Tilde expand a file or directory name. */
1310
1311/*ARGSUSED*/
1312const char *
1313zstilde_expand (qsys, zfile)
1314 const struct ssysteminfo *qsys;
1315 const char *zfile;
1316{
1317 static int calc;
1318 static char *zalc;
1319 const char *zdir;
1320 int clen;
1321
1322 if (zfile[0] != '~')
1323 return zfile;
1324 else if (zfile[1] == '\0' || zfile[1] == '/')
1325 {
1326 const char *zpub;
1327
1328 if (qsys->zpubdir == NULL)
1329 zpub = zPubdir;
1330 else
1331 zpub = qsys->zpubdir;
1332 if (zfile[1] == '\0')
1333 return zpub;
1334 else
1335 {
1336 zdir = zpub;
1337 zfile += 2;
1338 }
1339 }
1340 else
1341 {
1342 int cuserlen;
1343 char *zcopy;
1344 struct passwd *q;
1345
1346 ++zfile;
1347 cuserlen = strcspn (zfile, "/");
1348 zcopy = (char *) alloca (cuserlen + 1);
1349 strncpy (zcopy, zfile, cuserlen);
1350 zcopy[cuserlen] = '\0';
1351
1352 q = getpwnam (zcopy);
1353 if (q == NULL)
1354 {
1355 ulog (LOG_ERROR, "User %s not found", zcopy);
1356 return NULL;
1357 }
1358
1359 if (zfile[cuserlen] == '\0')
1360 return q->pw_dir;
1361 else
1362 {
1363 zdir = q->pw_dir;
1364 zfile += cuserlen + 1;
1365 }
1366 }
1367
1368 clen = strlen (zdir) + strlen (zfile) + 2;
1369 if (clen > calc)
1370 {
1371 zalc = (char *) xrealloc ((pointer) zalc, clen);
1372 calc = clen;
1373 }
1374
1375 sprintf (zalc, "%s/%s", zdir, zfile);
1376 return zalc;
1377}
1378\f
1379/* Do access(2) on a stat structure, except that the user name is
1380 provided. If the user name in zuser is NULL, require the file to
1381 be accessible to the world. Return TRUE if access is permitted,
1382 FALSE otherwise. This does not log an error message. */
1383
1384boolean
1385fsuser_access (q, imode, zuser)
1386 const struct stat *q;
1387 int imode;
1388 const char *zuser;
1389{
1390 static char *zuser_hold;
1391 static uid_t iuid_hold;
1392 static gid_t igid_hold;
1393 static int cgroups_hold;
1394 static gid_t *paigroups_hold;
1395 int ir, iw, ix, iand;
1396
1397 if (imode == F_OK)
1398 return TRUE;
1399
1400 if (zuser != NULL)
1401 {
1402 /* We keep static variables around for the last user we did, to
1403 avoid looking up a user multiple times. */
1404 if (zuser_hold == NULL || strcmp (zuser_hold, zuser) != 0)
1405 {
1406 struct passwd *qpwd;
1407
1408 if (zuser_hold != NULL)
1409 {
1410 xfree ((pointer) zuser_hold);
1411 zuser_hold = NULL;
1412 cgroups_hold = 0;
1413 xfree ((pointer) paigroups_hold);
1414 paigroups_hold = NULL;
1415 }
1416
1417 qpwd = getpwnam ((char *) zuser);
1418 if (qpwd == NULL)
1419 {
1420 /* Check this as a remote request. */
1421 zuser = NULL;
1422 }
1423 else
1424 {
1425#if HAVE_GETGRENT
1426 struct group *qg;
1427#endif
1428
1429 zuser_hold = xstrdup (zuser);
1430
1431 iuid_hold = qpwd->pw_uid;
1432 igid_hold = qpwd->pw_gid;
1433
1434#if HAVE_GETGRENT
1435 /* Get the list of groups for this user. This is
1436 definitely more appropriate for BSD than for System
1437 V. It may just be a waste of time, and perhaps it
1438 should be configurable. */
1439 setgrent ();
1440 while ((qg = getgrent ()) != NULL)
1441 {
1442 const char **pz;
1443
1444 if (qg->gr_gid == igid_hold)
1445 continue;
1446 for (pz = (const char **) qg->gr_mem; *pz != NULL; pz++)
1447 {
1448 if ((*pz)[0] == *zuser
1449 && strcmp (*pz, zuser) == 0)
1450 {
1451 paigroups_hold = ((gid_t *)
1452 (xrealloc
1453 ((pointer) paigroups_hold,
1454 ((cgroups_hold + 1)
1455 * sizeof (gid_t)))));
1456 paigroups_hold[cgroups_hold] = qg->gr_gid;
1457 ++cgroups_hold;
1458 break;
1459 }
1460 }
1461 }
1462 endgrent ();
1463#endif
1464 }
1465 }
1466 }
1467
1468
1469 /* Now do the actual access check. */
1470
1471 if (zuser != NULL)
1472 {
1473 /* The superuser can do anything. */
1474 if (iuid_hold == 0)
1475 return TRUE;
1476
1477 /* If this is the uid we're running under, there's no point to
1478 checking access further, because when we actually try the
1479 operation the system will do the checking for us. */
1480 if (iuid_hold == geteuid ())
1481 return TRUE;
1482 }
1483
1484 ir = S_IROTH;
1485 iw = S_IWOTH;
1486 ix = S_IXOTH;
1487
1488 if (zuser != NULL)
1489 {
1490 if (iuid_hold == q->st_uid)
1491 {
1492 ir = S_IRUSR;
1493 iw = S_IWUSR;
1494 ix = S_IXUSR;
1495 }
1496 else
1497 {
1498 boolean fgroup;
1499
1500 fgroup = FALSE;
1501 if (igid_hold == q->st_gid)
1502 fgroup = TRUE;
1503 else
1504 {
1505 int i;
1506
1507 for (i = 0; i < cgroups_hold; i++)
1508 {
1509 if (paigroups_hold[i] == q->st_gid)
1510 {
1511 fgroup = TRUE;
1512 break;
1513 }
1514 }
1515 }
1516
1517 if (fgroup)
1518 {
1519 ir = S_IRGRP;
1520 iw = S_IWGRP;
1521 ix = S_IXGRP;
1522 }
1523 }
1524 }
1525
1526 iand = 0;
1527 if ((imode & R_OK) != 0)
1528 iand |= ir;
1529 if ((imode & W_OK) != 0)
1530 iand |= iw;
1531 if ((imode & X_OK) != 0)
1532 iand |= ix;
1533
1534 return (q->st_mode & iand) == iand;
1535}
1536
1537/* See whether a file is in a directory, and optionally check access. */
1538
1539boolean
1540fsysdep_in_directory (qsys, zfile, zdir, fcheck, freadable, zuser)
1541 const struct ssysteminfo *qsys;
1542 const char *zfile;
1543 const char *zdir;
1544 boolean fcheck;
1545 boolean freadable;
1546 const char *zuser;
1547{
1548 int c;
1549 char *zcopy, *zslash;
1550 struct stat s;
1551
1552 if (*zdir == '~')
1553 {
1554 zdir = zstilde_expand (qsys, zdir);
1555 if (zdir == NULL)
1556 return FALSE;
1557 }
1558 c = strlen (zdir);
1559 if (zdir[c - 1] == '/')
1560 c--;
1561 if (strncmp (zfile, zdir, c) != 0
1562 || (zfile[c] != '/' && zfile[c] != '\0'))
1563 return FALSE;
1564 if (strstr (zfile + c, "/../") != NULL)
1565 return FALSE;
1566
1567 /* If we're not checking access, get out now. */
1568
1569 if (! fcheck)
1570 return TRUE;
1571
1572 zcopy = (char *) alloca (strlen (zfile) + 1);
1573 strcpy (zcopy, zfile);
1574
1575 /* Start checking directories after zdir. Otherwise, we would
1576 require that all directories down to /usr/spool/uucppublic be
1577 publically searchable; they probably are but it should not be
1578 requirement. */
1579
1580 zslash = zcopy + c;
1581 do
1582 {
1583 char b;
1584 struct stat shold;
1585
1586 b = *zslash;
1587 *zslash = '\0';
1588
1589 shold = s;
1590 if (stat (zcopy, &s) != 0)
1591 {
1592 if (errno != ENOENT)
1593 {
1594 ulog (LOG_ERROR, "stat (%s): %s", zcopy, strerror (errno));
1595 return FALSE;
1596 }
1597
1598 /* If this is the top directory, any problems will be caught
1599 later when we try to open it. */
1600 if (zslash == zcopy + c)
1601 return TRUE;
1602
1603 /* Go back and check the last directory for read or write
1604 access. */
1605 s = shold;
1606 break;
1607 }
1608
1609 /* If this is not a directory, get out of the loop. */
1610 if (! S_ISDIR (s.st_mode))
1611 break;
1612
1613 /* Make sure the directory is searchable. */
1614 if (! fsuser_access (&s, X_OK, zuser))
1615 {
1616 ulog (LOG_ERROR, "%s: %s", zcopy, strerror (EACCES));
1617 return FALSE;
1618 }
1619
1620 /* If we've reached the end of the string, get out. */
1621 if (b == '\0')
1622 break;
1623
1624 *zslash = b;
1625 }
1626 while ((zslash = strchr (zslash + 1, '/')) != NULL);
1627
1628 /* At this point s holds a stat on the last component of the path.
1629 We must check it for readability or writeability. */
1630
1631 if (! fsuser_access (&s, freadable ? R_OK : W_OK, zuser))
1632 {
1633 ulog (LOG_ERROR, "%s: %s", zcopy, strerror (EACCES));
1634 return FALSE;
1635 }
1636
1637 return TRUE;
1638}
1639\f
1640/* Start up a new program and end the current one. We always go
1641 through isspawn, and never exec directly. We don't have to worry
1642 about SIGHUP because the current process is either not a process
1643 group leader (uucp, uux) or it does not have a controlling terminal
1644 (uucico). */
1645
1646boolean
1647fsysdep_run (ffork, zprogram, zarg1, zarg2)
1648 boolean ffork;
1649 const char *zprogram;
1650 const char *zarg1;
1651 const char *zarg2;
1652{
1653 char *zlib;
1654 const char *azargs[4];
1655 int aidescs[3];
1656 pid_t ipid;
1657
1658 zlib = (char *) alloca (sizeof LIBDIR + sizeof "/" + strlen (zprogram));
1659 sprintf (zlib, "%s/%s", LIBDIR, zprogram);
1660
1661 azargs[0] = zlib;
1662 azargs[1] = zarg1;
1663 azargs[2] = zarg2;
1664 azargs[3] = NULL;
1665
1666 aidescs[0] = SPAWN_NULL;
1667 aidescs[1] = SPAWN_NULL;
1668 aidescs[2] = SPAWN_NULL;
1669
1670 /* We pass fshell as TRUE, which permits uucico and uuxqt to be
1671 replaced by shell scripts. */
1672 ipid = isspawn (azargs, aidescs, FALSE, FALSE, (const char *) NULL,
1673 FALSE, TRUE, (const char *) NULL,
1674 (const char *) NULL, (const char *) NULL);
1675 if (ipid < 0)
1676 {
1677 ulog (LOG_ERROR, "isspawn: %s", strerror (errno));
1678 return FALSE;
1679 }
1680
1681 if (ffork)
1682 return TRUE;
1683
1684 exit (EXIT_SUCCESS);
1685}
1686\f
1687/* Mail a message to a user. */
1688
1689boolean
1690fsysdep_mail (zto, zsubject, cstrs, paz)
1691 const char *zto;
1692 const char *zsubject;
1693 int cstrs;
1694 const char **paz;
1695{
1696 const char *az[3];
1697 FILE *e;
1698 pid_t ipid;
1699 time_t itime;
1700 int i;
1701
1702 az[0] = MAIL_PROGRAM;
1703 az[1] = zto;
1704 az[2] = NULL;
1705
1706 e = espopen (az, FALSE, &ipid);
1707 if (e == NULL)
1708 {
1709 ulog (LOG_ERROR, "espopen (%s): %s", MAIL_PROGRAM,
1710 strerror (errno));
1711 return FALSE;
1712 }
1713
1714 fprintf (e, "Subject: %s\n", zsubject);
1715 fprintf (e, "To: %s\n", zto);
1716
1717 /* We should probably put in a Date: header as well. */
1718
1719 fprintf (e, "\n");
1720
1721 (void) time (&itime);
1722 /* Remember that ctime includes a \n, so this skips a line. */
1723 fprintf (e, "Message from UUCP on %s %s\n", zLocalname,
1724 ctime (&itime));
1725
1726 for (i = 0; i < cstrs; i++)
1727 fputs (paz[i], e);
1728
1729 (void) fclose (e);
1730
1731 return iswait ((unsigned long) ipid, MAIL_PROGRAM) == 0;
1732}
1733\f
1734/* Make a directory with error checking. */
1735
1736static void
1737xmkdir (zdir)
1738 const char *zdir;
1739{
1740 if (mkdir ((char *) zdir, IDIRECTORY_MODE) < 0)
1741 ulog (LOG_FATAL, "mkdir (%s): %s", zdir, strerror (errno));
1742}
1743
1744/* Make the spool directory. */
1745
1746static void
1747usmake_spool_dir ()
1748{
1749 xmkdir (zSpooldir);
1750
1751 if (chdir (zSpooldir) < 0)
1752 ulog (LOG_FATAL, "chdir (%s): %s", zSpooldir, strerror (errno));
1753
1754#if SPOOLDIR_BSD42 | SPOOLDIR_BSD43
1755 xmkdir ("C.");
1756 xmkdir ("D.");
1757#if SPOOLDIR_BSD43
1758 xmkdir ("X.");
1759#endif /* SPOOLDIR_BSD43 */
1760 {
1761 char ab[sizeof "D.1234567X"];
1762
1763 sprintf (ab, "D.%.7s", zLocalname);
1764 xmkdir (ab);
1765#if SPOOLDIR_BSD43
1766 strcat (ab, "X");
1767 xmkdir (ab);
1768#endif /* SPOOLDIR_BSD43 */
1769 }
1770#endif /* SPOOLDIR_BSD42 | SPOOLDIR_BSD43 */
1771
1772#if SPOOLDIR_ULTRIX
1773 xmkdir ("sys");
1774 xmkdir ("sys/DEFAULT");
1775 xmkdir ("sys/DEFAULT/C.");
1776 xmkdir ("sys/DEFAULT/D.");
1777 xmkdir ("sys/DEFAULT/X.");
1778 {
1779 char ab[sizeof "sys/DEFAULT/D.1234567X"];
1780
1781 sprintf (ab, "sys/DEFAULT/D.%.7s", zLocalname);
1782 xmkdir (ab);
1783 strcat (ab, "X");
1784 xmkdir (ab);
1785 }
1786#endif /* SPOOLDIR_ULTRIX */
1787
1788#if SPOOLDIR_BSD43 | SPOOLDIR_ULTRIX | SPOOLDIR_TAYLOR
1789 xmkdir (".Temp");
1790#endif /* SPOOLDIR_BSD43 | SPOOLDIR_ULTRIX | SPOOLDIR_TAYLOR */
1791
1792 xmkdir (".Status");
1793 xmkdir (".Sequence");
1794 xmkdir (XQTDIR);
1795 xmkdir (PRESERVEDIR);
1796}
1797\f
1798/* Retry fork several times before giving up. */
1799
1800pid_t
1801isfork ()
1802{
1803 int i;
1804 pid_t iret;
1805
1806 for (i = 0; i < 10; i++)
1807 {
1808 iret = fork ();
1809 if (iret >= 0 || errno != EAGAIN)
1810 return iret;
1811 sleep (5);
1812 }
1813
1814 return iret;
1815}
1816\f
1817/* Spawn a child in a fairly secure fashion. This returns the process
1818 ID of the child or -1 on error. It takes far too many arguments:
1819
1820 pazargs -- arguments (element 0 is command)
1821 aidescs -- file descriptors for stdin, stdout and stderr
1822 fkeepuid -- TRUE if euid should be left unchanged
1823 fkeepenv -- TRUE if environment should be left unmodified
1824 zchdir -- directory to chdir to
1825 fnosigs -- TRUE if child should ignore SIGHUP, SIGINT and SIGQUIT
1826 fshell -- TRUE if should try /bin/sh if execve gets ENOEXEC
1827 zpath -- value for environment variable PATH
1828 zuu_machine -- value for environment variable UU_MACHINE
1829 zuu_user -- value for environment variable UU_USER
1830
1831 The aidescs array is three elements long. 0 is stdin, 1 is stdout
1832 and 2 is stderr. The array may contain either file descriptor
1833 numbers to dup appropriately, or one of the following:
1834
1835 SPAWN_NULL -- set descriptor to /dev/null
1836 SPAWN_READ_PIPE -- set aidescs element to pipe for parent to read
1837 SPAWN_WRITE_PIPE -- set aidescs element to pipe for parent to write
1838
1839 If fkeepenv is FALSE, a standard environment is created. The
1840 environment arguments (zpath, zuu_machine and zuu_user) are only
1841 used if fkeepenv is FALSE; any of them may be NULL. */
1842
1843pid_t
1844isspawn (pazargs, aidescs, fkeepuid, fkeepenv, zchdir, fnosigs, fshell,
1845 zpath, zuu_machine, zuu_user)
1846 const char **pazargs;
1847 int aidescs[3];
1848 boolean fkeepuid;
1849 boolean fkeepenv;
1850 const char *zchdir;
1851 boolean fnosigs;
1852 boolean fshell;
1853 const char *zpath;
1854 const char *zuu_machine;
1855 const char *zuu_user;
1856{
1857 char *zshcmd = NULL;
1858 int i;
1859 char *azenv[9];
1860 char **pazenv;
1861 boolean ferr;
1862 int ierr = 0;
1863 int onull;
1864 int aichild_descs[3];
1865 int cpar_close;
1866 int aipar_close[4];
1867 int cchild_close;
1868 int aichild_close[3];
1869 pid_t iret = 0;
1870 const char *zcmd;
1871
1872 /* If we might have to use the shell, allocate enough space for the
1873 quoted command before forking. Otherwise the allocation might
1874 modify the data segment and we could not safely use vfork. */
1875 if (fshell)
1876 {
1877 int clen;
1878
1879 clen = 0;
1880 for (i = 0; pazargs[i] != NULL; i++)
1881 clen += strlen (pazargs[i]);
1882 zshcmd = (char *) alloca (2 * clen + i);
1883 }
1884
1885 /* Set up a standard environment. This is again done before forking
1886 because it might modify the data segment. */
1887
1888 if (fkeepenv)
1889 pazenv = environ;
1890 else
1891 {
1892 const char *zterm, *ztz;
1893 char *zspace;
1894 int ienv;
1895
1896 if (zpath == NULL)
1897 zpath = CMDPATH;
1898
1899 azenv[0] = (char *) alloca (sizeof "PATH=" + strlen (zpath));
1900 sprintf (azenv[0], "PATH=%s", zpath);
1901 zspace = azenv[0] + sizeof "PATH=" - 1;
1902 while ((zspace = strchr (zspace, ' ')) != NULL)
1903 *zspace = ':';
1904
1905 azenv[1] = (char *) alloca (sizeof "HOME=" + strlen (zSpooldir));
1906 sprintf (azenv[1], "HOME=%s", zSpooldir);
1907
1908 zterm = getenv ("TERM");
1909 if (zterm == NULL)
1910 zterm = "unknown";
1911 azenv[2] = (char *) alloca (sizeof "TERM=" + strlen (zterm));
1912 sprintf (azenv[2], "TERM=%s", zterm);
1913
1914 azenv[3] = (char *) "SHELL=/bin/sh";
1915
1916 azenv[4] = (char *) alloca (sizeof "USER=" + strlen (OWNER));
1917 sprintf (azenv[4], "USER=%s", OWNER);
1918
1919 ienv = 5;
1920
1921 ztz = getenv ("TZ");
1922 if (ztz != NULL)
1923 {
1924 azenv[ienv] = (char *) alloca (sizeof "TZ=" + strlen (ztz));
1925 sprintf (azenv[ienv], "TZ=%s", ztz);
1926 ++ienv;
1927 }
1928
1929 if (zuu_machine != NULL)
1930 {
1931 azenv[ienv] = (char *) alloca (sizeof "UU_MACHINE="
1932 + strlen (zuu_machine));
1933 sprintf (azenv[ienv], "UU_MACHINE=%s", zuu_machine);
1934 ++ienv;
1935 }
1936
1937 if (zuu_user != NULL)
1938 {
1939 azenv[ienv] = (char *) alloca (sizeof "UU_USER="
1940 + strlen (zuu_user));
1941 sprintf (azenv[ienv], "UU_USER=%s", zuu_user);
1942 ++ienv;
1943 }
1944
1945 azenv[ienv] = NULL;
1946 pazenv = azenv;
1947 }
1948
1949 /* Set up any needed pipes. */
1950
1951 ferr = FALSE;
1952 onull = -1;
1953 cpar_close = 0;
1954 cchild_close = 0;
1955
1956 for (i = 0; i < 3; i++)
1957 {
1958 if (aidescs[i] == SPAWN_NULL)
1959 {
1960 if (onull < 0)
1961 {
1962 onull = open ("/dev/null", O_RDWR);
1963 if (onull < 0)
1964 {
1965 ierr = errno;
1966 ferr = TRUE;
1967 break;
1968 }
1969 aipar_close[cpar_close] = onull;
1970 ++cpar_close;
1971 }
1972 aichild_descs[i] = onull;
1973 }
1974 else if (aidescs[i] != SPAWN_READ_PIPE
1975 && aidescs[i] != SPAWN_WRITE_PIPE)
1976 aichild_descs[i] = aidescs[i];
1977 else
1978 {
1979 int aipipe[2];
1980
1981 if (pipe (aipipe) < 0)
1982 {
1983 ierr = errno;
1984 ferr = TRUE;
1985 break;
1986 }
1987
1988 if (aidescs[i] == SPAWN_READ_PIPE)
1989 {
1990 aidescs[i] = aipipe[0];
1991 aichild_close[cchild_close] = aipipe[0];
1992 aichild_descs[i] = aipipe[1];
1993 aipar_close[cpar_close] = aipipe[1];
1994 }
1995 else
1996 {
1997 aidescs[i] = aipipe[1];
1998 aichild_close[cchild_close] = aipipe[1];
1999 aichild_descs[i] = aipipe[0];
2000 aipar_close[cpar_close] = aipipe[0];
2001 }
2002
2003 ++cpar_close;
2004 ++cchild_close;
2005 }
2006 }
2007
2008#if DEBUG > 1
2009 if (! ferr && FDEBUGGING (DEBUG_EXECUTE))
2010 {
2011 ulog (LOG_DEBUG_START, "Forking %s", pazargs[0]);
2012 for (i = 1; pazargs[i] != NULL; i++)
2013 ulog (LOG_DEBUG_CONTINUE, " %s", pazargs[i]);
2014 ulog (LOG_DEBUG_END, "%s", "");
2015 }
2016#endif
2017
2018 if (! ferr)
2019 {
2020 /* This should really be vfork if available. */
2021 iret = isfork ();
2022 if (iret < 0)
2023 {
2024 ferr = TRUE;
2025 ierr = errno;
2026 }
2027 }
2028
2029 if (ferr)
2030 {
2031 for (i = 0; i < cpar_close; i++)
2032 (void) close (aipar_close[i]);
2033 for (i = 0; i < cchild_close; i++)
2034 (void) close (aichild_close[i]);
2035 errno = ierr;
2036 return -1;
2037 }
2038
2039 /* Here the fork has succeeded and all the pipes have been done. */
2040
2041 if (iret != 0)
2042 {
2043 /* The parent. Close the child's ends of the pipes and return
2044 the process ID. */
2045 for (i = 0; i < cpar_close; i++)
2046 (void) close (aipar_close[i]);
2047 return iret;
2048 }
2049
2050 /* The child. */
2051
2052#ifdef STDIN_FILENO
2053#if STDIN_FILENO != 0 || STDOUT_FILENO != 1 || STDERR_FILENO != 2
2054 #error The following code makes invalid assumptions
2055#endif
2056#endif
2057
2058 for (i = 0; i < 3; i++)
2059 if (aichild_descs[i] != i)
2060 (void) dup2 (aichild_descs[i], i);
2061
2062 for (i = 3; i < cSdescriptors; i++)
2063 (void) close (i);
2064
2065 zcmd = pazargs[0];
2066 pazargs[0] = strrchr (zcmd, '/');
2067 if (pazargs[0] == NULL)
2068 pazargs[0] = zcmd;
2069 else
2070 ++pazargs[0];
2071
2072 if (! fkeepuid)
2073 {
2074 (void) setuid (getuid ());
2075 (void) setgid (getgid ());
2076 }
2077
2078 if (zchdir != NULL)
2079 (void) chdir (zchdir);
2080
2081 if (fnosigs)
2082 {
2083#ifdef SIGHUP
2084 (void) signal (SIGHUP, SIG_IGN);
2085#endif
2086#ifdef SIGINT
2087 (void) signal (SIGINT, SIG_IGN);
2088#endif
2089#ifdef SIGQUIT
2090 (void) signal (SIGQUIT, SIG_IGN);
2091#endif
2092 }
2093
2094 (void) execve ((char *) zcmd, (char **) pazargs, pazenv);
2095
2096 /* The exec failed. If permitted, try using /bin/sh to execute a
2097 shell script. */
2098
2099 if (errno == ENOEXEC && fshell)
2100 {
2101 char *zto;
2102 const char *azshargs[4];
2103
2104 pazargs[0] = zcmd;
2105 zto = zshcmd;
2106 for (i = 0; pazargs[i] != NULL; i++)
2107 {
2108 const char *zfrom;
2109
2110 for (zfrom = pazargs[i]; *zfrom != '\0'; zfrom++)
2111 {
2112 /* Some versions of /bin/sh appear to have a bug such
2113 that quoting a '/' sometimes causes an error. I
2114 don't know exactly when this happens (I can recreate
2115 it on Ultrix 4.0), but in any case it is harmless to
2116 not quote a '/'. */
2117 if (*zfrom != '/')
2118 *zto++ = '\\';
2119 *zto++ = *zfrom;
2120 }
2121 *zto++ = ' ';
2122 }
2123 *(zto - 1) = '\0';
2124
2125 azshargs[0] = "sh";
2126 azshargs[1] = "-c";
2127 azshargs[2] = zshcmd;
2128 azshargs[3] = NULL;
2129
2130 (void) execve ((char *) "/bin/sh", (char **) azshargs, pazenv);
2131 }
2132
2133 _exit (EXIT_FAILURE);
2134
2135 /* Avoid compiler warning. */
2136 return -1;
2137}
2138
2139/* A version of popen that goes through isspawn. This actually takes
2140 an array of arguments rather than a string, and takes a boolean
2141 read/write value rather than a string. It sets *pipid to the
2142 process ID of the child. */
2143
2144FILE *
2145espopen (pazargs, frd, pipid)
2146 const char **pazargs;
2147 boolean frd;
2148 pid_t *pipid;
2149{
2150 int aidescs[3];
2151 pid_t ipid;
2152 FILE *eret;
2153
2154 if (frd)
2155 {
2156 aidescs[0] = SPAWN_NULL;
2157 aidescs[1] = SPAWN_READ_PIPE;
2158 }
2159 else
2160 {
2161 aidescs[0] = SPAWN_WRITE_PIPE;
2162 aidescs[1] = SPAWN_NULL;
2163 }
2164 aidescs[2] = SPAWN_NULL;
2165
2166 ipid = isspawn (pazargs, aidescs, FALSE, FALSE,
2167 (const char *) NULL, FALSE, TRUE,
2168 (const char *) NULL, (const char *) NULL,
2169 (const char *) NULL);
2170 if (ipid < 0)
2171 return NULL;
2172
2173 if (frd)
2174 eret = fdopen (aidescs[1], (char *) "r");
2175 else
2176 eret = fdopen (aidescs[0], (char *) "w");
2177
2178 if (eret == NULL)
2179 {
2180 int ierr;
2181
2182 ierr = errno;
2183 (void) close (frd ? aidescs[1] : aidescs[0]);
2184 (void) kill (ipid, SIGKILL);
2185 (void) iswait ((unsigned long) ipid, (const char *) NULL);
2186 errno = ierr;
2187 return NULL;
2188 }
2189
2190 *pipid = ipid;
2191
2192 return eret;
2193}
2194
2195/* Wait for a particular process to finish. The ipid argument should
2196 be pid_t, but then we couldn't have a prototype. If the zreport
2197 argument is not NULL, then a wait error will be logged, and if the
2198 exit status is non-zero it will be logged with zreport as the
2199 header of the log message. If the zreport argument is NULL, no
2200 errors will be logged. This function returns the exit status if
2201 the process exited normally, or -1 on error or if the process was
2202 killed by a signal (I don't just always return the exit status
2203 because then the calling code would have to prepared to handle
2204 union wait status vs. int status, and none of the callers care
2205 which signal killed the program anyhow).
2206
2207 This functions keeps waiting until the process finished, even if it
2208 is interrupted by a signal. I think this is right for all uses.
2209 The controversial one would be when called from uuxqt to wait for a
2210 requested process. Hitting uuxqt with SIGKILL will approximate the
2211 actions taken if we return from here with an error anyhow. If we
2212 do get a signal, we call ulog with a NULL argument to get it in the
2213 log file at about the right time. */
2214
2215int
2216iswait (ipid, zreport)
2217 unsigned long ipid;
2218 const char *zreport;
2219{
2220 wait_status istat;
2221
2222#if HAVE_WAITPID
2223 while (waitpid ((pid_t) ipid, &istat, 0) < 0)
2224 {
2225 if (errno != EINTR)
2226 {
2227 if (zreport != NULL)
2228 ulog (LOG_ERROR, "waitpid: %s", strerror (errno));
2229 return -1;
2230 }
2231 ulog (LOG_ERROR, (const char *) NULL);
2232 }
2233#else /* ! HAVE_WAITPID */
2234#if HAVE_WAIT4
2235 while (wait4 ((pid_t) ipid, &istat, 0, (struct rusage *) NULL) < 0)
2236 {
2237 if (errno != EINTR)
2238 {
2239 if (zreport != NULL)
2240 ulog (LOG_ERROR, "wait4: %s", strerror (errno));
2241 return -1;
2242 }
2243 ulog (LOG_ERROR, (const char *) NULL);
2244 }
2245#else /* ! HAVE_WAIT4 */
2246 pid_t igot;
2247
2248 /* We could theoretically get the wrong child here if we're in some
2249 kind of weird pipeline, so we don't give any error messages for
2250 it. */
2251 while ((igot = wait (&istat)) != (pid_t) ipid)
2252 {
2253 if (igot < 0)
2254 {
2255 if (errno != EINTR)
2256 {
2257 if (zreport != NULL)
2258 ulog (LOG_ERROR, "wait: %s", strerror (errno));
2259 return -1;
2260 }
2261 ulog (LOG_ERROR, (const char *) NULL);
2262 }
2263 }
2264#endif /* ! HAVE_WAIT4 */
2265#endif /* ! HAVE_WAITPID */
2266
2267 DEBUG_MESSAGE2 (DEBUG_EXECUTE, "%s %d",
2268 WIFEXITED (istat) ? "Exit status" : "Signal",
2269 WIFEXITED (istat) ? WEXITSTATUS (istat) : WTERMSIG (istat));
2270
2271 if (WIFEXITED (istat) && WEXITSTATUS (istat) == 0)
2272 return 0;
2273
2274 if (zreport != NULL)
2275 {
2276 if (! WIFEXITED (istat))
2277 ulog (LOG_ERROR, "%s: Got signal %d", zreport, WTERMSIG (istat));
2278 else
2279 ulog (LOG_ERROR, "%s: Exit status %d", zreport,
2280 WEXITSTATUS (istat));
2281 }
2282
2283 if (WIFEXITED (istat))
2284 return WEXITSTATUS (istat);
2285 else
2286 return -1;
2287}
2288\f
2289#if ! HAVE_REMOVE
2290
2291/* Remove a file. */
2292
2293int
2294remove (z)
2295 const char *z;
2296{
2297 return unlink (z);
2298}
2299
2300#endif /* ! HAVE_REMOVE */
2301
2302#if ! HAVE_STRERROR
2303
2304/* Some systems don't have a strerror definition, so we provide one.
2305 This function is, of course, system dependent. */
2306
2307char *
2308strerror (ierr)
2309 int ierr;
2310{
2311 extern int sys_nerr;
2312 extern char *sys_errlist[];
2313
2314 if (ierr >= 0 && ierr < sys_nerr)
2315 return sys_errlist[ierr];
2316 return (char *) "unknown error";
2317}
2318
2319#endif /* ! HAVE_STRERROR */
2320\f
2321#if ! HAVE_GETCWD && ! HAVE_GETWD
2322
2323/* Implement a simple getcwd that just calls /bin/pwd. I probably
2324 should include Roland McGrath's getcwd implementation here, since
2325 it doesn't fork, but it requires readdir support that I don't feel
2326 like contemplating just now. */
2327
2328static char *
2329getcwd (zbuf, cbuf)
2330 char *zbuf;
2331 int cbuf;
2332{
2333 const char *azargs[2];
2334 FILE *e;
2335 pid_t ipid;
2336 int cread;
2337 int ierr;
2338
2339 azargs[0] = PWD_PROGRAM;
2340 azargs[1] = NULL;
2341 e = espopen (azargs, TRUE, &ipid);
2342 if (e == NULL)
2343 return NULL;
2344
2345 ierr = 0;
2346
2347 cread = fread (zbuf, sizeof (char), cbuf, e);
2348 if (cread == 0)
2349 ierr = errno;
2350
2351 (void) fclose (e);
2352
2353 if (iswait ((unsigned long) ipid, (const char *) NULL) != 0)
2354 {
2355 ierr = EACCES;
2356 cread = 0;
2357 }
2358
2359 if (cread != 0)
2360 {
2361 if (zbuf[cread - 1] == '\n')
2362 zbuf[cread - 1] = '\0';
2363 else
2364 {
2365 ierr = ERANGE;
2366 cread = 0;
2367 }
2368 }
2369
2370 if (cread == 0)
2371 {
2372 errno = ierr;
2373 return NULL;
2374 }
2375
2376 return zbuf;
2377}
2378
2379#endif /* ! HAVE_GETCWD && ! HAVE_GETWD */
2380\f
2381#if ! HAVE_DUP2
2382
2383/* Emulate the dup2 call. I basically took this from the emacs 18.57
2384 distribution, although I cleaned it up a bit and made it POSIX
2385 compliant. */
2386
2387int
2388dup2 (oold, onew)
2389 int oold;
2390 int onew;
2391{
2392 if (oold == onew)
2393 return onew;
2394 (void) close (onew);
2395
2396#ifdef F_DUPFD
2397 return fcntl (oold, F_DUPFD, onew);
2398#else
2399 {
2400 int onext, oret, isave;
2401
2402 onext = dup (oold);
2403 if (onext == onew)
2404 return onext;
2405 if (onext < 0)
2406 return -1;
2407 oret = dup2 (oold, onew);
2408 isave = errno;
2409 (void) close (onext);
2410 errno = isave;
2411 return oret;
2412 }
2413#endif
2414}
2415
2416#endif /* ! HAVE_DUP2 */
2417\f
2418#if ! HAVE_OPENDIR
2419
2420/* Simple emulations of opendir/readdir/closedir for systems which
2421 have the original format of Unix directories. It's probably better
2422 to get Doug Gwyn's public domain set of emulation functions. */
2423
2424DIR *
2425opendir (zdir)
2426 const char *zdir;
2427{
2428 int o;
2429 struct stat s;
2430 DIR *qret;
2431
2432 o = open (zdir, O_RDONLY | O_NOCTTY, 0);
2433 if (o == -1)
2434 return NULL;
2435 if (fstat (o, &s) < 0)
2436 {
2437 (void) close (o);
2438 return NULL;
2439 }
2440 if (! S_ISDIR (s.st_mode))
2441 {
2442 (void) close (o);
2443 errno = ENOTDIR;
2444 return NULL;
2445 }
2446 qret = (DIR *) xmalloc (sizeof (DIR));
2447 qret->o = o;
2448 return qret;
2449}
2450
2451struct dirent *
2452readdir (q)
2453 DIR *q;
2454{
2455 struct direct sdir;
2456 int cgot;
2457
2458 do
2459 {
2460 cgot = read (q->o, &sdir, sizeof (struct direct));
2461 if (cgot <= 0)
2462 return NULL;
2463 if (cgot != sizeof (struct direct))
2464 {
2465 errno = ENOENT;
2466 return NULL;
2467 }
2468 }
2469 while (sdir.d_ino == 0);
2470
2471 strncpy (q->s.d_name, sdir.d_name, DIRSIZ);
2472 q->s.d_name[DIRSIZ] = '\0';
2473 return &q->s;
2474}
2475
2476int
2477closedir (q)
2478 DIR *q;
2479{
2480 int iret, isave;
2481
2482 iret = close (q->o);
2483 isave = errno;
2484 xfree (q);
2485 errno = isave;
2486 return iret;
2487}
2488
2489#endif /* ! HAVE_OPENDIR */
2490\f
2491#if ! HAVE_MKDIR
2492
2493/* We don't have the mkdir system call, so we invoke the suid program
2494 uudir to create the directory with the correct owner. */
2495
2496int
2497mkdir (zdir, imode)
2498 const char *zdir;
2499 int imode;
2500{
2501 const char *azargs[2];
2502 int aidescs[3];
2503 pid_t ipid;
2504
2505 /* /bin/mkdir will create the directory with mode 777, so we set our
2506 umask to get the mode we want. */
2507 (void) umask ((~ imode) & (S_IRWXU | S_IRWXG | S_IRWXO));
2508
2509 azargs[0] = UUDIR_PROGRAM;
2510 azargs[1] = NULL;
2511 aidescs[0] = SPAWN_NULL;
2512 aidescs[1] = SPAWN_NULL;
2513 aidescs[2] = SPAWN_NULL;
2514
2515 ipid = isspawn (azargs, aidescs, FALSE, FALSE, (const char *) NULL,
2516 TRUE, FALSE, (const char *) NULL,
2517 (const char *) NULL, (const char *) NULL);
2518
2519 (void) umask (0);
2520
2521 if (ipid < 0)
2522 return -1;
2523
2524 if (iswait ((unsigned long) ipid, (const char *) NULL) != 0)
2525 {
2526 /* Make up an errno value. */
2527 errno = EACCES;
2528 return -1;
2529 }
2530
2531 return 0;
2532}
2533
2534#endif /* ! HAVE_MKDIR */
2535\f
2536/*
2537 Local variables:
2538 mode:c
2539 End:
2540 */