init.c revision 35237d135807af84bf9b0e5b8d7f8633e58db6f5
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        execve(svc->args[0], (char**) svc->args, (char**) ENV);
248        _exit(127);
249    }
250
251    if (pid < 0) {
252        ERROR("failed to start '%s'\n", svc->name);
253        svc->pid = 0;
254        return;
255    }
256
257    svc->time_started = gettime();
258    svc->pid = pid;
259    svc->flags |= SVC_RUNNING;
260
261    notify_service_state(svc->name, "running");
262}
263
264void service_stop(struct service *svc)
265{
266        /* we are no longer running, nor should we
267         * attempt to restart
268         */
269    svc->flags &= (~(SVC_RUNNING|SVC_RESTARTING));
270
271        /* if the service has not yet started, prevent
272         * it from auto-starting with its class
273         */
274    svc->flags |= SVC_DISABLED;
275
276    if (svc->pid) {
277        NOTICE("service '%s' is being killed\n", svc->name);
278        kill(-svc->pid, SIGTERM);
279        notify_service_state(svc->name, "stopping");
280    } else {
281        notify_service_state(svc->name, "stopped");
282    }
283}
284
285void property_changed(const char *name, const char *value)
286{
287    if (property_triggers_enabled) {
288        queue_property_triggers(name, value);
289        drain_action_queue();
290    }
291}
292
293#define CRITICAL_CRASH_THRESHOLD    4       /* if we crash >4 times ... */
294#define CRITICAL_CRASH_WINDOW       (4*60)  /* ... in 4 minutes, goto recovery*/
295
296static int wait_for_one_process(int block)
297{
298    pid_t pid;
299    int status;
300    struct service *svc;
301    struct socketinfo *si;
302    time_t now;
303    struct listnode *node;
304    struct command *cmd;
305
306    while ( (pid = waitpid(-1, &status, block ? 0 : WNOHANG)) == -1 && errno == EINTR );
307    if (pid <= 0) return -1;
308    INFO("waitpid returned pid %d, status = %08x\n", pid, status);
309
310    svc = service_find_by_pid(pid);
311    if (!svc) {
312        ERROR("untracked pid %d exited\n", pid);
313        return 0;
314    }
315
316    NOTICE("process '%s', pid %d exited\n", svc->name, pid);
317
318    if (!(svc->flags & SVC_ONESHOT)) {
319        kill(-pid, SIGKILL);
320        NOTICE("process '%s' killing any children in process group\n", svc->name);
321    }
322
323    /* remove any sockets we may have created */
324    for (si = svc->sockets; si; si = si->next) {
325        char tmp[128];
326        snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR"/%s", si->name);
327        unlink(tmp);
328    }
329
330    svc->pid = 0;
331    svc->flags &= (~SVC_RUNNING);
332
333        /* oneshot processes go into the disabled state on exit */
334    if (svc->flags & SVC_ONESHOT) {
335        svc->flags |= SVC_DISABLED;
336    }
337
338        /* disabled processes do not get restarted automatically */
339    if (svc->flags & SVC_DISABLED) {
340        notify_service_state(svc->name, "stopped");
341        return 0;
342    }
343
344    now = gettime();
345    if (svc->flags & SVC_CRITICAL) {
346        if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) {
347            if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) {
348                ERROR("critical process '%s' exited %d times in %d minutes; "
349                      "rebooting into recovery mode\n", svc->name,
350                      CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60);
351                sync();
352                __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
353                         LINUX_REBOOT_CMD_RESTART2, "recovery");
354                return 0;
355            }
356        } else {
357            svc->time_crashed = now;
358            svc->nr_crashed = 1;
359        }
360    }
361
362    /* Execute all onrestart commands for this service. */
363    list_for_each(node, &svc->onrestart.commands) {
364        cmd = node_to_item(node, struct command, clist);
365        cmd->func(cmd->nargs, cmd->args);
366    }
367    svc->flags |= SVC_RESTARTING;
368    notify_service_state(svc->name, "restarting");
369    return 0;
370}
371
372static void restart_service_if_needed(struct service *svc)
373{
374    time_t next_start_time = svc->time_started + 5;
375
376    if (next_start_time <= gettime()) {
377        svc->flags &= (~SVC_RESTARTING);
378        service_start(svc);
379        return;
380    }
381
382    if ((next_start_time < process_needs_restart) ||
383        (process_needs_restart == 0)) {
384        process_needs_restart = next_start_time;
385    }
386}
387
388static void restart_processes()
389{
390    process_needs_restart = 0;
391    service_for_each_flags(SVC_RESTARTING,
392                           restart_service_if_needed);
393}
394
395static int signal_fd = -1;
396
397static void sigchld_handler(int s)
398{
399    write(signal_fd, &s, 1);
400}
401
402static void msg_start(const char *name)
403{
404    struct service *svc = service_find_by_name(name);
405
406    if (svc) {
407        service_start(svc);
408    } else {
409        ERROR("no such service '%s'\n", name);
410    }
411}
412
413static void msg_stop(const char *name)
414{
415    struct service *svc = service_find_by_name(name);
416
417    if (svc) {
418        service_stop(svc);
419    } else {
420        ERROR("no such service '%s'\n");
421    }
422}
423
424void handle_control_message(const char *msg, const char *arg)
425{
426    if (!strcmp(msg,"start")) {
427        msg_start(arg);
428    } else if (!strcmp(msg,"stop")) {
429        msg_stop(arg);
430    } else {
431        ERROR("unknown control msg '%s'\n", msg);
432    }
433}
434
435#define MAX_MTD_PARTITIONS 16
436
437static struct {
438    char name[16];
439    int number;
440} mtd_part_map[MAX_MTD_PARTITIONS];
441
442static int mtd_part_count = -1;
443
444static void find_mtd_partitions(void)
445{
446    int fd;
447    char buf[1024];
448    char *pmtdbufp;
449    ssize_t pmtdsize;
450    int r;
451
452    fd = open("/proc/mtd", O_RDONLY);
453    if (fd < 0)
454        return;
455
456    buf[sizeof(buf) - 1] = '\0';
457    pmtdsize = read(fd, buf, sizeof(buf) - 1);
458    pmtdbufp = buf;
459    while (pmtdsize > 0) {
460        int mtdnum, mtdsize, mtderasesize;
461        char mtdname[16];
462        mtdname[0] = '\0';
463        mtdnum = -1;
464        r = sscanf(pmtdbufp, "mtd%d: %x %x %15s",
465                   &mtdnum, &mtdsize, &mtderasesize, mtdname);
466        if ((r == 4) && (mtdname[0] == '"')) {
467            char *x = strchr(mtdname + 1, '"');
468            if (x) {
469                *x = 0;
470            }
471            INFO("mtd partition %d, %s\n", mtdnum, mtdname + 1);
472            if (mtd_part_count < MAX_MTD_PARTITIONS) {
473                strcpy(mtd_part_map[mtd_part_count].name, mtdname + 1);
474                mtd_part_map[mtd_part_count].number = mtdnum;
475                mtd_part_count++;
476            } else {
477                ERROR("too many mtd partitions\n");
478            }
479        }
480        while (pmtdsize > 0 && *pmtdbufp != '\n') {
481            pmtdbufp++;
482            pmtdsize--;
483        }
484        if (pmtdsize > 0) {
485            pmtdbufp++;
486            pmtdsize--;
487        }
488    }
489    close(fd);
490}
491
492int mtd_name_to_number(const char *name)
493{
494    int n;
495    if (mtd_part_count < 0) {
496        mtd_part_count = 0;
497        find_mtd_partitions();
498    }
499    for (n = 0; n < mtd_part_count; n++) {
500        if (!strcmp(name, mtd_part_map[n].name)) {
501            return mtd_part_map[n].number;
502        }
503    }
504    return -1;
505}
506
507static void import_kernel_nv(char *name, int in_qemu)
508{
509    char *value = strchr(name, '=');
510
511    if (value == 0) return;
512    *value++ = 0;
513    if (*name == 0) return;
514
515    if (!in_qemu)
516    {
517        /* on a real device, white-list the kernel options */
518        if (!strcmp(name,"qemu")) {
519            strlcpy(qemu, value, sizeof(qemu));
520        } else if (!strcmp(name,"androidboot.console")) {
521            strlcpy(console, value, sizeof(console));
522        } else if (!strcmp(name,"androidboot.mode")) {
523            strlcpy(bootmode, value, sizeof(bootmode));
524        } else if (!strcmp(name,"androidboot.serialno")) {
525            strlcpy(serialno, value, sizeof(serialno));
526        } else if (!strcmp(name,"androidboot.baseband")) {
527            strlcpy(baseband, value, sizeof(baseband));
528        } else if (!strcmp(name,"androidboot.carrier")) {
529            strlcpy(carrier, value, sizeof(carrier));
530        } else if (!strcmp(name,"androidboot.bootloader")) {
531            strlcpy(bootloader, value, sizeof(bootloader));
532        } else if (!strcmp(name,"androidboot.hardware")) {
533            strlcpy(hardware, value, sizeof(hardware));
534        } else {
535            qemu_cmdline(name, value);
536        }
537    } else {
538        /* in the emulator, export any kernel option with the
539         * ro.kernel. prefix */
540        char  buff[32];
541        int   len = snprintf( buff, sizeof(buff), "ro.kernel.%s", name );
542        if (len < (int)sizeof(buff)) {
543            property_set( buff, value );
544        }
545    }
546}
547
548static void import_kernel_cmdline(int in_qemu)
549{
550    char cmdline[1024];
551    char *ptr;
552    int fd;
553
554    fd = open("/proc/cmdline", O_RDONLY);
555    if (fd >= 0) {
556        int n = read(fd, cmdline, 1023);
557        if (n < 0) n = 0;
558
559        /* get rid of trailing newline, it happens */
560        if (n > 0 && cmdline[n-1] == '\n') n--;
561
562        cmdline[n] = 0;
563        close(fd);
564    } else {
565        cmdline[0] = 0;
566    }
567
568    ptr = cmdline;
569    while (ptr && *ptr) {
570        char *x = strchr(ptr, ' ');
571        if (x != 0) *x++ = 0;
572        import_kernel_nv(ptr, in_qemu);
573        ptr = x;
574    }
575
576        /* don't expose the raw commandline to nonpriv processes */
577    chmod("/proc/cmdline", 0440);
578}
579
580static void get_hardware_name(void)
581{
582    char data[1024];
583    int fd, n;
584    char *x, *hw, *rev;
585
586    /* Hardware string was provided on kernel command line */
587    if (hardware[0])
588        return;
589
590    fd = open("/proc/cpuinfo", O_RDONLY);
591    if (fd < 0) return;
592
593    n = read(fd, data, 1023);
594    close(fd);
595    if (n < 0) return;
596
597    data[n] = 0;
598    hw = strstr(data, "\nHardware");
599    rev = strstr(data, "\nRevision");
600
601    if (hw) {
602        x = strstr(hw, ": ");
603        if (x) {
604            x += 2;
605            n = 0;
606            while (*x && !isspace(*x)) {
607                hardware[n++] = tolower(*x);
608                x++;
609                if (n == 31) break;
610            }
611            hardware[n] = 0;
612        }
613    }
614
615    if (rev) {
616        x = strstr(rev, ": ");
617        if (x) {
618            revision = strtoul(x + 2, 0, 16);
619        }
620    }
621}
622
623static void drain_action_queue(void)
624{
625    struct listnode *node;
626    struct command *cmd;
627    struct action *act;
628    int ret;
629
630    while ((act = action_remove_queue_head())) {
631        INFO("processing action %p (%s)\n", act, act->name);
632        list_for_each(node, &act->commands) {
633            cmd = node_to_item(node, struct command, clist);
634            ret = cmd->func(cmd->nargs, cmd->args);
635            INFO("command '%s' r=%d\n", cmd->args[0], ret);
636        }
637    }
638}
639
640void open_devnull_stdio(void)
641{
642    int fd;
643    static const char *name = "/dev/__null__";
644    if (mknod(name, S_IFCHR | 0600, (1 << 8) | 3) == 0) {
645        fd = open(name, O_RDWR);
646        unlink(name);
647        if (fd >= 0) {
648            dup2(fd, 0);
649            dup2(fd, 1);
650            dup2(fd, 2);
651            if (fd > 2) {
652                close(fd);
653            }
654            return;
655        }
656    }
657
658    exit(1);
659}
660
661int main(int argc, char **argv)
662{
663    int device_fd = -1;
664    int property_set_fd = -1;
665    int signal_recv_fd = -1;
666    int s[2];
667    int fd;
668    struct sigaction act;
669    char tmp[PROP_VALUE_MAX];
670    struct pollfd ufds[4];
671    char *tmpdev;
672
673    act.sa_handler = sigchld_handler;
674    act.sa_flags = SA_NOCLDSTOP;
675    act.sa_mask = 0;
676    act.sa_restorer = NULL;
677    sigaction(SIGCHLD, &act, 0);
678
679    /* clear the umask */
680    umask(0);
681
682        /* Get the basic filesystem setup we need put
683         * together in the initramdisk on / and then we'll
684         * let the rc file figure out the rest.
685         */
686    mkdir("/dev", 0755);
687    mkdir("/proc", 0755);
688    mkdir("/sys", 0755);
689
690    mount("tmpfs", "/dev", "tmpfs", 0, "mode=0755");
691    mkdir("/dev/pts", 0755);
692    mkdir("/dev/socket", 0755);
693    mount("devpts", "/dev/pts", "devpts", 0, NULL);
694    mount("proc", "/proc", "proc", 0, NULL);
695    mount("sysfs", "/sys", "sysfs", 0, NULL);
696
697        /* We must have some place other than / to create the
698         * device nodes for kmsg and null, otherwise we won't
699         * be able to remount / read-only later on.
700         * Now that tmpfs is mounted on /dev, we can actually
701         * talk to the outside world.
702         */
703    open_devnull_stdio();
704    log_init();
705
706    INFO("reading config file\n");
707    parse_config_file("/init.rc");
708
709    /* pull the kernel commandline and ramdisk properties file in */
710    qemu_init();
711    import_kernel_cmdline(0);
712
713    get_hardware_name();
714    snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);
715    parse_config_file(tmp);
716
717    action_for_each_trigger("early-init", action_add_queue_tail);
718    drain_action_queue();
719
720    INFO("device init\n");
721    device_fd = device_init();
722
723    property_init();
724
725    if (console[0]) {
726        snprintf(tmp, sizeof(tmp), "/dev/%s", console);
727        console_name = strdup(tmp);
728    }
729
730    fd = open(console_name, O_RDWR);
731    if (fd >= 0)
732        have_console = 1;
733    close(fd);
734
735    if( load_565rle_image(INIT_IMAGE_FILE) ) {
736	fd = open("/dev/tty0", O_WRONLY);
737	if (fd >= 0) {
738	    const char *msg;
739            msg = "\n"
740		"\n"
741		"\n"
742		"\n"
743		"\n"
744		"\n"
745		"\n"  // console is 40 cols x 30 lines
746		"\n"
747		"\n"
748		"\n"
749		"\n"
750		"\n"
751		"\n"
752		"\n"
753		"             A N D R O I D ";
754	    write(fd, msg, strlen(msg));
755	    close(fd);
756	}
757    }
758
759    if (qemu[0])
760        import_kernel_cmdline(1);
761
762    if (!strcmp(bootmode,"factory"))
763        property_set("ro.factorytest", "1");
764    else if (!strcmp(bootmode,"factory2"))
765        property_set("ro.factorytest", "2");
766    else
767        property_set("ro.factorytest", "0");
768
769    property_set("ro.serialno", serialno[0] ? serialno : "");
770    property_set("ro.bootmode", bootmode[0] ? bootmode : "unknown");
771    property_set("ro.baseband", baseband[0] ? baseband : "unknown");
772    property_set("ro.carrier", carrier[0] ? carrier : "unknown");
773    property_set("ro.bootloader", bootloader[0] ? bootloader : "unknown");
774
775    property_set("ro.hardware", hardware);
776    snprintf(tmp, PROP_VALUE_MAX, "%d", revision);
777    property_set("ro.revision", tmp);
778
779        /* execute all the boot actions to get us started */
780    action_for_each_trigger("init", action_add_queue_tail);
781    drain_action_queue();
782
783        /* read any property files on system or data and
784         * fire up the property service.  This must happen
785         * after the ro.foo properties are set above so
786         * that /data/local.prop cannot interfere with them.
787         */
788    property_set_fd = start_property_service();
789
790    /* create a signalling mechanism for the sigchld handler */
791    if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) {
792        signal_fd = s[0];
793        signal_recv_fd = s[1];
794        fcntl(s[0], F_SETFD, FD_CLOEXEC);
795        fcntl(s[0], F_SETFL, O_NONBLOCK);
796        fcntl(s[1], F_SETFD, FD_CLOEXEC);
797        fcntl(s[1], F_SETFL, O_NONBLOCK);
798    }
799
800    /* make sure we actually have all the pieces we need */
801    if ((device_fd < 0) ||
802        (property_set_fd < 0) ||
803        (signal_recv_fd < 0)) {
804        ERROR("init startup failure\n");
805        return 1;
806    }
807
808    /* execute all the boot actions to get us started */
809    action_for_each_trigger("early-boot", action_add_queue_tail);
810    action_for_each_trigger("boot", action_add_queue_tail);
811    drain_action_queue();
812
813        /* run all property triggers based on current state of the properties */
814    queue_all_property_triggers();
815    drain_action_queue();
816
817        /* enable property triggers */
818    property_triggers_enabled = 1;
819
820    ufds[0].fd = device_fd;
821    ufds[0].events = POLLIN;
822    ufds[1].fd = property_set_fd;
823    ufds[1].events = POLLIN;
824    ufds[2].fd = signal_recv_fd;
825    ufds[2].events = POLLIN;
826
827#if BOOTCHART
828    bootchart_count = bootchart_init();
829    if (bootchart_count < 0) {
830        ERROR("bootcharting init failure\n");
831    } else if (bootchart_count > 0) {
832        NOTICE("bootcharting started (period=%d ms)\n", bootchart_count*BOOTCHART_POLLING_MS);
833    } else {
834        NOTICE("bootcharting ignored\n");
835    }
836#endif
837
838    for(;;) {
839        int nr, timeout = -1;
840
841        ufds[0].revents = 0;
842        ufds[1].revents = 0;
843        ufds[2].revents = 0;
844
845        drain_action_queue();
846        restart_processes();
847
848        if (process_needs_restart) {
849            timeout = (process_needs_restart - gettime()) * 1000;
850            if (timeout < 0)
851                timeout = 0;
852        }
853
854#if BOOTCHART
855        if (bootchart_count > 0) {
856            if (timeout < 0 || timeout > BOOTCHART_POLLING_MS)
857                timeout = BOOTCHART_POLLING_MS;
858            if (bootchart_step() < 0 || --bootchart_count == 0) {
859                bootchart_finish();
860                bootchart_count = 0;
861            }
862        }
863#endif
864        nr = poll(ufds, 3, timeout);
865        if (nr <= 0)
866            continue;
867
868        if (ufds[2].revents == POLLIN) {
869            /* we got a SIGCHLD - reap and restart as needed */
870            read(signal_recv_fd, tmp, sizeof(tmp));
871            while (!wait_for_one_process(0))
872                ;
873            continue;
874        }
875
876        if (ufds[0].revents == POLLIN)
877            handle_device_fd(device_fd);
878
879        if (ufds[1].revents == POLLIN)
880            handle_property_set_fd(property_set_fd);
881    }
882
883    return 0;
884}
885