blob: 0b9c0cfeb161b25a3c2223f1b18d92df11691b68 [file] [log] [blame]
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001/*
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>
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +000032#include <linux/loop.h>
Ken Sumrall7bc6e9e2011-05-26 20:01:39 -070033#include <cutils/partition_utils.h>
Dima Zavin84bf9af2011-12-20 13:44:41 -080034#include <sys/system_properties.h>
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070035
Stephen Smalleye46f9d52012-01-13 08:48:47 -050036#ifdef HAVE_SELINUX
37#include <selinux/selinux.h>
38#include <selinux/label.h>
39#endif
40
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070041#include "init.h"
42#include "keywords.h"
43#include "property_service.h"
44#include "devices.h"
Colin Cross6310a822010-04-20 14:29:05 -070045#include "init_parser.h"
Colin Cross3899e9f2010-04-13 20:35:46 -070046#include "util.h"
Colin Crossed8a7d82010-04-19 17:05:34 -070047#include "log.h"
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070048
49#include <private/android_filesystem_config.h>
50
51void add_environment(const char *name, const char *value);
52
53extern int init_module(void *, unsigned long, const char *);
54
55static int write_file(const char *path, const char *value)
56{
57 int fd, ret, len;
58
59 fd = open(path, O_WRONLY|O_CREAT, 0622);
60
61 if (fd < 0)
Mike Chan008abac2009-06-29 20:30:55 -070062 return -errno;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070063
64 len = strlen(value);
65
66 do {
67 ret = write(fd, value, len);
68 } while (ret < 0 && errno == EINTR);
69
70 close(fd);
71 if (ret < 0) {
Mike Chan008abac2009-06-29 20:30:55 -070072 return -errno;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070073 } else {
74 return 0;
75 }
76}
77
Benoit Goby58903012012-03-28 18:15:56 -070078static int _open(const char *path)
79{
80 int fd;
81
82 fd = open(path, O_RDONLY | O_NOFOLLOW);
83 if (fd < 0)
84 fd = open(path, O_WRONLY | O_NOFOLLOW);
85
86 return fd;
87}
88
Geremy Condra9ed1fe72012-03-20 12:49:55 -070089static int _chown(const char *path, unsigned int uid, unsigned int gid)
90{
91 int fd;
92 int ret;
93
Benoit Goby58903012012-03-28 18:15:56 -070094 fd = _open(path);
Geremy Condra9ed1fe72012-03-20 12:49:55 -070095 if (fd < 0) {
96 return -1;
97 }
98
99 ret = fchown(fd, uid, gid);
100 if (ret < 0) {
101 int errno_copy = errno;
102 close(fd);
103 errno = errno_copy;
104 return -1;
105 }
106
107 close(fd);
108
109 return 0;
110}
111
112static int _chmod(const char *path, mode_t mode)
113{
114 int fd;
115 int ret;
116
Benoit Goby58903012012-03-28 18:15:56 -0700117 fd = _open(path);
Geremy Condra9ed1fe72012-03-20 12:49:55 -0700118 if (fd < 0) {
119 return -1;
120 }
121
122 ret = fchmod(fd, mode);
123 if (ret < 0) {
124 int errno_copy = errno;
125 close(fd);
126 errno = errno_copy;
127 return -1;
128 }
129
130 close(fd);
131
132 return 0;
133}
134
The Android Open Source Project35237d12008-12-17 18:08:08 -0800135static int insmod(const char *filename, char *options)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700136{
137 void *module;
138 unsigned size;
139 int ret;
140
141 module = read_file(filename, &size);
142 if (!module)
143 return -1;
144
The Android Open Source Project35237d12008-12-17 18:08:08 -0800145 ret = init_module(module, size, options);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700146
147 free(module);
148
149 return ret;
150}
151
152static int setkey(struct kbentry *kbe)
153{
154 int fd, ret;
155
156 fd = open("/dev/tty0", O_RDWR | O_SYNC);
157 if (fd < 0)
158 return -1;
159
160 ret = ioctl(fd, KDSKBENT, kbe);
161
162 close(fd);
163 return ret;
164}
165
166static int __ifupdown(const char *interface, int up)
167{
168 struct ifreq ifr;
169 int s, ret;
170
171 strlcpy(ifr.ifr_name, interface, IFNAMSIZ);
172
173 s = socket(AF_INET, SOCK_DGRAM, 0);
174 if (s < 0)
175 return -1;
176
177 ret = ioctl(s, SIOCGIFFLAGS, &ifr);
178 if (ret < 0) {
179 goto done;
180 }
181
182 if (up)
183 ifr.ifr_flags |= IFF_UP;
184 else
185 ifr.ifr_flags &= ~IFF_UP;
186
187 ret = ioctl(s, SIOCSIFFLAGS, &ifr);
188
189done:
190 close(s);
191 return ret;
192}
193
194static void service_start_if_not_disabled(struct service *svc)
195{
196 if (!(svc->flags & SVC_DISABLED)) {
San Mehatf24e2522009-05-19 13:30:46 -0700197 service_start(svc, NULL);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700198 }
199}
200
Jay Freeman (saurik)e7cb1372008-11-17 06:41:10 +0000201int do_chdir(int nargs, char **args)
202{
203 chdir(args[1]);
204 return 0;
205}
206
207int do_chroot(int nargs, char **args)
208{
209 chroot(args[1]);
210 return 0;
211}
212
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700213int do_class_start(int nargs, char **args)
214{
215 /* Starting a class does not start services
216 * which are explicitly disabled. They must
217 * be started individually.
218 */
219 service_for_each_class(args[1], service_start_if_not_disabled);
220 return 0;
221}
222
223int do_class_stop(int nargs, char **args)
224{
225 service_for_each_class(args[1], service_stop);
226 return 0;
227}
228
Ken Sumrall752923c2010-12-03 16:33:31 -0800229int do_class_reset(int nargs, char **args)
230{
231 service_for_each_class(args[1], service_reset);
232 return 0;
233}
234
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700235int do_domainname(int nargs, char **args)
236{
237 return write_file("/proc/sys/kernel/domainname", args[1]);
238}
239
240int do_exec(int nargs, char **args)
241{
242 return -1;
243}
244
245int do_export(int nargs, char **args)
246{
247 add_environment(args[1], args[2]);
248 return 0;
249}
250
251int do_hostname(int nargs, char **args)
252{
253 return write_file("/proc/sys/kernel/hostname", args[1]);
254}
255
256int do_ifup(int nargs, char **args)
257{
258 return __ifupdown(args[1], 1);
259}
260
The Android Open Source Project35237d12008-12-17 18:08:08 -0800261
262static int do_insmod_inner(int nargs, char **args, int opt_len)
263{
264 char options[opt_len + 1];
265 int i;
266
267 options[0] = '\0';
268 if (nargs > 2) {
269 strcpy(options, args[2]);
270 for (i = 3; i < nargs; ++i) {
271 strcat(options, " ");
272 strcat(options, args[i]);
273 }
274 }
275
276 return insmod(args[1], options);
277}
278
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700279int do_insmod(int nargs, char **args)
280{
The Android Open Source Project35237d12008-12-17 18:08:08 -0800281 int i;
282 int size = 0;
283
284 if (nargs > 2) {
285 for (i = 2; i < nargs; ++i)
286 size += strlen(args[i]) + 1;
287 }
288
289 return do_insmod_inner(nargs, args, size);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700290}
291
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700292int do_mkdir(int nargs, char **args)
293{
294 mode_t mode = 0755;
Chia-chi Yeh27164dc2011-07-08 12:57:36 -0700295 int ret;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700296
297 /* mkdir <path> [mode] [owner] [group] */
298
299 if (nargs >= 3) {
300 mode = strtoul(args[2], 0, 8);
301 }
302
Chia-chi Yeh27164dc2011-07-08 12:57:36 -0700303 ret = mkdir(args[1], mode);
304 /* chmod in case the directory already exists */
305 if (ret == -1 && errno == EEXIST) {
Geremy Condra9ed1fe72012-03-20 12:49:55 -0700306 ret = _chmod(args[1], mode);
Chia-chi Yeh27164dc2011-07-08 12:57:36 -0700307 }
308 if (ret == -1) {
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700309 return -errno;
310 }
311
312 if (nargs >= 4) {
313 uid_t uid = decode_uid(args[3]);
314 gid_t gid = -1;
315
316 if (nargs == 5) {
317 gid = decode_uid(args[4]);
318 }
319
Geremy Condra9ed1fe72012-03-20 12:49:55 -0700320 if (_chown(args[1], uid, gid) < 0) {
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700321 return -errno;
322 }
323 }
324
325 return 0;
326}
327
328static struct {
329 const char *name;
330 unsigned flag;
331} mount_flags[] = {
332 { "noatime", MS_NOATIME },
333 { "nosuid", MS_NOSUID },
334 { "nodev", MS_NODEV },
335 { "nodiratime", MS_NODIRATIME },
336 { "ro", MS_RDONLY },
337 { "rw", 0 },
338 { "remount", MS_REMOUNT },
339 { "defaults", 0 },
340 { 0, 0 },
341};
342
Ken Sumrall752923c2010-12-03 16:33:31 -0800343#define DATA_MNT_POINT "/data"
344
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700345/* mount <type> <device> <path> <flags ...> <options> */
346int do_mount(int nargs, char **args)
347{
348 char tmp[64];
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000349 char *source, *target, *system;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700350 char *options = NULL;
351 unsigned flags = 0;
352 int n, i;
Colin Crosscd0f1732010-04-19 17:10:24 -0700353 int wait = 0;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700354
355 for (n = 4; n < nargs; n++) {
356 for (i = 0; mount_flags[i].name; i++) {
357 if (!strcmp(args[n], mount_flags[i].name)) {
358 flags |= mount_flags[i].flag;
359 break;
360 }
361 }
362
Colin Crosscd0f1732010-04-19 17:10:24 -0700363 if (!mount_flags[i].name) {
364 if (!strcmp(args[n], "wait"))
365 wait = 1;
366 /* if our last argument isn't a flag, wolf it up as an option string */
367 else if (n + 1 == nargs)
368 options = args[n];
369 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700370 }
371
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000372 system = args[1];
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700373 source = args[2];
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000374 target = args[3];
375
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700376 if (!strncmp(source, "mtd@", 4)) {
377 n = mtd_name_to_number(source + 4);
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000378 if (n < 0) {
379 return -1;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700380 }
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000381
382 sprintf(tmp, "/dev/block/mtdblock%d", n);
383
Colin Crosscd0f1732010-04-19 17:10:24 -0700384 if (wait)
385 wait_for_file(tmp, COMMAND_RETRY_TIMEOUT);
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000386 if (mount(tmp, target, system, flags, options) < 0) {
387 return -1;
388 }
389
Ken Sumralldd4d7862011-02-17 18:09:47 -0800390 goto exit_success;
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000391 } else if (!strncmp(source, "loop@", 5)) {
392 int mode, loop, fd;
393 struct loop_info info;
394
395 mode = (flags & MS_RDONLY) ? O_RDONLY : O_RDWR;
396 fd = open(source + 5, mode);
397 if (fd < 0) {
398 return -1;
399 }
400
401 for (n = 0; ; n++) {
402 sprintf(tmp, "/dev/block/loop%d", n);
403 loop = open(tmp, mode);
404 if (loop < 0) {
405 return -1;
406 }
407
408 /* if it is a blank loop device */
409 if (ioctl(loop, LOOP_GET_STATUS, &info) < 0 && errno == ENXIO) {
410 /* if it becomes our loop device */
411 if (ioctl(loop, LOOP_SET_FD, fd) >= 0) {
412 close(fd);
413
414 if (mount(tmp, target, system, flags, options) < 0) {
415 ioctl(loop, LOOP_CLR_FD, 0);
416 close(loop);
417 return -1;
418 }
419
420 close(loop);
Ken Sumralldd4d7862011-02-17 18:09:47 -0800421 goto exit_success;
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000422 }
423 }
424
425 close(loop);
426 }
427
428 close(fd);
429 ERROR("out of loopback devices");
430 return -1;
431 } else {
Colin Crosscd0f1732010-04-19 17:10:24 -0700432 if (wait)
433 wait_for_file(source, COMMAND_RETRY_TIMEOUT);
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000434 if (mount(source, target, system, flags, options) < 0) {
Ken Sumrall7bc6e9e2011-05-26 20:01:39 -0700435 /* If this fails, it may be an encrypted filesystem
436 * or it could just be wiped. If wiped, that will be
437 * handled later in the boot process.
Ken Sumrall752923c2010-12-03 16:33:31 -0800438 * We only support encrypting /data. Check
439 * if we're trying to mount it, and if so,
440 * assume it's encrypted, mount a tmpfs instead.
441 * Then save the orig mount parms in properties
442 * for vold to query when it mounts the real
443 * encrypted /data.
444 */
Ken Sumrall7bc6e9e2011-05-26 20:01:39 -0700445 if (!strcmp(target, DATA_MNT_POINT) && !partition_wiped(source)) {
Ken Sumrall752923c2010-12-03 16:33:31 -0800446 const char *tmpfs_options;
447
448 tmpfs_options = property_get("ro.crypto.tmpfs_options");
449
450 if (mount("tmpfs", target, "tmpfs", MS_NOATIME | MS_NOSUID | MS_NODEV,
451 tmpfs_options) < 0) {
452 return -1;
453 }
454
455 /* Set the property that triggers the framework to do a minimal
456 * startup and ask the user for a password
457 */
Ken Sumrall4e84d3b2011-01-14 12:44:09 -0800458 property_set("ro.crypto.state", "encrypted");
Ken Sumrall752923c2010-12-03 16:33:31 -0800459 property_set("vold.decrypt", "1");
460 } else {
461 return -1;
462 }
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000463 }
464
Ken Sumrall752923c2010-12-03 16:33:31 -0800465 if (!strcmp(target, DATA_MNT_POINT)) {
466 char fs_flags[32];
467
468 /* Save the original mount options */
469 property_set("ro.crypto.fs_type", system);
470 property_set("ro.crypto.fs_real_blkdev", source);
471 property_set("ro.crypto.fs_mnt_point", target);
472 if (options) {
473 property_set("ro.crypto.fs_options", options);
474 }
475 snprintf(fs_flags, sizeof(fs_flags), "0x%8.8x", flags);
476 property_set("ro.crypto.fs_flags", fs_flags);
477 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700478 }
Ken Sumralldd4d7862011-02-17 18:09:47 -0800479
480exit_success:
481 /* If not running encrypted, then set the property saying we are
482 * unencrypted, and also trigger the action for a nonencrypted system.
483 */
484 if (!strcmp(target, DATA_MNT_POINT)) {
Ken Sumrallc5c51032011-03-08 17:01:29 -0800485 const char *prop;
486
Ken Sumralldd4d7862011-02-17 18:09:47 -0800487 prop = property_get("ro.crypto.state");
488 if (! prop) {
489 prop = "notset";
490 }
491 if (strcmp(prop, "encrypted")) {
492 property_set("ro.crypto.state", "unencrypted");
493 action_for_each_trigger("nonencrypted", action_add_queue_tail);
494 }
495 }
496
497 return 0;
498
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700499}
500
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500501int do_setcon(int nargs, char **args) {
502#ifdef HAVE_SELINUX
503 if (is_selinux_enabled() <= 0)
504 return 0;
505 if (setcon(args[1]) < 0) {
506 return -errno;
507 }
508#endif
509 return 0;
510}
511
512int do_setenforce(int nargs, char **args) {
513#ifdef HAVE_SELINUX
514 if (is_selinux_enabled() <= 0)
515 return 0;
516 if (security_setenforce(atoi(args[1])) < 0) {
517 return -errno;
518 }
519#endif
520 return 0;
521}
522
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700523int do_setkey(int nargs, char **args)
524{
525 struct kbentry kbe;
526 kbe.kb_table = strtoul(args[1], 0, 0);
527 kbe.kb_index = strtoul(args[2], 0, 0);
528 kbe.kb_value = strtoul(args[3], 0, 0);
529 return setkey(&kbe);
530}
531
532int do_setprop(int nargs, char **args)
533{
Mike Lockwood1f0bd322011-06-08 17:31:27 -0700534 const char *name = args[1];
535 const char *value = args[2];
Dima Zavin84bf9af2011-12-20 13:44:41 -0800536 char prop_val[PROP_VALUE_MAX];
537 int ret;
Mike Lockwood1f0bd322011-06-08 17:31:27 -0700538
Dima Zavin84bf9af2011-12-20 13:44:41 -0800539 ret = expand_props(prop_val, value, sizeof(prop_val));
540 if (ret) {
541 ERROR("cannot expand '%s' while assigning to '%s'\n", value, name);
542 return -EINVAL;
Mike Lockwood1f0bd322011-06-08 17:31:27 -0700543 }
Dima Zavin84bf9af2011-12-20 13:44:41 -0800544 property_set(name, prop_val);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700545 return 0;
546}
547
548int do_setrlimit(int nargs, char **args)
549{
550 struct rlimit limit;
551 int resource;
552 resource = atoi(args[1]);
553 limit.rlim_cur = atoi(args[2]);
554 limit.rlim_max = atoi(args[3]);
555 return setrlimit(resource, &limit);
556}
557
558int do_start(int nargs, char **args)
559{
560 struct service *svc;
561 svc = service_find_by_name(args[1]);
562 if (svc) {
San Mehatf24e2522009-05-19 13:30:46 -0700563 service_start(svc, NULL);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700564 }
565 return 0;
566}
567
568int do_stop(int nargs, char **args)
569{
570 struct service *svc;
571 svc = service_find_by_name(args[1]);
572 if (svc) {
573 service_stop(svc);
574 }
575 return 0;
576}
577
578int do_restart(int nargs, char **args)
579{
580 struct service *svc;
581 svc = service_find_by_name(args[1]);
582 if (svc) {
583 service_stop(svc);
San Mehatf24e2522009-05-19 13:30:46 -0700584 service_start(svc, NULL);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700585 }
586 return 0;
587}
588
589int do_trigger(int nargs, char **args)
590{
Jay Freeman (saurik)11e1c422008-11-17 06:35:08 +0000591 action_for_each_trigger(args[1], action_add_queue_tail);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700592 return 0;
593}
594
595int do_symlink(int nargs, char **args)
596{
597 return symlink(args[1], args[2]);
598}
599
Ken Sumrall203bad52011-01-18 17:37:41 -0800600int do_rm(int nargs, char **args)
601{
602 return unlink(args[1]);
603}
604
605int do_rmdir(int nargs, char **args)
606{
607 return rmdir(args[1]);
608}
609
The Android Open Source Project35237d12008-12-17 18:08:08 -0800610int do_sysclktz(int nargs, char **args)
611{
612 struct timezone tz;
613
614 if (nargs != 2)
615 return -1;
616
617 memset(&tz, 0, sizeof(tz));
618 tz.tz_minuteswest = atoi(args[1]);
619 if (settimeofday(NULL, &tz))
620 return -1;
621 return 0;
622}
623
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700624int do_write(int nargs, char **args)
625{
Mike Lockwood1f0bd322011-06-08 17:31:27 -0700626 const char *path = args[1];
627 const char *value = args[2];
Dima Zavin84bf9af2011-12-20 13:44:41 -0800628 char prop_val[PROP_VALUE_MAX];
629 int ret;
Mike Lockwood2c4d5dc2011-06-07 17:30:11 -0700630
Dima Zavin84bf9af2011-12-20 13:44:41 -0800631 ret = expand_props(prop_val, value, sizeof(prop_val));
632 if (ret) {
633 ERROR("cannot expand '%s' while writing to '%s'\n", value, path);
634 return -EINVAL;
635 }
636 return write_file(path, prop_val);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700637}
638
San Mehat7c44fe52009-08-26 16:39:25 -0700639int do_copy(int nargs, char **args)
640{
641 char *buffer = NULL;
642 int rc = 0;
643 int fd1 = -1, fd2 = -1;
644 struct stat info;
645 int brtw, brtr;
646 char *p;
647
648 if (nargs != 3)
649 return -1;
650
651 if (stat(args[1], &info) < 0)
652 return -1;
653
654 if ((fd1 = open(args[1], O_RDONLY)) < 0)
655 goto out_err;
656
Tom Zhu4833d9f2009-09-28 19:53:12 -0500657 if ((fd2 = open(args[2], O_WRONLY|O_CREAT|O_TRUNC, 0660)) < 0)
San Mehat7c44fe52009-08-26 16:39:25 -0700658 goto out_err;
659
660 if (!(buffer = malloc(info.st_size)))
661 goto out_err;
662
663 p = buffer;
664 brtr = info.st_size;
665 while(brtr) {
666 rc = read(fd1, p, brtr);
667 if (rc < 0)
668 goto out_err;
669 if (rc == 0)
670 break;
671 p += rc;
672 brtr -= rc;
673 }
674
675 p = buffer;
676 brtw = info.st_size;
677 while(brtw) {
678 rc = write(fd2, p, brtw);
679 if (rc < 0)
680 goto out_err;
681 if (rc == 0)
682 break;
683 p += rc;
684 brtw -= rc;
685 }
686
687 rc = 0;
688 goto out;
689out_err:
690 rc = -1;
691out:
692 if (buffer)
693 free(buffer);
694 if (fd1 >= 0)
695 close(fd1);
696 if (fd2 >= 0)
697 close(fd2);
698 return rc;
699}
700
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700701int do_chown(int nargs, char **args) {
702 /* GID is optional. */
703 if (nargs == 3) {
Geremy Condra9ed1fe72012-03-20 12:49:55 -0700704 if (_chown(args[2], decode_uid(args[1]), -1) < 0)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700705 return -errno;
706 } else if (nargs == 4) {
Geremy Condra9ed1fe72012-03-20 12:49:55 -0700707 if (_chown(args[3], decode_uid(args[1]), decode_uid(args[2])) < 0)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700708 return -errno;
709 } else {
710 return -1;
711 }
712 return 0;
713}
714
715static mode_t get_mode(const char *s) {
716 mode_t mode = 0;
717 while (*s) {
718 if (*s >= '0' && *s <= '7') {
719 mode = (mode<<3) | (*s-'0');
720 } else {
721 return -1;
722 }
723 s++;
724 }
725 return mode;
726}
727
728int do_chmod(int nargs, char **args) {
729 mode_t mode = get_mode(args[1]);
Geremy Condra9ed1fe72012-03-20 12:49:55 -0700730 if (_chmod(args[2], mode) < 0) {
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700731 return -errno;
732 }
733 return 0;
734}
735
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500736int do_restorecon(int nargs, char **args) {
737#ifdef HAVE_SELINUX
738 char *secontext = NULL;
739 struct stat sb;
740 int i;
741
742 if (is_selinux_enabled() <= 0 || !sehandle)
743 return 0;
744
745 for (i = 1; i < nargs; i++) {
746 if (lstat(args[i], &sb) < 0)
747 return -errno;
748 if (selabel_lookup(sehandle, &secontext, args[i], sb.st_mode) < 0)
749 return -errno;
750 if (lsetfilecon(args[i], secontext) < 0) {
751 freecon(secontext);
752 return -errno;
753 }
754 freecon(secontext);
755 }
756#endif
757 return 0;
758}
759
760int do_setsebool(int nargs, char **args) {
761#ifdef HAVE_SELINUX
762 SELboolean *b = alloca(nargs * sizeof(SELboolean));
763 char *v;
764 int i;
765
766 if (is_selinux_enabled() <= 0)
767 return 0;
768
769 for (i = 1; i < nargs; i++) {
770 char *name = args[i];
771 v = strchr(name, '=');
772 if (!v) {
773 ERROR("setsebool: argument %s had no =\n", name);
774 return -EINVAL;
775 }
776 *v++ = 0;
777 b[i-1].name = name;
778 if (!strcmp(v, "1") || !strcasecmp(v, "true") || !strcasecmp(v, "on"))
779 b[i-1].value = 1;
780 else if (!strcmp(v, "0") || !strcasecmp(v, "false") || !strcasecmp(v, "off"))
781 b[i-1].value = 0;
782 else {
783 ERROR("setsebool: invalid value %s\n", v);
784 return -EINVAL;
785 }
786 }
787
788 if (security_set_boolean_list(nargs - 1, b, 0) < 0)
789 return -errno;
790#endif
791 return 0;
792}
793
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700794int do_loglevel(int nargs, char **args) {
795 if (nargs == 2) {
Dima Zavin8f912822011-08-31 18:26:17 -0700796 klog_set_level(atoi(args[1]));
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700797 return 0;
798 }
799 return -1;
800}
801
Ken Sumrallc5c51032011-03-08 17:01:29 -0800802int do_load_persist_props(int nargs, char **args) {
803 if (nargs == 1) {
804 load_persist_props();
805 return 0;
806 }
807 return -1;
808}
809
Colin Crosscd0f1732010-04-19 17:10:24 -0700810int do_wait(int nargs, char **args)
811{
812 if (nargs == 2) {
813 return wait_for_file(args[1], COMMAND_RETRY_TIMEOUT);
814 }
815 return -1;
816}