builtins.c revision 7bc6e9ebe4783d5fbae17d7249cb80e997531598
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#include <linux/loop.h>
33#include <cutils/partition_utils.h>
34
35#include "init.h"
36#include "keywords.h"
37#include "property_service.h"
38#include "devices.h"
39#include "init_parser.h"
40#include "util.h"
41#include "log.h"
42
43#include <private/android_filesystem_config.h>
44
45void add_environment(const char *name, const char *value);
46
47extern int init_module(void *, unsigned long, const char *);
48
49static int write_file(const char *path, const char *value)
50{
51    int fd, ret, len;
52
53    fd = open(path, O_WRONLY|O_CREAT, 0622);
54
55    if (fd < 0)
56        return -errno;
57
58    len = strlen(value);
59
60    do {
61        ret = write(fd, value, len);
62    } while (ret < 0 && errno == EINTR);
63
64    close(fd);
65    if (ret < 0) {
66        return -errno;
67    } else {
68        return 0;
69    }
70}
71
72static int insmod(const char *filename, char *options)
73{
74    void *module;
75    unsigned size;
76    int ret;
77
78    module = read_file(filename, &size);
79    if (!module)
80        return -1;
81
82    ret = init_module(module, size, options);
83
84    free(module);
85
86    return ret;
87}
88
89static int setkey(struct kbentry *kbe)
90{
91    int fd, ret;
92
93    fd = open("/dev/tty0", O_RDWR | O_SYNC);
94    if (fd < 0)
95        return -1;
96
97    ret = ioctl(fd, KDSKBENT, kbe);
98
99    close(fd);
100    return ret;
101}
102
103static int __ifupdown(const char *interface, int up)
104{
105    struct ifreq ifr;
106    int s, ret;
107
108    strlcpy(ifr.ifr_name, interface, IFNAMSIZ);
109
110    s = socket(AF_INET, SOCK_DGRAM, 0);
111    if (s < 0)
112        return -1;
113
114    ret = ioctl(s, SIOCGIFFLAGS, &ifr);
115    if (ret < 0) {
116        goto done;
117    }
118
119    if (up)
120        ifr.ifr_flags |= IFF_UP;
121    else
122        ifr.ifr_flags &= ~IFF_UP;
123
124    ret = ioctl(s, SIOCSIFFLAGS, &ifr);
125
126done:
127    close(s);
128    return ret;
129}
130
131static void service_start_if_not_disabled(struct service *svc)
132{
133    if (!(svc->flags & SVC_DISABLED)) {
134        service_start(svc, NULL);
135    }
136}
137
138int do_chdir(int nargs, char **args)
139{
140    chdir(args[1]);
141    return 0;
142}
143
144int do_chroot(int nargs, char **args)
145{
146    chroot(args[1]);
147    return 0;
148}
149
150int do_class_start(int nargs, char **args)
151{
152        /* Starting a class does not start services
153         * which are explicitly disabled.  They must
154         * be started individually.
155         */
156    service_for_each_class(args[1], service_start_if_not_disabled);
157    return 0;
158}
159
160int do_class_stop(int nargs, char **args)
161{
162    service_for_each_class(args[1], service_stop);
163    return 0;
164}
165
166int do_class_reset(int nargs, char **args)
167{
168    service_for_each_class(args[1], service_reset);
169    return 0;
170}
171
172int do_domainname(int nargs, char **args)
173{
174    return write_file("/proc/sys/kernel/domainname", args[1]);
175}
176
177int do_exec(int nargs, char **args)
178{
179    return -1;
180}
181
182int do_export(int nargs, char **args)
183{
184    add_environment(args[1], args[2]);
185    return 0;
186}
187
188int do_hostname(int nargs, char **args)
189{
190    return write_file("/proc/sys/kernel/hostname", args[1]);
191}
192
193int do_ifup(int nargs, char **args)
194{
195    return __ifupdown(args[1], 1);
196}
197
198
199static int do_insmod_inner(int nargs, char **args, int opt_len)
200{
201    char options[opt_len + 1];
202    int i;
203
204    options[0] = '\0';
205    if (nargs > 2) {
206        strcpy(options, args[2]);
207        for (i = 3; i < nargs; ++i) {
208            strcat(options, " ");
209            strcat(options, args[i]);
210        }
211    }
212
213    return insmod(args[1], options);
214}
215
216int do_insmod(int nargs, char **args)
217{
218    int i;
219    int size = 0;
220
221    if (nargs > 2) {
222        for (i = 2; i < nargs; ++i)
223            size += strlen(args[i]) + 1;
224    }
225
226    return do_insmod_inner(nargs, args, size);
227}
228
229int do_import(int nargs, char **args)
230{
231    return init_parse_config_file(args[1]);
232}
233
234int do_mkdir(int nargs, char **args)
235{
236    mode_t mode = 0755;
237
238    /* mkdir <path> [mode] [owner] [group] */
239
240    if (nargs >= 3) {
241        mode = strtoul(args[2], 0, 8);
242    }
243
244    if (mkdir(args[1], mode)) {
245        return -errno;
246    }
247
248    if (nargs >= 4) {
249        uid_t uid = decode_uid(args[3]);
250        gid_t gid = -1;
251
252        if (nargs == 5) {
253            gid = decode_uid(args[4]);
254        }
255
256        if (chown(args[1], uid, gid)) {
257            return -errno;
258        }
259    }
260
261    return 0;
262}
263
264static struct {
265    const char *name;
266    unsigned flag;
267} mount_flags[] = {
268    { "noatime",    MS_NOATIME },
269    { "nosuid",     MS_NOSUID },
270    { "nodev",      MS_NODEV },
271    { "nodiratime", MS_NODIRATIME },
272    { "ro",         MS_RDONLY },
273    { "rw",         0 },
274    { "remount",    MS_REMOUNT },
275    { "defaults",   0 },
276    { 0,            0 },
277};
278
279#define DATA_MNT_POINT "/data"
280
281/* mount <type> <device> <path> <flags ...> <options> */
282int do_mount(int nargs, char **args)
283{
284    char tmp[64];
285    char *source, *target, *system;
286    char *options = NULL;
287    unsigned flags = 0;
288    int n, i;
289    int wait = 0;
290
291    for (n = 4; n < nargs; n++) {
292        for (i = 0; mount_flags[i].name; i++) {
293            if (!strcmp(args[n], mount_flags[i].name)) {
294                flags |= mount_flags[i].flag;
295                break;
296            }
297        }
298
299        if (!mount_flags[i].name) {
300            if (!strcmp(args[n], "wait"))
301                wait = 1;
302            /* if our last argument isn't a flag, wolf it up as an option string */
303            else if (n + 1 == nargs)
304                options = args[n];
305        }
306    }
307
308    system = args[1];
309    source = args[2];
310    target = args[3];
311
312    if (!strncmp(source, "mtd@", 4)) {
313        n = mtd_name_to_number(source + 4);
314        if (n < 0) {
315            return -1;
316        }
317
318        sprintf(tmp, "/dev/block/mtdblock%d", n);
319
320        if (wait)
321            wait_for_file(tmp, COMMAND_RETRY_TIMEOUT);
322        if (mount(tmp, target, system, flags, options) < 0) {
323            return -1;
324        }
325
326        goto exit_success;
327    } else if (!strncmp(source, "loop@", 5)) {
328        int mode, loop, fd;
329        struct loop_info info;
330
331        mode = (flags & MS_RDONLY) ? O_RDONLY : O_RDWR;
332        fd = open(source + 5, mode);
333        if (fd < 0) {
334            return -1;
335        }
336
337        for (n = 0; ; n++) {
338            sprintf(tmp, "/dev/block/loop%d", n);
339            loop = open(tmp, mode);
340            if (loop < 0) {
341                return -1;
342            }
343
344            /* if it is a blank loop device */
345            if (ioctl(loop, LOOP_GET_STATUS, &info) < 0 && errno == ENXIO) {
346                /* if it becomes our loop device */
347                if (ioctl(loop, LOOP_SET_FD, fd) >= 0) {
348                    close(fd);
349
350                    if (mount(tmp, target, system, flags, options) < 0) {
351                        ioctl(loop, LOOP_CLR_FD, 0);
352                        close(loop);
353                        return -1;
354                    }
355
356                    close(loop);
357                    goto exit_success;
358                }
359            }
360
361            close(loop);
362        }
363
364        close(fd);
365        ERROR("out of loopback devices");
366        return -1;
367    } else {
368        if (wait)
369            wait_for_file(source, COMMAND_RETRY_TIMEOUT);
370        if (mount(source, target, system, flags, options) < 0) {
371            /* If this fails, it may be an encrypted filesystem
372             * or it could just be wiped.  If wiped, that will be
373             * handled later in the boot process.
374             * We only support encrypting /data.  Check
375             * if we're trying to mount it, and if so,
376             * assume it's encrypted, mount a tmpfs instead.
377             * Then save the orig mount parms in properties
378             * for vold to query when it mounts the real
379             * encrypted /data.
380             */
381            if (!strcmp(target, DATA_MNT_POINT) && !partition_wiped(source)) {
382                const char *tmpfs_options;
383
384                tmpfs_options = property_get("ro.crypto.tmpfs_options");
385
386                if (mount("tmpfs", target, "tmpfs", MS_NOATIME | MS_NOSUID | MS_NODEV,
387                    tmpfs_options) < 0) {
388                    return -1;
389                }
390
391                /* Set the property that triggers the framework to do a minimal
392                 * startup and ask the user for a password
393                 */
394                property_set("ro.crypto.state", "encrypted");
395                property_set("vold.decrypt", "1");
396            } else {
397                return -1;
398            }
399        }
400
401        if (!strcmp(target, DATA_MNT_POINT)) {
402            char fs_flags[32];
403
404            /* Save the original mount options */
405            property_set("ro.crypto.fs_type", system);
406            property_set("ro.crypto.fs_real_blkdev", source);
407            property_set("ro.crypto.fs_mnt_point", target);
408            if (options) {
409                property_set("ro.crypto.fs_options", options);
410            }
411            snprintf(fs_flags, sizeof(fs_flags), "0x%8.8x", flags);
412            property_set("ro.crypto.fs_flags", fs_flags);
413        }
414    }
415
416exit_success:
417    /* If not running encrypted, then set the property saying we are
418     * unencrypted, and also trigger the action for a nonencrypted system.
419     */
420    if (!strcmp(target, DATA_MNT_POINT)) {
421        const char *prop;
422
423        prop = property_get("ro.crypto.state");
424        if (! prop) {
425            prop = "notset";
426        }
427        if (strcmp(prop, "encrypted")) {
428            property_set("ro.crypto.state", "unencrypted");
429            action_for_each_trigger("nonencrypted", action_add_queue_tail);
430        }
431    }
432
433    return 0;
434
435}
436
437int do_setkey(int nargs, char **args)
438{
439    struct kbentry kbe;
440    kbe.kb_table = strtoul(args[1], 0, 0);
441    kbe.kb_index = strtoul(args[2], 0, 0);
442    kbe.kb_value = strtoul(args[3], 0, 0);
443    return setkey(&kbe);
444}
445
446int do_setprop(int nargs, char **args)
447{
448    property_set(args[1], args[2]);
449    return 0;
450}
451
452int do_setrlimit(int nargs, char **args)
453{
454    struct rlimit limit;
455    int resource;
456    resource = atoi(args[1]);
457    limit.rlim_cur = atoi(args[2]);
458    limit.rlim_max = atoi(args[3]);
459    return setrlimit(resource, &limit);
460}
461
462int do_start(int nargs, char **args)
463{
464    struct service *svc;
465    svc = service_find_by_name(args[1]);
466    if (svc) {
467        service_start(svc, NULL);
468    }
469    return 0;
470}
471
472int do_stop(int nargs, char **args)
473{
474    struct service *svc;
475    svc = service_find_by_name(args[1]);
476    if (svc) {
477        service_stop(svc);
478    }
479    return 0;
480}
481
482int do_restart(int nargs, char **args)
483{
484    struct service *svc;
485    svc = service_find_by_name(args[1]);
486    if (svc) {
487        service_stop(svc);
488        service_start(svc, NULL);
489    }
490    return 0;
491}
492
493int do_trigger(int nargs, char **args)
494{
495    action_for_each_trigger(args[1], action_add_queue_tail);
496    return 0;
497}
498
499int do_symlink(int nargs, char **args)
500{
501    return symlink(args[1], args[2]);
502}
503
504int do_rm(int nargs, char **args)
505{
506    return unlink(args[1]);
507}
508
509int do_rmdir(int nargs, char **args)
510{
511    return rmdir(args[1]);
512}
513
514int do_sysclktz(int nargs, char **args)
515{
516    struct timezone tz;
517
518    if (nargs != 2)
519        return -1;
520
521    memset(&tz, 0, sizeof(tz));
522    tz.tz_minuteswest = atoi(args[1]);
523    if (settimeofday(NULL, &tz))
524        return -1;
525    return 0;
526}
527
528int do_write(int nargs, char **args)
529{
530    return write_file(args[1], args[2]);
531}
532
533int do_copy(int nargs, char **args)
534{
535    char *buffer = NULL;
536    int rc = 0;
537    int fd1 = -1, fd2 = -1;
538    struct stat info;
539    int brtw, brtr;
540    char *p;
541
542    if (nargs != 3)
543        return -1;
544
545    if (stat(args[1], &info) < 0)
546        return -1;
547
548    if ((fd1 = open(args[1], O_RDONLY)) < 0)
549        goto out_err;
550
551    if ((fd2 = open(args[2], O_WRONLY|O_CREAT|O_TRUNC, 0660)) < 0)
552        goto out_err;
553
554    if (!(buffer = malloc(info.st_size)))
555        goto out_err;
556
557    p = buffer;
558    brtr = info.st_size;
559    while(brtr) {
560        rc = read(fd1, p, brtr);
561        if (rc < 0)
562            goto out_err;
563        if (rc == 0)
564            break;
565        p += rc;
566        brtr -= rc;
567    }
568
569    p = buffer;
570    brtw = info.st_size;
571    while(brtw) {
572        rc = write(fd2, p, brtw);
573        if (rc < 0)
574            goto out_err;
575        if (rc == 0)
576            break;
577        p += rc;
578        brtw -= rc;
579    }
580
581    rc = 0;
582    goto out;
583out_err:
584    rc = -1;
585out:
586    if (buffer)
587        free(buffer);
588    if (fd1 >= 0)
589        close(fd1);
590    if (fd2 >= 0)
591        close(fd2);
592    return rc;
593}
594
595int do_chown(int nargs, char **args) {
596    /* GID is optional. */
597    if (nargs == 3) {
598        if (chown(args[2], decode_uid(args[1]), -1) < 0)
599            return -errno;
600    } else if (nargs == 4) {
601        if (chown(args[3], decode_uid(args[1]), decode_uid(args[2])))
602            return -errno;
603    } else {
604        return -1;
605    }
606    return 0;
607}
608
609static mode_t get_mode(const char *s) {
610    mode_t mode = 0;
611    while (*s) {
612        if (*s >= '0' && *s <= '7') {
613            mode = (mode<<3) | (*s-'0');
614        } else {
615            return -1;
616        }
617        s++;
618    }
619    return mode;
620}
621
622int do_chmod(int nargs, char **args) {
623    mode_t mode = get_mode(args[1]);
624    if (chmod(args[2], mode) < 0) {
625        return -errno;
626    }
627    return 0;
628}
629
630int do_loglevel(int nargs, char **args) {
631    if (nargs == 2) {
632        log_set_level(atoi(args[1]));
633        return 0;
634    }
635    return -1;
636}
637
638int do_load_persist_props(int nargs, char **args) {
639    if (nargs == 1) {
640        load_persist_props();
641        return 0;
642    }
643    return -1;
644}
645
646int do_wait(int nargs, char **args)
647{
648    if (nargs == 2) {
649        return wait_for_file(args[1], COMMAND_RETRY_TIMEOUT);
650    }
651    return -1;
652}
653