• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
34 #include "init.h"
35 #include "keywords.h"
36 #include "property_service.h"
37 #include "devices.h"
38 
39 #include <private/android_filesystem_config.h>
40 
41 void add_environment(const char *name, const char *value);
42 
43 extern int init_module(void *, unsigned long, const char *);
44 
write_file(const char * path,const char * value)45 static int write_file(const char *path, const char *value)
46 {
47     int fd, ret, len;
48 
49     fd = open(path, O_WRONLY|O_CREAT, 0622);
50 
51     if (fd < 0)
52         return -errno;
53 
54     len = strlen(value);
55 
56     do {
57         ret = write(fd, value, len);
58     } while (ret < 0 && errno == EINTR);
59 
60     close(fd);
61     if (ret < 0) {
62         return -errno;
63     } else {
64         return 0;
65     }
66 }
67 
insmod(const char * filename,char * options)68 static int insmod(const char *filename, char *options)
69 {
70     void *module;
71     unsigned size;
72     int ret;
73 
74     module = read_file(filename, &size);
75     if (!module)
76         return -1;
77 
78     ret = init_module(module, size, options);
79 
80     free(module);
81 
82     return ret;
83 }
84 
setkey(struct kbentry * kbe)85 static int setkey(struct kbentry *kbe)
86 {
87     int fd, ret;
88 
89     fd = open("/dev/tty0", O_RDWR | O_SYNC);
90     if (fd < 0)
91         return -1;
92 
93     ret = ioctl(fd, KDSKBENT, kbe);
94 
95     close(fd);
96     return ret;
97 }
98 
__ifupdown(const char * interface,int up)99 static int __ifupdown(const char *interface, int up)
100 {
101     struct ifreq ifr;
102     int s, ret;
103 
104     strlcpy(ifr.ifr_name, interface, IFNAMSIZ);
105 
106     s = socket(AF_INET, SOCK_DGRAM, 0);
107     if (s < 0)
108         return -1;
109 
110     ret = ioctl(s, SIOCGIFFLAGS, &ifr);
111     if (ret < 0) {
112         goto done;
113     }
114 
115     if (up)
116         ifr.ifr_flags |= IFF_UP;
117     else
118         ifr.ifr_flags &= ~IFF_UP;
119 
120     ret = ioctl(s, SIOCSIFFLAGS, &ifr);
121 
122 done:
123     close(s);
124     return ret;
125 }
126 
service_start_if_not_disabled(struct service * svc)127 static void service_start_if_not_disabled(struct service *svc)
128 {
129     if (!(svc->flags & SVC_DISABLED)) {
130         service_start(svc, NULL);
131     }
132 }
133 
do_class_start(int nargs,char ** args)134 int do_class_start(int nargs, char **args)
135 {
136         /* Starting a class does not start services
137          * which are explicitly disabled.  They must
138          * be started individually.
139          */
140     service_for_each_class(args[1], service_start_if_not_disabled);
141     return 0;
142 }
143 
do_class_stop(int nargs,char ** args)144 int do_class_stop(int nargs, char **args)
145 {
146     service_for_each_class(args[1], service_stop);
147     return 0;
148 }
149 
do_domainname(int nargs,char ** args)150 int do_domainname(int nargs, char **args)
151 {
152     return write_file("/proc/sys/kernel/domainname", args[1]);
153 }
154 
do_exec(int nargs,char ** args)155 int do_exec(int nargs, char **args)
156 {
157     return -1;
158 }
159 
do_export(int nargs,char ** args)160 int do_export(int nargs, char **args)
161 {
162     add_environment(args[1], args[2]);
163     return 0;
164 }
165 
do_hostname(int nargs,char ** args)166 int do_hostname(int nargs, char **args)
167 {
168     return write_file("/proc/sys/kernel/hostname", args[1]);
169 }
170 
do_ifup(int nargs,char ** args)171 int do_ifup(int nargs, char **args)
172 {
173     return __ifupdown(args[1], 1);
174 }
175 
176 
do_insmod_inner(int nargs,char ** args,int opt_len)177 static int do_insmod_inner(int nargs, char **args, int opt_len)
178 {
179     char options[opt_len + 1];
180     int i;
181 
182     options[0] = '\0';
183     if (nargs > 2) {
184         strcpy(options, args[2]);
185         for (i = 3; i < nargs; ++i) {
186             strcat(options, " ");
187             strcat(options, args[i]);
188         }
189     }
190 
191     return insmod(args[1], options);
192 }
193 
do_insmod(int nargs,char ** args)194 int do_insmod(int nargs, char **args)
195 {
196     int i;
197     int size = 0;
198 
199     if (nargs > 2) {
200         for (i = 2; i < nargs; ++i)
201             size += strlen(args[i]) + 1;
202     }
203 
204     return do_insmod_inner(nargs, args, size);
205 }
206 
do_import(int nargs,char ** args)207 int do_import(int nargs, char **args)
208 {
209     return -1;
210 }
211 
do_mkdir(int nargs,char ** args)212 int do_mkdir(int nargs, char **args)
213 {
214     mode_t mode = 0755;
215 
216     /* mkdir <path> [mode] [owner] [group] */
217 
218     if (nargs >= 3) {
219         mode = strtoul(args[2], 0, 8);
220     }
221 
222     if (mkdir(args[1], mode)) {
223         return -errno;
224     }
225 
226     if (nargs >= 4) {
227         uid_t uid = decode_uid(args[3]);
228         gid_t gid = -1;
229 
230         if (nargs == 5) {
231             gid = decode_uid(args[4]);
232         }
233 
234         if (chown(args[1], uid, gid)) {
235             return -errno;
236         }
237     }
238 
239     return 0;
240 }
241 
242 static struct {
243     const char *name;
244     unsigned flag;
245 } mount_flags[] = {
246     { "noatime",    MS_NOATIME },
247     { "nosuid",     MS_NOSUID },
248     { "nodev",      MS_NODEV },
249     { "nodiratime", MS_NODIRATIME },
250     { "ro",         MS_RDONLY },
251     { "rw",         0 },
252     { "remount",    MS_REMOUNT },
253     { "defaults",   0 },
254     { 0,            0 },
255 };
256 
257 /* mount <type> <device> <path> <flags ...> <options> */
do_mount(int nargs,char ** args)258 int do_mount(int nargs, char **args)
259 {
260     char tmp[64];
261     char *source, *target, *system;
262     char *options = NULL;
263     unsigned flags = 0;
264     int n, i;
265 
266     for (n = 4; n < nargs; n++) {
267         for (i = 0; mount_flags[i].name; i++) {
268             if (!strcmp(args[n], mount_flags[i].name)) {
269                 flags |= mount_flags[i].flag;
270                 break;
271             }
272         }
273 
274         /* if our last argument isn't a flag, wolf it up as an option string */
275         if (n + 1 == nargs && !mount_flags[i].name)
276             options = args[n];
277     }
278 
279     system = args[1];
280     source = args[2];
281     target = args[3];
282 
283     if (!strncmp(source, "mtd@", 4)) {
284         n = mtd_name_to_number(source + 4);
285         if (n < 0) {
286             return -1;
287         }
288 
289         sprintf(tmp, "/dev/block/mtdblock%d", n);
290 
291         if (mount(tmp, target, system, flags, options) < 0) {
292             return -1;
293         }
294 
295         return 0;
296     } else if (!strncmp(source, "loop@", 5)) {
297         int mode, loop, fd;
298         struct loop_info info;
299 
300         mode = (flags & MS_RDONLY) ? O_RDONLY : O_RDWR;
301         fd = open(source + 5, mode);
302         if (fd < 0) {
303             return -1;
304         }
305 
306         for (n = 0; ; n++) {
307             sprintf(tmp, "/dev/block/loop%d", n);
308             loop = open(tmp, mode);
309             if (loop < 0) {
310                 return -1;
311             }
312 
313             /* if it is a blank loop device */
314             if (ioctl(loop, LOOP_GET_STATUS, &info) < 0 && errno == ENXIO) {
315                 /* if it becomes our loop device */
316                 if (ioctl(loop, LOOP_SET_FD, fd) >= 0) {
317                     close(fd);
318 
319                     if (mount(tmp, target, system, flags, options) < 0) {
320                         ioctl(loop, LOOP_CLR_FD, 0);
321                         close(loop);
322                         return -1;
323                     }
324 
325                     close(loop);
326                     return 0;
327                 }
328             }
329 
330             close(loop);
331         }
332 
333         close(fd);
334         ERROR("out of loopback devices");
335         return -1;
336     } else {
337         if (mount(source, target, system, flags, options) < 0) {
338             return -1;
339         }
340 
341         return 0;
342     }
343 }
344 
do_setkey(int nargs,char ** args)345 int do_setkey(int nargs, char **args)
346 {
347     struct kbentry kbe;
348     kbe.kb_table = strtoul(args[1], 0, 0);
349     kbe.kb_index = strtoul(args[2], 0, 0);
350     kbe.kb_value = strtoul(args[3], 0, 0);
351     return setkey(&kbe);
352 }
353 
do_setprop(int nargs,char ** args)354 int do_setprop(int nargs, char **args)
355 {
356     property_set(args[1], args[2]);
357     return 0;
358 }
359 
do_setrlimit(int nargs,char ** args)360 int do_setrlimit(int nargs, char **args)
361 {
362     struct rlimit limit;
363     int resource;
364     resource = atoi(args[1]);
365     limit.rlim_cur = atoi(args[2]);
366     limit.rlim_max = atoi(args[3]);
367     return setrlimit(resource, &limit);
368 }
369 
do_start(int nargs,char ** args)370 int do_start(int nargs, char **args)
371 {
372     struct service *svc;
373     svc = service_find_by_name(args[1]);
374     if (svc) {
375         service_start(svc, NULL);
376     }
377     return 0;
378 }
379 
do_stop(int nargs,char ** args)380 int do_stop(int nargs, char **args)
381 {
382     struct service *svc;
383     svc = service_find_by_name(args[1]);
384     if (svc) {
385         service_stop(svc);
386     }
387     return 0;
388 }
389 
do_restart(int nargs,char ** args)390 int do_restart(int nargs, char **args)
391 {
392     struct service *svc;
393     svc = service_find_by_name(args[1]);
394     if (svc) {
395         service_stop(svc);
396         service_start(svc, NULL);
397     }
398     return 0;
399 }
400 
do_trigger(int nargs,char ** args)401 int do_trigger(int nargs, char **args)
402 {
403     return 0;
404 }
405 
do_symlink(int nargs,char ** args)406 int do_symlink(int nargs, char **args)
407 {
408     return symlink(args[1], args[2]);
409 }
410 
do_sysclktz(int nargs,char ** args)411 int do_sysclktz(int nargs, char **args)
412 {
413     struct timezone tz;
414 
415     if (nargs != 2)
416         return -1;
417 
418     memset(&tz, 0, sizeof(tz));
419     tz.tz_minuteswest = atoi(args[1]);
420     if (settimeofday(NULL, &tz))
421         return -1;
422     return 0;
423 }
424 
do_write(int nargs,char ** args)425 int do_write(int nargs, char **args)
426 {
427     return write_file(args[1], args[2]);
428 }
429 
do_copy(int nargs,char ** args)430 int do_copy(int nargs, char **args)
431 {
432     char *buffer = NULL;
433     int rc = 0;
434     int fd1 = -1, fd2 = -1;
435     struct stat info;
436     int brtw, brtr;
437     char *p;
438 
439     if (nargs != 3)
440         return -1;
441 
442     if (stat(args[1], &info) < 0)
443         return -1;
444 
445     if ((fd1 = open(args[1], O_RDONLY)) < 0)
446         goto out_err;
447 
448     if ((fd2 = open(args[2], O_WRONLY|O_CREAT|O_TRUNC, 0660)) < 0)
449         goto out_err;
450 
451     if (!(buffer = malloc(info.st_size)))
452         goto out_err;
453 
454     p = buffer;
455     brtr = info.st_size;
456     while(brtr) {
457         rc = read(fd1, p, brtr);
458         if (rc < 0)
459             goto out_err;
460         if (rc == 0)
461             break;
462         p += rc;
463         brtr -= rc;
464     }
465 
466     p = buffer;
467     brtw = info.st_size;
468     while(brtw) {
469         rc = write(fd2, p, brtw);
470         if (rc < 0)
471             goto out_err;
472         if (rc == 0)
473             break;
474         p += rc;
475         brtw -= rc;
476     }
477 
478     rc = 0;
479     goto out;
480 out_err:
481     rc = -1;
482 out:
483     if (buffer)
484         free(buffer);
485     if (fd1 >= 0)
486         close(fd1);
487     if (fd2 >= 0)
488         close(fd2);
489     return rc;
490 }
491 
do_chown(int nargs,char ** args)492 int do_chown(int nargs, char **args) {
493     /* GID is optional. */
494     if (nargs == 3) {
495         if (chown(args[2], decode_uid(args[1]), -1) < 0)
496             return -errno;
497     } else if (nargs == 4) {
498         if (chown(args[3], decode_uid(args[1]), decode_uid(args[2])))
499             return -errno;
500     } else {
501         return -1;
502     }
503     return 0;
504 }
505 
get_mode(const char * s)506 static mode_t get_mode(const char *s) {
507     mode_t mode = 0;
508     while (*s) {
509         if (*s >= '0' && *s <= '7') {
510             mode = (mode<<3) | (*s-'0');
511         } else {
512             return -1;
513         }
514         s++;
515     }
516     return mode;
517 }
518 
do_chmod(int nargs,char ** args)519 int do_chmod(int nargs, char **args) {
520     mode_t mode = get_mode(args[1]);
521     if (chmod(args[2], mode) < 0) {
522         return -errno;
523     }
524     return 0;
525 }
526 
do_loglevel(int nargs,char ** args)527 int do_loglevel(int nargs, char **args) {
528     if (nargs == 2) {
529         log_set_level(atoi(args[1]));
530         return 0;
531     }
532     return -1;
533 }
534 
do_device(int nargs,char ** args)535 int do_device(int nargs, char **args) {
536     int len;
537     char tmp[64];
538     char *source = args[1];
539     int prefix = 0;
540 
541     if (nargs != 5)
542         return -1;
543     /* Check for wildcard '*' at the end which indicates a prefix. */
544     len = strlen(args[1]) - 1;
545     if (args[1][len] == '*') {
546         args[1][len] = '\0';
547         prefix = 1;
548     }
549     /* If path starts with mtd@ lookup the mount number. */
550     if (!strncmp(source, "mtd@", 4)) {
551         int n = mtd_name_to_number(source + 4);
552         if (n >= 0) {
553             snprintf(tmp, sizeof(tmp), "/dev/mtd/mtd%d", n);
554             source = tmp;
555         }
556     }
557     add_devperms_partners(source, get_mode(args[2]), decode_uid(args[3]),
558                           decode_uid(args[4]), prefix);
559     return 0;
560 }
561