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 <sys/types.h>
     18 #include <sys/stat.h>
     19 #include <fcntl.h>
     20 #include <unistd.h>
     21 #include <string.h>
     22 #include <stdio.h>
     23 #include <linux/kd.h>
     24 #include <errno.h>
     25 #include <sys/socket.h>
     26 #include <netinet/in.h>
     27 #include <linux/if.h>
     28 #include <arpa/inet.h>
     29 #include <stdlib.h>
     30 #include <sys/mount.h>
     31 #include <sys/resource.h>
     32 #include <linux/loop.h>
     33 #include <cutils/partition_utils.h>
     34 
     35 #include "init.h"
     36 #include "keywords.h"
     37 #include "property_service.h"
     38 #include "devices.h"
     39 #include "init_parser.h"
     40 #include "util.h"
     41 #include "log.h"
     42 
     43 #include <private/android_filesystem_config.h>
     44 
     45 void add_environment(const char *name, const char *value);
     46 
     47 extern int init_module(void *, unsigned long, const char *);
     48 
     49 static int write_file(const char *path, const char *value)
     50 {
     51     int fd, ret, len;
     52 
     53     fd = open(path, O_WRONLY|O_CREAT, 0622);
     54 
     55     if (fd < 0)
     56         return -errno;
     57 
     58     len = strlen(value);
     59 
     60     do {
     61         ret = write(fd, value, len);
     62     } while (ret < 0 && errno == EINTR);
     63 
     64     close(fd);
     65     if (ret < 0) {
     66         return -errno;
     67     } else {
     68         return 0;
     69     }
     70 }
     71 
     72 static int insmod(const char *filename, char *options)
     73 {
     74     void *module;
     75     unsigned size;
     76     int ret;
     77 
     78     module = read_file(filename, &size);
     79     if (!module)
     80         return -1;
     81 
     82     ret = init_module(module, size, options);
     83 
     84     free(module);
     85 
     86     return ret;
     87 }
     88 
     89 static int setkey(struct kbentry *kbe)
     90 {
     91     int fd, ret;
     92 
     93     fd = open("/dev/tty0", O_RDWR | O_SYNC);
     94     if (fd < 0)
     95         return -1;
     96 
     97     ret = ioctl(fd, KDSKBENT, kbe);
     98 
     99     close(fd);
    100     return ret;
    101 }
    102 
    103 static int __ifupdown(const char *interface, int up)
    104 {
    105     struct ifreq ifr;
    106     int s, ret;
    107 
    108     strlcpy(ifr.ifr_name, interface, IFNAMSIZ);
    109 
    110     s = socket(AF_INET, SOCK_DGRAM, 0);
    111     if (s < 0)
    112         return -1;
    113 
    114     ret = ioctl(s, SIOCGIFFLAGS, &ifr);
    115     if (ret < 0) {
    116         goto done;
    117     }
    118 
    119     if (up)
    120         ifr.ifr_flags |= IFF_UP;
    121     else
    122         ifr.ifr_flags &= ~IFF_UP;
    123 
    124     ret = ioctl(s, SIOCSIFFLAGS, &ifr);
    125 
    126 done:
    127     close(s);
    128     return ret;
    129 }
    130 
    131 static void service_start_if_not_disabled(struct service *svc)
    132 {
    133     if (!(svc->flags & SVC_DISABLED)) {
    134         service_start(svc, NULL);
    135     }
    136 }
    137 
    138 int do_chdir(int nargs, char **args)
    139 {
    140     chdir(args[1]);
    141     return 0;
    142 }
    143 
    144 int do_chroot(int nargs, char **args)
    145 {
    146     chroot(args[1]);
    147     return 0;
    148 }
    149 
    150 int do_class_start(int nargs, char **args)
    151 {
    152         /* Starting a class does not start services
    153          * which are explicitly disabled.  They must
    154          * be started individually.
    155          */
    156     service_for_each_class(args[1], service_start_if_not_disabled);
    157     return 0;
    158 }
    159 
    160 int do_class_stop(int nargs, char **args)
    161 {
    162     service_for_each_class(args[1], service_stop);
    163     return 0;
    164 }
    165 
    166 int do_class_reset(int nargs, char **args)
    167 {
    168     service_for_each_class(args[1], service_reset);
    169     return 0;
    170 }
    171 
    172 int do_domainname(int nargs, char **args)
    173 {
    174     return write_file("/proc/sys/kernel/domainname", args[1]);
    175 }
    176 
    177 int do_exec(int nargs, char **args)
    178 {
    179     return -1;
    180 }
    181 
    182 int do_export(int nargs, char **args)
    183 {
    184     add_environment(args[1], args[2]);
    185     return 0;
    186 }
    187 
    188 int do_hostname(int nargs, char **args)
    189 {
    190     return write_file("/proc/sys/kernel/hostname", args[1]);
    191 }
    192 
    193 int do_ifup(int nargs, char **args)
    194 {
    195     return __ifupdown(args[1], 1);
    196 }
    197 
    198 
    199 static int do_insmod_inner(int nargs, char **args, int opt_len)
    200 {
    201     char options[opt_len + 1];
    202     int i;
    203 
    204     options[0] = '\0';
    205     if (nargs > 2) {
    206         strcpy(options, args[2]);
    207         for (i = 3; i < nargs; ++i) {
    208             strcat(options, " ");
    209             strcat(options, args[i]);
    210         }
    211     }
    212 
    213     return insmod(args[1], options);
    214 }
    215 
    216 int do_insmod(int nargs, char **args)
    217 {
    218     int i;
    219     int size = 0;
    220 
    221     if (nargs > 2) {
    222         for (i = 2; i < nargs; ++i)
    223             size += strlen(args[i]) + 1;
    224     }
    225 
    226     return do_insmod_inner(nargs, args, size);
    227 }
    228 
    229 int do_mkdir(int nargs, char **args)
    230 {
    231     mode_t mode = 0755;
    232     int ret;
    233 
    234     /* mkdir <path> [mode] [owner] [group] */
    235 
    236     if (nargs >= 3) {
    237         mode = strtoul(args[2], 0, 8);
    238     }
    239 
    240     ret = mkdir(args[1], mode);
    241     /* chmod in case the directory already exists */
    242     if (ret == -1 && errno == EEXIST) {
    243         ret = chmod(args[1], mode);
    244     }
    245     if (ret == -1) {
    246         return -errno;
    247     }
    248 
    249     if (nargs >= 4) {
    250         uid_t uid = decode_uid(args[3]);
    251         gid_t gid = -1;
    252 
    253         if (nargs == 5) {
    254             gid = decode_uid(args[4]);
    255         }
    256 
    257         if (chown(args[1], uid, gid)) {
    258             return -errno;
    259         }
    260     }
    261 
    262     return 0;
    263 }
    264 
    265 static struct {
    266     const char *name;
    267     unsigned flag;
    268 } mount_flags[] = {
    269     { "noatime",    MS_NOATIME },
    270     { "nosuid",     MS_NOSUID },
    271     { "nodev",      MS_NODEV },
    272     { "nodiratime", MS_NODIRATIME },
    273     { "ro",         MS_RDONLY },
    274     { "rw",         0 },
    275     { "remount",    MS_REMOUNT },
    276     { "defaults",   0 },
    277     { 0,            0 },
    278 };
    279 
    280 #define DATA_MNT_POINT "/data"
    281 
    282 /* mount <type> <device> <path> <flags ...> <options> */
    283 int do_mount(int nargs, char **args)
    284 {
    285     char tmp[64];
    286     char *source, *target, *system;
    287     char *options = NULL;
    288     unsigned flags = 0;
    289     int n, i;
    290     int wait = 0;
    291 
    292     for (n = 4; n < nargs; n++) {
    293         for (i = 0; mount_flags[i].name; i++) {
    294             if (!strcmp(args[n], mount_flags[i].name)) {
    295                 flags |= mount_flags[i].flag;
    296                 break;
    297             }
    298         }
    299 
    300         if (!mount_flags[i].name) {
    301             if (!strcmp(args[n], "wait"))
    302                 wait = 1;
    303             /* if our last argument isn't a flag, wolf it up as an option string */
    304             else if (n + 1 == nargs)
    305                 options = args[n];
    306         }
    307     }
    308 
    309     system = args[1];
    310     source = args[2];
    311     target = args[3];
    312 
    313     if (!strncmp(source, "mtd@", 4)) {
    314         n = mtd_name_to_number(source + 4);
    315         if (n < 0) {
    316             return -1;
    317         }
    318 
    319         sprintf(tmp, "/dev/block/mtdblock%d", n);
    320 
    321         if (wait)
    322             wait_for_file(tmp, COMMAND_RETRY_TIMEOUT);
    323         if (mount(tmp, target, system, flags, options) < 0) {
    324             return -1;
    325         }
    326 
    327         goto exit_success;
    328     } else if (!strncmp(source, "loop@", 5)) {
    329         int mode, loop, fd;
    330         struct loop_info info;
    331 
    332         mode = (flags & MS_RDONLY) ? O_RDONLY : O_RDWR;
    333         fd = open(source + 5, mode);
    334         if (fd < 0) {
    335             return -1;
    336         }
    337 
    338         for (n = 0; ; n++) {
    339             sprintf(tmp, "/dev/block/loop%d", n);
    340             loop = open(tmp, mode);
    341             if (loop < 0) {
    342                 return -1;
    343             }
    344 
    345             /* if it is a blank loop device */
    346             if (ioctl(loop, LOOP_GET_STATUS, &info) < 0 && errno == ENXIO) {
    347                 /* if it becomes our loop device */
    348                 if (ioctl(loop, LOOP_SET_FD, fd) >= 0) {
    349                     close(fd);
    350 
    351                     if (mount(tmp, target, system, flags, options) < 0) {
    352                         ioctl(loop, LOOP_CLR_FD, 0);
    353                         close(loop);
    354                         return -1;
    355                     }
    356 
    357                     close(loop);
    358                     goto exit_success;
    359                 }
    360             }
    361 
    362             close(loop);
    363         }
    364 
    365         close(fd);
    366         ERROR("out of loopback devices");
    367         return -1;
    368     } else {
    369         if (wait)
    370             wait_for_file(source, COMMAND_RETRY_TIMEOUT);
    371         if (mount(source, target, system, flags, options) < 0) {
    372             /* If this fails, it may be an encrypted filesystem
    373              * or it could just be wiped.  If wiped, that will be
    374              * handled later in the boot process.
    375              * We only support encrypting /data.  Check
    376              * if we're trying to mount it, and if so,
    377              * assume it's encrypted, mount a tmpfs instead.
    378              * Then save the orig mount parms in properties
    379              * for vold to query when it mounts the real
    380              * encrypted /data.
    381              */
    382             if (!strcmp(target, DATA_MNT_POINT) && !partition_wiped(source)) {
    383                 const char *tmpfs_options;
    384 
    385                 tmpfs_options = property_get("ro.crypto.tmpfs_options");
    386 
    387                 if (mount("tmpfs", target, "tmpfs", MS_NOATIME | MS_NOSUID | MS_NODEV,
    388                     tmpfs_options) < 0) {
    389                     return -1;
    390                 }
    391 
    392                 /* Set the property that triggers the framework to do a minimal
    393                  * startup and ask the user for a password
    394                  */
    395                 property_set("ro.crypto.state", "encrypted");
    396                 property_set("vold.decrypt", "1");
    397             } else {
    398                 return -1;
    399             }
    400         }
    401 
    402         if (!strcmp(target, DATA_MNT_POINT)) {
    403             char fs_flags[32];
    404 
    405             /* Save the original mount options */
    406             property_set("ro.crypto.fs_type", system);
    407             property_set("ro.crypto.fs_real_blkdev", source);
    408             property_set("ro.crypto.fs_mnt_point", target);
    409             if (options) {
    410                 property_set("ro.crypto.fs_options", options);
    411             }
    412             snprintf(fs_flags, sizeof(fs_flags), "0x%8.8x", flags);
    413             property_set("ro.crypto.fs_flags", fs_flags);
    414         }
    415     }
    416 
    417 exit_success:
    418     /* If not running encrypted, then set the property saying we are
    419      * unencrypted, and also trigger the action for a nonencrypted system.
    420      */
    421     if (!strcmp(target, DATA_MNT_POINT)) {
    422         const char *prop;
    423 
    424         prop = property_get("ro.crypto.state");
    425         if (! prop) {
    426             prop = "notset";
    427         }
    428         if (strcmp(prop, "encrypted")) {
    429             property_set("ro.crypto.state", "unencrypted");
    430             action_for_each_trigger("nonencrypted", action_add_queue_tail);
    431         }
    432     }
    433 
    434     return 0;
    435 
    436 }
    437 
    438 int do_setkey(int nargs, char **args)
    439 {
    440     struct kbentry kbe;
    441     kbe.kb_table = strtoul(args[1], 0, 0);
    442     kbe.kb_index = strtoul(args[2], 0, 0);
    443     kbe.kb_value = strtoul(args[3], 0, 0);
    444     return setkey(&kbe);
    445 }
    446 
    447 int do_setprop(int nargs, char **args)
    448 {
    449     const char *name = args[1];
    450     const char *value = args[2];
    451 
    452     if (value[0] == '$') {
    453         /* Use the value of a system property if value starts with '$' */
    454         value++;
    455         if (value[0] != '$') {
    456             value = property_get(value);
    457             if (!value) {
    458                 ERROR("property %s has no value for assigning to %s\n", value, name);
    459                 return -EINVAL;
    460             }
    461         } /* else fall through to support double '$' prefix for setting properties
    462            * to string literals that start with '$'
    463            */
    464     }
    465 
    466     property_set(name, value);
    467     return 0;
    468 }
    469 
    470 int do_setrlimit(int nargs, char **args)
    471 {
    472     struct rlimit limit;
    473     int resource;
    474     resource = atoi(args[1]);
    475     limit.rlim_cur = atoi(args[2]);
    476     limit.rlim_max = atoi(args[3]);
    477     return setrlimit(resource, &limit);
    478 }
    479 
    480 int do_start(int nargs, char **args)
    481 {
    482     struct service *svc;
    483     svc = service_find_by_name(args[1]);
    484     if (svc) {
    485         service_start(svc, NULL);
    486     }
    487     return 0;
    488 }
    489 
    490 int do_stop(int nargs, char **args)
    491 {
    492     struct service *svc;
    493     svc = service_find_by_name(args[1]);
    494     if (svc) {
    495         service_stop(svc);
    496     }
    497     return 0;
    498 }
    499 
    500 int do_restart(int nargs, char **args)
    501 {
    502     struct service *svc;
    503     svc = service_find_by_name(args[1]);
    504     if (svc) {
    505         service_stop(svc);
    506         service_start(svc, NULL);
    507     }
    508     return 0;
    509 }
    510 
    511 int do_trigger(int nargs, char **args)
    512 {
    513     action_for_each_trigger(args[1], action_add_queue_tail);
    514     return 0;
    515 }
    516 
    517 int do_symlink(int nargs, char **args)
    518 {
    519     return symlink(args[1], args[2]);
    520 }
    521 
    522 int do_rm(int nargs, char **args)
    523 {
    524     return unlink(args[1]);
    525 }
    526 
    527 int do_rmdir(int nargs, char **args)
    528 {
    529     return rmdir(args[1]);
    530 }
    531 
    532 int do_sysclktz(int nargs, char **args)
    533 {
    534     struct timezone tz;
    535 
    536     if (nargs != 2)
    537         return -1;
    538 
    539     memset(&tz, 0, sizeof(tz));
    540     tz.tz_minuteswest = atoi(args[1]);
    541     if (settimeofday(NULL, &tz))
    542         return -1;
    543     return 0;
    544 }
    545 
    546 int do_write(int nargs, char **args)
    547 {
    548     const char *path = args[1];
    549     const char *value = args[2];
    550     if (value[0] == '$') {
    551         /* Write the value of a system property if value starts with '$' */
    552         value++;
    553         if (value[0] != '$') {
    554             value = property_get(value);
    555             if (!value) {
    556                 ERROR("property %s has no value for writing to %s\n", value, path);
    557                 return -EINVAL;
    558             }
    559         } /* else fall through to support double '$' prefix for writing
    560            * string literals that start with '$'
    561            */
    562     }
    563 
    564     return write_file(path, value);
    565 }
    566 
    567 int do_copy(int nargs, char **args)
    568 {
    569     char *buffer = NULL;
    570     int rc = 0;
    571     int fd1 = -1, fd2 = -1;
    572     struct stat info;
    573     int brtw, brtr;
    574     char *p;
    575 
    576     if (nargs != 3)
    577         return -1;
    578 
    579     if (stat(args[1], &info) < 0)
    580         return -1;
    581 
    582     if ((fd1 = open(args[1], O_RDONLY)) < 0)
    583         goto out_err;
    584 
    585     if ((fd2 = open(args[2], O_WRONLY|O_CREAT|O_TRUNC, 0660)) < 0)
    586         goto out_err;
    587 
    588     if (!(buffer = malloc(info.st_size)))
    589         goto out_err;
    590 
    591     p = buffer;
    592     brtr = info.st_size;
    593     while(brtr) {
    594         rc = read(fd1, p, brtr);
    595         if (rc < 0)
    596             goto out_err;
    597         if (rc == 0)
    598             break;
    599         p += rc;
    600         brtr -= rc;
    601     }
    602 
    603     p = buffer;
    604     brtw = info.st_size;
    605     while(brtw) {
    606         rc = write(fd2, p, brtw);
    607         if (rc < 0)
    608             goto out_err;
    609         if (rc == 0)
    610             break;
    611         p += rc;
    612         brtw -= rc;
    613     }
    614 
    615     rc = 0;
    616     goto out;
    617 out_err:
    618     rc = -1;
    619 out:
    620     if (buffer)
    621         free(buffer);
    622     if (fd1 >= 0)
    623         close(fd1);
    624     if (fd2 >= 0)
    625         close(fd2);
    626     return rc;
    627 }
    628 
    629 int do_chown(int nargs, char **args) {
    630     /* GID is optional. */
    631     if (nargs == 3) {
    632         if (chown(args[2], decode_uid(args[1]), -1) < 0)
    633             return -errno;
    634     } else if (nargs == 4) {
    635         if (chown(args[3], decode_uid(args[1]), decode_uid(args[2])))
    636             return -errno;
    637     } else {
    638         return -1;
    639     }
    640     return 0;
    641 }
    642 
    643 static mode_t get_mode(const char *s) {
    644     mode_t mode = 0;
    645     while (*s) {
    646         if (*s >= '0' && *s <= '7') {
    647             mode = (mode<<3) | (*s-'0');
    648         } else {
    649             return -1;
    650         }
    651         s++;
    652     }
    653     return mode;
    654 }
    655 
    656 int do_chmod(int nargs, char **args) {
    657     mode_t mode = get_mode(args[1]);
    658     if (chmod(args[2], mode) < 0) {
    659         return -errno;
    660     }
    661     return 0;
    662 }
    663 
    664 int do_loglevel(int nargs, char **args) {
    665     if (nargs == 2) {
    666         klog_set_level(atoi(args[1]));
    667         return 0;
    668     }
    669     return -1;
    670 }
    671 
    672 int do_load_persist_props(int nargs, char **args) {
    673     if (nargs == 1) {
    674         load_persist_props();
    675         return 0;
    676     }
    677     return -1;
    678 }
    679 
    680 int do_wait(int nargs, char **args)
    681 {
    682     if (nargs == 2) {
    683         return wait_for_file(args[1], COMMAND_RETRY_TIMEOUT);
    684     }
    685     return -1;
    686 }
    687