builtins.c revision 4f6e8d7a00cbeda1e70cc15be9c4af1018bdad53
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
33#include "init.h"
34#include "keywords.h"
35#include "property_service.h"
36#include "devices.h"
37
38#include <private/android_filesystem_config.h>
39
40void add_environment(const char *name, const char *value);
41
42extern int init_module(void *, unsigned long, const char *);
43
44static int write_file(const char *path, const char *value)
45{
46    int fd, ret, len;
47
48    fd = open(path, O_WRONLY|O_CREAT, 0622);
49
50    if (fd < 0)
51        return -1;
52
53    len = strlen(value);
54
55    do {
56        ret = write(fd, value, len);
57    } while (ret < 0 && errno == EINTR);
58
59    close(fd);
60    if (ret < 0) {
61        return -1;
62    } else {
63        return 0;
64    }
65}
66
67static int insmod(const char *filename)
68{
69    void *module;
70    unsigned size;
71    int ret;
72
73    module = read_file(filename, &size);
74    if (!module)
75        return -1;
76
77    ret = init_module(module, size, "");
78
79    free(module);
80
81    return ret;
82}
83
84static int setkey(struct kbentry *kbe)
85{
86    int fd, ret;
87
88    fd = open("/dev/tty0", O_RDWR | O_SYNC);
89    if (fd < 0)
90        return -1;
91
92    ret = ioctl(fd, KDSKBENT, kbe);
93
94    close(fd);
95    return ret;
96}
97
98static int __ifupdown(const char *interface, int up)
99{
100    struct ifreq ifr;
101    int s, ret;
102
103    strlcpy(ifr.ifr_name, interface, IFNAMSIZ);
104
105    s = socket(AF_INET, SOCK_DGRAM, 0);
106    if (s < 0)
107        return -1;
108
109    ret = ioctl(s, SIOCGIFFLAGS, &ifr);
110    if (ret < 0) {
111        goto done;
112    }
113
114    if (up)
115        ifr.ifr_flags |= IFF_UP;
116    else
117        ifr.ifr_flags &= ~IFF_UP;
118
119    ret = ioctl(s, SIOCSIFFLAGS, &ifr);
120
121done:
122    close(s);
123    return ret;
124}
125
126static void service_start_if_not_disabled(struct service *svc)
127{
128    if (!(svc->flags & SVC_DISABLED)) {
129        service_start(svc);
130    }
131}
132
133int do_class_start(int nargs, char **args)
134{
135        /* Starting a class does not start services
136         * which are explicitly disabled.  They must
137         * be started individually.
138         */
139    service_for_each_class(args[1], service_start_if_not_disabled);
140    return 0;
141}
142
143int do_class_stop(int nargs, char **args)
144{
145    service_for_each_class(args[1], service_stop);
146    return 0;
147}
148
149int do_domainname(int nargs, char **args)
150{
151    return write_file("/proc/sys/kernel/domainname", args[1]);
152}
153
154int do_exec(int nargs, char **args)
155{
156    return -1;
157}
158
159int do_export(int nargs, char **args)
160{
161    add_environment(args[1], args[2]);
162    return 0;
163}
164
165int do_hostname(int nargs, char **args)
166{
167    return write_file("/proc/sys/kernel/hostname", args[1]);
168}
169
170int do_ifup(int nargs, char **args)
171{
172    return __ifupdown(args[1], 1);
173}
174
175int do_insmod(int nargs, char **args)
176{
177    return insmod(args[1]);
178}
179
180int do_import(int nargs, char **args)
181{
182    return -1;
183}
184
185int do_mkdir(int nargs, char **args)
186{
187    mode_t mode = 0755;
188
189    /* mkdir <path> [mode] [owner] [group] */
190
191    if (nargs >= 3) {
192        mode = strtoul(args[2], 0, 8);
193    }
194
195    if (mkdir(args[1], mode)) {
196        return -errno;
197    }
198
199    if (nargs >= 4) {
200        uid_t uid = decode_uid(args[3]);
201        gid_t gid = -1;
202
203        if (nargs == 5) {
204            gid = decode_uid(args[4]);
205        }
206
207        if (chown(args[1], uid, gid)) {
208            return -errno;
209        }
210    }
211
212    return 0;
213}
214
215static struct {
216    const char *name;
217    unsigned flag;
218} mount_flags[] = {
219    { "noatime",    MS_NOATIME },
220    { "nosuid",     MS_NOSUID },
221    { "nodev",      MS_NODEV },
222    { "nodiratime", MS_NODIRATIME },
223    { "ro",         MS_RDONLY },
224    { "rw",         0 },
225    { "remount",    MS_REMOUNT },
226    { "defaults",   0 },
227    { 0,            0 },
228};
229
230/* mount <type> <device> <path> <flags ...> <options> */
231int do_mount(int nargs, char **args)
232{
233    char tmp[64];
234    char *source;
235    char *options = NULL;
236    unsigned flags = 0;
237    int n, i;
238
239    for (n = 4; n < nargs; n++) {
240        for (i = 0; mount_flags[i].name; i++) {
241            if (!strcmp(args[n], mount_flags[i].name)) {
242                flags |= mount_flags[i].flag;
243                break;
244            }
245        }
246
247        /* if our last argument isn't a flag, wolf it up as an option string */
248        if (n + 1 == nargs && !mount_flags[i].name)
249            options = args[n];
250    }
251
252    source = args[2];
253    if (!strncmp(source, "mtd@", 4)) {
254        n = mtd_name_to_number(source + 4);
255        if (n >= 0) {
256            sprintf(tmp, "/dev/block/mtdblock%d", n);
257            source = tmp;
258        }
259    }
260    return mount(source, args[3], args[1], flags, options);
261}
262
263int do_setkey(int nargs, char **args)
264{
265    struct kbentry kbe;
266    kbe.kb_table = strtoul(args[1], 0, 0);
267    kbe.kb_index = strtoul(args[2], 0, 0);
268    kbe.kb_value = strtoul(args[3], 0, 0);
269    return setkey(&kbe);
270}
271
272int do_setprop(int nargs, char **args)
273{
274    property_set(args[1], args[2]);
275    return 0;
276}
277
278int do_setrlimit(int nargs, char **args)
279{
280    struct rlimit limit;
281    int resource;
282    resource = atoi(args[1]);
283    limit.rlim_cur = atoi(args[2]);
284    limit.rlim_max = atoi(args[3]);
285    return setrlimit(resource, &limit);
286}
287
288int do_start(int nargs, char **args)
289{
290    struct service *svc;
291    svc = service_find_by_name(args[1]);
292    if (svc) {
293        service_start(svc);
294    }
295    return 0;
296}
297
298int do_stop(int nargs, char **args)
299{
300    struct service *svc;
301    svc = service_find_by_name(args[1]);
302    if (svc) {
303        service_stop(svc);
304    }
305    return 0;
306}
307
308int do_restart(int nargs, char **args)
309{
310    struct service *svc;
311    svc = service_find_by_name(args[1]);
312    if (svc) {
313        service_stop(svc);
314        service_start(svc);
315    }
316    return 0;
317}
318
319int do_trigger(int nargs, char **args)
320{
321    return 0;
322}
323
324int do_symlink(int nargs, char **args)
325{
326    return symlink(args[1], args[2]);
327}
328
329int do_write(int nargs, char **args)
330{
331    return write_file(args[1], args[2]);
332}
333
334int do_chown(int nargs, char **args) {
335    /* GID is optional. */
336    if (nargs == 3) {
337        if (chown(args[2], decode_uid(args[1]), -1) < 0)
338            return -errno;
339    } else if (nargs == 4) {
340        if (chown(args[3], decode_uid(args[1]), decode_uid(args[2])))
341            return -errno;
342    } else {
343        return -1;
344    }
345    return 0;
346}
347
348static mode_t get_mode(const char *s) {
349    mode_t mode = 0;
350    while (*s) {
351        if (*s >= '0' && *s <= '7') {
352            mode = (mode<<3) | (*s-'0');
353        } else {
354            return -1;
355        }
356        s++;
357    }
358    return mode;
359}
360
361int do_chmod(int nargs, char **args) {
362    mode_t mode = get_mode(args[1]);
363    if (chmod(args[2], mode) < 0) {
364        return -errno;
365    }
366    return 0;
367}
368
369int do_loglevel(int nargs, char **args) {
370    if (nargs == 2) {
371        log_set_level(atoi(args[1]));
372        return 0;
373    }
374    return -1;
375}
376
377int do_device(int nargs, char **args) {
378    int len;
379    char tmp[64];
380    char *source = args[1];
381    int prefix = 0;
382
383    if (nargs != 5)
384        return -1;
385    /* Check for wildcard '*' at the end which indicates a prefix. */
386    len = strlen(args[1]) - 1;
387    if (args[1][len] == '*') {
388        args[1][len] = '\0';
389        prefix = 1;
390    }
391    /* If path starts with mtd@ lookup the mount number. */
392    if (!strncmp(source, "mtd@", 4)) {
393        int n = mtd_name_to_number(source + 4);
394        if (n >= 0) {
395            snprintf(tmp, sizeof(tmp), "/dev/mtd/mtd%d", n);
396            source = tmp;
397        }
398    }
399    add_devperms_partners(source, get_mode(args[2]), decode_uid(args[3]),
400                          decode_uid(args[4]), prefix);
401    return 0;
402}
403