util.c revision ef3f7fa32b451bd6f180c4c1586a98cee41aa296
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 */
48static 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 */
66unsigned 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 */
88int 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
141out_unlink:
142    unlink(addr.sun_path);
143out_close:
144    close(fd);
145    return -1;
146}
147
148/* reads a file, making sure it is terminated with \n \0 */
149void *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
186oops:
187    close(fd);
188    if(data != 0) free(data);
189    return 0;
190}
191
192#define MAX_MTD_PARTITIONS 16
193
194static struct {
195    char name[16];
196    int number;
197} mtd_part_map[MAX_MTD_PARTITIONS];
198
199static int mtd_part_count = -1;
200
201static 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
249int 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 */
268time_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
282int 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 = make_dir(buf, mode);
306            if (ret && errno != EEXIST)
307                return ret;
308        }
309    }
310    ret = make_dir(pathname, mode);
311    if (ret && errno != EEXIST)
312        return ret;
313    return 0;
314}
315
316void sanitize(char *s)
317{
318    if (!s)
319        return;
320    while (isalnum(*s))
321        s++;
322    *s = 0;
323}
324void 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
348void 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
360int 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
372void 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
393void 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
437void 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
467int make_dir(const char *path, mode_t mode)
468{
469    int rc;
470
471#ifdef HAVE_SELINUX
472    char *secontext = NULL;
473
474    if (sehandle) {
475        selabel_lookup(sehandle, &secontext, path, mode);
476        setfscreatecon(secontext);
477    }
478#endif
479
480    rc = mkdir(path, mode);
481
482#ifdef HAVE_SELINUX
483    if (secontext) {
484        int save_errno = errno;
485        freecon(secontext);
486        setfscreatecon(NULL);
487        errno = save_errno;
488    }
489#endif
490    return rc;
491}
492
493int restorecon(const char *pathname)
494{
495#ifdef HAVE_SELINUX
496    char *secontext = NULL;
497    struct stat sb;
498    int i;
499
500    if (is_selinux_enabled() <= 0 || !sehandle)
501        return 0;
502
503    if (lstat(pathname, &sb) < 0)
504        return -errno;
505    if (selabel_lookup(sehandle, &secontext, pathname, sb.st_mode) < 0)
506        return -errno;
507    if (lsetfilecon(pathname, secontext) < 0) {
508        freecon(secontext);
509        return -errno;
510    }
511    freecon(secontext);
512#endif
513    return 0;
514}
515