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