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 <stdarg.h>
     18 #include <stdlib.h>
     19 #include <stdio.h>
     20 #include <string.h>
     21 #include <fcntl.h>
     22 #include <ctype.h>
     23 #include <errno.h>
     24 #include <time.h>
     25 
     26 #ifdef HAVE_SELINUX
     27 #include <selinux/label.h>
     28 #endif
     29 
     30 #include <sys/stat.h>
     31 #include <sys/types.h>
     32 #include <sys/socket.h>
     33 #include <sys/un.h>
     34 
     35 /* for ANDROID_SOCKET_* */
     36 #include <cutils/sockets.h>
     37 
     38 #include <private/android_filesystem_config.h>
     39 
     40 #include "init.h"
     41 #include "log.h"
     42 #include "util.h"
     43 
     44 /*
     45  * android_name_to_id - returns the integer uid/gid associated with the given
     46  * name, or -1U on error.
     47  */
     48 static unsigned int android_name_to_id(const char *name)
     49 {
     50     struct android_id_info *info = android_ids;
     51     unsigned int n;
     52 
     53     for (n = 0; n < android_id_count; n++) {
     54         if (!strcmp(info[n].name, name))
     55             return info[n].aid;
     56     }
     57 
     58     return -1U;
     59 }
     60 
     61 /*
     62  * decode_uid - decodes and returns the given string, which can be either the
     63  * numeric or name representation, into the integer uid or gid. Returns -1U on
     64  * error.
     65  */
     66 unsigned int decode_uid(const char *s)
     67 {
     68     unsigned int v;
     69 
     70     if (!s || *s == '\0')
     71         return -1U;
     72     if (isalpha(s[0]))
     73         return android_name_to_id(s);
     74 
     75     errno = 0;
     76     v = (unsigned int) strtoul(s, 0, 0);
     77     if (errno)
     78         return -1U;
     79     return v;
     80 }
     81 
     82 /*
     83  * create_socket - creates a Unix domain socket in ANDROID_SOCKET_DIR
     84  * ("/dev/socket") as dictated in init.rc. This socket is inherited by the
     85  * daemon. We communicate the file descriptor's value via the environment
     86  * variable ANDROID_SOCKET_ENV_PREFIX<name> ("ANDROID_SOCKET_foo").
     87  */
     88 int create_socket(const char *name, int type, mode_t perm, uid_t uid, gid_t gid)
     89 {
     90     struct sockaddr_un addr;
     91     int fd, ret;
     92 #ifdef HAVE_SELINUX
     93     char *secon;
     94 #endif
     95 
     96     fd = socket(PF_UNIX, type, 0);
     97     if (fd < 0) {
     98         ERROR("Failed to open socket '%s': %s\n", name, strerror(errno));
     99         return -1;
    100     }
    101 
    102     memset(&addr, 0 , sizeof(addr));
    103     addr.sun_family = AF_UNIX;
    104     snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s",
    105              name);
    106 
    107     ret = unlink(addr.sun_path);
    108     if (ret != 0 && errno != ENOENT) {
    109         ERROR("Failed to unlink old socket '%s': %s\n", name, strerror(errno));
    110         goto out_close;
    111     }
    112 
    113 #ifdef HAVE_SELINUX
    114     secon = NULL;
    115     if (sehandle) {
    116         ret = selabel_lookup(sehandle, &secon, addr.sun_path, S_IFSOCK);
    117         if (ret == 0)
    118             setfscreatecon(secon);
    119     }
    120 #endif
    121 
    122     ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
    123     if (ret) {
    124         ERROR("Failed to bind socket '%s': %s\n", name, strerror(errno));
    125         goto out_unlink;
    126     }
    127 
    128 #ifdef HAVE_SELINUX
    129     setfscreatecon(NULL);
    130     freecon(secon);
    131 #endif
    132 
    133     chown(addr.sun_path, uid, gid);
    134     chmod(addr.sun_path, perm);
    135 
    136     INFO("Created socket '%s' with mode '%o', user '%d', group '%d'\n",
    137          addr.sun_path, perm, uid, gid);
    138 
    139     return fd;
    140 
    141 out_unlink:
    142     unlink(addr.sun_path);
    143 out_close:
    144     close(fd);
    145     return -1;
    146 }
    147 
    148 /* reads a file, making sure it is terminated with \n \0 */
    149 void *read_file(const char *fn, unsigned *_sz)
    150 {
    151     char *data;
    152     int sz;
    153     int fd;
    154     struct stat sb;
    155 
    156     data = 0;
    157     fd = open(fn, O_RDONLY);
    158     if(fd < 0) return 0;
    159 
    160     // for security reasons, disallow world-writable
    161     // or group-writable files
    162     if (fstat(fd, &sb) < 0) {
    163         ERROR("fstat failed for '%s'\n", fn);
    164         goto oops;
    165     }
    166     if ((sb.st_mode & (S_IWGRP | S_IWOTH)) != 0) {
    167         ERROR("skipping insecure file '%s'\n", fn);
    168         goto oops;
    169     }
    170 
    171     sz = lseek(fd, 0, SEEK_END);
    172     if(sz < 0) goto oops;
    173 
    174     if(lseek(fd, 0, SEEK_SET) != 0) goto oops;
    175 
    176     data = (char*) malloc(sz + 2);
    177     if(data == 0) goto oops;
    178 
    179     if(read(fd, data, sz) != sz) goto oops;
    180     close(fd);
    181     data[sz] = '\n';
    182     data[sz+1] = 0;
    183     if(_sz) *_sz = sz;
    184     return data;
    185 
    186 oops:
    187     close(fd);
    188     if(data != 0) free(data);
    189     return 0;
    190 }
    191 
    192 #define MAX_MTD_PARTITIONS 16
    193 
    194 static struct {
    195     char name[16];
    196     int number;
    197 } mtd_part_map[MAX_MTD_PARTITIONS];
    198 
    199 static int mtd_part_count = -1;
    200 
    201 static void find_mtd_partitions(void)
    202 {
    203     int fd;
    204     char buf[1024];
    205     char *pmtdbufp;
    206     ssize_t pmtdsize;
    207     int r;
    208 
    209     fd = open("/proc/mtd", O_RDONLY);
    210     if (fd < 0)
    211         return;
    212 
    213     buf[sizeof(buf) - 1] = '\0';
    214     pmtdsize = read(fd, buf, sizeof(buf) - 1);
    215     pmtdbufp = buf;
    216     while (pmtdsize > 0) {
    217         int mtdnum, mtdsize, mtderasesize;
    218         char mtdname[16];
    219         mtdname[0] = '\0';
    220         mtdnum = -1;
    221         r = sscanf(pmtdbufp, "mtd%d: %x %x %15s",
    222                    &mtdnum, &mtdsize, &mtderasesize, mtdname);
    223         if ((r == 4) && (mtdname[0] == '"')) {
    224             char *x = strchr(mtdname + 1, '"');
    225             if (x) {
    226                 *x = 0;
    227             }
    228             INFO("mtd partition %d, %s\n", mtdnum, mtdname + 1);
    229             if (mtd_part_count < MAX_MTD_PARTITIONS) {
    230                 strcpy(mtd_part_map[mtd_part_count].name, mtdname + 1);
    231                 mtd_part_map[mtd_part_count].number = mtdnum;
    232                 mtd_part_count++;
    233             } else {
    234                 ERROR("too many mtd partitions\n");
    235             }
    236         }
    237         while (pmtdsize > 0 && *pmtdbufp != '\n') {
    238             pmtdbufp++;
    239             pmtdsize--;
    240         }
    241         if (pmtdsize > 0) {
    242             pmtdbufp++;
    243             pmtdsize--;
    244         }
    245     }
    246     close(fd);
    247 }
    248 
    249 int mtd_name_to_number(const char *name)
    250 {
    251     int n;
    252     if (mtd_part_count < 0) {
    253         mtd_part_count = 0;
    254         find_mtd_partitions();
    255     }
    256     for (n = 0; n < mtd_part_count; n++) {
    257         if (!strcmp(name, mtd_part_map[n].name)) {
    258             return mtd_part_map[n].number;
    259         }
    260     }
    261     return -1;
    262 }
    263 
    264 /*
    265  * gettime() - returns the time in seconds of the system's monotonic clock or
    266  * zero on error.
    267  */
    268 time_t gettime(void)
    269 {
    270     struct timespec ts;
    271     int ret;
    272 
    273     ret = clock_gettime(CLOCK_MONOTONIC, &ts);
    274     if (ret < 0) {
    275         ERROR("clock_gettime(CLOCK_MONOTONIC) failed: %s\n", strerror(errno));
    276         return 0;
    277     }
    278 
    279     return ts.tv_sec;
    280 }
    281 
    282 int mkdir_recursive(const char *pathname, mode_t mode)
    283 {
    284     char buf[128];
    285     const char *slash;
    286     const char *p = pathname;
    287     int width;
    288     int ret;
    289     struct stat info;
    290 
    291     while ((slash = strchr(p, '/')) != NULL) {
    292         width = slash - pathname;
    293         p = slash + 1;
    294         if (width < 0)
    295             break;
    296         if (width == 0)
    297             continue;
    298         if ((unsigned int)width > sizeof(buf) - 1) {
    299             ERROR("path too long for mkdir_recursive\n");
    300             return -1;
    301         }
    302         memcpy(buf, pathname, width);
    303         buf[width] = 0;
    304         if (stat(buf, &info) != 0) {
    305             ret = mkdir(buf, mode);
    306             if (ret && errno != EEXIST)
    307                 return ret;
    308         }
    309     }
    310     ret = mkdir(pathname, mode);
    311     if (ret && errno != EEXIST)
    312         return ret;
    313     return 0;
    314 }
    315 
    316 void sanitize(char *s)
    317 {
    318     if (!s)
    319         return;
    320     while (isalnum(*s))
    321         s++;
    322     *s = 0;
    323 }
    324 void make_link(const char *oldpath, const char *newpath)
    325 {
    326     int ret;
    327     char buf[256];
    328     char *slash;
    329     int width;
    330 
    331     slash = strrchr(newpath, '/');
    332     if (!slash)
    333         return;
    334     width = slash - newpath;
    335     if (width <= 0 || width > (int)sizeof(buf) - 1)
    336         return;
    337     memcpy(buf, newpath, width);
    338     buf[width] = 0;
    339     ret = mkdir_recursive(buf, 0755);
    340     if (ret)
    341         ERROR("Failed to create directory %s: %s (%d)\n", buf, strerror(errno), errno);
    342 
    343     ret = symlink(oldpath, newpath);
    344     if (ret && errno != EEXIST)
    345         ERROR("Failed to symlink %s to %s: %s (%d)\n", oldpath, newpath, strerror(errno), errno);
    346 }
    347 
    348 void remove_link(const char *oldpath, const char *newpath)
    349 {
    350     char path[256];
    351     ssize_t ret;
    352     ret = readlink(newpath, path, sizeof(path) - 1);
    353     if (ret <= 0)
    354         return;
    355     path[ret] = 0;
    356     if (!strcmp(path, oldpath))
    357         unlink(newpath);
    358 }
    359 
    360 int wait_for_file(const char *filename, int timeout)
    361 {
    362     struct stat info;
    363     time_t timeout_time = gettime() + timeout;
    364     int ret = -1;
    365 
    366     while (gettime() < timeout_time && ((ret = stat(filename, &info)) < 0))
    367         usleep(10000);
    368 
    369     return ret;
    370 }
    371 
    372 void open_devnull_stdio(void)
    373 {
    374     int fd;
    375     static const char *name = "/dev/__null__";
    376     if (mknod(name, S_IFCHR | 0600, (1 << 8) | 3) == 0) {
    377         fd = open(name, O_RDWR);
    378         unlink(name);
    379         if (fd >= 0) {
    380             dup2(fd, 0);
    381             dup2(fd, 1);
    382             dup2(fd, 2);
    383             if (fd > 2) {
    384                 close(fd);
    385             }
    386             return;
    387         }
    388     }
    389 
    390     exit(1);
    391 }
    392 
    393 void get_hardware_name(char *hardware, unsigned int *revision)
    394 {
    395     char data[1024];
    396     int fd, n;
    397     char *x, *hw, *rev;
    398 
    399     /* Hardware string was provided on kernel command line */
    400     if (hardware[0])
    401         return;
    402 
    403     fd = open("/proc/cpuinfo", O_RDONLY);
    404     if (fd < 0) return;
    405 
    406     n = read(fd, data, 1023);
    407     close(fd);
    408     if (n < 0) return;
    409 
    410     data[n] = 0;
    411     hw = strstr(data, "\nHardware");
    412     rev = strstr(data, "\nRevision");
    413 
    414     if (hw) {
    415         x = strstr(hw, ": ");
    416         if (x) {
    417             x += 2;
    418             n = 0;
    419             while (*x && *x != '\n') {
    420                 if (!isspace(*x))
    421                     hardware[n++] = tolower(*x);
    422                 x++;
    423                 if (n == 31) break;
    424             }
    425             hardware[n] = 0;
    426         }
    427     }
    428 
    429     if (rev) {
    430         x = strstr(rev, ": ");
    431         if (x) {
    432             *revision = strtoul(x + 2, 0, 16);
    433         }
    434     }
    435 }
    436 
    437 void import_kernel_cmdline(int in_qemu,
    438                            void (*import_kernel_nv)(char *name, int in_qemu))
    439 {
    440     char cmdline[1024];
    441     char *ptr;
    442     int fd;
    443 
    444     fd = open("/proc/cmdline", O_RDONLY);
    445     if (fd >= 0) {
    446         int n = read(fd, cmdline, 1023);
    447         if (n < 0) n = 0;
    448 
    449         /* get rid of trailing newline, it happens */
    450         if (n > 0 && cmdline[n-1] == '\n') n--;
    451 
    452         cmdline[n] = 0;
    453         close(fd);
    454     } else {
    455         cmdline[0] = 0;
    456     }
    457 
    458     ptr = cmdline;
    459     while (ptr && *ptr) {
    460         char *x = strchr(ptr, ' ');
    461         if (x != 0) *x++ = 0;
    462         import_kernel_nv(ptr, in_qemu);
    463         ptr = x;
    464     }
    465 }
    466