~ubuntu-branches/ubuntu/precise/util-linux/precise-proposed

« back to all changes in this revision

Viewing changes to simpleinit/simpleinit.c

  • Committer: Bazaar Package Importer
  • Author(s): Steve Langasek
  • Date: 2011-06-20 22:31:50 UTC
  • mfrom: (1.6.3 upstream) (4.5.1 sid)
  • Revision ID: james.westby@ubuntu.com-20110620223150-lz8wrv0946ihcz3z
Tags: 2.19.1-2ubuntu1
* Merge from Debian unstable, remaining changes:
  - Build for multiarch.
  - Add pre-depends on multiarch-support.
  - configure.ac: don't try to be clever about extracting a path name from
    $libdir to append to /usr in a way that's not overridable; instead,
    reuse the built-in configurable libexecdir.
  - Fix up the .pc.in files to know about libexecdir, so our substitutions
    don't leave us with unusable pkg-config files.
  - Install custom blkid.conf to use /dev/.blkid.tab since we don't
    expect device names to survive a reboot
  - Mention mountall(8) in fstab(5) manpages, along with its special
    options.
  - Since upstart is required in Ubuntu, the hwclock.sh init script is not
    called on startup and the hwclockfirst.sh init script is removed.
  - Drop depends on initscripts for the above.
  - Replace hwclock udev rule with an Upstart job.
  - For the case where mount is called with a directory to mount, look
    that directory up in mountall's /lib/init/fstab if we couldn't find
    it mentioned anywhere else.  This means "mount /proc", "mount /sys",
    etc. work.
  - mount.8 points to the cifs-utils package, not the obsolete smbfs one. 
* Dropped changes:
  - mount.preinst: lsb_release has been fixed in lucid and above to be
    usable without configuration, so we don't have to diverge from Debian
    here anymore.
* Changes merged upstream:
  - sfdisk support for '+' with '-N'
  - mount/umount.c: fix a segfault on umount with empty mtab entry
  - Fix arbitrary unmount with fuse security issue

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* simpleinit.c - poe@daimi.aau.dk */
 
2
/* Version 2.0.2 */
 
3
 
 
4
/* 1999-02-22 Arkadiusz Mi�kiewicz <misiek@pld.ORG.PL>
 
5
 * - added Native Language Support
 
6
 * 2001-01-25 Richard Gooch <rgooch@atnf.csiro.au>
 
7
 * - fixed bug with failed services so they may be later "reclaimed"
 
8
 * 2001-02-02 Richard Gooch <rgooch@atnf.csiro.au>
 
9
 * - fixed race when reading from pipe and reaping children
 
10
 * 2001-02-18 sam@quux.dropbear.id.au
 
11
 * - fixed bug in <get_path>: multiple INIT_PATH components did not work
 
12
 * 2001-02-21 Richard Gooch <rgooch@atnf.csiro.au>
 
13
 * - block signals in handlers, so that longjmp() doesn't kill context
 
14
 * 2001-02-25 Richard Gooch <rgooch@atnf.csiro.au>
 
15
 * - make default INIT_PATH the boot_prog (if it is a directory) - YECCH
 
16
 * 2002-11-20 patch from SuSE
 
17
 * - refuse initctl_fd if setting FD_CLOEXEC fails
 
18
 */
 
19
 
 
20
#include <sys/types.h>
 
21
#include <stdlib.h>
 
22
#include <unistd.h>
 
23
#include <stdio.h>
 
24
#include <ctype.h>
 
25
#include <fcntl.h>
 
26
#include <string.h>
 
27
#include <signal.h>
 
28
#include <errno.h>
 
29
#include <time.h>
 
30
#include <pwd.h>
 
31
#include <sys/file.h>
 
32
#include <sys/wait.h>
 
33
#include <sys/stat.h>
 
34
#include <sys/sysmacros.h>
 
35
#include <sys/time.h>
 
36
#include <sys/ioctl.h>
 
37
#include <dirent.h>
 
38
#include <termios.h>
 
39
#include <utmp.h>
 
40
#include <setjmp.h>
 
41
#include <sched.h>
 
42
#ifdef SHADOW_PWD
 
43
#  include <shadow.h>
 
44
#endif
 
45
 
 
46
#ifdef HAVE_CRYPT_H
 
47
#include <crypt.h>
 
48
#endif
 
49
 
 
50
#include "pathnames.h"
 
51
#include "linux_reboot.h"
 
52
#include "strutils.h"
 
53
#include "nls.h"
 
54
#include "simpleinit.h"
 
55
 
 
56
 
 
57
#define CMDSIZ     150  /* max size of a line in inittab */
 
58
#define NUMCMD     30   /* max number of lines in inittab */
 
59
#define NUMTOK     20   /* max number of tokens in inittab command */
 
60
#define PATH_SIZE  (CMDSIZ+CMDSIZ+1)
 
61
 
 
62
#define MAX_RESPAWN_RATE  5  /*  number of respawns per 100 seconds  */
 
63
 
 
64
#define TZFILE "/etc/TZ"
 
65
char tzone[CMDSIZ];
 
66
/* #define DEBUGGING */
 
67
 
 
68
/* Define this if you want init to ignore the termcap field in inittab for
 
69
   console ttys. */
 
70
/* #define SPECIAL_CONSOLE_TERM */
 
71
 
 
72
#define ever (;;)
 
73
 
 
74
struct initline {
 
75
        pid_t           pid;
 
76
        char            tty[10];
 
77
        char            termcap[30];
 
78
        char            *toks[NUMTOK];
 
79
        char            line[CMDSIZ];
 
80
        struct timeval  last_start;
 
81
        signed long     rate;
 
82
};
 
83
 
 
84
struct initline inittab[NUMCMD];
 
85
int numcmd;
 
86
int stopped = 0;        /* are we stopped */
 
87
static char boot_prog[PATH_SIZE] = _PATH_RC;
 
88
static char script_prefix[PATH_SIZE] = "\0";
 
89
static char final_prog[PATH_SIZE] = "\0";
 
90
static char init_path[PATH_SIZE] = "\0";
 
91
static int caught_sigint = 0;
 
92
static int no_reboot = 0;
 
93
static pid_t rc_child = -1;
 
94
static const char *initctl_name = "/dev/initctl";
 
95
static int initctl_fd = -1;
 
96
static volatile int do_longjmp = 0;
 
97
static sigjmp_buf jmp_env;
 
98
 
 
99
 
 
100
static void do_single (void);
 
101
static int do_rc_tty (const char *path);
 
102
static int process_path (const char *path, int (*func) (const char *path),
 
103
                         int ignore_dangling_symlink);
 
104
static int preload_file (const char *path);
 
105
static int run_file (const char *path);
 
106
static void spawn (int i), read_inittab (void);
 
107
static void sighup_handler (int sig);
 
108
static void sigtstp_handler (int sig);
 
109
static void sigint_handler (int sig);
 
110
static void sigchild_handler (int sig);
 
111
static void sigquit_handler (int sig);
 
112
static void sigterm_handler (int sig);
 
113
#ifdef SET_TZ
 
114
static void set_tz (void);
 
115
#endif
 
116
static void write_wtmp (void);
 
117
static pid_t mywait (int *status);
 
118
static int run_command (const char *file, const char *name, pid_t pid);
 
119
 
 
120
 
 
121
static void err (char *s)
 
122
{
 
123
        int fd;
 
124
        
 
125
        if((fd = open("/dev/console", O_WRONLY)) < 0) return;
 
126
 
 
127
        write(fd, "init: ", 6); 
 
128
        write(fd, s, strlen(s));
 
129
        close(fd);
 
130
}
 
131
 
 
132
static void enter_single (void)
 
133
{
 
134
    pid_t pid;
 
135
    int i;
 
136
 
 
137
    err(_("Booting to single user mode.\n"));
 
138
    if((pid = fork()) == 0) {
 
139
        /* the child */
 
140
        execl(_PATH_BSHELL, _PATH_BSHELL, NULL);
 
141
        err(_("exec of single user shell failed\n"));
 
142
    } else if(pid > 0) {
 
143
        while (waitpid (pid, &i, 0) != pid)  /*  Nothing  */;
 
144
    } else if(pid < 0) {
 
145
        err(_("fork of single user shell failed\n"));
 
146
    }
 
147
    unlink(_PATH_SINGLE);
 
148
}
 
149
 
 
150
int main(int argc, char *argv[])
 
151
{
 
152
        int                     vec, i;
 
153
        int                     want_single = 0;
 
154
        pid_t                   pid;
 
155
        struct sigaction        sa;
 
156
 
 
157
 
 
158
#ifdef SET_TZ
 
159
        set_tz();
 
160
#endif
 
161
        sigfillset (&sa.sa_mask);  /*  longjmp and nested signals don't mix  */
 
162
        sa.sa_flags = SA_ONESHOT;
 
163
        sa.sa_handler = sigint_handler;
 
164
        sigaction (SIGINT, &sa, NULL);
 
165
        sa.sa_flags = 0;
 
166
        sa.sa_handler = sigtstp_handler;
 
167
        sigaction (SIGTSTP, &sa, NULL);
 
168
        sa.sa_handler = sigterm_handler;
 
169
        sigaction (SIGTERM, &sa, NULL);
 
170
        sa.sa_handler = sigchild_handler;
 
171
        sigaction (SIGCHLD, &sa, NULL);
 
172
        sa.sa_handler = sigquit_handler;
 
173
        sigaction (SIGQUIT, &sa, NULL);
 
174
 
 
175
        setlocale(LC_ALL, "");
 
176
        bindtextdomain(PACKAGE, LOCALEDIR);
 
177
        textdomain(PACKAGE);
 
178
 
 
179
        my_reboot (LINUX_REBOOT_CMD_CAD_OFF);
 
180
        /*  Find script to run. Command-line overrides config file overrides
 
181
            built-in default  */
 
182
        for (i = 0; i < NUMCMD; i++) inittab[i].pid = -1;
 
183
        read_inittab ();
 
184
        for (i = 1; i < argc; i++) {
 
185
                if (strcmp (argv[i], "single") == 0)
 
186
                        want_single = 1;
 
187
                else if (strcmp (argv[i], "-noreboot") == 0)
 
188
                        no_reboot = 1;
 
189
                else if (strlen(script_prefix) + strlen(argv[i]) < PATH_SIZE) {
 
190
                        char path[PATH_SIZE];
 
191
 
 
192
                        strcpy (path, script_prefix);
 
193
                        strcat (path, argv[i]);
 
194
                        if (access (path, R_OK | X_OK) == 0)
 
195
                                strcpy (boot_prog, path);
 
196
                }
 
197
        }
 
198
        if (init_path[0] == '\0')
 
199
        {
 
200
            struct stat statbuf;
 
201
 
 
202
            if ( (stat (boot_prog, &statbuf) == 0) && S_ISDIR (statbuf.st_mode) )
 
203
            {
 
204
                strcpy (init_path, boot_prog);
 
205
                i = strlen (init_path);
 
206
                if (init_path[i - 1] == '/') init_path[i - 1] = '\0';
 
207
            }
 
208
        }
 
209
 
 
210
        if ( ( initctl_fd = open (initctl_name, O_RDWR, 0) ) < 0 ) {
 
211
                mkfifo (initctl_name, S_IRUSR | S_IWUSR);
 
212
                if ( ( initctl_fd = open (initctl_name, O_RDWR, 0) ) < 0 )
 
213
                        err ( _("error opening fifo\n") );
 
214
        }
 
215
 
 
216
        if (initctl_fd >= 0 && fcntl(initctl_fd, F_SETFD, FD_CLOEXEC) != 0) {
 
217
                err ( _("error setting close-on-exec on /dev/initctl") );
 
218
 
 
219
                /* Can the fcntl ever fail?  If it does, and we leave
 
220
                   the descriptor open in child processes, then any
 
221
                   process on the system will be able to write to
 
222
                   /dev/initctl and have us execute arbitrary commands
 
223
                   as root. So let's refuse to use the fifo in this case. */
 
224
 
 
225
                close(initctl_fd);
 
226
                initctl_fd = -1;
 
227
        }
 
228
 
 
229
        if ( want_single || (access (_PATH_SINGLE, R_OK) == 0) ) do_single ();
 
230
 
 
231
        /*If we get a SIGTSTP before multi-user mode, do nothing*/
 
232
        while (stopped)
 
233
                pause();
 
234
 
 
235
        if ( do_rc_tty (boot_prog) ) do_single ();
 
236
 
 
237
        while (stopped)  /*  Also if /etc/rc fails & we get SIGTSTP  */
 
238
                pause();
 
239
 
 
240
        write_wtmp();   /* write boottime record */
 
241
#ifdef DEBUGGING
 
242
        for(i = 0; i < numcmd; i++) {
 
243
                char **p;
 
244
                p = inittab[i].toks;
 
245
                printf("toks= %s %s %s %s\n",p[0], p[1], p[2], p[3]);
 
246
                printf("tty= %s\n", inittab[i].tty);
 
247
                printf("termcap= %s\n", inittab[i].termcap);
 
248
        }
 
249
        exit(EXIT_SUCCESS);
 
250
#endif
 
251
        signal (SIGHUP, sighup_handler);  /* Better semantics with signal(2) */
 
252
 
 
253
        for (i = 0; i < getdtablesize (); i++)
 
254
                if (i != initctl_fd) close (i);
 
255
 
 
256
        for(i = 0; i < numcmd; i++)
 
257
                spawn(i);
 
258
 
 
259
        if (final_prog[0] != '\0') {
 
260
                switch ( fork () )
 
261
                {
 
262
                  case 0:   /*  Child   */
 
263
                    execl (final_prog, final_prog, "start", NULL);
 
264
                    err ( _("error running finalprog\n") );
 
265
                    _exit (EXIT_FAILURE);
 
266
                    break;
 
267
                  case -1:  /*  Error   */
 
268
                    err ( _("error forking finalprog\n") );
 
269
                    break;
 
270
                  default:  /*  Parent  */
 
271
                    break;
 
272
                }
 
273
        }
 
274
 
 
275
        for ever {
 
276
                pid = mywait (&vec);
 
277
                if (pid < 1) continue;
 
278
 
 
279
                /* clear utmp entry, and append to wtmp if possible */
 
280
                {
 
281
                    struct utmp *ut;
 
282
                    int ut_fd, lf;
 
283
 
 
284
                    utmpname(_PATH_UTMP);
 
285
                    setutent();
 
286
                    while((ut = getutent())) {
 
287
                        if(ut->ut_pid == pid) {
 
288
                            time(&ut->ut_time);
 
289
                            memset(&ut->ut_user, 0, UT_NAMESIZE);
 
290
                            memset(&ut->ut_host, 0, sizeof(ut->ut_host));
 
291
                            ut->ut_type = DEAD_PROCESS;
 
292
                            ut->ut_pid = 0;
 
293
                            ut->ut_addr = 0;
 
294
                            /*endutent();*/
 
295
                            pututline(ut);
 
296
 
 
297
                            if ((lf = open(_PATH_WTMPLOCK, O_CREAT|O_WRONLY, 0660)) >= 0) {
 
298
                                flock(lf, LOCK_EX|LOCK_NB);
 
299
                                if((ut_fd = open(_PATH_WTMP, O_APPEND|O_WRONLY)) >= 0) {
 
300
                                    write(ut_fd, ut, sizeof(struct utmp));
 
301
                                    close(ut_fd);
 
302
                                }
 
303
                                flock(lf, LOCK_UN|LOCK_NB);
 
304
                                close(lf);
 
305
                            }
 
306
                            break;
 
307
                        }
 
308
                    }
 
309
                    endutent();
 
310
                }
 
311
 
 
312
                for(i = 0; i < numcmd; i++) {
 
313
                        if(pid == inittab[i].pid || inittab[i].pid < 0) {
 
314
                                if (stopped)
 
315
                                        inittab[i].pid = -1;
 
316
                                else
 
317
                                        spawn(i);
 
318
                                if (pid == inittab[i].pid)
 
319
                                        break;
 
320
                        }
 
321
                }
 
322
        }
 
323
}       
 
324
 
 
325
#define MAXTRIES 3 /* number of tries allowed when giving the password */
 
326
 
 
327
/*
 
328
 * return true if singleuser mode is allowed.
 
329
 * If /etc/securesingle exists ask for root password, otherwise always OK.
 
330
 */
 
331
static int check_single_ok (void)
 
332
{
 
333
    char *pass, *rootpass = NULL;
 
334
    struct passwd *pwd;
 
335
    int i;
 
336
 
 
337
    if (access (_PATH_SECURE, R_OK) != 0) return 1;
 
338
    if ( ( pwd = getpwnam ("root") ) || ( pwd = getpwuid (0) ) )
 
339
        rootpass = pwd->pw_passwd;
 
340
    else
 
341
        return 1; /* a bad /etc/passwd should not lock out */
 
342
 
 
343
    for (i = 0; i < MAXTRIES; i++)
 
344
    {
 
345
        pass = getpass (_("Password: "));
 
346
        if (pass == NULL) continue;
 
347
 
 
348
        if ( !strcmp (crypt (pass, rootpass), rootpass) ) return 1;
 
349
 
 
350
        puts (_("\nWrong password.\n"));
 
351
    }
 
352
    return 0;
 
353
}
 
354
 
 
355
static void do_single (void)
 
356
{
 
357
    char path[PATH_SIZE];
 
358
 
 
359
    if (caught_sigint) return;
 
360
    strcpy (path, script_prefix);
 
361
    strcat (path, "single");
 
362
    if (access (path, R_OK | X_OK) == 0)
 
363
        if (do_rc_tty (path) == 0) return;
 
364
    if ( check_single_ok () ) enter_single ();
 
365
}   /*  End Function do_single  */
 
366
 
 
367
/*
 
368
 * run boot script(s). The environment is passed to the script(s), so the RC
 
369
 * environment variable can be used to decide what to do.
 
370
 * RC may be set from LILO.
 
371
 * [RETURNS] 0 on success (exit status convention), otherwise error.
 
372
 */
 
373
static int do_rc_tty (const char *path)
 
374
{
 
375
    int status;
 
376
    pid_t pid;
 
377
    sigset_t ss;
 
378
 
 
379
    if (caught_sigint) return 0;
 
380
    process_path (path, preload_file, 0);
 
381
    /*  Launch off a subprocess to start a new session (required for frobbing
 
382
        the TTY) and capture control-C  */
 
383
    switch ( rc_child = fork () )
 
384
    {
 
385
      case 0:   /*  Child  */
 
386
        for (status = 1; status < NSIG; status++) signal (status, SIG_DFL);
 
387
        sigfillset (&ss);
 
388
        sigprocmask (SIG_UNBLOCK, &ss, NULL);
 
389
        sigdelset (&ss, SIGINT);
 
390
        sigdelset (&ss, SIGQUIT);
 
391
        setsid ();
 
392
        ioctl (0, TIOCSCTTY, 0);  /*  I want my control-C  */
 
393
        sigsuspend (&ss);  /*  Should never return, should just be killed  */
 
394
        break;             /*  No-one else is controlled by this TTY now   */
 
395
      case -1:  /*  Error  */
 
396
        return (1);
 
397
        /*break;*/
 
398
      default:  /*  Parent  */
 
399
        break;
 
400
    }
 
401
    /*  Parent  */
 
402
    process_path (path, run_file, 0);
 
403
    while (1)
 
404
    {
 
405
        if ( ( pid = mywait (&status) ) == rc_child )
 
406
            return (WTERMSIG (status) == SIGINT) ? 0 : 1;
 
407
        if (pid < 0) break;
 
408
    }
 
409
    kill (rc_child, SIGKILL);
 
410
    while (waitpid (rc_child, NULL, 0) != rc_child)  /*  Nothing  */;
 
411
    return 0;
 
412
}   /*  End Function do_rc_tty  */
 
413
 
 
414
static int process_path (const char *path, int (*func) (const char *path),
 
415
                         int ignore_dangling_symlink)
 
416
{
 
417
    struct stat statbuf;
 
418
    DIR *dp;
 
419
    struct dirent *de;
 
420
 
 
421
    if (lstat (path, &statbuf) != 0)
 
422
    {
 
423
        err (_("lstat of path failed\n") );
 
424
        return 1;
 
425
    }
 
426
    if ( S_ISLNK (statbuf.st_mode) )
 
427
    {
 
428
        if (stat (path, &statbuf) != 0)
 
429
        {
 
430
            if ( (errno == ENOENT) && ignore_dangling_symlink ) return 0;
 
431
            err (_("stat of path failed\n") );
 
432
            return 1;
 
433
        }
 
434
    }
 
435
    if ( !( statbuf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH) ) ) return 0;
 
436
    if ( !S_ISDIR (statbuf.st_mode) ) return (*func) (path);
 
437
    if ( ( dp = opendir (path) ) == NULL )
 
438
    {
 
439
        err (_("open of directory failed\n") );
 
440
        return 1;
 
441
    }
 
442
    while ( ( de = readdir (dp) ) != NULL )
 
443
    {
 
444
        int retval;
 
445
        char newpath[PATH_SIZE];
 
446
 
 
447
        if (de->d_name[0] == '.') continue;
 
448
        retval = snprintf (newpath, sizeof(newpath), "%s/%s", path, de->d_name);
 
449
        if (newpath[retval - 1] == '~') continue;  /*  Common mistake  */
 
450
        if ( ( retval = process_path (newpath, func, 1) ) ) return retval;
 
451
    }
 
452
    closedir (dp);
 
453
    return 0;
 
454
}   /*  End Function process_path  */
 
455
 
 
456
static int preload_file (const char *path)
 
457
{
 
458
    int fd;
 
459
    char ch;
 
460
 
 
461
    if ( ( fd = open (path, O_RDONLY, 0) ) < 0) return 0;
 
462
    while (read (fd, &ch, 1) == 1) lseek (fd, 1024, SEEK_CUR);
 
463
    close (fd);
 
464
    return 0;
 
465
}   /*  End Function preload_file  */
 
466
 
 
467
static int run_file (const char *path)
 
468
{
 
469
    const char *ptr;
 
470
 
 
471
    if ( ( ptr = strrchr ( (char *) path, '/' ) ) == NULL ) ptr = path;
 
472
    else ++ptr;
 
473
    return (run_command (path, ptr, 0) == SIG_FAILED) ? 1 : 0;
 
474
}   /*  End Function run_file  */
 
475
 
 
476
static void spawn (int i)
 
477
{
 
478
        pid_t pid;
 
479
        int j;
 
480
        signed long ds_taken;
 
481
        struct timeval ct;
 
482
 
 
483
        if (inittab[i].toks[0] == NULL) return;
 
484
 
 
485
        /*  Check if respawning too fast  */
 
486
        gettimeofday (&ct, NULL);
 
487
        ds_taken = ct.tv_sec - inittab[i].last_start.tv_sec;
 
488
 
 
489
        /* On the first iteration last_start==0 and ds_taken
 
490
           may be very large. Avoid overflow. -- Denis Vlasenko */
 
491
        if (ds_taken > 10000)
 
492
                ds_taken = 10000;
 
493
 
 
494
        ds_taken *= 10;
 
495
        ds_taken += (ct.tv_usec - inittab[i].last_start.tv_usec) / 100000;
 
496
        if (ds_taken < 1)
 
497
                ds_taken = 1;
 
498
        inittab[i].rate = (9 * inittab[i].rate + 1000 / ds_taken) / 10;
 
499
        if (inittab[i].rate > MAX_RESPAWN_RATE) {
 
500
                char txt[256];
 
501
 
 
502
                inittab[i].toks[0] = NULL;
 
503
                inittab[i].pid = -1;
 
504
                inittab[i].rate = 0;
 
505
                snprintf (txt, sizeof(txt),
 
506
                        _("respawning: \"%s\" too fast: quenching entry\n"),
 
507
                         inittab[i].tty);
 
508
                err (txt);
 
509
                return;
 
510
        }
 
511
 
 
512
        if((pid = fork()) < 0) {
 
513
                inittab[i].pid = -1;
 
514
                err(_("fork failed\n"));
 
515
                return;
 
516
        }
 
517
        if(pid) {
 
518
                /* this is the parent */
 
519
                inittab[i].pid = pid;
 
520
                inittab[i].last_start = ct;
 
521
                sched_yield ();
 
522
                return;
 
523
        } else {
 
524
                /* this is the child */
 
525
                char term[40];
 
526
#ifdef SET_TZ
 
527
                char tz[CMDSIZ];
 
528
#endif
 
529
                char *env[3];
 
530
                
 
531
                setsid();
 
532
                for(j = 0; j < getdtablesize(); j++)
 
533
                        (void) close(j);
 
534
 
 
535
                snprintf(term, sizeof(term), "TERM=%s", inittab[i].termcap);
 
536
                env[0] = term;
 
537
                env[1] = (char *)0;
 
538
#ifdef SET_TZ
 
539
                snprintf(tz, sizeof(tz), "TZ=%s", tzone);
 
540
                env[1] = tz;
 
541
#endif
 
542
                env[2] = (char *)0;
 
543
 
 
544
                execve(inittab[i].toks[0], inittab[i].toks, env);
 
545
                err(_("exec failed\n"));
 
546
                sleep(5);
 
547
                _exit(EXIT_FAILURE);
 
548
        }
 
549
}
 
550
 
 
551
static void read_inittab (void)
 
552
{
 
553
        FILE *f;
 
554
        char buf[CMDSIZ];
 
555
        int i,j,k;
 
556
        int has_prog = 0;
 
557
        char *ptr, *getty;
 
558
        char prog[PATH_SIZE];
 
559
#ifdef SPECIAL_CONSOLE_TERM
 
560
        char tty[50];
 
561
        struct stat stb;
 
562
#endif
 
563
        char *termenv;
 
564
        
 
565
        termenv = getenv("TERM");       /* set by kernel */
 
566
        /* termenv = "vt100"; */
 
567
                        
 
568
        if(!(f = fopen(_PATH_INITTAB, "r"))) {
 
569
                err(_("cannot open inittab\n"));
 
570
                return;
 
571
        }
 
572
 
 
573
        prog[0] = '\0';
 
574
        i = 0;
 
575
        while(!feof(f) && i < NUMCMD - 2) {
 
576
                if(fgets(buf, CMDSIZ - 1, f) == 0) break;
 
577
                buf[CMDSIZ-1] = 0;
 
578
 
 
579
                for(k = 0; k < CMDSIZ && buf[k]; k++) {
 
580
                        if ((buf[k] == '#') || (buf[k] == '\n')) { 
 
581
                                buf[k] = 0; break; 
 
582
                        }
 
583
                }
 
584
 
 
585
                if(buf[0] == 0 || buf[0] == '\n') continue;
 
586
                ptr = strchr (buf, '=');
 
587
                if (ptr) {
 
588
                        ptr++;
 
589
                        if ( !strncmp (buf, "bootprog", 8) ) {
 
590
                                while ( isspace (*ptr) ) ++ptr;
 
591
                                strcpy (prog, ptr);
 
592
                                has_prog = 1;
 
593
                                continue;
 
594
                        }
 
595
                        if ( !strncmp (buf, "fileprefix", 10) ) {
 
596
                                while ( isspace (*ptr) ) ++ptr;
 
597
                                strcpy (script_prefix, ptr);
 
598
                                continue;
 
599
                        }
 
600
                        if ( !strncmp (buf, "PATH", 4) ) {
 
601
                                while ( isspace (*ptr) ) ++ptr;
 
602
                                setenv ("PATH", ptr, 1);
 
603
                                continue;
 
604
                        }
 
605
                        if ( !strncmp (buf, "INIT_PATH", 9) ) {
 
606
                                while ( isspace (*ptr) ) ++ptr;
 
607
                                strcpy (init_path, ptr);
 
608
                                continue;
 
609
                        }
 
610
                        if ( !strncmp (buf, "finalprog", 8) ) {
 
611
                                while ( isspace (*ptr) ) ++ptr;
 
612
                                strcpy (final_prog, ptr);
 
613
                                continue;
 
614
                        }
 
615
                }
 
616
                        
 
617
 
 
618
                (void) strcpy(inittab[i].line, buf);
 
619
 
 
620
                (void) strtok(inittab[i].line, ":");
 
621
                xstrncpy(inittab[i].tty, inittab[i].line, 10);
 
622
                xstrncpy(inittab[i].termcap, strtok((char *)0, ":"), 30);
 
623
 
 
624
                getty = strtok((char *)0, ":");
 
625
                (void) strtok(getty, " \t\n");
 
626
                inittab[i].toks[0] = getty;
 
627
                j = 1;
 
628
                while((ptr = strtok((char *)0, " \t\n")))
 
629
                        inittab[i].toks[j++] = ptr;
 
630
                inittab[i].toks[j] = (char *)0;
 
631
 
 
632
#ifdef SPECIAL_CONSOLE_TERM
 
633
                /* special-case termcap for the console ttys */
 
634
                snprintf(tty, sizeof(tty), "/dev/%s", inittab[i].tty);
 
635
                if(!termenv || stat(tty, &stb) < 0) {
 
636
                        err(_("no TERM or cannot stat tty\n"));
 
637
                } else {
 
638
                        /* is it a console tty? */
 
639
                        if(major(stb.st_rdev) == 4 && minor(stb.st_rdev) < 64)
 
640
                                xstrncpy(inittab[i].termcap, termenv, 30);
 
641
                }
 
642
#endif
 
643
 
 
644
                i++;
 
645
        }
 
646
        fclose(f);
 
647
        numcmd = i;
 
648
        if (has_prog) {
 
649
                int len;
 
650
                char path[PATH_SIZE];
 
651
 
 
652
                strcpy (path, script_prefix);
 
653
                strcat (path, prog);
 
654
                len = strlen (path);
 
655
                if (path[len - 1] == '/') path[len - 1] = '\0';
 
656
                if (access (path, R_OK | X_OK) == 0)
 
657
                        strcpy (boot_prog, path);
 
658
        }
 
659
}   /*  End Function read_inittab  */
 
660
 
 
661
static void sighup_handler (int sig)
 
662
{
 
663
        int i,j;
 
664
        int oldnum;
 
665
        struct initline savetab[NUMCMD];
 
666
        int had_already;
 
667
 
 
668
        signal (SIGHUP, SIG_IGN);
 
669
        memcpy(savetab, inittab, NUMCMD * sizeof(struct initline));
 
670
        oldnum = numcmd;                
 
671
        read_inittab ();
 
672
        
 
673
        for(i = 0; i < numcmd; i++) {
 
674
                had_already = 0;
 
675
                for(j = 0; j < oldnum; j++) {
 
676
                        if(!strcmp(savetab[j].tty, inittab[i].tty)) {
 
677
                                had_already = 1;
 
678
                                if((inittab[i].pid = savetab[j].pid) < 0)
 
679
                                        spawn(i);
 
680
                        }
 
681
                }
 
682
                if (!had_already) spawn (i);
 
683
        }
 
684
        signal (SIGHUP, sighup_handler);
 
685
}   /*  End Function sighup_handler  */
 
686
 
 
687
static void sigtstp_handler (int sig)
 
688
{
 
689
    stopped = ~stopped;
 
690
    if (!stopped) sighup_handler (sig);
 
691
}   /*  End Function sigtstp_handler  */
 
692
 
 
693
static void sigterm_handler (int sig)
 
694
{
 
695
    int i;
 
696
 
 
697
    for (i = 0; i < numcmd; i++)
 
698
        if (inittab[i].pid > 0) kill (inittab[i].pid, SIGTERM);
 
699
}   /*  End Function sigterm_handler  */
 
700
 
 
701
static void sigint_handler (int sig)
 
702
{
 
703
    pid_t pid;
 
704
 
 
705
    caught_sigint = 1;
 
706
    kill (rc_child, SIGKILL);
 
707
    if (no_reboot) _exit (EXIT_FAILURE) /*kill (0, SIGKILL)*/;
 
708
    sync ();
 
709
    sync ();
 
710
    pid = fork ();
 
711
    if (pid > 0) return;  /*  Parent                     */
 
712
    if (pid == 0)         /*  Child: reboot properly...  */
 
713
        execl (_PATH_REBOOT, _PATH_REBOOT, (char *) 0);
 
714
 
 
715
    /* fork or exec failed, try the hard way... */
 
716
    my_reboot (LINUX_REBOOT_CMD_RESTART);
 
717
}   /*  End Function sigint_handler  */
 
718
 
 
719
static void sigchild_handler (int sig)
 
720
{
 
721
    if (!do_longjmp) return;
 
722
    siglongjmp (jmp_env, 1);
 
723
}
 
724
 
 
725
static void sigquit_handler (int sig)
 
726
{
 
727
    execl (_PATH_REBOOT, _PATH_REBOOT, NULL); /*  It knows pid=1 must sleep  */
 
728
}
 
729
 
 
730
#ifdef SET_TZ
 
731
static void set_tz (void)
 
732
{
 
733
        FILE *f;
 
734
        int len;
 
735
 
 
736
        if((f=fopen(TZFILE, "r")) == (FILE *)NULL) return;
 
737
        fgets(tzone, CMDSIZ-2, f);
 
738
        fclose(f);
 
739
        if((len=strlen(tzone)) < 2) return;
 
740
        tzone[len-1] = 0; /* get rid of the '\n' */
 
741
        setenv("TZ", tzone, 0);
 
742
}
 
743
#endif
 
744
 
 
745
static void write_wtmp (void)
 
746
{
 
747
    int fd, lf;
 
748
    struct utmp ut;
 
749
    
 
750
    memset((char *)&ut, 0, sizeof(ut));
 
751
    strcpy(ut.ut_line, "~");
 
752
    memset(ut.ut_name, 0, sizeof(ut.ut_name));
 
753
    time(&ut.ut_time);
 
754
    ut.ut_type = BOOT_TIME;
 
755
 
 
756
    if ((lf = open(_PATH_WTMPLOCK, O_CREAT|O_WRONLY, 0660)) >= 0) {
 
757
        flock(lf, LOCK_EX|LOCK_NB); /* make sure init won't hang */
 
758
        if((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND)) >= 0) {
 
759
            write(fd, (char *)&ut, sizeof(ut));
 
760
            close(fd);
 
761
        }
 
762
        flock(lf, LOCK_UN|LOCK_NB);
 
763
        close(lf);
 
764
    }
 
765
}   /*  End Function write_wtmp  */
 
766
 
 
767
 
 
768
struct needer_struct
 
769
{
 
770
    struct needer_struct *next;
 
771
    pid_t pid;
 
772
};
 
773
 
 
774
struct service_struct
 
775
{
 
776
    struct service_struct *prev, *next;    /*  Script services chain         */
 
777
    struct needer_struct *needers;         /*  Needers waiting for service   */
 
778
    struct script_struct *attempting_providers;
 
779
    int failed;                /*  TRUE if attempting provider failed badly  */
 
780
    char name[1];
 
781
};
 
782
 
 
783
struct script_struct
 
784
{
 
785
    pid_t pid;
 
786
    struct script_struct *prev, *next;              /*  For the list         */
 
787
    struct service_struct *first_service, *last_service; /*First is true name*/
 
788
    struct script_struct *next_attempting_provider; /*  Provider chain       */
 
789
};
 
790
 
 
791
struct list_head
 
792
{
 
793
    struct script_struct *first, *last;
 
794
    unsigned int num_entries;
 
795
};
 
796
 
 
797
 
 
798
static struct list_head available_list = {NULL, NULL, 0};
 
799
static struct list_head starting_list = {NULL, NULL, 0};
 
800
static struct service_struct *unavailable_services = NULL;  /*  For needers  */
 
801
static int num_needers = 0;
 
802
 
 
803
 
 
804
static int process_pidstat (pid_t pid, int status);
 
805
static void process_command (const struct command_struct *command);
 
806
static struct service_struct *find_service_in_list (const char *name,
 
807
                                                    struct service_struct *sv);
 
808
static struct script_struct *find_script_byname
 
809
    (const char *name,struct list_head *head, struct service_struct **service);
 
810
static struct script_struct *find_script_bypid (pid_t pid,
 
811
                                                struct list_head *head);
 
812
static void insert_entry (struct list_head *head, struct script_struct *entry);
 
813
static void remove_entry (struct list_head *head, struct script_struct *entry);
 
814
static void signal_needers (struct service_struct *service, int sig);
 
815
static void handle_nonworking (struct script_struct *script);
 
816
static int force_progress (void);
 
817
static void show_scripts (FILE *fp, const struct script_struct *script,
 
818
                          const char *type);
 
819
static const char *get_path (const char *file);
 
820
 
 
821
 
 
822
static pid_t mywait (int *status)
 
823
/*  [RETURNS] The pid for a process to be reaped, 0 if no process is to be
 
824
    reaped, and less than 0 if the boot scripts appear to have finished.
 
825
*/
 
826
{
 
827
    pid_t pid;
 
828
    sigset_t ss;
 
829
    long buffer[COMMAND_SIZE / sizeof (long)];
 
830
    struct command_struct *command = (struct command_struct *) buffer;
 
831
 
 
832
    if (initctl_fd < 0) return wait (status);
 
833
    /*  Some magic to avoid races which can result in lost signals   */
 
834
    command->command = -1;
 
835
    if ( sigsetjmp (jmp_env, 1) )
 
836
    {   /*  Jump from signal handler  */
 
837
        do_longjmp = 0;
 
838
        process_command (command);
 
839
        return 0;
 
840
    }
 
841
    sigemptyset (&ss);  /*  Block SIGCHLD so wait status cannot be lost  */
 
842
    sigaddset (&ss, SIGCHLD);
 
843
    sigprocmask (SIG_BLOCK, &ss, NULL);
 
844
    if ( ( pid = waitpid (-1, status, WNOHANG) ) > 0 )
 
845
    {
 
846
        sigprocmask (SIG_UNBLOCK, &ss, NULL);
 
847
        return process_pidstat (pid, *status);
 
848
    }
 
849
    do_longjmp = 1;  /*  After this, SIGCHLD will cause a jump backwards  */
 
850
    sigprocmask (SIG_UNBLOCK, &ss, NULL);
 
851
    read (initctl_fd, buffer, sizeof(buffer));
 
852
    do_longjmp = 0;
 
853
    process_command (command);
 
854
    return 0;
 
855
}   /*  End Function mywait  */
 
856
 
 
857
static pid_t process_pidstat (pid_t pid, int status)
 
858
/*  [RETURNS] The pid for a process to be reaped, 0 if no process is to be
 
859
    reaped, and less than 0 if the boot scripts appear to have finished.
 
860
*/
 
861
{
 
862
    int failed;
 
863
    struct script_struct *script;
 
864
    struct service_struct *service;
 
865
 
 
866
    if ( ( script = find_script_bypid (pid, &starting_list) ) == NULL )
 
867
        return pid;
 
868
    remove_entry (&starting_list, script);
 
869
    if ( WIFEXITED (status) && (WEXITSTATUS (status) == 0) )
 
870
    {
 
871
        struct script_struct *provider;
 
872
 
 
873
        /*  Notify needers and other providers  */
 
874
        for (service = script->first_service; service != NULL;
 
875
             service = service->next)
 
876
        {
 
877
            signal_needers (service, SIG_PRESENT);
 
878
            for (provider = service->attempting_providers; provider != NULL;
 
879
                 provider = provider->next_attempting_provider)
 
880
                kill (provider->pid, SIG_PRESENT);
 
881
            service->attempting_providers = NULL;
 
882
        }
 
883
        insert_entry (&available_list, script);
 
884
        return force_progress ();
 
885
    }
 
886
    failed = ( WIFEXITED (status) && (WEXITSTATUS (status) == 2) ) ? 0 : 1;
 
887
    for (service = script->first_service; service != NULL;
 
888
         service = service->next)
 
889
        service->failed = failed;
 
890
    handle_nonworking (script);
 
891
    return force_progress ();
 
892
}   /*  End Function process_pidstat  */
 
893
 
 
894
static void process_command (const struct command_struct *command)
 
895
{
 
896
    int ival;
 
897
    struct script_struct *script;
 
898
    struct service_struct *service;
 
899
 
 
900
    switch (command->command)
 
901
    {
 
902
      case COMMAND_TEST:
 
903
        kill (command->pid,
 
904
              (find_script_byname (command->name, &available_list,
 
905
                                   NULL) == NULL) ?
 
906
              SIG_NOT_PRESENT : SIG_PRESENT);
 
907
        break;
 
908
      case COMMAND_NEED:
 
909
        ival = run_command (command->name, command->name, command->pid);
 
910
        if (ival == 0)
 
911
        {
 
912
            ++num_needers;
 
913
            force_progress ();
 
914
        }
 
915
        else kill (command->pid, ival);
 
916
        break;
 
917
      case COMMAND_ROLLBACK:
 
918
        if (command->name[0] == '\0') script = NULL;
 
919
        else
 
920
        {
 
921
            if ( ( script = find_script_byname (command->name, &available_list,
 
922
                                                NULL) ) == NULL )
 
923
            {
 
924
                kill (command->pid, SIG_NOT_PRESENT);
 
925
                break;
 
926
            }
 
927
        }
 
928
        while (script != available_list.first)
 
929
        {
 
930
            pid_t pid;
 
931
            struct script_struct *victim = available_list.first;
 
932
            char txt[256];
 
933
 
 
934
            if ( ( pid = fork () ) == 0 )   /*  Child   */
 
935
            {
 
936
                for (ival = 1; ival < NSIG; ival++) signal (ival, SIG_DFL);
 
937
                open ("/dev/console", O_RDONLY, 0);
 
938
                open ("/dev/console", O_RDWR, 0);
 
939
                dup2 (1, 2);
 
940
                execlp (get_path (victim->first_service->name),
 
941
                        victim->first_service->name, "stop", NULL);
 
942
                snprintf (txt, sizeof(txt),
 
943
                        _("error at stopping service \"%s\"\n"),
 
944
                         victim->first_service->name);
 
945
                err (txt);
 
946
                _exit (SIG_NOT_STOPPED);
 
947
            }
 
948
            else if (pid == -1) break;      /*  Error   */
 
949
            else                            /*  Parent  */
 
950
            {
 
951
                while (waitpid (pid, &ival, 0) != pid) /*  Nothing  */;
 
952
                if ( WIFEXITED (ival) && (WEXITSTATUS (ival) == 0) )
 
953
                {
 
954
                    snprintf (txt, sizeof(txt),
 
955
                             _("Stopped service: %s\n"),
 
956
                             victim->first_service->name);
 
957
                    remove_entry (&available_list, victim);
 
958
                    free (victim);
 
959
                    err (txt);
 
960
                }
 
961
                else break;
 
962
            }
 
963
        }
 
964
        kill (command->pid,
 
965
              (script ==available_list.first) ? SIG_STOPPED : SIG_NOT_STOPPED);
 
966
        break;
 
967
      case COMMAND_DUMP_LIST:
 
968
        if (fork () == 0) /* Do it in a child process so pid=1 doesn't block */
 
969
        {
 
970
            FILE *fp;
 
971
 
 
972
            if ( ( fp = fopen (command->name, "w") ) == NULL ) _exit (EXIT_FAILURE);
 
973
            show_scripts (fp, available_list.first, "AVAILABLE");
 
974
            show_scripts (fp, starting_list.first, "STARTING");
 
975
            fputs ("UNAVAILABLE SERVICES:\n", fp);
 
976
            for (service = unavailable_services; service != NULL;
 
977
                 service = service->next)
 
978
                fprintf (fp, "%s (%s)\n", service->name,
 
979
                         service->failed ? "FAILED" : "not configured");
 
980
            fclose (fp);
 
981
            _exit (EXIT_SUCCESS);
 
982
        }
 
983
        break;
 
984
      case COMMAND_PROVIDE:
 
985
        /*  Sanity check  */
 
986
        if ( ( script = find_script_bypid (command->ppid, &starting_list) )
 
987
             == NULL )
 
988
        {
 
989
            kill (command->pid, SIG_NOT_CHILD);
 
990
            break;
 
991
        }
 
992
        if (find_script_byname (command->name, &available_list, NULL) != NULL)
 
993
        {
 
994
            kill (command->pid, SIG_PRESENT);
 
995
            break;
 
996
        }
 
997
        if (find_script_byname (command->name, &starting_list, &service)
 
998
            != NULL)
 
999
        {   /*  Someone else is trying to provide  */
 
1000
            script->next_attempting_provider = service->attempting_providers;
 
1001
            service->attempting_providers = script;
 
1002
            break;
 
1003
        }
 
1004
        if ( ( service = find_service_in_list (command->name,
 
1005
                                               unavailable_services) )
 
1006
             == NULL )
 
1007
        {   /*  We're the first to try and provide: create it  */
 
1008
            if ( ( service =
 
1009
                   calloc (1, strlen (command->name) + sizeof *service) )
 
1010
                 == NULL )
 
1011
            {
 
1012
                kill (command->pid, SIG_NOT_CHILD);
 
1013
                break;
 
1014
            }
 
1015
            strcpy (service->name, command->name);
 
1016
        }
 
1017
        else
 
1018
        {   /*  Orphaned service: unhook and grab it  */
 
1019
            if (service->prev == NULL) unavailable_services = service->next;
 
1020
            else service->prev->next = service->next;
 
1021
            if (service->next != NULL) service->next->prev = service->prev;
 
1022
            service->next = NULL;
 
1023
        }
 
1024
        service->prev = script->last_service;
 
1025
        script->last_service->next = service;
 
1026
        script->last_service = service;
 
1027
        kill (command->pid, SIG_NOT_PRESENT);
 
1028
        break;
 
1029
      case -1:
 
1030
      default:
 
1031
        break;
 
1032
    }
 
1033
}   /*  End Function process_command  */
 
1034
 
 
1035
static int run_command (const char *file, const char *name, pid_t pid)
 
1036
{
 
1037
    struct script_struct *script;
 
1038
    struct needer_struct *needer = NULL;
 
1039
    struct service_struct *service;
 
1040
 
 
1041
    if (find_script_byname (name, &available_list, NULL) != NULL)
 
1042
        return SIG_PRESENT;
 
1043
    if (pid != 0)
 
1044
    {
 
1045
        needer = calloc (1, sizeof *needer);
 
1046
        if (needer == NULL) return SIG_FAILED;
 
1047
        needer->pid = pid;
 
1048
    }
 
1049
    script = find_script_byname (name, &starting_list, &service);
 
1050
    if (script == NULL)
 
1051
        service = find_service_in_list (name, unavailable_services);
 
1052
    if (service == NULL)
 
1053
    {
 
1054
        int i;
 
1055
        char txt[1024];
 
1056
 
 
1057
        if ( ( script = calloc (1, sizeof *script) ) == NULL )
 
1058
        {
 
1059
            free (needer);
 
1060
            return SIG_FAILED;
 
1061
        }
 
1062
        service = calloc (1, strlen (name) + sizeof *service);
 
1063
        if (service == NULL)
 
1064
        {
 
1065
            free (script);
 
1066
            return SIG_FAILED;
 
1067
        }
 
1068
        strcpy (service->name, name);
 
1069
        switch ( script->pid = fork () )
 
1070
        {
 
1071
          case 0:   /*  Child   */
 
1072
            for (i = 1; i < NSIG; i++) signal (i, SIG_DFL);
 
1073
            execlp (get_path (file), service->name, "start", NULL);
 
1074
            snprintf (txt, sizeof(txt),
 
1075
                _("error at starting service \"%s\"\n"), service->name);
 
1076
            err (txt);
 
1077
            _exit (SIG_FAILED);
 
1078
            break;
 
1079
          case -1:  /*  Error   */
 
1080
            service->next = unavailable_services;
 
1081
            if (unavailable_services != NULL)
 
1082
                unavailable_services->prev = service;
 
1083
            unavailable_services = service;
 
1084
            free (script);
 
1085
            free (needer);
 
1086
            return SIG_FAILED;
 
1087
            /*break;*/
 
1088
          default:  /*  Parent  */
 
1089
            script->first_service = service;
 
1090
            script->last_service = service;
 
1091
            insert_entry (&starting_list, script);
 
1092
            sched_yield ();
 
1093
            break;
 
1094
        }
 
1095
    }
 
1096
    if (needer == NULL) return 0;
 
1097
    needer->next = service->needers;
 
1098
    service->needers = needer;
 
1099
    return 0;
 
1100
}   /*  End Function run_command  */
 
1101
 
 
1102
static struct service_struct *find_service_in_list (const char *name,
 
1103
                                                    struct service_struct *sv)
 
1104
{
 
1105
    for (; sv != NULL; sv = sv->next)
 
1106
        if (strcmp (sv->name, name) == 0) return (sv);
 
1107
    return NULL;
 
1108
}   /*  End Function find_service_in_list  */
 
1109
 
 
1110
static struct script_struct *find_script_byname (const char *name,
 
1111
                                                 struct list_head *head,
 
1112
                                                 struct service_struct **service)
 
1113
{
 
1114
    struct script_struct *script;
 
1115
 
 
1116
    for (script = head->first; script != NULL; script = script->next)
 
1117
    {
 
1118
        struct service_struct *sv;
 
1119
 
 
1120
        if ( ( sv = find_service_in_list (name, script->first_service) )
 
1121
             != NULL )
 
1122
        {
 
1123
            if (service != NULL) *service = sv;
 
1124
            return (script);
 
1125
        }
 
1126
    }
 
1127
    if (service != NULL) *service = NULL;
 
1128
    return NULL;
 
1129
}   /*  End Function find_script_byname  */
 
1130
 
 
1131
static struct script_struct *find_script_bypid (pid_t pid,
 
1132
                                                struct list_head *head)
 
1133
{
 
1134
    struct script_struct *script;
 
1135
 
 
1136
    for (script = head->first; script != NULL; script = script->next)
 
1137
        if (script->pid == pid) return (script);
 
1138
    return NULL;
 
1139
}   /*  End Function find_script_bypid  */
 
1140
 
 
1141
static void insert_entry (struct list_head *head, struct script_struct *entry)
 
1142
{
 
1143
    if (entry == NULL) return;
 
1144
    entry->prev = NULL;
 
1145
    entry->next = head->first;
 
1146
    if (head->first != NULL) head->first->prev = entry;
 
1147
    head->first = entry;
 
1148
    if (head->last == NULL) head->last = entry;
 
1149
    ++head->num_entries;
 
1150
}   /*  End Function insert_entry  */
 
1151
 
 
1152
static void remove_entry (struct list_head *head, struct script_struct *entry)
 
1153
{
 
1154
    if (entry->prev == NULL) head->first = entry->next;
 
1155
    else entry->prev->next = entry->next;
 
1156
    if (entry->next == NULL) head->last = entry->prev;
 
1157
    else entry->next->prev = entry->prev;
 
1158
    --head->num_entries;
 
1159
}   /*  End Function remove_entry  */
 
1160
 
 
1161
static void signal_needers (struct service_struct *service, int sig)
 
1162
{
 
1163
    struct needer_struct *needer, *next_needer;
 
1164
 
 
1165
    for (needer = service->needers; needer != NULL; needer = next_needer)
 
1166
    {
 
1167
        kill (needer->pid, sig);
 
1168
        next_needer = needer->next;
 
1169
        free (needer);
 
1170
        --num_needers;
 
1171
    }
 
1172
    service->needers = NULL;
 
1173
}   /*  End Function signal_needers  */
 
1174
 
 
1175
static void handle_nonworking (struct script_struct *script)
 
1176
{
 
1177
    struct service_struct *service, *next;
 
1178
 
 
1179
    for (service = script->first_service; service != NULL; service = next)
 
1180
    {
 
1181
        struct script_struct *provider = service->attempting_providers;
 
1182
 
 
1183
        next = service->next;
 
1184
        if (provider == NULL)
 
1185
        {
 
1186
            service->prev = NULL;
 
1187
            service->next = unavailable_services;
 
1188
            if (unavailable_services != NULL)
 
1189
                unavailable_services->prev = service;
 
1190
            unavailable_services = service;
 
1191
            continue;
 
1192
        }
 
1193
        service->attempting_providers = provider->next_attempting_provider;
 
1194
        provider->last_service->next = service;
 
1195
        service->prev = provider->last_service;
 
1196
        provider->last_service = service;
 
1197
        service->next = NULL;
 
1198
        kill (provider->pid, SIG_NOT_PRESENT);
 
1199
    }
 
1200
    free (script);
 
1201
}   /*  End Function handle_nonworking  */
 
1202
 
 
1203
static int force_progress (void)
 
1204
/*  [RETURNS] 0 if boot scripts are still running, else -1.
 
1205
*/
 
1206
{
 
1207
    struct service_struct *service;
 
1208
 
 
1209
    if (starting_list.num_entries > num_needers) return 0;
 
1210
    /*  No progress can be made: signal needers  */
 
1211
    for (service = unavailable_services; service != NULL;
 
1212
         service = service->next)
 
1213
        signal_needers (service,
 
1214
                        service->failed ? SIG_FAILED : SIG_NOT_PRESENT);
 
1215
    return (starting_list.num_entries < 1) ? -1 : 0;
 
1216
}   /*  End Function force_progress  */
 
1217
 
 
1218
static void show_scripts (FILE *fp, const struct script_struct *script,
 
1219
                          const char *type)
 
1220
{
 
1221
    fprintf (fp, "%s SERVICES:\n", type);
 
1222
    for (; script != NULL; script = script->next)
 
1223
    {
 
1224
        struct service_struct *service = script->first_service;
 
1225
 
 
1226
        fputs (service->name, fp);
 
1227
        for (service = service->next; service != NULL; service = service->next)
 
1228
            fprintf (fp, "  (%s)", service->name);
 
1229
        putc ('\n', fp);
 
1230
    }
 
1231
}   /*  End Function show_scripts  */
 
1232
 
 
1233
static const char *get_path (const char *file)
 
1234
{
 
1235
    char *p1, *p2;
 
1236
    static char path[PATH_SIZE];
 
1237
 
 
1238
    if (file[0] == '/') return file;
 
1239
    if (init_path[0] == '\0') return file;
 
1240
    for (p1 = init_path; *p1 != '\0'; p1 = p2)
 
1241
    {
 
1242
        if ( ( p2 = strchr (p1, ':') ) == NULL )
 
1243
            p2 = p1 + strlen (p1);
 
1244
        strncpy (path, p1, p2 - p1);
 
1245
        path[p2 - p1] = '/';
 
1246
        strcpy (path + (p2 - p1) + 1, file);
 
1247
        if (*p2 == ':') ++p2;
 
1248
        if (access (path, X_OK) == 0) return path;
 
1249
    }
 
1250
    return file;
 
1251
}   /*  End Function get_path  */