init.c revision 77d0c65b950570edd5241a8f2ebecfc3acbc5135
1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <unistd.h>
21#include <fcntl.h>
22#include <ctype.h>
23#include <signal.h>
24#include <sys/wait.h>
25#include <sys/mount.h>
26#include <sys/stat.h>
27#include <sys/poll.h>
28#include <time.h>
29#include <errno.h>
30#include <stdarg.h>
31#include <mtd/mtd-user.h>
32#include <sys/types.h>
33#include <sys/socket.h>
34#include <sys/un.h>
35#include <sys/reboot.h>
36
37#include <cutils/sockets.h>
38#include <termios.h>
39#include <linux/kd.h>
40
41#include <sys/system_properties.h>
42
43#include "devices.h"
44#include "init.h"
45#include "property_service.h"
46#include "bootchart.h"
47
48static int property_triggers_enabled = 0;
49
50#if BOOTCHART
51static int   bootchart_count;
52#endif
53
54static char console[32];
55static char serialno[32];
56static char bootmode[32];
57static char baseband[32];
58static char carrier[32];
59static char bootloader[32];
60static char hardware[32];
61static unsigned revision = 0;
62static char qemu[32];
63
64static void drain_action_queue(void);
65
66static void notify_service_state(const char *name, const char *state)
67{
68    char pname[PROP_NAME_MAX];
69    int len = strlen(name);
70    if ((len + 10) > PROP_NAME_MAX)
71        return;
72    snprintf(pname, sizeof(pname), "init.svc.%s", name);
73    property_set(pname, state);
74}
75
76static int have_console;
77static char *console_name = "/dev/console";
78static time_t process_needs_restart;
79
80static const char *ENV[32];
81
82/* add_environment - add "key=value" to the current environment */
83int add_environment(const char *key, const char *val)
84{
85    int n;
86
87    for (n = 0; n < 31; n++) {
88        if (!ENV[n]) {
89            size_t len = strlen(key) + strlen(val) + 2;
90            char *entry = malloc(len);
91            snprintf(entry, len, "%s=%s", key, val);
92            ENV[n] = entry;
93            return 0;
94        }
95    }
96
97    return 1;
98}
99
100static void zap_stdio(void)
101{
102    int fd;
103    fd = open("/dev/null", O_RDWR);
104    dup2(fd, 0);
105    dup2(fd, 1);
106    dup2(fd, 2);
107    close(fd);
108}
109
110static void open_console()
111{
112    int fd;
113    if ((fd = open(console_name, O_RDWR)) < 0) {
114        fd = open("/dev/null", O_RDWR);
115    }
116    dup2(fd, 0);
117    dup2(fd, 1);
118    dup2(fd, 2);
119    close(fd);
120}
121
122/*
123 * gettime() - returns the time in seconds of the system's monotonic clock or
124 * zero on error.
125 */
126static time_t gettime(void)
127{
128    struct timespec ts;
129    int ret;
130
131    ret = clock_gettime(CLOCK_MONOTONIC, &ts);
132    if (ret < 0) {
133        ERROR("clock_gettime(CLOCK_MONOTONIC) failed: %s\n", strerror(errno));
134        return 0;
135    }
136
137    return ts.tv_sec;
138}
139
140static void publish_socket(const char *name, int fd)
141{
142    char key[64] = ANDROID_SOCKET_ENV_PREFIX;
143    char val[64];
144
145    strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,
146            name,
147            sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));
148    snprintf(val, sizeof(val), "%d", fd);
149    add_environment(key, val);
150
151    /* make sure we don't close-on-exec */
152    fcntl(fd, F_SETFD, 0);
153}
154
155void service_start(struct service *svc)
156{
157    struct stat s;
158    pid_t pid;
159    int needs_console;
160    int n;
161
162        /* starting a service removes it from the disabled
163         * state and immediately takes it out of the restarting
164         * state if it was in there
165         */
166    svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING));
167    svc->time_started = 0;
168
169        /* running processes require no additional work -- if
170         * they're in the process of exiting, we've ensured
171         * that they will immediately restart on exit, unless
172         * they are ONESHOT
173         */
174    if (svc->flags & SVC_RUNNING) {
175        return;
176    }
177
178    needs_console = (svc->flags & SVC_CONSOLE) ? 1 : 0;
179    if (needs_console && (!have_console)) {
180        ERROR("service '%s' requires console\n", svc->name);
181        svc->flags |= SVC_DISABLED;
182        return;
183    }
184
185    if (stat(svc->args[0], &s) != 0) {
186        ERROR("cannot find '%s', disabling '%s'\n", svc->args[0], svc->name);
187        svc->flags |= SVC_DISABLED;
188        return;
189    }
190
191    NOTICE("starting '%s'\n", svc->name);
192
193    pid = fork();
194
195    if (pid == 0) {
196        struct socketinfo *si;
197        struct svcenvinfo *ei;
198        char tmp[32];
199        int fd, sz;
200
201        get_property_workspace(&fd, &sz);
202        sprintf(tmp, "%d,%d", dup(fd), sz);
203        add_environment("ANDROID_PROPERTY_WORKSPACE", tmp);
204
205        for (ei = svc->envvars; ei; ei = ei->next)
206            add_environment(ei->name, ei->value);
207
208        for (si = svc->sockets; si; si = si->next) {
209            int s = create_socket(si->name,
210                                  !strcmp(si->type, "dgram") ?
211                                  SOCK_DGRAM : SOCK_STREAM,
212                                  si->perm, si->uid, si->gid);
213            if (s >= 0) {
214                publish_socket(si->name, s);
215            }
216        }
217
218        if (needs_console) {
219            setsid();
220            open_console();
221        } else {
222            zap_stdio();
223        }
224
225#if 0
226        for (n = 0; svc->args[n]; n++) {
227            INFO("args[%d] = '%s'\n", n, svc->args[n]);
228        }
229        for (n = 0; ENV[n]; n++) {
230            INFO("env[%d] = '%s'\n", n, ENV[n]);
231        }
232#endif
233
234        setpgid(0, getpid());
235
236	/* as requested, set our gid, supplemental gids, and uid */
237        if (svc->gid) {
238            setgid(svc->gid);
239        }
240        if (svc->nr_supp_gids) {
241            setgroups(svc->nr_supp_gids, svc->supp_gids);
242        }
243        if (svc->uid) {
244            setuid(svc->uid);
245        }
246
247        if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0) {
248            ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno));
249        }
250        _exit(127);
251    }
252
253    if (pid < 0) {
254        ERROR("failed to start '%s'\n", svc->name);
255        svc->pid = 0;
256        return;
257    }
258
259    svc->time_started = gettime();
260    svc->pid = pid;
261    svc->flags |= SVC_RUNNING;
262
263    notify_service_state(svc->name, "running");
264}
265
266void service_stop(struct service *svc)
267{
268        /* we are no longer running, nor should we
269         * attempt to restart
270         */
271    svc->flags &= (~(SVC_RUNNING|SVC_RESTARTING));
272
273        /* if the service has not yet started, prevent
274         * it from auto-starting with its class
275         */
276    svc->flags |= SVC_DISABLED;
277
278    if (svc->pid) {
279        NOTICE("service '%s' is being killed\n", svc->name);
280        kill(-svc->pid, SIGTERM);
281        notify_service_state(svc->name, "stopping");
282    } else {
283        notify_service_state(svc->name, "stopped");
284    }
285}
286
287void property_changed(const char *name, const char *value)
288{
289    if (property_triggers_enabled) {
290        queue_property_triggers(name, value);
291        drain_action_queue();
292    }
293}
294
295#define CRITICAL_CRASH_THRESHOLD    4       /* if we crash >4 times ... */
296#define CRITICAL_CRASH_WINDOW       (4*60)  /* ... in 4 minutes, goto recovery*/
297
298static int wait_for_one_process(int block)
299{
300    pid_t pid;
301    int status;
302    struct service *svc;
303    struct socketinfo *si;
304    time_t now;
305    struct listnode *node;
306    struct command *cmd;
307
308    while ( (pid = waitpid(-1, &status, block ? 0 : WNOHANG)) == -1 && errno == EINTR );
309    if (pid <= 0) return -1;
310    INFO("waitpid returned pid %d, status = %08x\n", pid, status);
311
312    svc = service_find_by_pid(pid);
313    if (!svc) {
314        ERROR("untracked pid %d exited\n", pid);
315        return 0;
316    }
317
318    NOTICE("process '%s', pid %d exited\n", svc->name, pid);
319
320    if (!(svc->flags & SVC_ONESHOT)) {
321        kill(-pid, SIGKILL);
322        NOTICE("process '%s' killing any children in process group\n", svc->name);
323    }
324
325    /* remove any sockets we may have created */
326    for (si = svc->sockets; si; si = si->next) {
327        char tmp[128];
328        snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR"/%s", si->name);
329        unlink(tmp);
330    }
331
332    svc->pid = 0;
333    svc->flags &= (~SVC_RUNNING);
334
335        /* oneshot processes go into the disabled state on exit */
336    if (svc->flags & SVC_ONESHOT) {
337        svc->flags |= SVC_DISABLED;
338    }
339
340        /* disabled processes do not get restarted automatically */
341    if (svc->flags & SVC_DISABLED) {
342        notify_service_state(svc->name, "stopped");
343        return 0;
344    }
345
346    now = gettime();
347    if (svc->flags & SVC_CRITICAL) {
348        if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) {
349            if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) {
350                ERROR("critical process '%s' exited %d times in %d minutes; "
351                      "rebooting into recovery mode\n", svc->name,
352                      CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60);
353                sync();
354                __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
355                         LINUX_REBOOT_CMD_RESTART2, "recovery");
356                return 0;
357            }
358        } else {
359            svc->time_crashed = now;
360            svc->nr_crashed = 1;
361        }
362    }
363
364    /* Execute all onrestart commands for this service. */
365    list_for_each(node, &svc->onrestart.commands) {
366        cmd = node_to_item(node, struct command, clist);
367        cmd->func(cmd->nargs, cmd->args);
368    }
369    svc->flags |= SVC_RESTARTING;
370    notify_service_state(svc->name, "restarting");
371    return 0;
372}
373
374static void restart_service_if_needed(struct service *svc)
375{
376    time_t next_start_time = svc->time_started + 5;
377
378    if (next_start_time <= gettime()) {
379        svc->flags &= (~SVC_RESTARTING);
380        service_start(svc);
381        return;
382    }
383
384    if ((next_start_time < process_needs_restart) ||
385        (process_needs_restart == 0)) {
386        process_needs_restart = next_start_time;
387    }
388}
389
390static void restart_processes()
391{
392    process_needs_restart = 0;
393    service_for_each_flags(SVC_RESTARTING,
394                           restart_service_if_needed);
395}
396
397static int signal_fd = -1;
398
399static void sigchld_handler(int s)
400{
401    write(signal_fd, &s, 1);
402}
403
404static void msg_start(const char *name)
405{
406    struct service *svc = service_find_by_name(name);
407
408    if (svc) {
409        service_start(svc);
410    } else {
411        ERROR("no such service '%s'\n", name);
412    }
413}
414
415static void msg_stop(const char *name)
416{
417    struct service *svc = service_find_by_name(name);
418
419    if (svc) {
420        service_stop(svc);
421    } else {
422        ERROR("no such service '%s'\n");
423    }
424}
425
426void handle_control_message(const char *msg, const char *arg)
427{
428    if (!strcmp(msg,"start")) {
429        msg_start(arg);
430    } else if (!strcmp(msg,"stop")) {
431        msg_stop(arg);
432    } else {
433        ERROR("unknown control msg '%s'\n", msg);
434    }
435}
436
437#define MAX_MTD_PARTITIONS 16
438
439static struct {
440    char name[16];
441    int number;
442} mtd_part_map[MAX_MTD_PARTITIONS];
443
444static int mtd_part_count = -1;
445
446static void find_mtd_partitions(void)
447{
448    int fd;
449    char buf[1024];
450    char *pmtdbufp;
451    ssize_t pmtdsize;
452    int r;
453
454    fd = open("/proc/mtd", O_RDONLY);
455    if (fd < 0)
456        return;
457
458    buf[sizeof(buf) - 1] = '\0';
459    pmtdsize = read(fd, buf, sizeof(buf) - 1);
460    pmtdbufp = buf;
461    while (pmtdsize > 0) {
462        int mtdnum, mtdsize, mtderasesize;
463        char mtdname[16];
464        mtdname[0] = '\0';
465        mtdnum = -1;
466        r = sscanf(pmtdbufp, "mtd%d: %x %x %15s",
467                   &mtdnum, &mtdsize, &mtderasesize, mtdname);
468        if ((r == 4) && (mtdname[0] == '"')) {
469            char *x = strchr(mtdname + 1, '"');
470            if (x) {
471                *x = 0;
472            }
473            INFO("mtd partition %d, %s\n", mtdnum, mtdname + 1);
474            if (mtd_part_count < MAX_MTD_PARTITIONS) {
475                strcpy(mtd_part_map[mtd_part_count].name, mtdname + 1);
476                mtd_part_map[mtd_part_count].number = mtdnum;
477                mtd_part_count++;
478            } else {
479                ERROR("too many mtd partitions\n");
480            }
481        }
482        while (pmtdsize > 0 && *pmtdbufp != '\n') {
483            pmtdbufp++;
484            pmtdsize--;
485        }
486        if (pmtdsize > 0) {
487            pmtdbufp++;
488            pmtdsize--;
489        }
490    }
491    close(fd);
492}
493
494int mtd_name_to_number(const char *name)
495{
496    int n;
497    if (mtd_part_count < 0) {
498        mtd_part_count = 0;
499        find_mtd_partitions();
500    }
501    for (n = 0; n < mtd_part_count; n++) {
502        if (!strcmp(name, mtd_part_map[n].name)) {
503            return mtd_part_map[n].number;
504        }
505    }
506    return -1;
507}
508
509static void import_kernel_nv(char *name, int in_qemu)
510{
511    char *value = strchr(name, '=');
512
513    if (value == 0) return;
514    *value++ = 0;
515    if (*name == 0) return;
516
517    if (!in_qemu)
518    {
519        /* on a real device, white-list the kernel options */
520        if (!strcmp(name,"qemu")) {
521            strlcpy(qemu, value, sizeof(qemu));
522        } else if (!strcmp(name,"androidboot.console")) {
523            strlcpy(console, value, sizeof(console));
524        } else if (!strcmp(name,"androidboot.mode")) {
525            strlcpy(bootmode, value, sizeof(bootmode));
526        } else if (!strcmp(name,"androidboot.serialno")) {
527            strlcpy(serialno, value, sizeof(serialno));
528        } else if (!strcmp(name,"androidboot.baseband")) {
529            strlcpy(baseband, value, sizeof(baseband));
530        } else if (!strcmp(name,"androidboot.carrier")) {
531            strlcpy(carrier, value, sizeof(carrier));
532        } else if (!strcmp(name,"androidboot.bootloader")) {
533            strlcpy(bootloader, value, sizeof(bootloader));
534        } else if (!strcmp(name,"androidboot.hardware")) {
535            strlcpy(hardware, value, sizeof(hardware));
536        } else {
537            qemu_cmdline(name, value);
538        }
539    } else {
540        /* in the emulator, export any kernel option with the
541         * ro.kernel. prefix */
542        char  buff[32];
543        int   len = snprintf( buff, sizeof(buff), "ro.kernel.%s", name );
544        if (len < (int)sizeof(buff)) {
545            property_set( buff, value );
546        }
547    }
548}
549
550static void import_kernel_cmdline(int in_qemu)
551{
552    char cmdline[1024];
553    char *ptr;
554    int fd;
555
556    fd = open("/proc/cmdline", O_RDONLY);
557    if (fd >= 0) {
558        int n = read(fd, cmdline, 1023);
559        if (n < 0) n = 0;
560
561        /* get rid of trailing newline, it happens */
562        if (n > 0 && cmdline[n-1] == '\n') n--;
563
564        cmdline[n] = 0;
565        close(fd);
566    } else {
567        cmdline[0] = 0;
568    }
569
570    ptr = cmdline;
571    while (ptr && *ptr) {
572        char *x = strchr(ptr, ' ');
573        if (x != 0) *x++ = 0;
574        import_kernel_nv(ptr, in_qemu);
575        ptr = x;
576    }
577
578        /* don't expose the raw commandline to nonpriv processes */
579    chmod("/proc/cmdline", 0440);
580}
581
582static void get_hardware_name(void)
583{
584    char data[1024];
585    int fd, n;
586    char *x, *hw, *rev;
587
588    /* Hardware string was provided on kernel command line */
589    if (hardware[0])
590        return;
591
592    fd = open("/proc/cpuinfo", O_RDONLY);
593    if (fd < 0) return;
594
595    n = read(fd, data, 1023);
596    close(fd);
597    if (n < 0) return;
598
599    data[n] = 0;
600    hw = strstr(data, "\nHardware");
601    rev = strstr(data, "\nRevision");
602
603    if (hw) {
604        x = strstr(hw, ": ");
605        if (x) {
606            x += 2;
607            n = 0;
608            while (*x && !isspace(*x)) {
609                hardware[n++] = tolower(*x);
610                x++;
611                if (n == 31) break;
612            }
613            hardware[n] = 0;
614        }
615    }
616
617    if (rev) {
618        x = strstr(rev, ": ");
619        if (x) {
620            revision = strtoul(x + 2, 0, 16);
621        }
622    }
623}
624
625static void drain_action_queue(void)
626{
627    struct listnode *node;
628    struct command *cmd;
629    struct action *act;
630    int ret;
631
632    while ((act = action_remove_queue_head())) {
633        INFO("processing action %p (%s)\n", act, act->name);
634        list_for_each(node, &act->commands) {
635            cmd = node_to_item(node, struct command, clist);
636            ret = cmd->func(cmd->nargs, cmd->args);
637            INFO("command '%s' r=%d\n", cmd->args[0], ret);
638        }
639    }
640}
641
642void open_devnull_stdio(void)
643{
644    int fd;
645    static const char *name = "/dev/__null__";
646    if (mknod(name, S_IFCHR | 0600, (1 << 8) | 3) == 0) {
647        fd = open(name, O_RDWR);
648        unlink(name);
649        if (fd >= 0) {
650            dup2(fd, 0);
651            dup2(fd, 1);
652            dup2(fd, 2);
653            if (fd > 2) {
654                close(fd);
655            }
656            return;
657        }
658    }
659
660    exit(1);
661}
662
663int main(int argc, char **argv)
664{
665    int device_fd = -1;
666    int property_set_fd = -1;
667    int signal_recv_fd = -1;
668    int s[2];
669    int fd;
670    struct sigaction act;
671    char tmp[PROP_VALUE_MAX];
672    struct pollfd ufds[4];
673    char *tmpdev;
674
675    act.sa_handler = sigchld_handler;
676    act.sa_flags = SA_NOCLDSTOP;
677    act.sa_mask = 0;
678    act.sa_restorer = NULL;
679    sigaction(SIGCHLD, &act, 0);
680
681    /* clear the umask */
682    umask(0);
683
684        /* Get the basic filesystem setup we need put
685         * together in the initramdisk on / and then we'll
686         * let the rc file figure out the rest.
687         */
688    mkdir("/dev", 0755);
689    mkdir("/proc", 0755);
690    mkdir("/sys", 0755);
691
692    mount("tmpfs", "/dev", "tmpfs", 0, "mode=0755");
693    mkdir("/dev/pts", 0755);
694    mkdir("/dev/socket", 0755);
695    mount("devpts", "/dev/pts", "devpts", 0, NULL);
696    mount("proc", "/proc", "proc", 0, NULL);
697    mount("sysfs", "/sys", "sysfs", 0, NULL);
698
699        /* We must have some place other than / to create the
700         * device nodes for kmsg and null, otherwise we won't
701         * be able to remount / read-only later on.
702         * Now that tmpfs is mounted on /dev, we can actually
703         * talk to the outside world.
704         */
705    open_devnull_stdio();
706    log_init();
707
708    INFO("reading config file\n");
709    parse_config_file("/init.rc");
710
711    /* pull the kernel commandline and ramdisk properties file in */
712    qemu_init();
713    import_kernel_cmdline(0);
714
715    get_hardware_name();
716    snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);
717    parse_config_file(tmp);
718
719    action_for_each_trigger("early-init", action_add_queue_tail);
720    drain_action_queue();
721
722    INFO("device init\n");
723    device_fd = device_init();
724
725    property_init();
726
727    if (console[0]) {
728        snprintf(tmp, sizeof(tmp), "/dev/%s", console);
729        console_name = strdup(tmp);
730    }
731
732    fd = open(console_name, O_RDWR);
733    if (fd >= 0)
734        have_console = 1;
735    close(fd);
736
737    if( load_565rle_image(INIT_IMAGE_FILE) ) {
738	fd = open("/dev/tty0", O_WRONLY);
739	if (fd >= 0) {
740	    const char *msg;
741            msg = "\n"
742		"\n"
743		"\n"
744		"\n"
745		"\n"
746		"\n"
747		"\n"  // console is 40 cols x 30 lines
748		"\n"
749		"\n"
750		"\n"
751		"\n"
752		"\n"
753		"\n"
754		"\n"
755		"             A N D R O I D ";
756	    write(fd, msg, strlen(msg));
757	    close(fd);
758	}
759    }
760
761    if (qemu[0])
762        import_kernel_cmdline(1);
763
764    if (!strcmp(bootmode,"factory"))
765        property_set("ro.factorytest", "1");
766    else if (!strcmp(bootmode,"factory2"))
767        property_set("ro.factorytest", "2");
768    else
769        property_set("ro.factorytest", "0");
770
771    property_set("ro.serialno", serialno[0] ? serialno : "");
772    property_set("ro.bootmode", bootmode[0] ? bootmode : "unknown");
773    property_set("ro.baseband", baseband[0] ? baseband : "unknown");
774    property_set("ro.carrier", carrier[0] ? carrier : "unknown");
775    property_set("ro.bootloader", bootloader[0] ? bootloader : "unknown");
776
777    property_set("ro.hardware", hardware);
778    snprintf(tmp, PROP_VALUE_MAX, "%d", revision);
779    property_set("ro.revision", tmp);
780
781        /* execute all the boot actions to get us started */
782    action_for_each_trigger("init", action_add_queue_tail);
783    drain_action_queue();
784
785        /* read any property files on system or data and
786         * fire up the property service.  This must happen
787         * after the ro.foo properties are set above so
788         * that /data/local.prop cannot interfere with them.
789         */
790    property_set_fd = start_property_service();
791
792    /* create a signalling mechanism for the sigchld handler */
793    if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) {
794        signal_fd = s[0];
795        signal_recv_fd = s[1];
796        fcntl(s[0], F_SETFD, FD_CLOEXEC);
797        fcntl(s[0], F_SETFL, O_NONBLOCK);
798        fcntl(s[1], F_SETFD, FD_CLOEXEC);
799        fcntl(s[1], F_SETFL, O_NONBLOCK);
800    }
801
802    /* make sure we actually have all the pieces we need */
803    if ((device_fd < 0) ||
804        (property_set_fd < 0) ||
805        (signal_recv_fd < 0)) {
806        ERROR("init startup failure\n");
807        return 1;
808    }
809
810    /* execute all the boot actions to get us started */
811    action_for_each_trigger("early-boot", action_add_queue_tail);
812    action_for_each_trigger("boot", action_add_queue_tail);
813    drain_action_queue();
814
815        /* run all property triggers based on current state of the properties */
816    queue_all_property_triggers();
817    drain_action_queue();
818
819        /* enable property triggers */
820    property_triggers_enabled = 1;
821
822    ufds[0].fd = device_fd;
823    ufds[0].events = POLLIN;
824    ufds[1].fd = property_set_fd;
825    ufds[1].events = POLLIN;
826    ufds[2].fd = signal_recv_fd;
827    ufds[2].events = POLLIN;
828
829#if BOOTCHART
830    bootchart_count = bootchart_init();
831    if (bootchart_count < 0) {
832        ERROR("bootcharting init failure\n");
833    } else if (bootchart_count > 0) {
834        NOTICE("bootcharting started (period=%d ms)\n", bootchart_count*BOOTCHART_POLLING_MS);
835    } else {
836        NOTICE("bootcharting ignored\n");
837    }
838#endif
839
840    for(;;) {
841        int nr, timeout = -1;
842
843        ufds[0].revents = 0;
844        ufds[1].revents = 0;
845        ufds[2].revents = 0;
846
847        drain_action_queue();
848        restart_processes();
849
850        if (process_needs_restart) {
851            timeout = (process_needs_restart - gettime()) * 1000;
852            if (timeout < 0)
853                timeout = 0;
854        }
855
856#if BOOTCHART
857        if (bootchart_count > 0) {
858            if (timeout < 0 || timeout > BOOTCHART_POLLING_MS)
859                timeout = BOOTCHART_POLLING_MS;
860            if (bootchart_step() < 0 || --bootchart_count == 0) {
861                bootchart_finish();
862                bootchart_count = 0;
863            }
864        }
865#endif
866        nr = poll(ufds, 3, timeout);
867        if (nr <= 0)
868            continue;
869
870        if (ufds[2].revents == POLLIN) {
871            /* we got a SIGCHLD - reap and restart as needed */
872            read(signal_recv_fd, tmp, sizeof(tmp));
873            while (!wait_for_one_process(0))
874                ;
875            continue;
876        }
877
878        if (ufds[0].revents == POLLIN)
879            handle_device_fd(device_fd);
880
881        if (ufds[1].revents == POLLIN)
882            handle_property_set_fd(property_set_fd);
883    }
884
885    return 0;
886}
887