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