Home | History | Annotate | Download | only in init
      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 <errno.h>
     29 #include <stdarg.h>
     30 #include <mtd/mtd-user.h>
     31 #include <sys/types.h>
     32 #include <sys/socket.h>
     33 #include <sys/un.h>
     34 #include <libgen.h>
     35 
     36 #include <cutils/sockets.h>
     37 #include <cutils/iosched_policy.h>
     38 #include <private/android_filesystem_config.h>
     39 #include <termios.h>
     40 
     41 #include <sys/system_properties.h>
     42 
     43 #include "devices.h"
     44 #include "init.h"
     45 #include "list.h"
     46 #include "log.h"
     47 #include "property_service.h"
     48 #include "bootchart.h"
     49 #include "signal_handler.h"
     50 #include "keychords.h"
     51 #include "init_parser.h"
     52 #include "util.h"
     53 #include "ueventd.h"
     54 
     55 static int property_triggers_enabled = 0;
     56 
     57 #if BOOTCHART
     58 static int   bootchart_count;
     59 #endif
     60 
     61 static char console[32];
     62 static char serialno[32];
     63 static char bootmode[32];
     64 static char baseband[32];
     65 static char carrier[32];
     66 static char bootloader[32];
     67 static char hardware[32];
     68 static unsigned revision = 0;
     69 static char qemu[32];
     70 
     71 static struct action *cur_action = NULL;
     72 static struct command *cur_command = NULL;
     73 static struct listnode *command_queue = NULL;
     74 
     75 void notify_service_state(const char *name, const char *state)
     76 {
     77     char pname[PROP_NAME_MAX];
     78     int len = strlen(name);
     79     if ((len + 10) > PROP_NAME_MAX)
     80         return;
     81     snprintf(pname, sizeof(pname), "init.svc.%s", name);
     82     property_set(pname, state);
     83 }
     84 
     85 static int have_console;
     86 static char *console_name = "/dev/console";
     87 static time_t process_needs_restart;
     88 
     89 static const char *ENV[32];
     90 
     91 /* add_environment - add "key=value" to the current environment */
     92 int add_environment(const char *key, const char *val)
     93 {
     94     int n;
     95 
     96     for (n = 0; n < 31; n++) {
     97         if (!ENV[n]) {
     98             size_t len = strlen(key) + strlen(val) + 2;
     99             char *entry = malloc(len);
    100             snprintf(entry, len, "%s=%s", key, val);
    101             ENV[n] = entry;
    102             return 0;
    103         }
    104     }
    105 
    106     return 1;
    107 }
    108 
    109 static void zap_stdio(void)
    110 {
    111     int fd;
    112     fd = open("/dev/null", O_RDWR);
    113     dup2(fd, 0);
    114     dup2(fd, 1);
    115     dup2(fd, 2);
    116     close(fd);
    117 }
    118 
    119 static void open_console()
    120 {
    121     int fd;
    122     if ((fd = open(console_name, O_RDWR)) < 0) {
    123         fd = open("/dev/null", O_RDWR);
    124     }
    125     dup2(fd, 0);
    126     dup2(fd, 1);
    127     dup2(fd, 2);
    128     close(fd);
    129 }
    130 
    131 static void publish_socket(const char *name, int fd)
    132 {
    133     char key[64] = ANDROID_SOCKET_ENV_PREFIX;
    134     char val[64];
    135 
    136     strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,
    137             name,
    138             sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));
    139     snprintf(val, sizeof(val), "%d", fd);
    140     add_environment(key, val);
    141 
    142     /* make sure we don't close-on-exec */
    143     fcntl(fd, F_SETFD, 0);
    144 }
    145 
    146 void service_start(struct service *svc, const char *dynamic_args)
    147 {
    148     struct stat s;
    149     pid_t pid;
    150     int needs_console;
    151     int n;
    152 
    153         /* starting a service removes it from the disabled
    154          * state and immediately takes it out of the restarting
    155          * state if it was in there
    156          */
    157     svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING));
    158     svc->time_started = 0;
    159 
    160         /* running processes require no additional work -- if
    161          * they're in the process of exiting, we've ensured
    162          * that they will immediately restart on exit, unless
    163          * they are ONESHOT
    164          */
    165     if (svc->flags & SVC_RUNNING) {
    166         return;
    167     }
    168 
    169     needs_console = (svc->flags & SVC_CONSOLE) ? 1 : 0;
    170     if (needs_console && (!have_console)) {
    171         ERROR("service '%s' requires console\n", svc->name);
    172         svc->flags |= SVC_DISABLED;
    173         return;
    174     }
    175 
    176     if (stat(svc->args[0], &s) != 0) {
    177         ERROR("cannot find '%s', disabling '%s'\n", svc->args[0], svc->name);
    178         svc->flags |= SVC_DISABLED;
    179         return;
    180     }
    181 
    182     if ((!(svc->flags & SVC_ONESHOT)) && dynamic_args) {
    183         ERROR("service '%s' must be one-shot to use dynamic args, disabling\n",
    184                svc->args[0]);
    185         svc->flags |= SVC_DISABLED;
    186         return;
    187     }
    188 
    189     NOTICE("starting '%s'\n", svc->name);
    190 
    191     pid = fork();
    192 
    193     if (pid == 0) {
    194         struct socketinfo *si;
    195         struct svcenvinfo *ei;
    196         char tmp[32];
    197         int fd, sz;
    198 
    199         if (properties_inited()) {
    200             get_property_workspace(&fd, &sz);
    201             sprintf(tmp, "%d,%d", dup(fd), sz);
    202             add_environment("ANDROID_PROPERTY_WORKSPACE", tmp);
    203         }
    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 socket_type = (
    210                     !strcmp(si->type, "stream") ? SOCK_STREAM :
    211                         (!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));
    212             int s = create_socket(si->name, socket_type,
    213                                   si->perm, si->uid, si->gid);
    214             if (s >= 0) {
    215                 publish_socket(si->name, s);
    216             }
    217         }
    218 
    219         if (svc->ioprio_class != IoSchedClass_NONE) {
    220             if (android_set_ioprio(getpid(), svc->ioprio_class, svc->ioprio_pri)) {
    221                 ERROR("Failed to set pid %d ioprio = %d,%d: %s\n",
    222                       getpid(), svc->ioprio_class, svc->ioprio_pri, strerror(errno));
    223             }
    224         }
    225 
    226         if (needs_console) {
    227             setsid();
    228             open_console();
    229         } else {
    230             zap_stdio();
    231         }
    232 
    233 #if 0
    234         for (n = 0; svc->args[n]; n++) {
    235             INFO("args[%d] = '%s'\n", n, svc->args[n]);
    236         }
    237         for (n = 0; ENV[n]; n++) {
    238             INFO("env[%d] = '%s'\n", n, ENV[n]);
    239         }
    240 #endif
    241 
    242         setpgid(0, getpid());
    243 
    244     /* as requested, set our gid, supplemental gids, and uid */
    245         if (svc->gid) {
    246             setgid(svc->gid);
    247         }
    248         if (svc->nr_supp_gids) {
    249             setgroups(svc->nr_supp_gids, svc->supp_gids);
    250         }
    251         if (svc->uid) {
    252             setuid(svc->uid);
    253         }
    254 
    255         if (!dynamic_args) {
    256             if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0) {
    257                 ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno));
    258             }
    259         } else {
    260             char *arg_ptrs[INIT_PARSER_MAXARGS+1];
    261             int arg_idx = svc->nargs;
    262             char *tmp = strdup(dynamic_args);
    263             char *next = tmp;
    264             char *bword;
    265 
    266             /* Copy the static arguments */
    267             memcpy(arg_ptrs, svc->args, (svc->nargs * sizeof(char *)));
    268 
    269             while((bword = strsep(&next, " "))) {
    270                 arg_ptrs[arg_idx++] = bword;
    271                 if (arg_idx == INIT_PARSER_MAXARGS)
    272                     break;
    273             }
    274             arg_ptrs[arg_idx] = '\0';
    275             execve(svc->args[0], (char**) arg_ptrs, (char**) ENV);
    276         }
    277         _exit(127);
    278     }
    279 
    280     if (pid < 0) {
    281         ERROR("failed to start '%s'\n", svc->name);
    282         svc->pid = 0;
    283         return;
    284     }
    285 
    286     svc->time_started = gettime();
    287     svc->pid = pid;
    288     svc->flags |= SVC_RUNNING;
    289 
    290     if (properties_inited())
    291         notify_service_state(svc->name, "running");
    292 }
    293 
    294 void service_stop(struct service *svc)
    295 {
    296         /* we are no longer running, nor should we
    297          * attempt to restart
    298          */
    299     svc->flags &= (~(SVC_RUNNING|SVC_RESTARTING));
    300 
    301         /* if the service has not yet started, prevent
    302          * it from auto-starting with its class
    303          */
    304     svc->flags |= SVC_DISABLED;
    305 
    306     if (svc->pid) {
    307         NOTICE("service '%s' is being killed\n", svc->name);
    308         kill(-svc->pid, SIGTERM);
    309         notify_service_state(svc->name, "stopping");
    310     } else {
    311         notify_service_state(svc->name, "stopped");
    312     }
    313 }
    314 
    315 void property_changed(const char *name, const char *value)
    316 {
    317     if (property_triggers_enabled)
    318         queue_property_triggers(name, value);
    319 }
    320 
    321 static void restart_service_if_needed(struct service *svc)
    322 {
    323     time_t next_start_time = svc->time_started + 5;
    324 
    325     if (next_start_time <= gettime()) {
    326         svc->flags &= (~SVC_RESTARTING);
    327         service_start(svc, NULL);
    328         return;
    329     }
    330 
    331     if ((next_start_time < process_needs_restart) ||
    332         (process_needs_restart == 0)) {
    333         process_needs_restart = next_start_time;
    334     }
    335 }
    336 
    337 static void restart_processes()
    338 {
    339     process_needs_restart = 0;
    340     service_for_each_flags(SVC_RESTARTING,
    341                            restart_service_if_needed);
    342 }
    343 
    344 static void msg_start(const char *name)
    345 {
    346     struct service *svc;
    347     char *tmp = NULL;
    348     char *args = NULL;
    349 
    350     if (!strchr(name, ':'))
    351         svc = service_find_by_name(name);
    352     else {
    353         tmp = strdup(name);
    354         args = strchr(tmp, ':');
    355         *args = '\0';
    356         args++;
    357 
    358         svc = service_find_by_name(tmp);
    359     }
    360 
    361     if (svc) {
    362         service_start(svc, args);
    363     } else {
    364         ERROR("no such service '%s'\n", name);
    365     }
    366     if (tmp)
    367         free(tmp);
    368 }
    369 
    370 static void msg_stop(const char *name)
    371 {
    372     struct service *svc = service_find_by_name(name);
    373 
    374     if (svc) {
    375         service_stop(svc);
    376     } else {
    377         ERROR("no such service '%s'\n", name);
    378     }
    379 }
    380 
    381 void handle_control_message(const char *msg, const char *arg)
    382 {
    383     if (!strcmp(msg,"start")) {
    384         msg_start(arg);
    385     } else if (!strcmp(msg,"stop")) {
    386         msg_stop(arg);
    387     } else {
    388         ERROR("unknown control msg '%s'\n", msg);
    389     }
    390 }
    391 
    392 static void import_kernel_nv(char *name, int in_qemu)
    393 {
    394     char *value = strchr(name, '=');
    395 
    396     if (value == 0) return;
    397     *value++ = 0;
    398     if (*name == 0) return;
    399 
    400     if (!in_qemu)
    401     {
    402         /* on a real device, white-list the kernel options */
    403         if (!strcmp(name,"qemu")) {
    404             strlcpy(qemu, value, sizeof(qemu));
    405         } else if (!strcmp(name,"androidboot.console")) {
    406             strlcpy(console, value, sizeof(console));
    407         } else if (!strcmp(name,"androidboot.mode")) {
    408             strlcpy(bootmode, value, sizeof(bootmode));
    409         } else if (!strcmp(name,"androidboot.serialno")) {
    410             strlcpy(serialno, value, sizeof(serialno));
    411         } else if (!strcmp(name,"androidboot.baseband")) {
    412             strlcpy(baseband, value, sizeof(baseband));
    413         } else if (!strcmp(name,"androidboot.carrier")) {
    414             strlcpy(carrier, value, sizeof(carrier));
    415         } else if (!strcmp(name,"androidboot.bootloader")) {
    416             strlcpy(bootloader, value, sizeof(bootloader));
    417         } else if (!strcmp(name,"androidboot.hardware")) {
    418             strlcpy(hardware, value, sizeof(hardware));
    419         }
    420     } else {
    421         /* in the emulator, export any kernel option with the
    422          * ro.kernel. prefix */
    423         char  buff[32];
    424         int   len = snprintf( buff, sizeof(buff), "ro.kernel.%s", name );
    425         if (len < (int)sizeof(buff)) {
    426             property_set( buff, value );
    427         }
    428     }
    429 }
    430 
    431 static void import_kernel_cmdline(int in_qemu)
    432 {
    433     char cmdline[1024];
    434     char *ptr;
    435     int fd;
    436 
    437     fd = open("/proc/cmdline", O_RDONLY);
    438     if (fd >= 0) {
    439         int n = read(fd, cmdline, 1023);
    440         if (n < 0) n = 0;
    441 
    442         /* get rid of trailing newline, it happens */
    443         if (n > 0 && cmdline[n-1] == '\n') n--;
    444 
    445         cmdline[n] = 0;
    446         close(fd);
    447     } else {
    448         cmdline[0] = 0;
    449     }
    450 
    451     ptr = cmdline;
    452     while (ptr && *ptr) {
    453         char *x = strchr(ptr, ' ');
    454         if (x != 0) *x++ = 0;
    455         import_kernel_nv(ptr, in_qemu);
    456         ptr = x;
    457     }
    458 
    459         /* don't expose the raw commandline to nonpriv processes */
    460     chmod("/proc/cmdline", 0440);
    461 }
    462 
    463 static struct command *get_first_command(struct action *act)
    464 {
    465     struct listnode *node;
    466     node = list_head(&act->commands);
    467     if (!node)
    468         return NULL;
    469 
    470     return node_to_item(node, struct command, clist);
    471 }
    472 
    473 static struct command *get_next_command(struct action *act, struct command *cmd)
    474 {
    475     struct listnode *node;
    476     node = cmd->clist.next;
    477     if (!node)
    478         return NULL;
    479     if (node == &act->commands)
    480         return NULL;
    481 
    482     return node_to_item(node, struct command, clist);
    483 }
    484 
    485 static int is_last_command(struct action *act, struct command *cmd)
    486 {
    487     return (list_tail(&act->commands) == &cmd->clist);
    488 }
    489 
    490 void execute_one_command(void)
    491 {
    492     int ret;
    493 
    494     if (!cur_action || !cur_command || is_last_command(cur_action, cur_command)) {
    495         cur_action = action_remove_queue_head();
    496         cur_command = NULL;
    497         if (!cur_action)
    498             return;
    499         INFO("processing action %p (%s)\n", cur_action, cur_action->name);
    500         cur_command = get_first_command(cur_action);
    501     } else {
    502         cur_command = get_next_command(cur_action, cur_command);
    503     }
    504 
    505     if (!cur_command)
    506         return;
    507 
    508     ret = cur_command->func(cur_command->nargs, cur_command->args);
    509     INFO("command '%s' r=%d\n", cur_command->args[0], ret);
    510 }
    511 
    512 static int wait_for_coldboot_done_action(int nargs, char **args)
    513 {
    514     int ret;
    515     INFO("wait for %s\n", coldboot_done);
    516     ret = wait_for_file(coldboot_done, COMMAND_RETRY_TIMEOUT);
    517     if (ret)
    518         ERROR("Timed out waiting for %s\n", coldboot_done);
    519     return ret;
    520 }
    521 
    522 static int property_init_action(int nargs, char **args)
    523 {
    524     INFO("property init\n");
    525     property_init();
    526     return 0;
    527 }
    528 
    529 static int keychord_init_action(int nargs, char **args)
    530 {
    531     keychord_init();
    532     return 0;
    533 }
    534 
    535 static int console_init_action(int nargs, char **args)
    536 {
    537     int fd;
    538     char tmp[PROP_VALUE_MAX];
    539 
    540     if (console[0]) {
    541         snprintf(tmp, sizeof(tmp), "/dev/%s", console);
    542         console_name = strdup(tmp);
    543     }
    544 
    545     fd = open(console_name, O_RDWR);
    546     if (fd >= 0)
    547         have_console = 1;
    548     close(fd);
    549 
    550     if( load_565rle_image(INIT_IMAGE_FILE) ) {
    551         fd = open("/dev/tty0", O_WRONLY);
    552         if (fd >= 0) {
    553             const char *msg;
    554                 msg = "\n"
    555             "\n"
    556             "\n"
    557             "\n"
    558             "\n"
    559             "\n"
    560             "\n"  // console is 40 cols x 30 lines
    561             "\n"
    562             "\n"
    563             "\n"
    564             "\n"
    565             "\n"
    566             "\n"
    567             "\n"
    568             "             A N D R O I D ";
    569             write(fd, msg, strlen(msg));
    570             close(fd);
    571         }
    572     }
    573     return 0;
    574 }
    575 
    576 static int set_init_properties_action(int nargs, char **args)
    577 {
    578     char tmp[PROP_VALUE_MAX];
    579 
    580     if (qemu[0])
    581         import_kernel_cmdline(1);
    582 
    583     if (!strcmp(bootmode,"factory"))
    584         property_set("ro.factorytest", "1");
    585     else if (!strcmp(bootmode,"factory2"))
    586         property_set("ro.factorytest", "2");
    587     else
    588         property_set("ro.factorytest", "0");
    589 
    590     property_set("ro.serialno", serialno[0] ? serialno : "");
    591     property_set("ro.bootmode", bootmode[0] ? bootmode : "unknown");
    592     property_set("ro.baseband", baseband[0] ? baseband : "unknown");
    593     property_set("ro.carrier", carrier[0] ? carrier : "unknown");
    594     property_set("ro.bootloader", bootloader[0] ? bootloader : "unknown");
    595 
    596     property_set("ro.hardware", hardware);
    597     snprintf(tmp, PROP_VALUE_MAX, "%d", revision);
    598     property_set("ro.revision", tmp);
    599     return 0;
    600 }
    601 
    602 static int property_service_init_action(int nargs, char **args)
    603 {
    604     /* read any property files on system or data and
    605      * fire up the property service.  This must happen
    606      * after the ro.foo properties are set above so
    607      * that /data/local.prop cannot interfere with them.
    608      */
    609     start_property_service();
    610     return 0;
    611 }
    612 
    613 static int signal_init_action(int nargs, char **args)
    614 {
    615     signal_init();
    616     return 0;
    617 }
    618 
    619 static int check_startup_action(int nargs, char **args)
    620 {
    621     /* make sure we actually have all the pieces we need */
    622     if ((get_property_set_fd() < 0) ||
    623         (get_signal_fd() < 0)) {
    624         ERROR("init startup failure\n");
    625         exit(1);
    626     }
    627     return 0;
    628 }
    629 
    630 static int queue_property_triggers_action(int nargs, char **args)
    631 {
    632     queue_all_property_triggers();
    633     /* enable property triggers */
    634     property_triggers_enabled = 1;
    635     return 0;
    636 }
    637 
    638 #if BOOTCHART
    639 static int bootchart_init_action(int nargs, char **args)
    640 {
    641     bootchart_count = bootchart_init();
    642     if (bootchart_count < 0) {
    643         ERROR("bootcharting init failure\n");
    644     } else if (bootchart_count > 0) {
    645         NOTICE("bootcharting started (period=%d ms)\n", bootchart_count*BOOTCHART_POLLING_MS);
    646     } else {
    647         NOTICE("bootcharting ignored\n");
    648     }
    649 }
    650 #endif
    651 
    652 int main(int argc, char **argv)
    653 {
    654     int fd_count = 0;
    655     struct pollfd ufds[4];
    656     char *tmpdev;
    657     char* debuggable;
    658     char tmp[32];
    659     int property_set_fd_init = 0;
    660     int signal_fd_init = 0;
    661     int keychord_fd_init = 0;
    662 
    663     if (!strcmp(basename(argv[0]), "ueventd"))
    664         return ueventd_main(argc, argv);
    665 
    666     /* clear the umask */
    667     umask(0);
    668 
    669         /* Get the basic filesystem setup we need put
    670          * together in the initramdisk on / and then we'll
    671          * let the rc file figure out the rest.
    672          */
    673     mkdir("/dev", 0755);
    674     mkdir("/proc", 0755);
    675     mkdir("/sys", 0755);
    676 
    677     mount("tmpfs", "/dev", "tmpfs", 0, "mode=0755");
    678     mkdir("/dev/pts", 0755);
    679     mkdir("/dev/socket", 0755);
    680     mount("devpts", "/dev/pts", "devpts", 0, NULL);
    681     mount("proc", "/proc", "proc", 0, NULL);
    682     mount("sysfs", "/sys", "sysfs", 0, NULL);
    683 
    684         /* We must have some place other than / to create the
    685          * device nodes for kmsg and null, otherwise we won't
    686          * be able to remount / read-only later on.
    687          * Now that tmpfs is mounted on /dev, we can actually
    688          * talk to the outside world.
    689          */
    690     open_devnull_stdio();
    691     log_init();
    692 
    693     INFO("reading config file\n");
    694     init_parse_config_file("/init.rc");
    695 
    696     /* pull the kernel commandline and ramdisk properties file in */
    697     import_kernel_cmdline(0);
    698 
    699     get_hardware_name(hardware, &revision);
    700     snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);
    701     init_parse_config_file(tmp);
    702 
    703     action_for_each_trigger("early-init", action_add_queue_tail);
    704 
    705     queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");
    706     queue_builtin_action(property_init_action, "property_init");
    707     queue_builtin_action(keychord_init_action, "keychord_init");
    708     queue_builtin_action(console_init_action, "console_init");
    709     queue_builtin_action(set_init_properties_action, "set_init_properties");
    710 
    711         /* execute all the boot actions to get us started */
    712     action_for_each_trigger("init", action_add_queue_tail);
    713     action_for_each_trigger("early-fs", action_add_queue_tail);
    714     action_for_each_trigger("fs", action_add_queue_tail);
    715     action_for_each_trigger("post-fs", action_add_queue_tail);
    716 
    717     queue_builtin_action(property_service_init_action, "property_service_init");
    718     queue_builtin_action(signal_init_action, "signal_init");
    719     queue_builtin_action(check_startup_action, "check_startup");
    720 
    721     /* execute all the boot actions to get us started */
    722     action_for_each_trigger("early-boot", action_add_queue_tail);
    723     action_for_each_trigger("boot", action_add_queue_tail);
    724 
    725         /* run all property triggers based on current state of the properties */
    726     queue_builtin_action(queue_property_triggers_action, "queue_propety_triggers");
    727 
    728 
    729 #if BOOTCHART
    730     queue_builtin_action(bootchart_init_action, "bootchart_init");
    731 #endif
    732 
    733     for(;;) {
    734         int nr, i, timeout = -1;
    735 
    736         execute_one_command();
    737         restart_processes();
    738 
    739         if (!property_set_fd_init && get_property_set_fd() > 0) {
    740             ufds[fd_count].fd = get_property_set_fd();
    741             ufds[fd_count].events = POLLIN;
    742             ufds[fd_count].revents = 0;
    743             fd_count++;
    744             property_set_fd_init = 1;
    745         }
    746         if (!signal_fd_init && get_signal_fd() > 0) {
    747             ufds[fd_count].fd = get_signal_fd();
    748             ufds[fd_count].events = POLLIN;
    749             ufds[fd_count].revents = 0;
    750             fd_count++;
    751             signal_fd_init = 1;
    752         }
    753         if (!keychord_fd_init && get_keychord_fd() > 0) {
    754             ufds[fd_count].fd = get_keychord_fd();
    755             ufds[fd_count].events = POLLIN;
    756             ufds[fd_count].revents = 0;
    757             fd_count++;
    758             keychord_fd_init = 1;
    759         }
    760 
    761         if (process_needs_restart) {
    762             timeout = (process_needs_restart - gettime()) * 1000;
    763             if (timeout < 0)
    764                 timeout = 0;
    765         }
    766 
    767         if (!action_queue_empty() || cur_action)
    768             timeout = 0;
    769 
    770 #if BOOTCHART
    771         if (bootchart_count > 0) {
    772             if (timeout < 0 || timeout > BOOTCHART_POLLING_MS)
    773                 timeout = BOOTCHART_POLLING_MS;
    774             if (bootchart_step() < 0 || --bootchart_count == 0) {
    775                 bootchart_finish();
    776                 bootchart_count = 0;
    777             }
    778         }
    779 #endif
    780 
    781         nr = poll(ufds, fd_count, timeout);
    782         if (nr <= 0)
    783             continue;
    784 
    785         for (i = 0; i < fd_count; i++) {
    786             if (ufds[i].revents == POLLIN) {
    787                 if (ufds[i].fd == get_property_set_fd())
    788                     handle_property_set_fd();
    789                 else if (ufds[i].fd == get_keychord_fd())
    790                     handle_keychord();
    791                 else if (ufds[i].fd == get_signal_fd())
    792                     handle_signal();
    793             }
    794         }
    795     }
    796 
    797     return 0;
    798 }
    799