~ubuntu-branches/ubuntu/saucy/sysvinit/saucy

« back to all changes in this revision

Viewing changes to .pc/63_init_keep_utf8_ttyflag.patch/src/init.c

  • Committer: Package Import Robot
  • Author(s): Roger Leigh, Kel Modderman, Roger Leigh, [:space:
  • Date: 2011-12-13 20:11:48 UTC
  • mfrom: (2.1.32 sid)
  • mto: (2.1.33 sid)
  • mto: This revision was merged to the branch mainline in revision 178.
  • Revision ID: package-import@ubuntu.com-20111213201148-dzhk6hdjkm4r1atb
Tags: 2.88dsf-14
[ Kel Modderman ]
* Add support for s390x, thanks to Aurelien Jarno <aurel32@debian.org>.
  (Closes: #641107)

[ Roger Leigh ]
* debian/rules:
  - Add build-arch and -indep rules. (Closes: #648472)
  - Remove dpatch usage.
  - Use dh and debhelper compat level 9.
* debian/control:
  - Add git version control information.
  - Upgrade to Standards-Version 3.9.2.
  - Add myself to Uploaders.
* Use dpkg 3.0 (quilt) source format.  Rediffed
  debian/patches/40_multiarch_libcrypt.patch which was not well
  formed and failed to apply.
* initscripts:
  - Make /etc/mtab a symlink to /proc/mounts. (Closes: #494001)
    Note that this is only done when the root filesystem is writable
    and /proc/mount is readable.
  - Support the ceph network filesystem. (Closes: #580579).  Thanks
    to Sage Weil.
  - Restore boot-time cleaning of /var/run and /var/lock, used by
    systems which currently do not use a tmpfs for /run.
  - Remove /lib/init/rw: Add Breaks for all packages which used
    /lib/init/rw, and which now use /run.  Unmount and remove
    following upgrade.
  - Don't create /run/.run-transition on upgrade, only on actually
    setting up a transitional bind mount.
  - Add Breaks on all packages previously using /lib/init/rw, in
    order to permit removal of /lib/init/rw.  It is not possible to
    remove prior to rebooting due to initscripts being required to
    be configured by the packages transitioning to /run.  Remove in
    wheezy+1.
  - Remove trailing period from the initscripts init script log
    message.  (Closes: #648881).  Thanks to Clint Byrum.
  - /etc/network/if-up.d/mountnfs: grep: character class syntax is
    [[:space:]], not [:space:]. (Closes: #631077, #645655).  Thanks to
    Milan Kocian and Jan-Benedict Glaw.  Also simplify function logic
    using a for loop rather than a while loop.  Thanks to Corey Hickey.
* sysv-rc:
  - Remove splash support and use of removed /dev/.initramfs.
    (Closes: #643558).  Thanks to Michael Biebl.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Init         A System-V Init Clone.
 
3
 *
 
4
 * Usage:       /sbin/init
 
5
 *                   init [0123456SsQqAaBbCc]
 
6
 *                telinit [0123456SsQqAaBbCc]
 
7
 *
 
8
 * Version:     @(#)init.c  2.86  30-Jul-2004  miquels@cistron.nl
 
9
 */
 
10
#define VERSION "2.88"
 
11
#define DATE    "26-Mar-2010"
 
12
/*
 
13
 *              This file is part of the sysvinit suite,
 
14
 *              Copyright (C) 1991-2004 Miquel van Smoorenburg.
 
15
 *
 
16
 *              This program is free software; you can redistribute it and/or modify
 
17
 *              it under the terms of the GNU General Public License as published by
 
18
 *              the Free Software Foundation; either version 2 of the License, or
 
19
 *              (at your option) any later version.
 
20
 *
 
21
 *              This program is distributed in the hope that it will be useful,
 
22
 *              but WITHOUT ANY WARRANTY; without even the implied warranty of
 
23
 *              MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
24
 *              GNU General Public License for more details.
 
25
 *
 
26
 *              You should have received a copy of the GNU General Public License
 
27
 *              along with this program; if not, write to the Free Software
 
28
 *              Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
29
 *
 
30
 */
 
31
 
 
32
#include <sys/types.h>
 
33
#include <sys/stat.h>
 
34
#include <sys/ioctl.h>
 
35
#include <sys/wait.h>
 
36
#ifdef __linux__
 
37
#include <sys/kd.h>
 
38
#endif
 
39
#include <sys/resource.h>
 
40
#include <stdlib.h>
 
41
#include <unistd.h>
 
42
#include <errno.h>
 
43
#include <stdio.h>
 
44
#include <time.h>
 
45
#include <fcntl.h>
 
46
#include <string.h>
 
47
#include <signal.h>
 
48
#include <termios.h>
 
49
#include <utmp.h>
 
50
#include <ctype.h>
 
51
#include <stdarg.h>
 
52
#include <sys/syslog.h>
 
53
#include <sys/time.h>
 
54
 
 
55
#ifdef WITH_SELINUX
 
56
#  include <selinux/selinux.h>
 
57
#  include <sys/mount.h>
 
58
#  ifndef MNT_DETACH /* present in glibc 2.10, missing in 2.7 */
 
59
#    define MNT_DETACH 2
 
60
#  endif
 
61
#endif
 
62
 
 
63
#ifdef __i386__
 
64
#  ifdef __GLIBC__
 
65
     /* GNU libc 2.x */
 
66
#    define STACK_DEBUG 1
 
67
#    if (__GLIBC__ == 2 && __GLIBC_MINOR__ == 0)
 
68
       /* Only glibc 2.0 needs this */
 
69
#      include <sigcontext.h>
 
70
#    elif ( __GLIBC__ > 2) && ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1))
 
71
#      include <bits/sigcontext.h>
 
72
#    endif
 
73
#  endif
 
74
#endif
 
75
 
 
76
#include "init.h"
 
77
#include "initreq.h"
 
78
#include "paths.h"
 
79
#include "reboot.h"
 
80
#include "set.h"
 
81
 
 
82
#ifndef SIGPWR
 
83
#  define SIGPWR SIGUSR2
 
84
#endif
 
85
 
 
86
#ifndef CBAUD
 
87
#  define CBAUD         0
 
88
#endif
 
89
#ifndef CBAUDEX
 
90
#  define CBAUDEX       0
 
91
#endif
 
92
 
 
93
/* Set a signal handler. */
 
94
#define SETSIG(sa, sig, fun, flags) \
 
95
                do { \
 
96
                        sa.sa_handler = fun; \
 
97
                        sa.sa_flags = flags; \
 
98
                        sigemptyset(&sa.sa_mask); \
 
99
                        sigaction(sig, &sa, NULL); \
 
100
                } while(0)
 
101
 
 
102
/* Version information */
 
103
char *Version = "@(#) init " VERSION "  " DATE "  miquels@cistron.nl";
 
104
char *bootmsg = "version " VERSION " %s";
 
105
#define E_VERSION "INIT_VERSION=sysvinit-" VERSION
 
106
 
 
107
CHILD *family = NULL;           /* The linked list of all entries */
 
108
CHILD *newFamily = NULL;        /* The list after inittab re-read */
 
109
 
 
110
CHILD ch_emerg = {              /* Emergency shell */
 
111
        WAITING, 0, 0, 0, 0,
 
112
        "~~",
 
113
        "S",
 
114
        3,
 
115
        "/sbin/sulogin",
 
116
        NULL,
 
117
        NULL
 
118
};
 
119
 
 
120
char runlevel = 'S';            /* The current run level */
 
121
char thislevel = 'S';           /* The current runlevel */
 
122
char prevlevel = 'N';           /* Previous runlevel */
 
123
int dfl_level = 0;              /* Default runlevel */
 
124
sig_atomic_t got_cont = 0;      /* Set if we received the SIGCONT signal */
 
125
sig_atomic_t got_signals;       /* Set if we received a signal. */
 
126
int emerg_shell = 0;            /* Start emergency shell? */
 
127
int wrote_wtmp_reboot = 1;      /* Set when we wrote the reboot record */
 
128
int wrote_utmp_reboot = 1;      /* Set when we wrote the reboot record */
 
129
int wrote_wtmp_rlevel = 1;      /* Set when we wrote the runlevel record */
 
130
int wrote_utmp_rlevel = 1;      /* Set when we wrote the runlevel record */
 
131
int sltime = 5;                 /* Sleep time between TERM and KILL */
 
132
char *argv0;                    /* First arguments; show up in ps listing */
 
133
int maxproclen;                 /* Maximal length of argv[0] with \0 */
 
134
struct utmp utproto;            /* Only used for sizeof(utproto.ut_id) */
 
135
char *console_dev;              /* Console device. */
 
136
int pipe_fd = -1;               /* /dev/initctl */
 
137
int did_boot = 0;               /* Did we already do BOOT* stuff? */
 
138
int main(int, char **);
 
139
 
 
140
/*      Used by re-exec part */
 
141
int reload = 0;                 /* Should we do initialization stuff? */
 
142
char *myname="/sbin/init";      /* What should we exec */
 
143
int oops_error;                 /* Used by some of the re-exec code. */
 
144
const char *Signature = "12567362";     /* Signature for re-exec fd */
 
145
 
 
146
/* Macro to see if this is a special action */
 
147
#define ISPOWER(i) ((i) == POWERWAIT || (i) == POWERFAIL || \
 
148
                    (i) == POWEROKWAIT || (i) == POWERFAILNOW || \
 
149
                    (i) == CTRLALTDEL)
 
150
 
 
151
/* ascii values for the `action' field. */
 
152
struct actions {
 
153
  char *name;
 
154
  int act;
 
155
} actions[] = {
 
156
  { "respawn",     RESPAWN      },
 
157
  { "wait",        WAIT         },
 
158
  { "once",        ONCE         },
 
159
  { "boot",        BOOT         },
 
160
  { "bootwait",    BOOTWAIT     },
 
161
  { "powerfail",   POWERFAIL    },
 
162
  { "powerfailnow",POWERFAILNOW },
 
163
  { "powerwait",   POWERWAIT    },
 
164
  { "powerokwait", POWEROKWAIT  },
 
165
  { "ctrlaltdel",  CTRLALTDEL   },
 
166
  { "off",         OFF          },
 
167
  { "ondemand",    ONDEMAND     },
 
168
  { "initdefault", INITDEFAULT  },
 
169
  { "sysinit",     SYSINIT      },
 
170
  { "kbrequest",   KBREQUEST    },
 
171
  { NULL,          0            },
 
172
};
 
173
 
 
174
/*
 
175
 *      State parser token table (see receive_state)
 
176
 */
 
177
struct {
 
178
  char name[4]; 
 
179
  int cmd;
 
180
} cmds[] = {
 
181
  { "VER",         C_VER        },
 
182
  { "END",         C_END        },
 
183
  { "REC",         C_REC        },
 
184
  { "EOR",         C_EOR        },
 
185
  { "LEV",         C_LEV        },
 
186
  { "FL ",         C_FLAG       },
 
187
  { "AC ",         C_ACTION     },
 
188
  { "CMD",         C_PROCESS    },
 
189
  { "PID",         C_PID        },
 
190
  { "EXS",         C_EXS        },
 
191
  { "-RL",         D_RUNLEVEL   },
 
192
  { "-TL",         D_THISLEVEL  },
 
193
  { "-PL",         D_PREVLEVEL  },
 
194
  { "-SI",         D_GOTSIGN    },
 
195
  { "-WR",         D_WROTE_WTMP_REBOOT},
 
196
  { "-WU",         D_WROTE_UTMP_REBOOT},
 
197
  { "-ST",         D_SLTIME     },
 
198
  { "-DB",         D_DIDBOOT    },
 
199
  { "-LW",         D_WROTE_WTMP_RLEVEL},
 
200
  { "-LU",         D_WROTE_UTMP_RLEVEL},
 
201
  { "",            0            }
 
202
};
 
203
struct {
 
204
        char *name;
 
205
        int mask;
 
206
} flags[]={
 
207
        {"RU",RUNNING},
 
208
        {"DE",DEMAND},
 
209
        {"XD",XECUTED},
 
210
        {"WT",WAITING},
 
211
        {NULL,0}
 
212
};
 
213
 
 
214
#define NR_EXTRA_ENV    16
 
215
char *extra_env[NR_EXTRA_ENV];
 
216
 
 
217
 
 
218
/*
 
219
 *      Sleep a number of seconds.
 
220
 *
 
221
 *      This only works correctly because the linux select updates
 
222
 *      the elapsed time in the struct timeval passed to select!
 
223
 */
 
224
static
 
225
void do_sleep(int sec)
 
226
{
 
227
        struct timeval tv;
 
228
 
 
229
        tv.tv_sec = sec;
 
230
        tv.tv_usec = 0;
 
231
 
 
232
        while(select(0, NULL, NULL, NULL, &tv) < 0 && errno == EINTR)
 
233
                ;
 
234
}
 
235
 
 
236
 
 
237
/*
 
238
 *      Non-failing allocation routines (init cannot fail).
 
239
 */
 
240
static
 
241
void *imalloc(size_t size)
 
242
{
 
243
        void    *m;
 
244
 
 
245
        while ((m = malloc(size)) == NULL) {
 
246
                initlog(L_VB, "out of memory");
 
247
                do_sleep(5);
 
248
        }
 
249
        memset(m, 0, size);
 
250
        return m;
 
251
}
 
252
 
 
253
static
 
254
char *istrdup(char *s)
 
255
{
 
256
        char    *m;
 
257
        int     l;
 
258
 
 
259
        l = strlen(s) + 1;
 
260
        m = imalloc(l);
 
261
        memcpy(m, s, l);
 
262
        return m;
 
263
}
 
264
 
 
265
 
 
266
/*
 
267
 *      Send the state info of the previous running init to
 
268
 *      the new one, in a version-independant way.
 
269
 */
 
270
static
 
271
void send_state(int fd)
 
272
{
 
273
        FILE    *fp;
 
274
        CHILD   *p;
 
275
        int     i,val;
 
276
 
 
277
        fp = fdopen(fd,"w");
 
278
 
 
279
        fprintf(fp, "VER%s\n", Version);
 
280
        fprintf(fp, "-RL%c\n", runlevel);
 
281
        fprintf(fp, "-TL%c\n", thislevel);
 
282
        fprintf(fp, "-PL%c\n", prevlevel);
 
283
        fprintf(fp, "-SI%u\n", got_signals);
 
284
        fprintf(fp, "-WR%d\n", wrote_wtmp_reboot);
 
285
        fprintf(fp, "-WU%d\n", wrote_utmp_reboot);
 
286
        fprintf(fp, "-ST%d\n", sltime);
 
287
        fprintf(fp, "-DB%d\n", did_boot);
 
288
 
 
289
        for (p = family; p; p = p->next) {
 
290
                fprintf(fp, "REC%s\n", p->id);
 
291
                fprintf(fp, "LEV%s\n", p->rlevel);
 
292
                for (i = 0, val = p->flags; flags[i].mask; i++)
 
293
                        if (val & flags[i].mask) {
 
294
                                val &= ~flags[i].mask;
 
295
                                fprintf(fp, "FL %s\n",flags[i].name);
 
296
                        }
 
297
                fprintf(fp, "PID%d\n",p->pid);
 
298
                fprintf(fp, "EXS%u\n",p->exstat);
 
299
                for(i = 0; actions[i].act; i++)
 
300
                        if (actions[i].act == p->action) {
 
301
                                fprintf(fp, "AC %s\n", actions[i].name);
 
302
                                break;
 
303
                        }
 
304
                fprintf(fp, "CMD%s\n", p->process);
 
305
                fprintf(fp, "EOR\n");
 
306
        }
 
307
        fprintf(fp, "END\n");
 
308
        fclose(fp);
 
309
}
 
310
 
 
311
/*
 
312
 *      Read a string from a file descriptor.
 
313
 *      FIXME: why not use fgets() ?
 
314
 */
 
315
static int get_string(char *p, int size, FILE *f)
 
316
{
 
317
        int     c;
 
318
 
 
319
        while ((c = getc(f)) != EOF && c != '\n') {
 
320
                if (--size > 0)
 
321
                        *p++ = c;
 
322
        }
 
323
        *p = '\0';
 
324
        return (c != EOF) && (size > 0);
 
325
}
 
326
 
 
327
/*
 
328
 *      Read trailing data from the state pipe until we see a newline.
 
329
 */
 
330
static int get_void(FILE *f)
 
331
{
 
332
        int     c;
 
333
 
 
334
        while ((c = getc(f)) != EOF && c != '\n')
 
335
                ;
 
336
 
 
337
        return (c != EOF);
 
338
}
 
339
 
 
340
/*
 
341
 *      Read the next "command" from the state pipe.
 
342
 */
 
343
static int get_cmd(FILE *f)
 
344
{
 
345
        char    cmd[4] = "   ";
 
346
        int     i;
 
347
 
 
348
        if (fread(cmd, 1, sizeof(cmd) - 1, f) != sizeof(cmd) - 1)
 
349
                return C_EOF;
 
350
 
 
351
        for(i = 0; cmds[i].cmd && strcmp(cmds[i].name, cmd) != 0; i++)
 
352
                ;
 
353
        return cmds[i].cmd;
 
354
}
 
355
 
 
356
/*
 
357
 *      Read a CHILD * from the state pipe.
 
358
 */
 
359
static CHILD *get_record(FILE *f)
 
360
{
 
361
        int     cmd;
 
362
        char    s[32];
 
363
        int     i;
 
364
        CHILD   *p;
 
365
 
 
366
        do {
 
367
                switch (cmd = get_cmd(f)) {
 
368
                        case C_END:
 
369
                                get_void(f);
 
370
                                return NULL;
 
371
                        case 0:
 
372
                                get_void(f);
 
373
                                break;
 
374
                        case C_REC:
 
375
                                break;
 
376
                        case D_RUNLEVEL:
 
377
                                fscanf(f, "%c\n", &runlevel);
 
378
                                break;
 
379
                        case D_THISLEVEL:
 
380
                                fscanf(f, "%c\n", &thislevel);
 
381
                                break;
 
382
                        case D_PREVLEVEL:
 
383
                                fscanf(f, "%c\n", &prevlevel);
 
384
                                break;
 
385
                        case D_GOTSIGN:
 
386
                                fscanf(f, "%u\n", &got_signals);
 
387
                                break;
 
388
                        case D_WROTE_WTMP_REBOOT:
 
389
                                fscanf(f, "%d\n", &wrote_wtmp_reboot);
 
390
                                break;
 
391
                        case D_WROTE_UTMP_REBOOT:
 
392
                                fscanf(f, "%d\n", &wrote_utmp_reboot);
 
393
                                break;
 
394
                        case D_SLTIME:
 
395
                                fscanf(f, "%d\n", &sltime);
 
396
                                break;
 
397
                        case D_DIDBOOT:
 
398
                                fscanf(f, "%d\n", &did_boot);
 
399
                                break;
 
400
                        case D_WROTE_WTMP_RLEVEL:
 
401
                                fscanf(f, "%d\n", &wrote_wtmp_rlevel);
 
402
                                break;
 
403
                        case D_WROTE_UTMP_RLEVEL:
 
404
                                fscanf(f, "%d\n", &wrote_utmp_rlevel);
 
405
                                break;
 
406
                        default:
 
407
                                if (cmd > 0 || cmd == C_EOF) {
 
408
                                        oops_error = -1;
 
409
                                        return NULL;
 
410
                                }
 
411
                }
 
412
        } while (cmd != C_REC);
 
413
 
 
414
        p = imalloc(sizeof(CHILD));
 
415
        get_string(p->id, sizeof(p->id), f);
 
416
 
 
417
        do switch(cmd = get_cmd(f)) {
 
418
                case 0:
 
419
                case C_EOR:
 
420
                        get_void(f);
 
421
                        break;
 
422
                case C_PID:
 
423
                        fscanf(f, "%d\n", &(p->pid));
 
424
                        break;
 
425
                case C_EXS:
 
426
                        fscanf(f, "%u\n", &(p->exstat));
 
427
                        break;
 
428
                case C_LEV:
 
429
                        get_string(p->rlevel, sizeof(p->rlevel), f);
 
430
                        break;
 
431
                case C_PROCESS:
 
432
                        get_string(p->process, sizeof(p->process), f);
 
433
                        break;
 
434
                case C_FLAG:
 
435
                        get_string(s, sizeof(s), f);
 
436
                        for(i = 0; flags[i].name; i++) {
 
437
                                if (strcmp(flags[i].name,s) == 0)
 
438
                                        break;
 
439
                        }
 
440
                        p->flags |= flags[i].mask;
 
441
                        break;
 
442
                case C_ACTION:
 
443
                        get_string(s, sizeof(s), f);
 
444
                        for(i = 0; actions[i].name; i++) {
 
445
                                if (strcmp(actions[i].name, s) == 0)
 
446
                                        break;
 
447
                        }
 
448
                        p->action = actions[i].act ? actions[i].act : OFF;
 
449
                        break;
 
450
                default:
 
451
                        free(p);
 
452
                        oops_error = -1;
 
453
                        return NULL;
 
454
        } while( cmd != C_EOR);
 
455
 
 
456
        return p;
 
457
}
 
458
 
 
459
/*
 
460
 *      Read the complete state info from the state pipe.
 
461
 *      Returns 0 on success
 
462
 */
 
463
static
 
464
int receive_state(int fd)
 
465
{
 
466
        FILE    *f;
 
467
        char    old_version[256];
 
468
        CHILD   **pp;
 
469
 
 
470
        f = fdopen(fd, "r");
 
471
 
 
472
        if (get_cmd(f) != C_VER)
 
473
                return -1;
 
474
        get_string(old_version, sizeof(old_version), f);
 
475
        oops_error = 0;
 
476
        for (pp = &family; (*pp = get_record(f)) != NULL; pp = &((*pp)->next))
 
477
                ;
 
478
        fclose(f);
 
479
        return oops_error;
 
480
}
 
481
 
 
482
/*
 
483
 *      Set the process title.
 
484
 */
 
485
#ifdef __GNUC__
 
486
__attribute__ ((format (printf, 1, 2)))
 
487
#endif
 
488
static int setproctitle(char *fmt, ...)
 
489
{
 
490
        va_list ap;
 
491
        int len;
 
492
        char buf[256];
 
493
 
 
494
        buf[0] = 0;
 
495
 
 
496
        va_start(ap, fmt);
 
497
        len = vsnprintf(buf, sizeof(buf), fmt, ap);
 
498
        va_end(ap);
 
499
 
 
500
        if (maxproclen > 1) {
 
501
                memset(argv0, 0, maxproclen);
 
502
                strncpy(argv0, buf, maxproclen - 1);
 
503
        }
 
504
 
 
505
        return len;
 
506
}
 
507
 
 
508
/*
 
509
 *      Set console_dev to a working console.
 
510
 */
 
511
static
 
512
void console_init(void)
 
513
{
 
514
        int fd;
 
515
        int tried_devcons = 0;
 
516
        int tried_vtmaster = 0;
 
517
        char *s;
 
518
 
 
519
        if ((s = getenv("CONSOLE")) != NULL)
 
520
                console_dev = s;
 
521
        else {
 
522
                console_dev = CONSOLE;
 
523
                tried_devcons++;
 
524
        }
 
525
 
 
526
        while ((fd = open(console_dev, O_RDONLY|O_NONBLOCK)) < 0) {
 
527
                if (!tried_devcons) {
 
528
                        tried_devcons++;
 
529
                        console_dev = CONSOLE;
 
530
                        continue;
 
531
                }
 
532
                if (!tried_vtmaster) {
 
533
                        tried_vtmaster++;
 
534
                        console_dev = VT_MASTER;
 
535
                        continue;
 
536
                }
 
537
                break;
 
538
        }
 
539
        if (fd < 0)
 
540
                console_dev = "/dev/null";
 
541
        else
 
542
                close(fd);
 
543
}
 
544
 
 
545
 
 
546
/*
 
547
 *      Open the console with retries.
 
548
 */
 
549
static
 
550
int console_open(int mode)
 
551
{
 
552
        int f, fd = -1;
 
553
        int m;
 
554
 
 
555
        /*
 
556
         *      Open device in nonblocking mode.
 
557
         */
 
558
        m = mode | O_NONBLOCK;
 
559
 
 
560
        /*
 
561
         *      Retry the open five times.
 
562
         */
 
563
        for(f = 0; f < 5; f++) {
 
564
                if ((fd = open(console_dev, m)) >= 0) break;
 
565
                usleep(10000);
 
566
        }
 
567
 
 
568
        if (fd < 0) return fd;
 
569
 
 
570
        /*
 
571
         *      Set original flags.
 
572
         */
 
573
        if (m != mode)
 
574
                fcntl(fd, F_SETFL, mode);
 
575
        return fd;
 
576
}
 
577
 
 
578
/*
 
579
 *      We got a signal (HUP PWR WINCH ALRM INT)
 
580
 */
 
581
static
 
582
void signal_handler(int sig)
 
583
{
 
584
        ADDSET(got_signals, sig);
 
585
}
 
586
 
 
587
/*
 
588
 *      SIGCHLD: one of our children has died.
 
589
 */
 
590
static
 
591
# ifdef __GNUC__
 
592
void chld_handler(int sig __attribute__((unused)))
 
593
# else
 
594
void chld_handler(int sig)
 
595
# endif
 
596
{
 
597
        CHILD           *ch;
 
598
        int             pid, st;
 
599
        int             saved_errno = errno;
 
600
 
 
601
        /*
 
602
         *      Find out which process(es) this was (were)
 
603
         */
 
604
        while((pid = waitpid(-1, &st, WNOHANG)) != 0) {
 
605
                if (errno == ECHILD) break;
 
606
                for( ch = family; ch; ch = ch->next )
 
607
                        if ( ch->pid == pid && (ch->flags & RUNNING) ) {
 
608
                                INITDBG(L_VB,
 
609
                                        "chld_handler: marked %d as zombie",
 
610
                                        ch->pid);
 
611
                                ADDSET(got_signals, SIGCHLD);
 
612
                                ch->exstat = st;
 
613
                                ch->flags |= ZOMBIE;
 
614
                                if (ch->new) {
 
615
                                        ch->new->exstat = st;
 
616
                                        ch->new->flags |= ZOMBIE;
 
617
                                }
 
618
                                break;
 
619
                        }
 
620
                if (ch == NULL) {
 
621
                        INITDBG(L_VB, "chld_handler: unknown child %d exited.",
 
622
                                pid);
 
623
                }
 
624
        }
 
625
        errno = saved_errno;
 
626
}
 
627
 
 
628
/*
 
629
 *      Linux ignores all signals sent to init when the
 
630
 *      SIG_DFL handler is installed. Therefore we must catch SIGTSTP
 
631
 *      and SIGCONT, or else they won't work....
 
632
 *
 
633
 *      The SIGCONT handler
 
634
 */
 
635
static
 
636
# ifdef __GNUC__
 
637
void cont_handler(int sig __attribute__((unused)))
 
638
# else
 
639
void cont_handler(int sig)
 
640
# endif
 
641
{
 
642
        got_cont = 1;
 
643
}
 
644
 
 
645
/*
 
646
 *      Fork and dump core in /.
 
647
 */
 
648
static
 
649
void coredump(void)
 
650
{
 
651
        static int              dumped = 0;
 
652
        struct rlimit           rlim;
 
653
        sigset_t                mask;
 
654
 
 
655
        if (dumped) return;
 
656
        dumped = 1;
 
657
 
 
658
        if (fork() != 0) return;
 
659
 
 
660
        sigfillset(&mask);
 
661
        sigprocmask(SIG_SETMASK, &mask, NULL);
 
662
 
 
663
        rlim.rlim_cur = RLIM_INFINITY;
 
664
        rlim.rlim_max = RLIM_INFINITY;
 
665
        setrlimit(RLIMIT_CORE, &rlim);
 
666
        chdir("/");
 
667
 
 
668
        signal(SIGSEGV, SIG_DFL);
 
669
        raise(SIGSEGV);
 
670
        sigdelset(&mask, SIGSEGV);
 
671
        sigprocmask(SIG_SETMASK, &mask, NULL);
 
672
 
 
673
        do_sleep(5);
 
674
        exit(0);
 
675
}
 
676
 
 
677
/*
 
678
 *      OOPS: segmentation violation!
 
679
 *      If we have the info, print where it occured.
 
680
 *      Then sleep 30 seconds and try to continue.
 
681
 */
 
682
static
 
683
#if defined(STACK_DEBUG) && defined(__linux__)
 
684
# ifdef __GNUC__
 
685
void segv_handler(int sig __attribute__((unused)), struct sigcontext ctx)
 
686
# else
 
687
void segv_handler(int sig, struct sigcontext ctx)
 
688
# endif
 
689
{
 
690
        char    *p = "";
 
691
        int     saved_errno = errno;
 
692
 
 
693
        if ((void *)ctx.eip >= (void *)do_sleep &&
 
694
            (void *)ctx.eip < (void *)main)
 
695
                p = " (code)";
 
696
        initlog(L_VB, "PANIC: segmentation violation at %p%s! "
 
697
                  "sleeping for 30 seconds.", (void *)ctx.eip, p);
 
698
        coredump();
 
699
        do_sleep(30);
 
700
        errno = saved_errno;
 
701
}
 
702
#else
 
703
# ifdef __GNUC__
 
704
void segv_handler(int sig __attribute__((unused)))
 
705
# else
 
706
void segv_handler(int sig)
 
707
# endif
 
708
{
 
709
        int     saved_errno = errno;
 
710
 
 
711
        initlog(L_VB,
 
712
                "PANIC: segmentation violation! sleeping for 30 seconds.");
 
713
        coredump();
 
714
        do_sleep(30);
 
715
        errno = saved_errno;
 
716
}
 
717
#endif
 
718
 
 
719
/*
 
720
 *      The SIGSTOP & SIGTSTP handler
 
721
 */
 
722
static
 
723
# ifdef __GNUC__
 
724
void stop_handler(int sig __attribute__((unused)))
 
725
# else
 
726
void stop_handler(int sig)
 
727
# endif
 
728
{
 
729
        int     saved_errno = errno;
 
730
 
 
731
        got_cont = 0;
 
732
        while(!got_cont) pause();
 
733
        got_cont = 0;
 
734
        errno = saved_errno;
 
735
}
 
736
 
 
737
/*
 
738
 *      Set terminal settings to reasonable defaults
 
739
 */
 
740
static
 
741
void console_stty(void)
 
742
{
 
743
        struct termios tty;
 
744
        int fd;
 
745
 
 
746
        if ((fd = console_open(O_RDWR|O_NOCTTY)) < 0) {
 
747
                initlog(L_VB, "can't open %s", console_dev);
 
748
                return;
 
749
        }
 
750
 
 
751
#ifdef __FreeBSD_kernel__
 
752
        /*
 
753
         * The kernel of FreeBSD expects userland to set TERM.  Usually, we want
 
754
         * "cons25".  Later, gettys might disagree on this (i.e. we're not using
 
755
         * syscons) but some boot scripts, like /etc/init.d/xserver-xorg, still
 
756
         * need a non-dumb terminal.
 
757
         */
 
758
        putenv ("TERM=cons25");
 
759
#endif
 
760
 
 
761
        (void) tcgetattr(fd, &tty);
 
762
 
 
763
        tty.c_cflag &= CBAUD|CBAUDEX|CSIZE|CSTOPB|PARENB|PARODD;
 
764
        tty.c_cflag |= HUPCL|CLOCAL|CREAD;
 
765
 
 
766
        tty.c_cc[VINTR]     = CINTR;
 
767
        tty.c_cc[VQUIT]     = CQUIT;
 
768
        tty.c_cc[VERASE]    = CERASE; /* ASCII DEL (0177) */
 
769
        tty.c_cc[VKILL]     = CKILL;
 
770
        tty.c_cc[VEOF]      = CEOF;
 
771
        tty.c_cc[VTIME]     = 0;
 
772
        tty.c_cc[VMIN]      = 1;
 
773
#ifdef VSWTC /* not defined on FreeBSD */
 
774
        tty.c_cc[VSWTC]     = _POSIX_VDISABLE;
 
775
#endif /* VSWTC */
 
776
        tty.c_cc[VSTART]    = CSTART;
 
777
        tty.c_cc[VSTOP]     = CSTOP;
 
778
        tty.c_cc[VSUSP]     = CSUSP;
 
779
        tty.c_cc[VEOL]      = _POSIX_VDISABLE;
 
780
        tty.c_cc[VREPRINT]  = CREPRINT;
 
781
        tty.c_cc[VDISCARD]  = CDISCARD;
 
782
        tty.c_cc[VWERASE]   = CWERASE;
 
783
        tty.c_cc[VLNEXT]    = CLNEXT;
 
784
        tty.c_cc[VEOL2]     = _POSIX_VDISABLE;
 
785
 
 
786
        /*
 
787
         *      Set pre and post processing
 
788
         */
 
789
        tty.c_iflag = IGNPAR|ICRNL|IXON|IXANY;
 
790
#ifdef IUTF8 /* Not defined on FreeBSD */
 
791
        tty.c_iflag |= IUTF8;
 
792
#endif /* IUTF8 */
 
793
        tty.c_oflag = OPOST|ONLCR;
 
794
        tty.c_lflag = ISIG|ICANON|ECHO|ECHOCTL|ECHOPRT|ECHOKE;
 
795
 
 
796
#if defined(SANE_TIO) && (SANE_TIO == 1)
 
797
        /*
 
798
         *      Disable flow control (-ixon), ignore break (ignbrk),
 
799
         *      and make nl/cr more usable (sane).
 
800
         */
 
801
        tty.c_iflag |=  IGNBRK;
 
802
        tty.c_iflag &= ~(BRKINT|INLCR|IGNCR|IXON);
 
803
        tty.c_oflag &= ~(OCRNL|ONLRET);
 
804
#endif
 
805
        /*
 
806
         *      Now set the terminal line.
 
807
         *      We don't care about non-transmitted output data
 
808
         *      and non-read input data.
 
809
         */
 
810
        (void) tcsetattr(fd, TCSANOW, &tty);
 
811
        (void) tcflush(fd, TCIOFLUSH);
 
812
        (void) close(fd);
 
813
}
 
814
 
 
815
/*
 
816
 *      Print to the system console
 
817
 */
 
818
void print(char *s)
 
819
{
 
820
        int fd;
 
821
 
 
822
        if ((fd = console_open(O_WRONLY|O_NOCTTY|O_NDELAY)) >= 0) {
 
823
                write(fd, s, strlen(s));
 
824
                close(fd);
 
825
        }
 
826
}
 
827
 
 
828
/*
 
829
 *      Log something to a logfile and the console.
 
830
 */
 
831
#ifdef __GNUC__
 
832
__attribute__ ((format (printf, 2, 3)))
 
833
#endif
 
834
void initlog(int loglevel, char *s, ...)
 
835
{
 
836
        va_list va_alist;
 
837
        char buf[256];
 
838
        sigset_t nmask, omask;
 
839
 
 
840
        va_start(va_alist, s);
 
841
        vsnprintf(buf, sizeof(buf), s, va_alist);
 
842
        va_end(va_alist);
 
843
 
 
844
        if (loglevel & L_SY) {
 
845
                /*
 
846
                 *      Re-establish connection with syslogd every time.
 
847
                 *      Block signals while talking to syslog.
 
848
                 */
 
849
                sigfillset(&nmask);
 
850
                sigprocmask(SIG_BLOCK, &nmask, &omask);
 
851
                openlog("init", 0, LOG_DAEMON);
 
852
                syslog(LOG_INFO, "%s", buf);
 
853
                closelog();
 
854
                sigprocmask(SIG_SETMASK, &omask, NULL);
 
855
        }
 
856
 
 
857
        /*
 
858
         *      And log to the console.
 
859
         */
 
860
        if (loglevel & L_CO) {
 
861
                print("\rINIT: ");
 
862
                print(buf);
 
863
                print("\r\n");
 
864
        }
 
865
}
 
866
 
 
867
 
 
868
/*
 
869
 *      Build a new environment for execve().
 
870
 */
 
871
char **init_buildenv(int child)
 
872
{
 
873
        char            i_lvl[] = "RUNLEVEL=x";
 
874
        char            i_prev[] = "PREVLEVEL=x";
 
875
        char            i_cons[32];
 
876
        char            i_shell[] = "SHELL=" SHELL;
 
877
        char            **e;
 
878
        int             n, i;
 
879
 
 
880
        for (n = 0; environ[n]; n++)
 
881
                ;
 
882
        n += NR_EXTRA_ENV;
 
883
        if (child)
 
884
                n += 8;
 
885
        e = calloc(n, sizeof(char *));
 
886
 
 
887
        for (n = 0; environ[n]; n++)
 
888
                e[n] = istrdup(environ[n]);
 
889
 
 
890
        for (i = 0; i < NR_EXTRA_ENV; i++) {
 
891
                if (extra_env[i])
 
892
                        e[n++] = istrdup(extra_env[i]);
 
893
        }
 
894
 
 
895
        if (child) {
 
896
                snprintf(i_cons, sizeof(i_cons), "CONSOLE=%s", console_dev);
 
897
                i_lvl[9]   = thislevel;
 
898
                i_prev[10] = prevlevel;
 
899
                e[n++] = istrdup(i_shell);
 
900
                e[n++] = istrdup(i_lvl);
 
901
                e[n++] = istrdup(i_prev);
 
902
                e[n++] = istrdup(i_cons);
 
903
                e[n++] = istrdup(E_VERSION);
 
904
        }
 
905
 
 
906
        e[n++] = NULL;
 
907
 
 
908
        return e;
 
909
}
 
910
 
 
911
 
 
912
void init_freeenv(char **e)
 
913
{
 
914
        int             n;
 
915
 
 
916
        for (n = 0; e[n]; n++)
 
917
                free(e[n]);
 
918
        free(e);
 
919
}
 
920
 
 
921
 
 
922
/*
 
923
 *      Fork and execute.
 
924
 *
 
925
 *      This function is too long and indents too deep.
 
926
 *
 
927
 */
 
928
static
 
929
pid_t spawn(CHILD *ch, int *res)
 
930
{
 
931
  char *args[16];               /* Argv array */
 
932
  char buf[136];                /* Line buffer */
 
933
  int f, st;                    /* Scratch variables */
 
934
  char *ptr;                    /* Ditto */
 
935
  time_t t;                     /* System time */
 
936
  int oldAlarm;                 /* Previous alarm value */
 
937
  char *proc = ch->process;     /* Command line */
 
938
  pid_t pid, pgrp;              /* child, console process group. */
 
939
  sigset_t nmask, omask;        /* For blocking SIGCHLD */
 
940
  struct sigaction sa;
 
941
 
 
942
  *res = -1;
 
943
  buf[sizeof(buf) - 1] = 0;
 
944
 
 
945
  /* Skip '+' if it's there */
 
946
  if (proc[0] == '+') proc++;
 
947
 
 
948
  ch->flags |= XECUTED;
 
949
 
 
950
  if (ch->action == RESPAWN || ch->action == ONDEMAND) {
 
951
        /* Is the date stamp from less than 2 minutes ago? */
 
952
        time(&t);
 
953
        if (ch->tm + TESTTIME > t) {
 
954
                ch->count++;
 
955
        } else {
 
956
                ch->count = 0;
 
957
                ch->tm = t;
 
958
        }
 
959
 
 
960
        /* Do we try to respawn too fast? */
 
961
        if (ch->count >= MAXSPAWN) {
 
962
 
 
963
          initlog(L_VB,
 
964
                "Id \"%s\" respawning too fast: disabled for %d minutes",
 
965
                ch->id, SLEEPTIME / 60);
 
966
          ch->flags &= ~RUNNING;
 
967
          ch->flags |= FAILING;
 
968
 
 
969
          /* Remember the time we stopped */
 
970
          ch->tm = t;
 
971
 
 
972
          /* Try again in 5 minutes */
 
973
          oldAlarm = alarm(0);
 
974
          if (oldAlarm > SLEEPTIME || oldAlarm <= 0) oldAlarm = SLEEPTIME;
 
975
          alarm(oldAlarm);
 
976
          return(-1);
 
977
        }
 
978
  }
 
979
 
 
980
  /* See if there is an "initscript" (except in single user mode). */
 
981
  if (access(INITSCRIPT, R_OK) == 0 && runlevel != 'S') {
 
982
        /* Build command line using "initscript" */
 
983
        args[1] = SHELL;
 
984
        args[2] = INITSCRIPT;
 
985
        args[3] = ch->id;
 
986
        args[4] = ch->rlevel;
 
987
        args[5] = "unknown";
 
988
        for(f = 0; actions[f].name; f++) {
 
989
                if (ch->action == actions[f].act) {
 
990
                        args[5] = actions[f].name;
 
991
                        break;
 
992
                }
 
993
        }
 
994
        args[6] = proc;
 
995
        args[7] = NULL;
 
996
  } else if (strpbrk(proc, "~`!$^&*()=|\\{}[];\"'<>?")) {
 
997
  /* See if we need to fire off a shell for this command */
 
998
        /* Give command line to shell */
 
999
        args[1] = SHELL;
 
1000
        args[2] = "-c";
 
1001
        strcpy(buf, "exec ");
 
1002
        strncat(buf, proc, sizeof(buf) - strlen(buf) - 1);
 
1003
        args[3] = buf;
 
1004
        args[4] = NULL;
 
1005
  } else {
 
1006
        /* Split up command line arguments */
 
1007
        buf[0] = 0;
 
1008
        strncat(buf, proc, sizeof(buf) - 1);
 
1009
        ptr = buf;
 
1010
        for(f = 1; f < 15; f++) {
 
1011
                /* Skip white space */
 
1012
                while(*ptr == ' ' || *ptr == '\t') ptr++;
 
1013
                args[f] = ptr;
 
1014
                
 
1015
                /* May be trailing space.. */
 
1016
                if (*ptr == 0) break;
 
1017
 
 
1018
                /* Skip this `word' */
 
1019
                while(*ptr && *ptr != ' ' && *ptr != '\t' && *ptr != '#')
 
1020
                        ptr++;
 
1021
                
 
1022
                /* If end-of-line, break */     
 
1023
                if (*ptr == '#' || *ptr == 0) {
 
1024
                        f++;
 
1025
                        *ptr = 0;
 
1026
                        break;
 
1027
                }
 
1028
                /* End word with \0 and continue */
 
1029
                *ptr++ = 0;
 
1030
        }
 
1031
        args[f] = NULL;
 
1032
  }
 
1033
  args[0] = args[1];
 
1034
  while(1) {
 
1035
        /*
 
1036
         *      Block sigchild while forking.
 
1037
         */
 
1038
        sigemptyset(&nmask);
 
1039
        sigaddset(&nmask, SIGCHLD);
 
1040
        sigprocmask(SIG_BLOCK, &nmask, &omask);
 
1041
 
 
1042
        if ((pid = fork()) == 0) {
 
1043
 
 
1044
                close(0);
 
1045
                close(1);
 
1046
                close(2);
 
1047
                if (pipe_fd >= 0) close(pipe_fd);
 
1048
 
 
1049
                sigprocmask(SIG_SETMASK, &omask, NULL);
 
1050
 
 
1051
                /*
 
1052
                 *      In sysinit, boot, bootwait or single user mode:
 
1053
                 *      for any wait-type subprocess we _force_ the console
 
1054
                 *      to be its controlling tty.
 
1055
                 */
 
1056
                if (strchr("*#sS", runlevel) && ch->flags & WAITING) {
 
1057
                        /*
 
1058
                         *      We fork once extra. This is so that we can
 
1059
                         *      wait and change the process group and session
 
1060
                         *      of the console after exit of the leader.
 
1061
                         */
 
1062
                        setsid();
 
1063
                        if ((f = console_open(O_RDWR|O_NOCTTY)) >= 0) {
 
1064
                                /* Take over controlling tty by force */
 
1065
                                (void)ioctl(f, TIOCSCTTY, 1);
 
1066
                                dup(f);
 
1067
                                dup(f);
 
1068
                        }
 
1069
 
 
1070
                        /*
 
1071
                         * 4 Sep 2001, Andrea Arcangeli:
 
1072
                         * Fix a race in spawn() that is used to deadlock init in a
 
1073
                         * waitpid() loop: must set the childhandler as default before forking
 
1074
                         * off the child or the chld_handler could run before the waitpid loop
 
1075
                         * has a chance to find its zombie-child.
 
1076
                         */
 
1077
                        SETSIG(sa, SIGCHLD, SIG_DFL, SA_RESTART);
 
1078
                        if ((pid = fork()) < 0) {
 
1079
                                initlog(L_VB, "cannot fork: %s",
 
1080
                                        strerror(errno));
 
1081
                                exit(1);
 
1082
                        }
 
1083
                        if (pid > 0) {
 
1084
                                pid_t rc;
 
1085
                                /*
 
1086
                                 *      Ignore keyboard signals etc.
 
1087
                                 *      Then wait for child to exit.
 
1088
                                 */
 
1089
                                SETSIG(sa, SIGINT, SIG_IGN, SA_RESTART);
 
1090
                                SETSIG(sa, SIGTSTP, SIG_IGN, SA_RESTART);
 
1091
                                SETSIG(sa, SIGQUIT, SIG_IGN, SA_RESTART);
 
1092
 
 
1093
                                while ((rc = waitpid(pid, &st, 0)) != pid)
 
1094
                                        if (rc < 0 && errno == ECHILD)
 
1095
                                                break;
 
1096
 
 
1097
                                /*
 
1098
                                 *      Small optimization. See if stealing
 
1099
                                 *      controlling tty back is needed.
 
1100
                                 */
 
1101
                                pgrp = tcgetpgrp(f);
 
1102
                                if (pgrp != getpid())
 
1103
                                        exit(0);
 
1104
 
 
1105
                                /*
 
1106
                                 *      Steal controlling tty away. We do
 
1107
                                 *      this with a temporary process.
 
1108
                                 */
 
1109
                                if ((pid = fork()) < 0) {
 
1110
                                        initlog(L_VB, "cannot fork: %s",
 
1111
                                                strerror(errno));
 
1112
                                        exit(1);
 
1113
                                }
 
1114
                                if (pid == 0) {
 
1115
                                        setsid();
 
1116
                                        (void)ioctl(f, TIOCSCTTY, 1);
 
1117
                                        exit(0);
 
1118
                                }
 
1119
                                while((rc = waitpid(pid, &st, 0)) != pid)
 
1120
                                        if (rc < 0 && errno == ECHILD)
 
1121
                                                break;
 
1122
                                exit(0);
 
1123
                        }
 
1124
 
 
1125
                        /* Set ioctl settings to default ones */
 
1126
                        console_stty();
 
1127
 
 
1128
                } else {
 
1129
                        setsid();
 
1130
                        if ((f = console_open(O_RDWR|O_NOCTTY)) < 0) {
 
1131
                                initlog(L_VB, "open(%s): %s", console_dev,
 
1132
                                        strerror(errno));
 
1133
                                f = open("/dev/null", O_RDWR);
 
1134
                        }
 
1135
                        dup(f);
 
1136
                        dup(f);
 
1137
                }
 
1138
 
 
1139
                /*
 
1140
                 * Update utmp/wtmp file prior to starting
 
1141
                 * any child.  This MUST be done right here in
 
1142
                 * the child process in order to prevent a race
 
1143
                 * condition that occurs when the child
 
1144
                 * process' time slice executes before the
 
1145
                 * parent (can and does happen in a uniprocessor
 
1146
                 * environment).  If the child is a getty and
 
1147
                 * the race condition happens, then init's utmp
 
1148
                 * update will happen AFTER the getty runs
 
1149
                 * and expects utmp to be updated already!
 
1150
                 *
 
1151
                 * Do NOT log if process field starts with '+'
 
1152
                 * FIXME: that's for compatibility with *very*
 
1153
                 * old getties - probably it can be taken out.
 
1154
                 */
 
1155
                if (ch->process[0] != '+')
 
1156
                        write_utmp_wtmp("", ch->id, getpid(), INIT_PROCESS, "");
 
1157
 
 
1158
                /* Reset all the signals, set up environment */
 
1159
                for(f = 1; f < NSIG; f++) SETSIG(sa, f, SIG_DFL, SA_RESTART);
 
1160
                environ = init_buildenv(1);
 
1161
 
 
1162
                /*
 
1163
                 *      Execute prog. In case of ENOEXEC try again
 
1164
                 *      as a shell script.
 
1165
                 */
 
1166
                execvp(args[1], args + 1);
 
1167
                if (errno == ENOEXEC) {
 
1168
                        args[1] = SHELL;
 
1169
                        args[2] = "-c";
 
1170
                        strcpy(buf, "exec ");
 
1171
                        strncat(buf, proc, sizeof(buf) - strlen(buf) - 1);
 
1172
                        args[3] = buf;
 
1173
                        args[4] = NULL;
 
1174
                        execvp(args[1], args + 1);
 
1175
                }
 
1176
                initlog(L_VB, "cannot execute \"%s\"", args[1]);
 
1177
 
 
1178
                if (ch->process[0] != '+')
 
1179
                        write_utmp_wtmp("", ch->id, getpid(), DEAD_PROCESS, NULL);
 
1180
                exit(1);
 
1181
        }
 
1182
        *res = pid;
 
1183
        sigprocmask(SIG_SETMASK, &omask, NULL);
 
1184
 
 
1185
        INITDBG(L_VB, "Started id %s (pid %d)", ch->id, pid);
 
1186
 
 
1187
        if (pid == -1) {
 
1188
                initlog(L_VB, "cannot fork, retry..");
 
1189
                do_sleep(5);
 
1190
                continue;
 
1191
        }
 
1192
        return(pid);
 
1193
  }
 
1194
}
 
1195
 
 
1196
/*
 
1197
 *      Start a child running!
 
1198
 */
 
1199
static
 
1200
void startup(CHILD *ch)
 
1201
{
 
1202
        /*
 
1203
         *      See if it's disabled
 
1204
         */
 
1205
        if (ch->flags & FAILING) return;
 
1206
 
 
1207
        switch(ch->action) {
 
1208
 
 
1209
                case SYSINIT:
 
1210
                case BOOTWAIT:
 
1211
                case WAIT:
 
1212
                case POWERWAIT:
 
1213
                case POWERFAILNOW:
 
1214
                case POWEROKWAIT:
 
1215
                case CTRLALTDEL:
 
1216
                        if (!(ch->flags & XECUTED)) ch->flags |= WAITING;
 
1217
                case KBREQUEST:
 
1218
                case BOOT:
 
1219
                case POWERFAIL:
 
1220
                case ONCE:
 
1221
                        if (ch->flags & XECUTED) break;
 
1222
                case ONDEMAND:
 
1223
                case RESPAWN:
 
1224
                        ch->flags |= RUNNING;
 
1225
                        (void)spawn(ch, &(ch->pid));
 
1226
                        break;
 
1227
        }
 
1228
}
 
1229
 
 
1230
 
 
1231
/*
 
1232
 *      Read the inittab file.
 
1233
 */
 
1234
static
 
1235
void read_inittab(void)
 
1236
{
 
1237
  FILE          *fp;                    /* The INITTAB file */
 
1238
  CHILD         *ch, *old, *i;          /* Pointers to CHILD structure */
 
1239
  CHILD         *head = NULL;           /* Head of linked list */
 
1240
#ifdef INITLVL
 
1241
  struct stat   st;                     /* To stat INITLVL */
 
1242
#endif
 
1243
  sigset_t      nmask, omask;           /* For blocking SIGCHLD. */
 
1244
  char          buf[256];               /* Line buffer */
 
1245
  char          err[64];                /* Error message. */
 
1246
  char          *id, *rlevel,
 
1247
                *action, *process;      /* Fields of a line */
 
1248
  char          *p;
 
1249
  int           lineNo = 0;             /* Line number in INITTAB file */
 
1250
  int           actionNo;               /* Decoded action field */
 
1251
  int           f;                      /* Counter */
 
1252
  int           round;                  /* round 0 for SIGTERM, 1 for SIGKILL */
 
1253
  int           foundOne = 0;           /* No killing no sleep */
 
1254
  int           talk;                   /* Talk to the user */
 
1255
  int           done = 0;               /* Ready yet? */
 
1256
 
 
1257
#if DEBUG
 
1258
  if (newFamily != NULL) {
 
1259
        INITDBG(L_VB, "PANIC newFamily != NULL");
 
1260
        exit(1);
 
1261
  }
 
1262
  INITDBG(L_VB, "Reading inittab");
 
1263
#endif
 
1264
 
 
1265
  /*
 
1266
   *    Open INITTAB and real line by line.
 
1267
   */
 
1268
  if ((fp = fopen(INITTAB, "r")) == NULL)
 
1269
        initlog(L_VB, "No inittab file found");
 
1270
 
 
1271
  while(!done) {
 
1272
        /*
 
1273
         *      Add single user shell entry at the end.
 
1274
         */
 
1275
        if (fp == NULL || fgets(buf, sizeof(buf), fp) == NULL) {
 
1276
                done = 1;
 
1277
                /*
 
1278
                 *      See if we have a single user entry.
 
1279
                 */
 
1280
                for(old = newFamily; old; old = old->next)
 
1281
                        if (strpbrk(old->rlevel, "S")) break;
 
1282
                if (old == NULL)
 
1283
                        snprintf(buf, sizeof(buf), "~~:S:wait:%s\n", SULOGIN);
 
1284
                else
 
1285
                        continue;
 
1286
        }
 
1287
        lineNo++;
 
1288
        /*
 
1289
         *      Skip comments and empty lines
 
1290
         */
 
1291
        for(p = buf; *p == ' ' || *p == '\t'; p++)
 
1292
                ;
 
1293
        if (*p == '#' || *p == '\n') continue;
 
1294
 
 
1295
        /*
 
1296
         *      Decode the fields
 
1297
         */
 
1298
        id =      strsep(&p, ":");
 
1299
        rlevel =  strsep(&p, ":");
 
1300
        action =  strsep(&p, ":");
 
1301
        process = strsep(&p, "\n");
 
1302
 
 
1303
        /*
 
1304
         *      Check if syntax is OK. Be very verbose here, to
 
1305
         *      avoid newbie postings on comp.os.linux.setup :)
 
1306
         */
 
1307
        err[0] = 0;
 
1308
        if (!id || !*id) strcpy(err, "missing id field");
 
1309
        if (!rlevel)     strcpy(err, "missing runlevel field");
 
1310
        if (!process)    strcpy(err, "missing process field");
 
1311
        if (!action || !*action)
 
1312
                        strcpy(err, "missing action field");
 
1313
        if (id && strlen(id) > sizeof(utproto.ut_id))
 
1314
                sprintf(err, "id field too long (max %d characters)",
 
1315
                        (int)sizeof(utproto.ut_id));
 
1316
        if (rlevel && strlen(rlevel) > 11)
 
1317
                strcpy(err, "rlevel field too long (max 11 characters)");
 
1318
        if (process && strlen(process) > 127)
 
1319
                strcpy(err, "process field too long");
 
1320
        if (action && strlen(action) > 32)
 
1321
                strcpy(err, "action field too long");
 
1322
        if (err[0] != 0) {
 
1323
                initlog(L_VB, "%s[%d]: %s", INITTAB, lineNo, err);
 
1324
                INITDBG(L_VB, "%s:%s:%s:%s", id, rlevel, action, process);
 
1325
                continue;
 
1326
        }
 
1327
  
 
1328
        /*
 
1329
         *      Decode the "action" field
 
1330
         */
 
1331
        actionNo = -1;
 
1332
        for(f = 0; actions[f].name; f++)
 
1333
                if (strcasecmp(action, actions[f].name) == 0) {
 
1334
                        actionNo = actions[f].act;
 
1335
                        break;
 
1336
                }
 
1337
        if (actionNo == -1) {
 
1338
                initlog(L_VB, "%s[%d]: %s: unknown action field",
 
1339
                        INITTAB, lineNo, action);
 
1340
                continue;
 
1341
        }
 
1342
 
 
1343
        /*
 
1344
         *      See if the id field is unique
 
1345
         */
 
1346
        for(old = newFamily; old; old = old->next) {
 
1347
                if(strcmp(old->id, id) == 0 && strcmp(id, "~~")) {
 
1348
                        initlog(L_VB, "%s[%d]: duplicate ID field \"%s\"",
 
1349
                                INITTAB, lineNo, id);
 
1350
                        break;
 
1351
                }
 
1352
        }
 
1353
        if (old) continue;
 
1354
 
 
1355
        /*
 
1356
         *      Allocate a CHILD structure
 
1357
         */
 
1358
        ch = imalloc(sizeof(CHILD));
 
1359
 
 
1360
        /*
 
1361
         *      And fill it in.
 
1362
         */
 
1363
        ch->action = actionNo;
 
1364
        strncpy(ch->id, id, sizeof(utproto.ut_id) + 1); /* Hack for different libs. */
 
1365
        strncpy(ch->process, process, sizeof(ch->process) - 1);
 
1366
        if (rlevel[0]) {
 
1367
                for(f = 0; f < (int)sizeof(rlevel) - 1 && rlevel[f]; f++) {
 
1368
                        ch->rlevel[f] = rlevel[f];
 
1369
                        if (ch->rlevel[f] == 's') ch->rlevel[f] = 'S';
 
1370
                }
 
1371
                strncpy(ch->rlevel, rlevel, sizeof(ch->rlevel) - 1);
 
1372
        } else {
 
1373
                strcpy(ch->rlevel, "0123456789");
 
1374
                if (ISPOWER(ch->action))
 
1375
                        strcpy(ch->rlevel, "S0123456789");
 
1376
        }
 
1377
        /*
 
1378
         *      We have the fake runlevel '#' for SYSINIT  and
 
1379
         *      '*' for BOOT and BOOTWAIT.
 
1380
         */
 
1381
        if (ch->action == SYSINIT) strcpy(ch->rlevel, "#");
 
1382
        if (ch->action == BOOT || ch->action == BOOTWAIT)
 
1383
                strcpy(ch->rlevel, "*");
 
1384
 
 
1385
        /*
 
1386
         *      Now add it to the linked list. Special for powerfail.
 
1387
         */
 
1388
        if (ISPOWER(ch->action)) {
 
1389
 
 
1390
                /*
 
1391
                 *      Disable by default
 
1392
                 */
 
1393
                ch->flags |= XECUTED;
 
1394
 
 
1395
                /*
 
1396
                 *      Tricky: insert at the front of the list..
 
1397
                 */
 
1398
                old = NULL;
 
1399
                for(i = newFamily; i; i = i->next) {
 
1400
                        if (!ISPOWER(i->action)) break;
 
1401
                        old = i;
 
1402
                }
 
1403
                /*
 
1404
                 *      Now add after entry "old"
 
1405
                 */
 
1406
                if (old) {
 
1407
                        ch->next = i;
 
1408
                        old->next = ch;
 
1409
                        if (i == NULL) head = ch;
 
1410
                } else {
 
1411
                        ch->next = newFamily;
 
1412
                        newFamily = ch;
 
1413
                        if (ch->next == NULL) head = ch;
 
1414
                }
 
1415
        } else {
 
1416
                /*
 
1417
                 *      Just add at end of the list
 
1418
                 */
 
1419
                if (ch->action == KBREQUEST) ch->flags |= XECUTED;
 
1420
                ch->next = NULL;
 
1421
                if (head)
 
1422
                        head->next = ch;
 
1423
                else
 
1424
                        newFamily = ch;
 
1425
                head = ch;
 
1426
        }
 
1427
 
 
1428
        /*
 
1429
         *      Walk through the old list comparing id fields
 
1430
         */
 
1431
        for(old = family; old; old = old->next)
 
1432
                if (strcmp(old->id, ch->id) == 0) {
 
1433
                        old->new = ch;
 
1434
                        break;
 
1435
                }
 
1436
  }
 
1437
  /*
 
1438
   *    We're done.
 
1439
   */
 
1440
  if (fp) fclose(fp);
 
1441
 
 
1442
  /*
 
1443
   *    Loop through the list of children, and see if they need to
 
1444
   *    be killed. 
 
1445
   */
 
1446
 
 
1447
  INITDBG(L_VB, "Checking for children to kill");
 
1448
  for(round = 0; round < 2; round++) {
 
1449
    talk = 1;
 
1450
    for(ch = family; ch; ch = ch->next) {
 
1451
        ch->flags &= ~KILLME;
 
1452
 
 
1453
        /*
 
1454
         *      Is this line deleted?
 
1455
         */
 
1456
        if (ch->new == NULL) ch->flags |= KILLME;
 
1457
 
 
1458
        /*
 
1459
         *      If the entry has changed, kill it anyway. Note that
 
1460
         *      we do not check ch->process, only the "action" field.
 
1461
         *      This way, you can turn an entry "off" immediately, but
 
1462
         *      changes in the command line will only become effective
 
1463
         *      after the running version has exited.
 
1464
         */
 
1465
        if (ch->new && ch->action != ch->new->action) ch->flags |= KILLME;
 
1466
 
 
1467
        /*
 
1468
         *      Only BOOT processes may live in all levels
 
1469
         */
 
1470
        if (ch->action != BOOT &&
 
1471
            strchr(ch->rlevel, runlevel) == NULL) {
 
1472
                /*
 
1473
                 *      Ondemand procedures live always,
 
1474
                 *      except in single user
 
1475
                 */
 
1476
                if (runlevel == 'S' || !(ch->flags & DEMAND))
 
1477
                        ch->flags |= KILLME;
 
1478
        }
 
1479
 
 
1480
        /*
 
1481
         *      Now, if this process may live note so in the new list
 
1482
         */
 
1483
        if ((ch->flags & KILLME) == 0) {
 
1484
                ch->new->flags  = ch->flags;
 
1485
                ch->new->pid    = ch->pid;
 
1486
                ch->new->exstat = ch->exstat;
 
1487
                continue;
 
1488
        }
 
1489
 
 
1490
 
 
1491
        /*
 
1492
         *      Is this process still around?
 
1493
         */
 
1494
        if ((ch->flags & RUNNING) == 0) {
 
1495
                ch->flags &= ~KILLME;
 
1496
                continue;
 
1497
        }
 
1498
        INITDBG(L_VB, "Killing \"%s\"", ch->process);
 
1499
        switch(round) {
 
1500
                case 0: /* Send TERM signal */
 
1501
                        if (talk)
 
1502
                                initlog(L_CO,
 
1503
                                        "Sending processes the TERM signal");
 
1504
                        kill(-(ch->pid), SIGTERM);
 
1505
                        foundOne = 1;
 
1506
                        break;
 
1507
                case 1: /* Send KILL signal and collect status */
 
1508
                        if (talk)
 
1509
                                initlog(L_CO,
 
1510
                                        "Sending processes the KILL signal");
 
1511
                        kill(-(ch->pid), SIGKILL);
 
1512
                        break;
 
1513
        }
 
1514
        talk = 0;
 
1515
        
 
1516
    }
 
1517
    /*
 
1518
     *  See if we have to wait 5 seconds
 
1519
     */
 
1520
    if (foundOne && round == 0) {
 
1521
        /*
 
1522
         *      Yup, but check every second if we still have children.
 
1523
         */
 
1524
        for(f = 0; f < sltime; f++) {
 
1525
                for(ch = family; ch; ch = ch->next) {
 
1526
                        if (!(ch->flags & KILLME)) continue;
 
1527
                        if ((ch->flags & RUNNING) && !(ch->flags & ZOMBIE))
 
1528
                                break;
 
1529
                }
 
1530
                if (ch == NULL) {
 
1531
                        /*
 
1532
                         *      No running children, skip SIGKILL
 
1533
                         */
 
1534
                        round = 1;
 
1535
                        foundOne = 0; /* Skip the sleep below. */
 
1536
                        break;
 
1537
                }
 
1538
                do_sleep(1);
 
1539
        }
 
1540
    }
 
1541
  }
 
1542
 
 
1543
  /*
 
1544
   *    Now give all processes the chance to die and collect exit statuses.
 
1545
   */
 
1546
  if (foundOne) do_sleep(1);
 
1547
  for(ch = family; ch; ch = ch->next)
 
1548
        if (ch->flags & KILLME) {
 
1549
                if (!(ch->flags & ZOMBIE))
 
1550
                    initlog(L_CO, "Pid %d [id %s] seems to hang", ch->pid,
 
1551
                                ch->id);
 
1552
                else {
 
1553
                    INITDBG(L_VB, "Updating utmp for pid %d [id %s]",
 
1554
                                ch->pid, ch->id);
 
1555
                    ch->flags &= ~RUNNING;
 
1556
                    if (ch->process[0] != '+')
 
1557
                        write_utmp_wtmp("", ch->id, ch->pid, DEAD_PROCESS, NULL);
 
1558
                }
 
1559
        }
 
1560
 
 
1561
  /*
 
1562
   *    Both rounds done; clean up the list.
 
1563
   */
 
1564
  sigemptyset(&nmask);
 
1565
  sigaddset(&nmask, SIGCHLD);
 
1566
  sigprocmask(SIG_BLOCK, &nmask, &omask);
 
1567
  for(ch = family; ch; ch = old) {
 
1568
        old = ch->next;
 
1569
        free(ch);
 
1570
  }
 
1571
  family = newFamily;
 
1572
  for(ch = family; ch; ch = ch->next) ch->new = NULL;
 
1573
  newFamily = NULL;
 
1574
  sigprocmask(SIG_SETMASK, &omask, NULL);
 
1575
 
 
1576
#ifdef INITLVL
 
1577
  /*
 
1578
   *    Dispose of INITLVL file.
 
1579
   */
 
1580
  if (lstat(INITLVL, &st) >= 0 && S_ISLNK(st.st_mode)) {
 
1581
        /*
 
1582
         *      INITLVL is a symbolic link, so just truncate the file.
 
1583
         */
 
1584
        close(open(INITLVL, O_WRONLY|O_TRUNC));
 
1585
  } else {
 
1586
        /*
 
1587
         *      Delete INITLVL file.
 
1588
         */
 
1589
        unlink(INITLVL);
 
1590
  }
 
1591
#endif
 
1592
#ifdef INITLVL2
 
1593
  /*
 
1594
   *    Dispose of INITLVL2 file.
 
1595
   */
 
1596
  if (lstat(INITLVL2, &st) >= 0 && S_ISLNK(st.st_mode)) {
 
1597
        /*
 
1598
         *      INITLVL2 is a symbolic link, so just truncate the file.
 
1599
         */
 
1600
        close(open(INITLVL2, O_WRONLY|O_TRUNC));
 
1601
  } else {
 
1602
        /*
 
1603
         *      Delete INITLVL2 file.
 
1604
         */
 
1605
        unlink(INITLVL2);
 
1606
  }
 
1607
#endif
 
1608
}
 
1609
 
 
1610
/*
 
1611
 *      Walk through the family list and start up children.
 
1612
 *      The entries that do not belong here at all are removed
 
1613
 *      from the list.
 
1614
 */
 
1615
static
 
1616
void start_if_needed(void)
 
1617
{
 
1618
        CHILD *ch;              /* Pointer to child */
 
1619
        int delete;             /* Delete this entry from list? */
 
1620
 
 
1621
        INITDBG(L_VB, "Checking for children to start");
 
1622
 
 
1623
        for(ch = family; ch; ch = ch->next) {
 
1624
 
 
1625
#if DEBUG
 
1626
                if (ch->rlevel[0] == 'C') {
 
1627
                        INITDBG(L_VB, "%s: flags %d", ch->process, ch->flags);
 
1628
                }
 
1629
#endif
 
1630
 
 
1631
                /* Are we waiting for this process? Then quit here. */
 
1632
                if (ch->flags & WAITING) break;
 
1633
 
 
1634
                /* Already running? OK, don't touch it */
 
1635
                if (ch->flags & RUNNING) continue;
 
1636
 
 
1637
                /* See if we have to start it up */
 
1638
                delete = 1;
 
1639
                if (strchr(ch->rlevel, runlevel) ||
 
1640
                    ((ch->flags & DEMAND) && !strchr("#*Ss", runlevel))) {
 
1641
                        startup(ch);
 
1642
                        delete = 0;
 
1643
                }
 
1644
 
 
1645
                if (delete) {
 
1646
                        /* FIXME: is this OK? */
 
1647
                        ch->flags &= ~(RUNNING|WAITING);
 
1648
                        if (!ISPOWER(ch->action) && ch->action != KBREQUEST)
 
1649
                                ch->flags &= ~XECUTED;
 
1650
                        ch->pid = 0;
 
1651
                } else
 
1652
                        /* Do we have to wait for this process? */
 
1653
                        if (ch->flags & WAITING) break;
 
1654
        }
 
1655
        /* Done. */
 
1656
}
 
1657
 
 
1658
/*
 
1659
 *      Ask the user on the console for a runlevel
 
1660
 */
 
1661
static
 
1662
int ask_runlevel(void)
 
1663
{
 
1664
        const char      prompt[] = "\nEnter runlevel: ";
 
1665
        char            buf[8];
 
1666
        int             lvl = -1;
 
1667
        int             fd;
 
1668
 
 
1669
        console_stty();
 
1670
        fd = console_open(O_RDWR|O_NOCTTY);
 
1671
 
 
1672
        if (fd < 0) return('S');
 
1673
 
 
1674
        while(!strchr("0123456789S", lvl)) {
 
1675
                write(fd, prompt, sizeof(prompt) - 1);
 
1676
                buf[0] = 0;
 
1677
                read(fd, buf, sizeof(buf));
 
1678
                if (buf[0] != 0 && (buf[1] == '\r' || buf[1] == '\n'))
 
1679
                        lvl = buf[0];
 
1680
                if (islower(lvl)) lvl = toupper(lvl);
 
1681
        }
 
1682
        close(fd);
 
1683
        return lvl;
 
1684
}
 
1685
 
 
1686
/*
 
1687
 *      Search the INITTAB file for the 'initdefault' field, with the default
 
1688
 *      runlevel. If this fails, ask the user to supply a runlevel.
 
1689
 */
 
1690
static
 
1691
int get_init_default(void)
 
1692
{
 
1693
        CHILD *ch;
 
1694
        int lvl = -1;
 
1695
        char *p;
 
1696
 
 
1697
        /*
 
1698
         *      Look for initdefault.
 
1699
         */
 
1700
        for(ch = family; ch; ch = ch->next)
 
1701
                if (ch->action == INITDEFAULT) {
 
1702
                        p = ch->rlevel;
 
1703
                        while(*p) {
 
1704
                                if (*p > lvl) lvl = *p;
 
1705
                                p++;
 
1706
                        }
 
1707
                        break;
 
1708
                }
 
1709
        /*
 
1710
         *      See if level is valid
 
1711
         */
 
1712
        if (lvl > 0) {
 
1713
                if (islower(lvl)) lvl = toupper(lvl);
 
1714
                if (strchr("0123456789S", lvl) == NULL) {
 
1715
                        initlog(L_VB,
 
1716
                                "Initdefault level '%c' is invalid", lvl);
 
1717
                        lvl = 0;
 
1718
                }
 
1719
        }
 
1720
        /*
 
1721
         *      Ask for runlevel on console if needed.
 
1722
         */
 
1723
        if (lvl <= 0) lvl = ask_runlevel();
 
1724
 
 
1725
        /*
 
1726
         *      Log the fact that we have a runlevel now.
 
1727
         */
 
1728
        return lvl;
 
1729
}
 
1730
 
 
1731
 
 
1732
/*
 
1733
 *      We got signaled.
 
1734
 *
 
1735
 *      Do actions for the new level. If we are compatible with
 
1736
 *      the "old" INITLVL and arg == 0, try to read the new
 
1737
 *      runlevel from that file first.
 
1738
 */
 
1739
static
 
1740
int read_level(int arg)
 
1741
{
 
1742
        CHILD           *ch;                    /* Walk through list */
 
1743
        unsigned char   foo = 'X';              /* Contents of INITLVL */
 
1744
        int             ok = 1;
 
1745
#ifdef INITLVL
 
1746
        FILE            *fp;
 
1747
        struct stat     stt;
 
1748
        int             st;
 
1749
#endif
 
1750
 
 
1751
        if (arg) foo = arg;
 
1752
 
 
1753
#ifdef INITLVL
 
1754
        ok = 0;
 
1755
 
 
1756
        if (arg == 0) {
 
1757
                fp = NULL;
 
1758
                if (stat(INITLVL, &stt) != 0 || stt.st_size != 0L)
 
1759
                        fp = fopen(INITLVL, "r");
 
1760
#ifdef INITLVL2
 
1761
                if (fp == NULL &&
 
1762
                    (stat(INITLVL2, &stt) != 0 || stt.st_size != 0L))
 
1763
                        fp = fopen(INITLVL2, "r");
 
1764
#endif
 
1765
                if (fp == NULL) {
 
1766
                        /* INITLVL file empty or not there - act as 'init q' */
 
1767
                        initlog(L_SY, "Re-reading inittab");
 
1768
                        return(runlevel);
 
1769
                }
 
1770
                ok = fscanf(fp, "%c %d", &foo, &st);
 
1771
                fclose(fp);
 
1772
        } else {
 
1773
                /* We go to the new runlevel passed as an argument. */
 
1774
                foo = arg;
 
1775
                ok = 1;
 
1776
        }
 
1777
        if (ok == 2) sltime = st;
 
1778
 
 
1779
#endif /* INITLVL */
 
1780
 
 
1781
        if (islower(foo)) foo = toupper(foo);
 
1782
        if (ok < 1 || ok > 2 || strchr("QS0123456789ABCU", foo) == NULL) {
 
1783
                initlog(L_VB, "bad runlevel: %c", foo);
 
1784
                return runlevel;
 
1785
        }
 
1786
 
 
1787
        /* Log this action */
 
1788
        switch(foo) {
 
1789
                case 'S':
 
1790
                        initlog(L_VB, "Going single user");
 
1791
                        break;
 
1792
                case 'Q':
 
1793
                        initlog(L_SY, "Re-reading inittab");
 
1794
                        break;
 
1795
                case 'A':
 
1796
                case 'B':
 
1797
                case 'C':
 
1798
                        initlog(L_SY,
 
1799
                                "Activating demand-procedures for '%c'", foo);
 
1800
                        break;
 
1801
                case 'U':
 
1802
                        initlog(L_SY, "Trying to re-exec init");
 
1803
                        return 'U';
 
1804
                default:
 
1805
                        initlog(L_VB, "Switching to runlevel: %c", foo);
 
1806
        }
 
1807
 
 
1808
        if (foo == 'Q') {
 
1809
#if defined(SIGINT_ONLYONCE) && (SIGINT_ONLYONCE == 1)
 
1810
                /* Re-enable signal from keyboard */
 
1811
                struct sigaction sa;
 
1812
                SETSIG(sa, SIGINT, signal_handler, 0);
 
1813
#endif
 
1814
                return runlevel;
 
1815
        }
 
1816
 
 
1817
        /* Check if this is a runlevel a, b or c */
 
1818
        if (strchr("ABC", foo)) {
 
1819
                if (runlevel == 'S') return(runlevel);
 
1820
 
 
1821
                /* Read inittab again first! */
 
1822
                read_inittab();
 
1823
 
 
1824
                /* Mark those special tasks */
 
1825
                for(ch = family; ch; ch = ch->next)
 
1826
                        if (strchr(ch->rlevel, foo) != NULL ||
 
1827
                            strchr(ch->rlevel, tolower(foo)) != NULL) {
 
1828
                                ch->flags |= DEMAND;
 
1829
                                ch->flags &= ~XECUTED;
 
1830
                                INITDBG(L_VB,
 
1831
                                        "Marking (%s) as ondemand, flags %d",
 
1832
                                        ch->id, ch->flags);
 
1833
                        }
 
1834
                return runlevel;
 
1835
        }
 
1836
 
 
1837
        /* Store both the old and the new runlevel. */
 
1838
        wrote_utmp_rlevel = 0;
 
1839
        wrote_wtmp_rlevel = 0;
 
1840
        write_utmp_wtmp("runlevel", "~~", foo + 256*runlevel, RUN_LVL, "~");
 
1841
        thislevel = foo;
 
1842
        prevlevel = runlevel;
 
1843
        return foo;
 
1844
}
 
1845
 
 
1846
 
 
1847
/*
 
1848
 *      This procedure is called after every signal (SIGHUP, SIGALRM..)
 
1849
 *
 
1850
 *      Only clear the 'failing' flag if the process is sleeping
 
1851
 *      longer than 5 minutes, or inittab was read again due
 
1852
 *      to user interaction.
 
1853
 */
 
1854
static
 
1855
void fail_check(void)
 
1856
{
 
1857
        CHILD   *ch;                    /* Pointer to child structure */
 
1858
        time_t  t;                      /* System time */
 
1859
        time_t  next_alarm = 0;         /* When to set next alarm */
 
1860
 
 
1861
        time(&t);
 
1862
 
 
1863
        for(ch = family; ch; ch = ch->next) {
 
1864
 
 
1865
                if (ch->flags & FAILING) {
 
1866
                        /* Can we free this sucker? */
 
1867
                        if (ch->tm + SLEEPTIME < t) {
 
1868
                                ch->flags &= ~FAILING;
 
1869
                                ch->count = 0;
 
1870
                                ch->tm = 0;
 
1871
                        } else {
 
1872
                                /* No, we'll look again later */
 
1873
                                if (next_alarm == 0 ||
 
1874
                                    ch->tm + SLEEPTIME > next_alarm)
 
1875
                                        next_alarm = ch->tm + SLEEPTIME;
 
1876
                        }
 
1877
                }
 
1878
        }
 
1879
        if (next_alarm) {
 
1880
                next_alarm -= t;
 
1881
                if (next_alarm < 1) next_alarm = 1;
 
1882
                alarm(next_alarm);
 
1883
        }
 
1884
}
 
1885
 
 
1886
/* Set all 'Fail' timers to 0 */
 
1887
static
 
1888
void fail_cancel(void)
 
1889
{
 
1890
        CHILD *ch;
 
1891
 
 
1892
        for(ch = family; ch; ch = ch->next) {
 
1893
                ch->count = 0;
 
1894
                ch->tm = 0;
 
1895
                ch->flags &= ~FAILING;
 
1896
        }
 
1897
}
 
1898
 
 
1899
/*
 
1900
 *      Start up powerfail entries.
 
1901
 */
 
1902
static
 
1903
void do_power_fail(int pwrstat)
 
1904
{
 
1905
        CHILD *ch;
 
1906
 
 
1907
        /*
 
1908
         *      Tell powerwait & powerfail entries to start up
 
1909
         */
 
1910
        for (ch = family; ch; ch = ch->next) {
 
1911
                if (pwrstat == 'O') {
 
1912
                        /*
 
1913
                         *      The power is OK again.
 
1914
                         */
 
1915
                        if (ch->action == POWEROKWAIT)
 
1916
                                ch->flags &= ~XECUTED;
 
1917
                } else if (pwrstat == 'L') {
 
1918
                        /*
 
1919
                         *      Low battery, shut down now.
 
1920
                         */
 
1921
                        if (ch->action == POWERFAILNOW)
 
1922
                                ch->flags &= ~XECUTED;
 
1923
                } else {
 
1924
                        /*
 
1925
                         *      Power is failing, shutdown imminent
 
1926
                         */
 
1927
                        if (ch->action == POWERFAIL || ch->action == POWERWAIT)
 
1928
                                ch->flags &= ~XECUTED;
 
1929
                }
 
1930
        }
 
1931
}
 
1932
 
 
1933
/*
 
1934
 *      Check for state-pipe presence
 
1935
 */
 
1936
static
 
1937
int check_pipe(int fd)
 
1938
{
 
1939
        struct timeval  t;
 
1940
        fd_set          s;
 
1941
        char            signature[8];
 
1942
 
 
1943
        FD_ZERO(&s);
 
1944
        FD_SET(fd, &s);
 
1945
        t.tv_sec = t.tv_usec = 0;
 
1946
 
 
1947
        if (select(fd+1, &s, NULL, NULL, &t) != 1)
 
1948
                return 0;
 
1949
        if (read(fd, signature, 8) != 8)
 
1950
                 return 0;
 
1951
        return strncmp(Signature, signature, 8) == 0;
 
1952
}
 
1953
 
 
1954
/*
 
1955
 *       Make a state-pipe.
 
1956
 */
 
1957
static
 
1958
int make_pipe(int fd)
 
1959
{
 
1960
        int fds[2];
 
1961
 
 
1962
        pipe(fds);
 
1963
        dup2(fds[0], fd);
 
1964
        close(fds[0]);
 
1965
        fcntl(fds[1], F_SETFD, 1);
 
1966
        fcntl(fd, F_SETFD, 0);
 
1967
        write(fds[1], Signature, 8);
 
1968
 
 
1969
        return fds[1];
 
1970
}
 
1971
 
 
1972
/*
 
1973
 *      Attempt to re-exec.
 
1974
 */
 
1975
static
 
1976
void re_exec(void)
 
1977
{
 
1978
        CHILD           *ch;
 
1979
        sigset_t        mask, oldset;
 
1980
        pid_t           pid;
 
1981
        char            **env;
 
1982
        int             fd;
 
1983
 
 
1984
        if (strchr("S0123456",runlevel) == NULL)
 
1985
                return;
 
1986
 
 
1987
        /*
 
1988
         *      Reset the alarm, and block all signals.
 
1989
         */
 
1990
        alarm(0);
 
1991
        sigfillset(&mask);
 
1992
        sigprocmask(SIG_BLOCK, &mask, &oldset);
 
1993
 
 
1994
        /*
 
1995
         *      construct a pipe fd --> STATE_PIPE and write a signature
 
1996
         */
 
1997
        fd = make_pipe(STATE_PIPE);
 
1998
 
 
1999
        /* 
 
2000
         * It's a backup day today, so I'm pissed off.  Being a BOFH, however, 
 
2001
         * does have it's advantages...
 
2002
         */
 
2003
        fail_cancel();
 
2004
        close(pipe_fd);
 
2005
        pipe_fd = -1;
 
2006
        DELSET(got_signals, SIGCHLD);
 
2007
        DELSET(got_signals, SIGHUP);
 
2008
        DELSET(got_signals, SIGUSR1);
 
2009
 
 
2010
        /*
 
2011
         *      That should be cleaned.
 
2012
         */
 
2013
        for(ch = family; ch; ch = ch->next)
 
2014
            if (ch->flags & ZOMBIE) {
 
2015
                INITDBG(L_VB, "Child died, PID= %d", ch->pid);
 
2016
                ch->flags &= ~(RUNNING|ZOMBIE|WAITING);
 
2017
                if (ch->process[0] != '+')
 
2018
                        write_utmp_wtmp("", ch->id, ch->pid, DEAD_PROCESS, NULL);
 
2019
            }
 
2020
 
 
2021
        if ((pid = fork()) == 0) {
 
2022
                /*
 
2023
                 *      Child sends state information to the parent.
 
2024
                 */
 
2025
                send_state(fd);
 
2026
                exit(0);
 
2027
        }
 
2028
 
 
2029
        /*
 
2030
         *      The existing init process execs a new init binary.
 
2031
         */
 
2032
        env = init_buildenv(0);
 
2033
        execle(myname, myname, "--init", NULL, env);
 
2034
 
 
2035
        /*
 
2036
         *      We shouldn't be here, something failed. 
 
2037
         *      Bitch, close the state pipe, unblock signals and return.
 
2038
         */
 
2039
        close(fd);
 
2040
        close(STATE_PIPE);
 
2041
        sigprocmask(SIG_SETMASK, &oldset, NULL);
 
2042
        init_freeenv(env);
 
2043
        initlog(L_CO, "Attempt to re-exec failed");
 
2044
}
 
2045
 
 
2046
/*
 
2047
 *      Redo utmp/wtmp entries if required or requested
 
2048
 *      Check for written records and size of utmp
 
2049
 */
 
2050
static
 
2051
void redo_utmp_wtmp(void)
 
2052
{
 
2053
        struct stat ustat;
 
2054
        const int ret = stat(UTMP_FILE, &ustat);
 
2055
 
 
2056
        if ((ret < 0) || (ustat.st_size == 0))
 
2057
                wrote_utmp_rlevel = wrote_utmp_reboot = 0;
 
2058
 
 
2059
        if ((wrote_wtmp_reboot == 0) || (wrote_utmp_reboot == 0))
 
2060
                write_utmp_wtmp("reboot", "~~", 0, BOOT_TIME, "~");
 
2061
 
 
2062
        if ((wrote_wtmp_rlevel == 0) || (wrote_wtmp_rlevel == 0))
 
2063
                write_utmp_wtmp("runlevel", "~~", thislevel + 256 * prevlevel, RUN_LVL, "~");
 
2064
}
 
2065
 
 
2066
/*
 
2067
 *      We got a change runlevel request through the
 
2068
 *      init.fifo. Process it.
 
2069
 */
 
2070
static
 
2071
void fifo_new_level(int level)
 
2072
{
 
2073
#if CHANGE_WAIT
 
2074
        CHILD   *ch;
 
2075
#endif
 
2076
        int     oldlevel;
 
2077
 
 
2078
        if (level == runlevel) return;
 
2079
 
 
2080
#if CHANGE_WAIT
 
2081
        /* Are we waiting for a child? */
 
2082
        for(ch = family; ch; ch = ch->next)
 
2083
                if (ch->flags & WAITING) break;
 
2084
        if (ch == NULL)
 
2085
#endif
 
2086
        {
 
2087
                /* We need to go into a new runlevel */
 
2088
                oldlevel = runlevel;
 
2089
                runlevel = read_level(level);
 
2090
                if (runlevel == 'U') {
 
2091
                        runlevel = oldlevel;
 
2092
                        re_exec();
 
2093
                } else {
 
2094
                        if (oldlevel != 'S' && runlevel == 'S') console_stty();
 
2095
                        if (runlevel == '6' || runlevel == '0' ||
 
2096
                            runlevel == '1') console_stty();
 
2097
                        if (runlevel  > '1' && runlevel  < '6') redo_utmp_wtmp();
 
2098
                        read_inittab();
 
2099
                        fail_cancel();
 
2100
                        setproctitle("init [%c]", (int)runlevel);
 
2101
                }
 
2102
        }
 
2103
}
 
2104
 
 
2105
 
 
2106
/*
 
2107
 *      Set/unset environment variables. The variables are
 
2108
 *      encoded as KEY=VAL\0KEY=VAL\0\0. With "=VAL" it means
 
2109
 *      setenv, without it means unsetenv.
 
2110
 */
 
2111
static
 
2112
void initcmd_setenv(char *data, int size)
 
2113
{
 
2114
        char            *env, *p, *e, *eq;
 
2115
        int             i, sz;
 
2116
 
 
2117
        e = data + size;
 
2118
 
 
2119
        while (*data && data < e) {
 
2120
                eq = NULL;
 
2121
                for (p = data; *p && p < e; p++)
 
2122
                        if (*p == '=') eq = p;
 
2123
                if (*p) break;
 
2124
                env = data;
 
2125
                data = ++p;
 
2126
 
 
2127
                sz = eq ? (eq - env) : (p - env);
 
2128
 
 
2129
                /*initlog(L_SY, "init_setenv: %s, %s, %d", env, eq, sz);*/
 
2130
 
 
2131
                /*
 
2132
                 *      We only allow INIT_* to be set.
 
2133
                 */
 
2134
                if (strncmp(env, "INIT_", 5) != 0)
 
2135
                        continue;
 
2136
 
 
2137
                /* Free existing vars. */
 
2138
                for (i = 0; i < NR_EXTRA_ENV; i++) {
 
2139
                        if (extra_env[i] == NULL) continue;
 
2140
                        if (!strncmp(extra_env[i], env, sz) &&
 
2141
                            extra_env[i][sz] == '=') {
 
2142
                                free(extra_env[i]);
 
2143
                                extra_env[i] = NULL;
 
2144
                        }
 
2145
                }
 
2146
 
 
2147
                /* Set new vars if needed. */
 
2148
                if (eq == NULL) continue;
 
2149
                for (i = 0; i < NR_EXTRA_ENV; i++) {
 
2150
                        if (extra_env[i] == NULL) {
 
2151
                                extra_env[i] = istrdup(env);
 
2152
                                break;
 
2153
                        }
 
2154
                }
 
2155
        }
 
2156
}
 
2157
 
 
2158
 
 
2159
/*
 
2160
 *      Read from the init FIFO. Processes like telnetd and rlogind can
 
2161
 *      ask us to create login processes on their behalf.
 
2162
 *
 
2163
 *      FIXME:  this needs to be finished. NOT that it is buggy, but we need
 
2164
 *              to add the telnetd/rlogind stuff so people can start using it.
 
2165
 *              Maybe move to using an AF_UNIX socket so we can use
 
2166
 *              the 2.2 kernel credential stuff to see who we're talking to.
 
2167
 *      
 
2168
 */
 
2169
static
 
2170
void check_init_fifo(void)
 
2171
{
 
2172
  struct init_request   request;
 
2173
  struct timeval        tv;
 
2174
  struct stat           st, st2;
 
2175
  fd_set                fds;
 
2176
  int                   n;
 
2177
  int                   quit = 0;
 
2178
 
 
2179
  /*
 
2180
   *    First, try to create /dev/initctl if not present.
 
2181
   */
 
2182
  if (stat(INIT_FIFO, &st2) < 0 && errno == ENOENT)
 
2183
        (void)mkfifo(INIT_FIFO, 0600);
 
2184
 
 
2185
  /*
 
2186
   *    If /dev/initctl is open, stat the file to see if it
 
2187
   *    is still the _same_ inode.
 
2188
   */
 
2189
  if (pipe_fd >= 0) {
 
2190
        fstat(pipe_fd, &st);
 
2191
        if (stat(INIT_FIFO, &st2) < 0 ||
 
2192
            st.st_dev != st2.st_dev ||
 
2193
            st.st_ino != st2.st_ino) {
 
2194
                close(pipe_fd);
 
2195
                pipe_fd = -1;
 
2196
        }
 
2197
  }
 
2198
 
 
2199
  /*
 
2200
   *    Now finally try to open /dev/initctl
 
2201
   */
 
2202
  if (pipe_fd < 0) {
 
2203
        if ((pipe_fd = open(INIT_FIFO, O_RDWR|O_NONBLOCK)) >= 0) {
 
2204
                fstat(pipe_fd, &st);
 
2205
                if (!S_ISFIFO(st.st_mode)) {
 
2206
                        initlog(L_VB, "%s is not a fifo", INIT_FIFO);
 
2207
                        close(pipe_fd);
 
2208
                        pipe_fd = -1;
 
2209
                }
 
2210
        }
 
2211
        if (pipe_fd >= 0) {
 
2212
                /*
 
2213
                 *      Don't use fd's 0, 1 or 2.
 
2214
                 */
 
2215
                (void) dup2(pipe_fd, PIPE_FD);
 
2216
                close(pipe_fd);
 
2217
                pipe_fd = PIPE_FD;
 
2218
 
 
2219
                /*
 
2220
                 *      Return to caller - we'll be back later.
 
2221
                 */
 
2222
        }
 
2223
  }
 
2224
 
 
2225
  /* Wait for data to appear, _if_ the pipe was opened. */
 
2226
  if (pipe_fd >= 0) while(!quit) {
 
2227
 
 
2228
        /* Do select, return on EINTR. */
 
2229
        FD_ZERO(&fds);
 
2230
        FD_SET(pipe_fd, &fds);
 
2231
        tv.tv_sec = 5;
 
2232
        tv.tv_usec = 0;
 
2233
        n = select(pipe_fd + 1, &fds, NULL, NULL, &tv);
 
2234
        if (n <= 0) {
 
2235
                if (n == 0 || errno == EINTR) return;
 
2236
                continue;
 
2237
        }
 
2238
 
 
2239
        /* Read the data, return on EINTR. */
 
2240
        n = read(pipe_fd, &request, sizeof(request));
 
2241
        if (n == 0) {
 
2242
                /*
 
2243
                 *      End of file. This can't happen under Linux (because
 
2244
                 *      the pipe is opened O_RDWR - see select() in the
 
2245
                 *      kernel) but you never know...
 
2246
                 */
 
2247
                close(pipe_fd);
 
2248
                pipe_fd = -1;
 
2249
                return;
 
2250
        }
 
2251
        if (n <= 0) {
 
2252
                if (errno == EINTR) return;
 
2253
                initlog(L_VB, "error reading initrequest");
 
2254
                continue;
 
2255
        }
 
2256
 
 
2257
        /*
 
2258
         *      This is a convenient point to also try to
 
2259
         *      find the console device or check if it changed.
 
2260
         */
 
2261
        console_init();
 
2262
 
 
2263
        /*
 
2264
         *      Process request.
 
2265
         */
 
2266
        if (request.magic != INIT_MAGIC || n != sizeof(request)) {
 
2267
                initlog(L_VB, "got bogus initrequest");
 
2268
                continue;
 
2269
        }
 
2270
        switch(request.cmd) {
 
2271
                case INIT_CMD_RUNLVL:
 
2272
                        sltime = request.sleeptime;
 
2273
                        fifo_new_level(request.runlevel);
 
2274
                        quit = 1;
 
2275
                        break;
 
2276
                case INIT_CMD_POWERFAIL:
 
2277
                        sltime = request.sleeptime;
 
2278
                        do_power_fail('F');
 
2279
                        quit = 1;
 
2280
                        break;
 
2281
                case INIT_CMD_POWERFAILNOW:
 
2282
                        sltime = request.sleeptime;
 
2283
                        do_power_fail('L');
 
2284
                        quit = 1;
 
2285
                        break;
 
2286
                case INIT_CMD_POWEROK:
 
2287
                        sltime = request.sleeptime;
 
2288
                        do_power_fail('O');
 
2289
                        quit = 1;
 
2290
                        break;
 
2291
                case INIT_CMD_SETENV:
 
2292
                        initcmd_setenv(request.i.data, sizeof(request.i.data));
 
2293
                        break;
 
2294
                default:
 
2295
                        initlog(L_VB, "got unimplemented initrequest.");
 
2296
                        break;
 
2297
        }
 
2298
  }
 
2299
 
 
2300
  /*
 
2301
   *    We come here if the pipe couldn't be opened.
 
2302
   */
 
2303
  if (pipe_fd < 0) pause();
 
2304
 
 
2305
}
 
2306
 
 
2307
 
 
2308
/*
 
2309
 *      This function is used in the transition
 
2310
 *      sysinit (-> single user) boot -> multi-user.
 
2311
 */
 
2312
static
 
2313
void boot_transitions()
 
2314
{
 
2315
  CHILD         *ch;
 
2316
  static int    newlevel = 0;
 
2317
  static int    warn = 1;
 
2318
  int           loglevel;
 
2319
  int           oldlevel;
 
2320
 
 
2321
  /* Check if there is something to wait for! */
 
2322
  for( ch = family; ch; ch = ch->next )
 
2323
        if ((ch->flags & RUNNING) && ch->action != BOOT) break;
 
2324
     
 
2325
  if (ch == NULL) {
 
2326
        /* No processes left in this level, proceed to next level. */
 
2327
        loglevel = -1;
 
2328
        oldlevel = 'N';
 
2329
        switch(runlevel) {
 
2330
                case '#': /* SYSINIT -> BOOT */
 
2331
                        INITDBG(L_VB, "SYSINIT -> BOOT");
 
2332
 
 
2333
                        /* Write a boot record. */
 
2334
                        wrote_utmp_reboot = 0;
 
2335
                        wrote_wtmp_reboot = 0;
 
2336
                        write_utmp_wtmp("reboot", "~~", 0, BOOT_TIME, "~");
 
2337
 
 
2338
                        /* Get our run level */
 
2339
                        newlevel = dfl_level ? dfl_level : get_init_default();
 
2340
                        if (newlevel == 'S') {
 
2341
                                runlevel = newlevel;
 
2342
                                /* Not really 'S' but show anyway. */
 
2343
                                setproctitle("init [S]");
 
2344
                        } else
 
2345
                                runlevel = '*';
 
2346
                        break;
 
2347
                case '*': /* BOOT -> NORMAL */
 
2348
                        INITDBG(L_VB, "BOOT -> NORMAL");
 
2349
                        if (runlevel != newlevel)
 
2350
                                loglevel = newlevel;
 
2351
                        runlevel = newlevel;
 
2352
                        did_boot = 1;
 
2353
                        warn = 1;
 
2354
                        break;
 
2355
                case 'S': /* Ended SU mode */
 
2356
                case 's':
 
2357
                        INITDBG(L_VB, "END SU MODE");
 
2358
                        newlevel = get_init_default();
 
2359
                        if (!did_boot && newlevel != 'S')
 
2360
                                runlevel = '*';
 
2361
                        else {
 
2362
                                if (runlevel != newlevel)
 
2363
                                        loglevel = newlevel;
 
2364
                                runlevel = newlevel;
 
2365
                                oldlevel = 'S';
 
2366
                        }
 
2367
                        warn = 1;
 
2368
                        for(ch = family; ch; ch = ch->next)
 
2369
                            if (strcmp(ch->rlevel, "S") == 0)
 
2370
                                ch->flags &= ~(FAILING|WAITING|XECUTED);
 
2371
                        break;
 
2372
                default:
 
2373
                        if (warn)
 
2374
                          initlog(L_VB,
 
2375
                                "no more processes left in this runlevel");
 
2376
                        warn = 0;
 
2377
                        loglevel = -1;
 
2378
                        if (got_signals == 0)
 
2379
                                check_init_fifo();
 
2380
                        break;
 
2381
        }
 
2382
        if (loglevel > 0) {
 
2383
                initlog(L_VB, "Entering runlevel: %c", runlevel);
 
2384
                wrote_utmp_rlevel = 0;
 
2385
                wrote_wtmp_rlevel = 0;
 
2386
                write_utmp_wtmp("runlevel", "~~", runlevel + 256 * oldlevel, RUN_LVL, "~");
 
2387
                thislevel = runlevel;
 
2388
                prevlevel = oldlevel;
 
2389
                setproctitle("init [%c]", (int)runlevel);
 
2390
        }
 
2391
  }
 
2392
}
 
2393
 
 
2394
/*
 
2395
 *      Init got hit by a signal. See which signal it is,
 
2396
 *      and act accordingly.
 
2397
 */
 
2398
static
 
2399
void process_signals()
 
2400
{
 
2401
  CHILD         *ch;
 
2402
  int           pwrstat;
 
2403
  int           oldlevel;
 
2404
  int           fd;
 
2405
  char          c;
 
2406
 
 
2407
  if (ISMEMBER(got_signals, SIGPWR)) {
 
2408
        INITDBG(L_VB, "got SIGPWR");
 
2409
        /* See _what_ kind of SIGPWR this is. */
 
2410
        pwrstat = 0;
 
2411
        if ((fd = open(PWRSTAT, O_RDONLY)) >= 0) {
 
2412
                c = 0;
 
2413
                read(fd, &c, 1);
 
2414
                pwrstat = c;
 
2415
                close(fd);
 
2416
                unlink(PWRSTAT);
 
2417
        } else if ((fd = open(PWRSTAT_OLD, O_RDONLY)) >= 0) {
 
2418
                /* Path changed 2010-03-20.  Look for the old path for a while. */
 
2419
                initlog(L_VB, "warning: found obsolete path %s, use %s instead",
 
2420
                        PWRSTAT_OLD, PWRSTAT);
 
2421
                c = 0;
 
2422
                read(fd, &c, 1);
 
2423
                pwrstat = c;
 
2424
                close(fd);
 
2425
                unlink(PWRSTAT_OLD);
 
2426
        }
 
2427
        do_power_fail(pwrstat);
 
2428
        DELSET(got_signals, SIGPWR);
 
2429
  }
 
2430
 
 
2431
  if (ISMEMBER(got_signals, SIGINT)) {
 
2432
#if defined(SIGINT_ONLYONCE) && (SIGINT_ONLYONCE == 1)
 
2433
        /* Ignore any further signal from keyboard */
 
2434
        struct sigaction sa;
 
2435
        SETSIG(sa, SIGINT, SIG_IGN, SA_RESTART);
 
2436
#endif
 
2437
        INITDBG(L_VB, "got SIGINT");
 
2438
        /* Tell ctrlaltdel entry to start up */
 
2439
        for(ch = family; ch; ch = ch->next)
 
2440
                if (ch->action == CTRLALTDEL)
 
2441
                        ch->flags &= ~XECUTED;
 
2442
        DELSET(got_signals, SIGINT);
 
2443
  }
 
2444
 
 
2445
  if (ISMEMBER(got_signals, SIGWINCH)) {
 
2446
        INITDBG(L_VB, "got SIGWINCH");
 
2447
        /* Tell kbrequest entry to start up */
 
2448
        for(ch = family; ch; ch = ch->next)
 
2449
                if (ch->action == KBREQUEST)
 
2450
                        ch->flags &= ~XECUTED;
 
2451
        DELSET(got_signals, SIGWINCH);
 
2452
  }
 
2453
 
 
2454
  if (ISMEMBER(got_signals, SIGALRM)) {
 
2455
        INITDBG(L_VB, "got SIGALRM");
 
2456
        /* The timer went off: check it out */
 
2457
        DELSET(got_signals, SIGALRM);
 
2458
  }
 
2459
 
 
2460
  if (ISMEMBER(got_signals, SIGCHLD)) {
 
2461
        INITDBG(L_VB, "got SIGCHLD");
 
2462
        /* First set flag to 0 */
 
2463
        DELSET(got_signals, SIGCHLD);
 
2464
 
 
2465
        /* See which child this was */
 
2466
        for(ch = family; ch; ch = ch->next)
 
2467
            if (ch->flags & ZOMBIE) {
 
2468
                INITDBG(L_VB, "Child died, PID= %d", ch->pid);
 
2469
                ch->flags &= ~(RUNNING|ZOMBIE|WAITING);
 
2470
                if (ch->process[0] != '+')
 
2471
                        write_utmp_wtmp("", ch->id, ch->pid, DEAD_PROCESS, NULL);
 
2472
            }
 
2473
 
 
2474
  }
 
2475
 
 
2476
  if (ISMEMBER(got_signals, SIGHUP)) {
 
2477
        INITDBG(L_VB, "got SIGHUP");
 
2478
#if CHANGE_WAIT
 
2479
        /* Are we waiting for a child? */
 
2480
        for(ch = family; ch; ch = ch->next)
 
2481
                if (ch->flags & WAITING) break;
 
2482
        if (ch == NULL)
 
2483
#endif
 
2484
        {
 
2485
                /* We need to go into a new runlevel */
 
2486
                oldlevel = runlevel;
 
2487
#ifdef INITLVL
 
2488
                runlevel = read_level(0);
 
2489
#endif
 
2490
                if (runlevel == 'U') {
 
2491
                        runlevel = oldlevel;
 
2492
                        re_exec();
 
2493
                } else {
 
2494
                        if (oldlevel != 'S' && runlevel == 'S') console_stty();
 
2495
                        if (runlevel == '6' || runlevel == '0' ||
 
2496
                            runlevel == '1') console_stty();
 
2497
                        read_inittab();
 
2498
                        fail_cancel();
 
2499
                        setproctitle("init [%c]", (int)runlevel);
 
2500
                        DELSET(got_signals, SIGHUP);
 
2501
                }
 
2502
        }
 
2503
  }
 
2504
  if (ISMEMBER(got_signals, SIGUSR1)) {
 
2505
        /*
 
2506
         *      SIGUSR1 means close and reopen /dev/initctl
 
2507
         */
 
2508
        INITDBG(L_VB, "got SIGUSR1");
 
2509
        close(pipe_fd);
 
2510
        pipe_fd = -1;
 
2511
        DELSET(got_signals, SIGUSR1);
 
2512
  }
 
2513
}
 
2514
 
 
2515
/*
 
2516
 *      The main loop
 
2517
 */ 
 
2518
static
 
2519
void init_main(void)
 
2520
{
 
2521
  CHILD                 *ch;
 
2522
  struct sigaction      sa;
 
2523
  sigset_t              sgt;
 
2524
  int                   f, st;
 
2525
 
 
2526
  if (!reload) {
 
2527
  
 
2528
#if INITDEBUG
 
2529
        /*
 
2530
         * Fork so we can debug the init process.
 
2531
         */
 
2532
        if ((f = fork()) > 0) {
 
2533
                static const char killmsg[] = "PRNT: init killed.\r\n";
 
2534
                pid_t rc;
 
2535
 
 
2536
                while((rc = wait(&st)) != f)
 
2537
                        if (rc < 0 && errno == ECHILD)
 
2538
                                break;
 
2539
                write(1, killmsg, sizeof(killmsg) - 1);
 
2540
                while(1) pause();
 
2541
        }
 
2542
#endif
 
2543
 
 
2544
#ifdef __linux__
 
2545
        /*
 
2546
         *      Tell the kernel to send us SIGINT when CTRL-ALT-DEL
 
2547
         *      is pressed, and that we want to handle keyboard signals.
 
2548
         */
 
2549
        init_reboot(BMAGIC_SOFT);
 
2550
        if ((f = open(VT_MASTER, O_RDWR | O_NOCTTY)) >= 0) {
 
2551
                (void) ioctl(f, KDSIGACCEPT, SIGWINCH);
 
2552
                close(f);
 
2553
        } else
 
2554
                (void) ioctl(0, KDSIGACCEPT, SIGWINCH);
 
2555
#endif
 
2556
 
 
2557
        /*
 
2558
         *      Ignore all signals.
 
2559
         */
 
2560
        for(f = 1; f <= NSIG; f++)
 
2561
                SETSIG(sa, f, SIG_IGN, SA_RESTART);
 
2562
  }
 
2563
 
 
2564
  SETSIG(sa, SIGALRM,  signal_handler, 0);
 
2565
  SETSIG(sa, SIGHUP,   signal_handler, 0);
 
2566
  SETSIG(sa, SIGINT,   signal_handler, 0);
 
2567
  SETSIG(sa, SIGCHLD,  chld_handler, SA_RESTART);
 
2568
  SETSIG(sa, SIGPWR,   signal_handler, 0);
 
2569
  SETSIG(sa, SIGWINCH, signal_handler, 0);
 
2570
  SETSIG(sa, SIGUSR1,  signal_handler, 0);
 
2571
  SETSIG(sa, SIGSTOP,  stop_handler, SA_RESTART);
 
2572
  SETSIG(sa, SIGTSTP,  stop_handler, SA_RESTART);
 
2573
  SETSIG(sa, SIGCONT,  cont_handler, SA_RESTART);
 
2574
  SETSIG(sa, SIGSEGV,  (void (*)(int))segv_handler, SA_RESTART);
 
2575
 
 
2576
  console_init();
 
2577
 
 
2578
  if (!reload) {
 
2579
        int fd;
 
2580
 
 
2581
        /* Close whatever files are open, and reset the console. */
 
2582
        close(0);
 
2583
        close(1);
 
2584
        close(2);
 
2585
        console_stty();
 
2586
        setsid();
 
2587
 
 
2588
        /*
 
2589
         *      Set default PATH variable.
 
2590
         */
 
2591
        setenv("PATH", PATH_DEFAULT, 1 /* Overwrite */);
 
2592
 
 
2593
        /*
 
2594
         *      Initialize /var/run/utmp (only works if /var is on
 
2595
         *      root and mounted rw)
 
2596
         */
 
2597
        if ((fd = open(UTMP_FILE, O_WRONLY|O_CREAT|O_TRUNC, 0644)) >= 0)
 
2598
                close(fd);
 
2599
 
 
2600
        /*
 
2601
         *      Say hello to the world
 
2602
         */
 
2603
        initlog(L_CO, bootmsg, "booting");
 
2604
 
 
2605
        /*
 
2606
         *      See if we have to start an emergency shell.
 
2607
         */
 
2608
        if (emerg_shell) {
 
2609
                pid_t rc;
 
2610
                SETSIG(sa, SIGCHLD, SIG_DFL, SA_RESTART);
 
2611
                if (spawn(&ch_emerg, &f) > 0) {
 
2612
                        while((rc = wait(&st)) != f)
 
2613
                                if (rc < 0 && errno == ECHILD)
 
2614
                                        break;
 
2615
                }
 
2616
                SETSIG(sa, SIGCHLD,  chld_handler, SA_RESTART);
 
2617
        }
 
2618
 
 
2619
        /*
 
2620
         *      Start normal boot procedure.
 
2621
         */
 
2622
        runlevel = '#';
 
2623
        read_inittab();
 
2624
  
 
2625
  } else {
 
2626
        /*
 
2627
         *      Restart: unblock signals and let the show go on
 
2628
         */
 
2629
        initlog(L_CO, bootmsg, "reloading");
 
2630
        sigfillset(&sgt);
 
2631
        sigprocmask(SIG_UNBLOCK, &sgt, NULL);
 
2632
 
 
2633
        /*
 
2634
         *      Set default PATH variable.
 
2635
         */
 
2636
        setenv("PATH", PATH_DEFAULT, 0 /* Don't overwrite */);
 
2637
  }
 
2638
  start_if_needed();
 
2639
 
 
2640
  while(1) {
 
2641
 
 
2642
     /* See if we need to make the boot transitions. */
 
2643
     boot_transitions();
 
2644
     INITDBG(L_VB, "init_main: waiting..");
 
2645
 
 
2646
     /* Check if there are processes to be waited on. */
 
2647
     for(ch = family; ch; ch = ch->next)
 
2648
        if ((ch->flags & RUNNING) && ch->action != BOOT) break;
 
2649
 
 
2650
#if CHANGE_WAIT
 
2651
     /* Wait until we get hit by some signal. */
 
2652
     while (ch != NULL && got_signals == 0) {
 
2653
        if (ISMEMBER(got_signals, SIGHUP)) {
 
2654
                /* See if there are processes to be waited on. */
 
2655
                for(ch = family; ch; ch = ch->next)
 
2656
                        if (ch->flags & WAITING) break;
 
2657
        }
 
2658
        if (ch != NULL) check_init_fifo();
 
2659
     }
 
2660
#else /* CHANGE_WAIT */
 
2661
     if (ch != NULL && got_signals == 0) check_init_fifo();
 
2662
#endif /* CHANGE_WAIT */
 
2663
 
 
2664
     /* Check the 'failing' flags */
 
2665
     fail_check();
 
2666
 
 
2667
     /* Process any signals. */
 
2668
     process_signals();
 
2669
 
 
2670
     /* See what we need to start up (again) */
 
2671
     start_if_needed();
 
2672
  }
 
2673
  /*NOTREACHED*/
 
2674
}
 
2675
 
 
2676
/*
 
2677
 * Tell the user about the syntax we expect.
 
2678
 */
 
2679
static
 
2680
void usage(char *s)
 
2681
{
 
2682
        fprintf(stderr, "Usage: %s {-e VAR[=VAL] | [-t SECONDS] {0|1|2|3|4|5|6|S|s|Q|q|A|a|B|b|C|c|U|u}}\n", s);
 
2683
        exit(1);
 
2684
}
 
2685
 
 
2686
static
 
2687
int telinit(char *progname, int argc, char **argv)
 
2688
{
 
2689
#ifdef TELINIT_USES_INITLVL
 
2690
        FILE                    *fp;
 
2691
#endif
 
2692
        struct init_request     request;
 
2693
        struct sigaction        sa;
 
2694
        int                     f, fd, l;
 
2695
        char                    *env = NULL;
 
2696
 
 
2697
        memset(&request, 0, sizeof(request));
 
2698
        request.magic     = INIT_MAGIC;
 
2699
 
 
2700
        while ((f = getopt(argc, argv, "t:e:")) != EOF) switch(f) {
 
2701
                case 't':
 
2702
                        sltime = atoi(optarg);
 
2703
                        break;
 
2704
                case 'e':
 
2705
                        if (env == NULL)
 
2706
                                env = request.i.data;
 
2707
                        l = strlen(optarg);
 
2708
                        if (env + l + 2 > request.i.data + sizeof(request.i.data)) {
 
2709
                                fprintf(stderr, "%s: -e option data "
 
2710
                                        "too large\n", progname);
 
2711
                                exit(1);
 
2712
                        }
 
2713
                        memcpy(env, optarg, l);
 
2714
                        env += l;
 
2715
                        *env++ = 0;
 
2716
                        break;
 
2717
                default:
 
2718
                        usage(progname);
 
2719
                        break;
 
2720
        }
 
2721
 
 
2722
        if (env) *env++ = 0;
 
2723
 
 
2724
        if (env) {
 
2725
                if (argc != optind)
 
2726
                        usage(progname);
 
2727
                request.cmd = INIT_CMD_SETENV;
 
2728
        } else {
 
2729
                if (argc - optind != 1 || strlen(argv[optind]) != 1)
 
2730
                        usage(progname);
 
2731
                if (!strchr("0123456789SsQqAaBbCcUu", argv[optind][0]))
 
2732
                        usage(progname);
 
2733
                request.cmd = INIT_CMD_RUNLVL;
 
2734
                request.runlevel  = env ? 0 : argv[optind][0];
 
2735
                request.sleeptime = sltime;
 
2736
        }
 
2737
 
 
2738
        /* Change to the root directory. */
 
2739
        chdir("/");
 
2740
 
 
2741
        /* Open the fifo and write a command. */
 
2742
        /* Make sure we don't hang on opening /dev/initctl */
 
2743
        SETSIG(sa, SIGALRM, signal_handler, 0);
 
2744
        alarm(3);
 
2745
        if ((fd = open(INIT_FIFO, O_WRONLY)) >= 0) {
 
2746
                ssize_t p = 0;
 
2747
                size_t s  = sizeof(request);
 
2748
                void *ptr = &request;
 
2749
 
 
2750
                while (s > 0) {
 
2751
                        p = write(fd, ptr, s);
 
2752
                        if (p < 0) {
 
2753
                                if (errno == EINTR || errno == EAGAIN)
 
2754
                                        continue;
 
2755
                                break;
 
2756
                        }
 
2757
                        ptr += p;
 
2758
                        s -= p;
 
2759
                }
 
2760
                close(fd);
 
2761
                alarm(0);
 
2762
                return 0;
 
2763
        }
 
2764
 
 
2765
#ifdef TELINIT_USES_INITLVL
 
2766
        if (request.cmd == INIT_CMD_RUNLVL) {
 
2767
                /* Fallthrough to the old method. */
 
2768
 
 
2769
                /* Now write the new runlevel. */
 
2770
                if ((fp = fopen(INITLVL, "w")) == NULL) {
 
2771
                        fprintf(stderr, "%s: cannot create %s\n",
 
2772
                                progname, INITLVL);
 
2773
                        exit(1);
 
2774
                }
 
2775
                fprintf(fp, "%s %d", argv[optind], sltime);
 
2776
                fclose(fp);
 
2777
 
 
2778
                /* And tell init about the pending runlevel change. */
 
2779
                if (kill(INITPID, SIGHUP) < 0) perror(progname);
 
2780
 
 
2781
                return 0;
 
2782
        }
 
2783
#endif
 
2784
 
 
2785
        fprintf(stderr, "%s: ", progname);
 
2786
        if (ISMEMBER(got_signals, SIGALRM)) {
 
2787
                fprintf(stderr, "timeout opening/writing control channel %s\n",
 
2788
                        INIT_FIFO);
 
2789
        } else {
 
2790
                perror(INIT_FIFO);
 
2791
        }
 
2792
        return 1;
 
2793
}
 
2794
 
 
2795
/*
 
2796
 * Main entry for init and telinit.
 
2797
 */
 
2798
int main(int argc, char **argv)
 
2799
{
 
2800
        char                    *p;
 
2801
        int                     f;
 
2802
        int                     isinit;
 
2803
#ifdef WITH_SELINUX
 
2804
        int                     enforce = 0;
 
2805
#endif
 
2806
 
 
2807
        /* Get my own name */
 
2808
        if ((p = strrchr(argv[0], '/')) != NULL)
 
2809
                p++;
 
2810
        else
 
2811
                p = argv[0];
 
2812
 
 
2813
        /* Common umask */
 
2814
        umask(022);
 
2815
 
 
2816
        /* Quick check */
 
2817
        if (geteuid() != 0) {
 
2818
                fprintf(stderr, "%s: must be superuser.\n", p);
 
2819
                exit(1);
 
2820
        }
 
2821
 
 
2822
        /*
 
2823
         *      Is this telinit or init ?
 
2824
         */
 
2825
        isinit = (getpid() == 1);
 
2826
        for (f = 1; f < argc; f++) {
 
2827
                if (!strcmp(argv[f], "-i") || !strcmp(argv[f], "--init")) {
 
2828
                        isinit = 1;
 
2829
                        break;
 
2830
                }
 
2831
        }
 
2832
        if (!isinit) exit(telinit(p, argc, argv));
 
2833
 
 
2834
        /*
 
2835
         *      Check for re-exec
 
2836
         */     
 
2837
        if (check_pipe(STATE_PIPE)) {
 
2838
 
 
2839
                receive_state(STATE_PIPE);
 
2840
 
 
2841
                myname = istrdup(argv[0]);
 
2842
                argv0 = argv[0];
 
2843
                maxproclen = 0;
 
2844
                for (f = 0; f < argc; f++)
 
2845
                        maxproclen += strlen(argv[f]) + 1;
 
2846
                reload = 1;
 
2847
                setproctitle("init [%c]", (int)runlevel);
 
2848
 
 
2849
                init_main();
 
2850
        }
 
2851
 
 
2852
        /* Check command line arguments */
 
2853
        maxproclen = strlen(argv[0]) + 1;
 
2854
        for(f = 1; f < argc; f++) {
 
2855
                if (!strcmp(argv[f], "single") || !strcmp(argv[f], "-s"))
 
2856
                        dfl_level = 'S';
 
2857
                else if (!strcmp(argv[f], "-a") || !strcmp(argv[f], "auto"))
 
2858
                        putenv("AUTOBOOT=YES");
 
2859
                else if (!strcmp(argv[f], "-b") || !strcmp(argv[f],"emergency"))
 
2860
                        emerg_shell = 1;
 
2861
                else if (!strcmp(argv[f], "-z")) {
 
2862
                        /* Ignore -z xxx */
 
2863
                        if (argv[f + 1]) f++;
 
2864
                } else if (strchr("0123456789sS", argv[f][0])
 
2865
                        && strlen(argv[f]) == 1)
 
2866
                        dfl_level = argv[f][0];
 
2867
                /* "init u" in the very beginning makes no sense */
 
2868
                if (dfl_level == 's') dfl_level = 'S';
 
2869
                maxproclen += strlen(argv[f]) + 1;
 
2870
        }
 
2871
 
 
2872
#ifdef WITH_SELINUX
 
2873
        if (getenv("SELINUX_INIT") == NULL) {
 
2874
          const int rc = mount("proc", "/proc", "proc", 0, 0);
 
2875
          if (is_selinux_enabled() > 0) {
 
2876
            putenv("SELINUX_INIT=YES");
 
2877
            if (rc == 0) umount2("/proc", MNT_DETACH);
 
2878
            if (selinux_init_load_policy(&enforce) == 0) {
 
2879
              execv(myname, argv);
 
2880
            } else {
 
2881
              if (enforce > 0) {
 
2882
                /* SELinux in enforcing mode but load_policy failed */
 
2883
                /* At this point, we probably can't open /dev/console, so log() won't work */
 
2884
                fprintf(stderr,"Unable to load SELinux Policy. Machine is in enforcing mode. Halting now.\n");
 
2885
                exit(1);
 
2886
              }
 
2887
            }
 
2888
          }
 
2889
          if (rc == 0) umount2("/proc", MNT_DETACH);
 
2890
        }
 
2891
#endif  
 
2892
        /* Start booting. */
 
2893
        argv0 = argv[0];
 
2894
        argv[1] = NULL;
 
2895
        setproctitle("init boot");
 
2896
        init_main();
 
2897
 
 
2898
        /*NOTREACHED*/
 
2899
        return 0;
 
2900
}