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