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