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 
     34 #include "init.h"
     35 #include "keywords.h"
     36 #include "property_service.h"
     37 #include "devices.h"
     38 
     39 #include <private/android_filesystem_config.h>
     40 
     41 void add_environment(const char *name, const char *value);
     42 
     43 extern int init_module(void *, unsigned long, const char *);
     44 
     45 static int write_file(const char *path, const char *value)
     46 {
     47     int fd, ret, len;
     48 
     49     fd = open(path, O_WRONLY|O_CREAT, 0622);
     50 
     51     if (fd < 0)
     52         return -errno;
     53 
     54     len = strlen(value);
     55 
     56     do {
     57         ret = write(fd, value, len);
     58     } while (ret < 0 && errno == EINTR);
     59 
     60     close(fd);
     61     if (ret < 0) {
     62         return -errno;
     63     } else {
     64         return 0;
     65     }
     66 }
     67 
     68 static int insmod(const char *filename, char *options)
     69 {
     70     void *module;
     71     unsigned size;
     72     int ret;
     73 
     74     module = read_file(filename, &size);
     75     if (!module)
     76         return -1;
     77 
     78     ret = init_module(module, size, options);
     79 
     80     free(module);
     81 
     82     return ret;
     83 }
     84 
     85 static int setkey(struct kbentry *kbe)
     86 {
     87     int fd, ret;
     88 
     89     fd = open("/dev/tty0", O_RDWR | O_SYNC);
     90     if (fd < 0)
     91         return -1;
     92 
     93     ret = ioctl(fd, KDSKBENT, kbe);
     94 
     95     close(fd);
     96     return ret;
     97 }
     98 
     99 static int __ifupdown(const char *interface, int up)
    100 {
    101     struct ifreq ifr;
    102     int s, ret;
    103 
    104     strlcpy(ifr.ifr_name, interface, IFNAMSIZ);
    105 
    106     s = socket(AF_INET, SOCK_DGRAM, 0);
    107     if (s < 0)
    108         return -1;
    109 
    110     ret = ioctl(s, SIOCGIFFLAGS, &ifr);
    111     if (ret < 0) {
    112         goto done;
    113     }
    114 
    115     if (up)
    116         ifr.ifr_flags |= IFF_UP;
    117     else
    118         ifr.ifr_flags &= ~IFF_UP;
    119 
    120     ret = ioctl(s, SIOCSIFFLAGS, &ifr);
    121 
    122 done:
    123     close(s);
    124     return ret;
    125 }
    126 
    127 static void service_start_if_not_disabled(struct service *svc)
    128 {
    129     if (!(svc->flags & SVC_DISABLED)) {
    130         service_start(svc, NULL);
    131     }
    132 }
    133 
    134 int do_chdir(int nargs, char **args)
    135 {
    136     chdir(args[1]);
    137     return 0;
    138 }
    139 
    140 int do_chroot(int nargs, char **args)
    141 {
    142     chroot(args[1]);
    143     return 0;
    144 }
    145 
    146 int do_class_start(int nargs, char **args)
    147 {
    148         /* Starting a class does not start services
    149          * which are explicitly disabled.  They must
    150          * be started individually.
    151          */
    152     service_for_each_class(args[1], service_start_if_not_disabled);
    153     return 0;
    154 }
    155 
    156 int do_class_stop(int nargs, char **args)
    157 {
    158     service_for_each_class(args[1], service_stop);
    159     return 0;
    160 }
    161 
    162 int do_domainname(int nargs, char **args)
    163 {
    164     return write_file("/proc/sys/kernel/domainname", args[1]);
    165 }
    166 
    167 int do_exec(int nargs, char **args)
    168 {
    169     return -1;
    170 }
    171 
    172 int do_export(int nargs, char **args)
    173 {
    174     add_environment(args[1], args[2]);
    175     return 0;
    176 }
    177 
    178 int do_hostname(int nargs, char **args)
    179 {
    180     return write_file("/proc/sys/kernel/hostname", args[1]);
    181 }
    182 
    183 int do_ifup(int nargs, char **args)
    184 {
    185     return __ifupdown(args[1], 1);
    186 }
    187 
    188 
    189 static int do_insmod_inner(int nargs, char **args, int opt_len)
    190 {
    191     char options[opt_len + 1];
    192     int i;
    193 
    194     options[0] = '\0';
    195     if (nargs > 2) {
    196         strcpy(options, args[2]);
    197         for (i = 3; i < nargs; ++i) {
    198             strcat(options, " ");
    199             strcat(options, args[i]);
    200         }
    201     }
    202 
    203     return insmod(args[1], options);
    204 }
    205 
    206 int do_insmod(int nargs, char **args)
    207 {
    208     int i;
    209     int size = 0;
    210 
    211     if (nargs > 2) {
    212         for (i = 2; i < nargs; ++i)
    213             size += strlen(args[i]) + 1;
    214     }
    215 
    216     return do_insmod_inner(nargs, args, size);
    217 }
    218 
    219 int do_import(int nargs, char **args)
    220 {
    221     return parse_config_file(args[1]);
    222 }
    223 
    224 int do_mkdir(int nargs, char **args)
    225 {
    226     mode_t mode = 0755;
    227 
    228     /* mkdir <path> [mode] [owner] [group] */
    229 
    230     if (nargs >= 3) {
    231         mode = strtoul(args[2], 0, 8);
    232     }
    233 
    234     if (mkdir(args[1], mode)) {
    235         return -errno;
    236     }
    237 
    238     if (nargs >= 4) {
    239         uid_t uid = decode_uid(args[3]);
    240         gid_t gid = -1;
    241 
    242         if (nargs == 5) {
    243             gid = decode_uid(args[4]);
    244         }
    245 
    246         if (chown(args[1], uid, gid)) {
    247             return -errno;
    248         }
    249     }
    250 
    251     return 0;
    252 }
    253 
    254 static struct {
    255     const char *name;
    256     unsigned flag;
    257 } mount_flags[] = {
    258     { "noatime",    MS_NOATIME },
    259     { "nosuid",     MS_NOSUID },
    260     { "nodev",      MS_NODEV },
    261     { "nodiratime", MS_NODIRATIME },
    262     { "ro",         MS_RDONLY },
    263     { "rw",         0 },
    264     { "remount",    MS_REMOUNT },
    265     { "defaults",   0 },
    266     { 0,            0 },
    267 };
    268 
    269 /* mount <type> <device> <path> <flags ...> <options> */
    270 int do_mount(int nargs, char **args)
    271 {
    272     char tmp[64];
    273     char *source, *target, *system;
    274     char *options = NULL;
    275     unsigned flags = 0;
    276     int n, i;
    277 
    278     for (n = 4; n < nargs; n++) {
    279         for (i = 0; mount_flags[i].name; i++) {
    280             if (!strcmp(args[n], mount_flags[i].name)) {
    281                 flags |= mount_flags[i].flag;
    282                 break;
    283             }
    284         }
    285 
    286         /* if our last argument isn't a flag, wolf it up as an option string */
    287         if (n + 1 == nargs && !mount_flags[i].name)
    288             options = args[n];
    289     }
    290 
    291     system = args[1];
    292     source = args[2];
    293     target = args[3];
    294 
    295     if (!strncmp(source, "mtd@", 4)) {
    296         n = mtd_name_to_number(source + 4);
    297         if (n < 0) {
    298             return -1;
    299         }
    300 
    301         sprintf(tmp, "/dev/block/mtdblock%d", n);
    302 
    303         if (mount(tmp, target, system, flags, options) < 0) {
    304             return -1;
    305         }
    306 
    307         return 0;
    308     } else if (!strncmp(source, "loop@", 5)) {
    309         int mode, loop, fd;
    310         struct loop_info info;
    311 
    312         mode = (flags & MS_RDONLY) ? O_RDONLY : O_RDWR;
    313         fd = open(source + 5, mode);
    314         if (fd < 0) {
    315             return -1;
    316         }
    317 
    318         for (n = 0; ; n++) {
    319             sprintf(tmp, "/dev/block/loop%d", n);
    320             loop = open(tmp, mode);
    321             if (loop < 0) {
    322                 return -1;
    323             }
    324 
    325             /* if it is a blank loop device */
    326             if (ioctl(loop, LOOP_GET_STATUS, &info) < 0 && errno == ENXIO) {
    327                 /* if it becomes our loop device */
    328                 if (ioctl(loop, LOOP_SET_FD, fd) >= 0) {
    329                     close(fd);
    330 
    331                     if (mount(tmp, target, system, flags, options) < 0) {
    332                         ioctl(loop, LOOP_CLR_FD, 0);
    333                         close(loop);
    334                         return -1;
    335                     }
    336 
    337                     close(loop);
    338                     return 0;
    339                 }
    340             }
    341 
    342             close(loop);
    343         }
    344 
    345         close(fd);
    346         ERROR("out of loopback devices");
    347         return -1;
    348     } else {
    349         if (mount(source, target, system, flags, options) < 0) {
    350             return -1;
    351         }
    352 
    353         return 0;
    354     }
    355 }
    356 
    357 int do_setkey(int nargs, char **args)
    358 {
    359     struct kbentry kbe;
    360     kbe.kb_table = strtoul(args[1], 0, 0);
    361     kbe.kb_index = strtoul(args[2], 0, 0);
    362     kbe.kb_value = strtoul(args[3], 0, 0);
    363     return setkey(&kbe);
    364 }
    365 
    366 int do_setprop(int nargs, char **args)
    367 {
    368     property_set(args[1], args[2]);
    369     return 0;
    370 }
    371 
    372 int do_setrlimit(int nargs, char **args)
    373 {
    374     struct rlimit limit;
    375     int resource;
    376     resource = atoi(args[1]);
    377     limit.rlim_cur = atoi(args[2]);
    378     limit.rlim_max = atoi(args[3]);
    379     return setrlimit(resource, &limit);
    380 }
    381 
    382 int do_start(int nargs, char **args)
    383 {
    384     struct service *svc;
    385     svc = service_find_by_name(args[1]);
    386     if (svc) {
    387         service_start(svc, NULL);
    388     }
    389     return 0;
    390 }
    391 
    392 int do_stop(int nargs, char **args)
    393 {
    394     struct service *svc;
    395     svc = service_find_by_name(args[1]);
    396     if (svc) {
    397         service_stop(svc);
    398     }
    399     return 0;
    400 }
    401 
    402 int do_restart(int nargs, char **args)
    403 {
    404     struct service *svc;
    405     svc = service_find_by_name(args[1]);
    406     if (svc) {
    407         service_stop(svc);
    408         service_start(svc, NULL);
    409     }
    410     return 0;
    411 }
    412 
    413 int do_trigger(int nargs, char **args)
    414 {
    415     action_for_each_trigger(args[1], action_add_queue_tail);
    416     drain_action_queue();
    417     return 0;
    418 }
    419 
    420 int do_symlink(int nargs, char **args)
    421 {
    422     return symlink(args[1], args[2]);
    423 }
    424 
    425 int do_sysclktz(int nargs, char **args)
    426 {
    427     struct timezone tz;
    428 
    429     if (nargs != 2)
    430         return -1;
    431 
    432     memset(&tz, 0, sizeof(tz));
    433     tz.tz_minuteswest = atoi(args[1]);
    434     if (settimeofday(NULL, &tz))
    435         return -1;
    436     return 0;
    437 }
    438 
    439 int do_write(int nargs, char **args)
    440 {
    441     return write_file(args[1], args[2]);
    442 }
    443 
    444 int do_copy(int nargs, char **args)
    445 {
    446     char *buffer = NULL;
    447     int rc = 0;
    448     int fd1 = -1, fd2 = -1;
    449     struct stat info;
    450     int brtw, brtr;
    451     char *p;
    452 
    453     if (nargs != 3)
    454         return -1;
    455 
    456     if (stat(args[1], &info) < 0)
    457         return -1;
    458 
    459     if ((fd1 = open(args[1], O_RDONLY)) < 0)
    460         goto out_err;
    461 
    462     if ((fd2 = open(args[2], O_WRONLY|O_CREAT|O_TRUNC, 0660)) < 0)
    463         goto out_err;
    464 
    465     if (!(buffer = malloc(info.st_size)))
    466         goto out_err;
    467 
    468     p = buffer;
    469     brtr = info.st_size;
    470     while(brtr) {
    471         rc = read(fd1, p, brtr);
    472         if (rc < 0)
    473             goto out_err;
    474         if (rc == 0)
    475             break;
    476         p += rc;
    477         brtr -= rc;
    478     }
    479 
    480     p = buffer;
    481     brtw = info.st_size;
    482     while(brtw) {
    483         rc = write(fd2, p, brtw);
    484         if (rc < 0)
    485             goto out_err;
    486         if (rc == 0)
    487             break;
    488         p += rc;
    489         brtw -= rc;
    490     }
    491 
    492     rc = 0;
    493     goto out;
    494 out_err:
    495     rc = -1;
    496 out:
    497     if (buffer)
    498         free(buffer);
    499     if (fd1 >= 0)
    500         close(fd1);
    501     if (fd2 >= 0)
    502         close(fd2);
    503     return rc;
    504 }
    505 
    506 int do_chown(int nargs, char **args) {
    507     /* GID is optional. */
    508     if (nargs == 3) {
    509         if (chown(args[2], decode_uid(args[1]), -1) < 0)
    510             return -errno;
    511     } else if (nargs == 4) {
    512         if (chown(args[3], decode_uid(args[1]), decode_uid(args[2])))
    513             return -errno;
    514     } else {
    515         return -1;
    516     }
    517     return 0;
    518 }
    519 
    520 static mode_t get_mode(const char *s) {
    521     mode_t mode = 0;
    522     while (*s) {
    523         if (*s >= '0' && *s <= '7') {
    524             mode = (mode<<3) | (*s-'0');
    525         } else {
    526             return -1;
    527         }
    528         s++;
    529     }
    530     return mode;
    531 }
    532 
    533 int do_chmod(int nargs, char **args) {
    534     mode_t mode = get_mode(args[1]);
    535     if (chmod(args[2], mode) < 0) {
    536         return -errno;
    537     }
    538     return 0;
    539 }
    540 
    541 int do_loglevel(int nargs, char **args) {
    542     if (nargs == 2) {
    543         log_set_level(atoi(args[1]));
    544         return 0;
    545     }
    546     return -1;
    547 }
    548 
    549 int do_device(int nargs, char **args) {
    550     int len;
    551     char tmp[64];
    552     char *source = args[1];
    553     int prefix = 0;
    554 
    555     if (nargs != 5)
    556         return -1;
    557     /* Check for wildcard '*' at the end which indicates a prefix. */
    558     len = strlen(args[1]) - 1;
    559     if (args[1][len] == '*') {
    560         args[1][len] = '\0';
    561         prefix = 1;
    562     }
    563     /* If path starts with mtd@ lookup the mount number. */
    564     if (!strncmp(source, "mtd@", 4)) {
    565         int n = mtd_name_to_number(source + 4);
    566         if (n >= 0) {
    567             snprintf(tmp, sizeof(tmp), "/dev/mtd/mtd%d", n);
    568             source = tmp;
    569         }
    570     }
    571     add_devperms_partners(source, get_mode(args[2]), decode_uid(args[3]),
    572                           decode_uid(args[4]), prefix);
    573     return 0;
    574 }
    575