blob: a05ca453689018cc285f94fded89ff24d7b7d135 [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 Goby93574c62012-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 Condra42a93492012-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 Goby93574c62012-03-28 18:15:56 -070094 fd = _open(path);
Geremy Condra42a93492012-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 Goby93574c62012-03-28 18:15:56 -0700117 fd = _open(path);
Geremy Condra42a93492012-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
Stephen Smalleye096e362012-06-11 13:37:39 -0400303 ret = make_dir(args[1], mode);
Chia-chi Yeh27164dc2011-07-08 12:57:36 -0700304 /* chmod in case the directory already exists */
305 if (ret == -1 && errno == EEXIST) {
Geremy Condra42a93492012-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 Condra42a93492012-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 },
Lars Svenssonb6ee25e2011-07-14 13:39:09 +0200333 { "noexec", MS_NOEXEC },
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700334 { "nosuid", MS_NOSUID },
335 { "nodev", MS_NODEV },
336 { "nodiratime", MS_NODIRATIME },
337 { "ro", MS_RDONLY },
338 { "rw", 0 },
339 { "remount", MS_REMOUNT },
340 { "defaults", 0 },
341 { 0, 0 },
342};
343
Ken Sumrall752923c2010-12-03 16:33:31 -0800344#define DATA_MNT_POINT "/data"
345
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700346/* mount <type> <device> <path> <flags ...> <options> */
347int do_mount(int nargs, char **args)
348{
349 char tmp[64];
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000350 char *source, *target, *system;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700351 char *options = NULL;
352 unsigned flags = 0;
353 int n, i;
Colin Crosscd0f1732010-04-19 17:10:24 -0700354 int wait = 0;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700355
356 for (n = 4; n < nargs; n++) {
357 for (i = 0; mount_flags[i].name; i++) {
358 if (!strcmp(args[n], mount_flags[i].name)) {
359 flags |= mount_flags[i].flag;
360 break;
361 }
362 }
363
Colin Crosscd0f1732010-04-19 17:10:24 -0700364 if (!mount_flags[i].name) {
365 if (!strcmp(args[n], "wait"))
366 wait = 1;
367 /* if our last argument isn't a flag, wolf it up as an option string */
368 else if (n + 1 == nargs)
369 options = args[n];
370 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700371 }
372
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000373 system = args[1];
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700374 source = args[2];
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000375 target = args[3];
376
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700377 if (!strncmp(source, "mtd@", 4)) {
378 n = mtd_name_to_number(source + 4);
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000379 if (n < 0) {
380 return -1;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700381 }
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000382
383 sprintf(tmp, "/dev/block/mtdblock%d", n);
384
Colin Crosscd0f1732010-04-19 17:10:24 -0700385 if (wait)
386 wait_for_file(tmp, COMMAND_RETRY_TIMEOUT);
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000387 if (mount(tmp, target, system, flags, options) < 0) {
388 return -1;
389 }
390
Ken Sumralldd4d7862011-02-17 18:09:47 -0800391 goto exit_success;
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000392 } else if (!strncmp(source, "loop@", 5)) {
393 int mode, loop, fd;
394 struct loop_info info;
395
396 mode = (flags & MS_RDONLY) ? O_RDONLY : O_RDWR;
397 fd = open(source + 5, mode);
398 if (fd < 0) {
399 return -1;
400 }
401
402 for (n = 0; ; n++) {
403 sprintf(tmp, "/dev/block/loop%d", n);
404 loop = open(tmp, mode);
405 if (loop < 0) {
406 return -1;
407 }
408
409 /* if it is a blank loop device */
410 if (ioctl(loop, LOOP_GET_STATUS, &info) < 0 && errno == ENXIO) {
411 /* if it becomes our loop device */
412 if (ioctl(loop, LOOP_SET_FD, fd) >= 0) {
413 close(fd);
414
415 if (mount(tmp, target, system, flags, options) < 0) {
416 ioctl(loop, LOOP_CLR_FD, 0);
417 close(loop);
418 return -1;
419 }
420
421 close(loop);
Ken Sumralldd4d7862011-02-17 18:09:47 -0800422 goto exit_success;
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000423 }
424 }
425
426 close(loop);
427 }
428
429 close(fd);
430 ERROR("out of loopback devices");
431 return -1;
432 } else {
Colin Crosscd0f1732010-04-19 17:10:24 -0700433 if (wait)
434 wait_for_file(source, COMMAND_RETRY_TIMEOUT);
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000435 if (mount(source, target, system, flags, options) < 0) {
Ken Sumrall7bc6e9e2011-05-26 20:01:39 -0700436 /* If this fails, it may be an encrypted filesystem
437 * or it could just be wiped. If wiped, that will be
438 * handled later in the boot process.
Ken Sumrall752923c2010-12-03 16:33:31 -0800439 * We only support encrypting /data. Check
440 * if we're trying to mount it, and if so,
441 * assume it's encrypted, mount a tmpfs instead.
442 * Then save the orig mount parms in properties
443 * for vold to query when it mounts the real
444 * encrypted /data.
445 */
Ken Sumrall7bc6e9e2011-05-26 20:01:39 -0700446 if (!strcmp(target, DATA_MNT_POINT) && !partition_wiped(source)) {
Ken Sumrall752923c2010-12-03 16:33:31 -0800447 const char *tmpfs_options;
448
449 tmpfs_options = property_get("ro.crypto.tmpfs_options");
450
451 if (mount("tmpfs", target, "tmpfs", MS_NOATIME | MS_NOSUID | MS_NODEV,
452 tmpfs_options) < 0) {
453 return -1;
454 }
455
456 /* Set the property that triggers the framework to do a minimal
457 * startup and ask the user for a password
458 */
Ken Sumrall4e84d3b2011-01-14 12:44:09 -0800459 property_set("ro.crypto.state", "encrypted");
Ken Sumrall752923c2010-12-03 16:33:31 -0800460 property_set("vold.decrypt", "1");
461 } else {
462 return -1;
463 }
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000464 }
465
Ken Sumrall752923c2010-12-03 16:33:31 -0800466 if (!strcmp(target, DATA_MNT_POINT)) {
467 char fs_flags[32];
468
469 /* Save the original mount options */
470 property_set("ro.crypto.fs_type", system);
471 property_set("ro.crypto.fs_real_blkdev", source);
472 property_set("ro.crypto.fs_mnt_point", target);
473 if (options) {
474 property_set("ro.crypto.fs_options", options);
475 }
476 snprintf(fs_flags, sizeof(fs_flags), "0x%8.8x", flags);
477 property_set("ro.crypto.fs_flags", fs_flags);
478 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700479 }
Ken Sumralldd4d7862011-02-17 18:09:47 -0800480
481exit_success:
482 /* If not running encrypted, then set the property saying we are
483 * unencrypted, and also trigger the action for a nonencrypted system.
484 */
485 if (!strcmp(target, DATA_MNT_POINT)) {
Ken Sumrallc5c51032011-03-08 17:01:29 -0800486 const char *prop;
487
Ken Sumralldd4d7862011-02-17 18:09:47 -0800488 prop = property_get("ro.crypto.state");
489 if (! prop) {
490 prop = "notset";
491 }
492 if (strcmp(prop, "encrypted")) {
493 property_set("ro.crypto.state", "unencrypted");
494 action_for_each_trigger("nonencrypted", action_add_queue_tail);
495 }
496 }
497
498 return 0;
499
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700500}
501
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500502int do_setcon(int nargs, char **args) {
503#ifdef HAVE_SELINUX
504 if (is_selinux_enabled() <= 0)
505 return 0;
506 if (setcon(args[1]) < 0) {
507 return -errno;
508 }
509#endif
510 return 0;
511}
512
513int do_setenforce(int nargs, char **args) {
514#ifdef HAVE_SELINUX
515 if (is_selinux_enabled() <= 0)
516 return 0;
517 if (security_setenforce(atoi(args[1])) < 0) {
518 return -errno;
519 }
520#endif
521 return 0;
522}
523
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700524int do_setkey(int nargs, char **args)
525{
526 struct kbentry kbe;
527 kbe.kb_table = strtoul(args[1], 0, 0);
528 kbe.kb_index = strtoul(args[2], 0, 0);
529 kbe.kb_value = strtoul(args[3], 0, 0);
530 return setkey(&kbe);
531}
532
533int do_setprop(int nargs, char **args)
534{
Mike Lockwood1f0bd322011-06-08 17:31:27 -0700535 const char *name = args[1];
536 const char *value = args[2];
Dima Zavin84bf9af2011-12-20 13:44:41 -0800537 char prop_val[PROP_VALUE_MAX];
538 int ret;
Mike Lockwood1f0bd322011-06-08 17:31:27 -0700539
Dima Zavin84bf9af2011-12-20 13:44:41 -0800540 ret = expand_props(prop_val, value, sizeof(prop_val));
541 if (ret) {
542 ERROR("cannot expand '%s' while assigning to '%s'\n", value, name);
543 return -EINVAL;
Mike Lockwood1f0bd322011-06-08 17:31:27 -0700544 }
Dima Zavin84bf9af2011-12-20 13:44:41 -0800545 property_set(name, prop_val);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700546 return 0;
547}
548
549int do_setrlimit(int nargs, char **args)
550{
551 struct rlimit limit;
552 int resource;
553 resource = atoi(args[1]);
554 limit.rlim_cur = atoi(args[2]);
555 limit.rlim_max = atoi(args[3]);
556 return setrlimit(resource, &limit);
557}
558
559int do_start(int nargs, char **args)
560{
561 struct service *svc;
562 svc = service_find_by_name(args[1]);
563 if (svc) {
San Mehatf24e2522009-05-19 13:30:46 -0700564 service_start(svc, NULL);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700565 }
566 return 0;
567}
568
569int do_stop(int nargs, char **args)
570{
571 struct service *svc;
572 svc = service_find_by_name(args[1]);
573 if (svc) {
574 service_stop(svc);
575 }
576 return 0;
577}
578
579int do_restart(int nargs, char **args)
580{
581 struct service *svc;
582 svc = service_find_by_name(args[1]);
583 if (svc) {
584 service_stop(svc);
San Mehatf24e2522009-05-19 13:30:46 -0700585 service_start(svc, NULL);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700586 }
587 return 0;
588}
589
590int do_trigger(int nargs, char **args)
591{
Jay Freeman (saurik)11e1c422008-11-17 06:35:08 +0000592 action_for_each_trigger(args[1], action_add_queue_tail);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700593 return 0;
594}
595
596int do_symlink(int nargs, char **args)
597{
598 return symlink(args[1], args[2]);
599}
600
Ken Sumrall203bad52011-01-18 17:37:41 -0800601int do_rm(int nargs, char **args)
602{
603 return unlink(args[1]);
604}
605
606int do_rmdir(int nargs, char **args)
607{
608 return rmdir(args[1]);
609}
610
The Android Open Source Project35237d12008-12-17 18:08:08 -0800611int do_sysclktz(int nargs, char **args)
612{
613 struct timezone tz;
614
615 if (nargs != 2)
616 return -1;
617
618 memset(&tz, 0, sizeof(tz));
619 tz.tz_minuteswest = atoi(args[1]);
620 if (settimeofday(NULL, &tz))
621 return -1;
622 return 0;
623}
624
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700625int do_write(int nargs, char **args)
626{
Mike Lockwood1f0bd322011-06-08 17:31:27 -0700627 const char *path = args[1];
628 const char *value = args[2];
Dima Zavin84bf9af2011-12-20 13:44:41 -0800629 char prop_val[PROP_VALUE_MAX];
630 int ret;
Mike Lockwood2c4d5dc2011-06-07 17:30:11 -0700631
Dima Zavin84bf9af2011-12-20 13:44:41 -0800632 ret = expand_props(prop_val, value, sizeof(prop_val));
633 if (ret) {
634 ERROR("cannot expand '%s' while writing to '%s'\n", value, path);
635 return -EINVAL;
636 }
637 return write_file(path, prop_val);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700638}
639
San Mehat7c44fe52009-08-26 16:39:25 -0700640int do_copy(int nargs, char **args)
641{
642 char *buffer = NULL;
643 int rc = 0;
644 int fd1 = -1, fd2 = -1;
645 struct stat info;
646 int brtw, brtr;
647 char *p;
648
649 if (nargs != 3)
650 return -1;
651
652 if (stat(args[1], &info) < 0)
653 return -1;
654
655 if ((fd1 = open(args[1], O_RDONLY)) < 0)
656 goto out_err;
657
Tom Zhu4833d9f2009-09-28 19:53:12 -0500658 if ((fd2 = open(args[2], O_WRONLY|O_CREAT|O_TRUNC, 0660)) < 0)
San Mehat7c44fe52009-08-26 16:39:25 -0700659 goto out_err;
660
661 if (!(buffer = malloc(info.st_size)))
662 goto out_err;
663
664 p = buffer;
665 brtr = info.st_size;
666 while(brtr) {
667 rc = read(fd1, p, brtr);
668 if (rc < 0)
669 goto out_err;
670 if (rc == 0)
671 break;
672 p += rc;
673 brtr -= rc;
674 }
675
676 p = buffer;
677 brtw = info.st_size;
678 while(brtw) {
679 rc = write(fd2, p, brtw);
680 if (rc < 0)
681 goto out_err;
682 if (rc == 0)
683 break;
684 p += rc;
685 brtw -= rc;
686 }
687
688 rc = 0;
689 goto out;
690out_err:
691 rc = -1;
692out:
693 if (buffer)
694 free(buffer);
695 if (fd1 >= 0)
696 close(fd1);
697 if (fd2 >= 0)
698 close(fd2);
699 return rc;
700}
701
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700702int do_chown(int nargs, char **args) {
703 /* GID is optional. */
704 if (nargs == 3) {
Geremy Condra42a93492012-03-20 12:49:55 -0700705 if (_chown(args[2], decode_uid(args[1]), -1) < 0)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700706 return -errno;
707 } else if (nargs == 4) {
Geremy Condra42a93492012-03-20 12:49:55 -0700708 if (_chown(args[3], decode_uid(args[1]), decode_uid(args[2])) < 0)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700709 return -errno;
710 } else {
711 return -1;
712 }
713 return 0;
714}
715
716static mode_t get_mode(const char *s) {
717 mode_t mode = 0;
718 while (*s) {
719 if (*s >= '0' && *s <= '7') {
720 mode = (mode<<3) | (*s-'0');
721 } else {
722 return -1;
723 }
724 s++;
725 }
726 return mode;
727}
728
729int do_chmod(int nargs, char **args) {
730 mode_t mode = get_mode(args[1]);
Geremy Condra42a93492012-03-20 12:49:55 -0700731 if (_chmod(args[2], mode) < 0) {
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700732 return -errno;
733 }
734 return 0;
735}
736
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500737int do_restorecon(int nargs, char **args) {
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500738 int i;
739
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500740 for (i = 1; i < nargs; i++) {
Stephen Smalleye096e362012-06-11 13:37:39 -0400741 if (restorecon(args[i]) < 0)
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500742 return -errno;
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500743 }
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500744 return 0;
745}
746
747int do_setsebool(int nargs, char **args) {
748#ifdef HAVE_SELINUX
749 SELboolean *b = alloca(nargs * sizeof(SELboolean));
750 char *v;
751 int i;
752
753 if (is_selinux_enabled() <= 0)
754 return 0;
755
756 for (i = 1; i < nargs; i++) {
757 char *name = args[i];
758 v = strchr(name, '=');
759 if (!v) {
760 ERROR("setsebool: argument %s had no =\n", name);
761 return -EINVAL;
762 }
763 *v++ = 0;
764 b[i-1].name = name;
765 if (!strcmp(v, "1") || !strcasecmp(v, "true") || !strcasecmp(v, "on"))
766 b[i-1].value = 1;
767 else if (!strcmp(v, "0") || !strcasecmp(v, "false") || !strcasecmp(v, "off"))
768 b[i-1].value = 0;
769 else {
770 ERROR("setsebool: invalid value %s\n", v);
771 return -EINVAL;
772 }
773 }
774
775 if (security_set_boolean_list(nargs - 1, b, 0) < 0)
776 return -errno;
777#endif
778 return 0;
779}
780
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700781int do_loglevel(int nargs, char **args) {
782 if (nargs == 2) {
Dima Zavin8f912822011-08-31 18:26:17 -0700783 klog_set_level(atoi(args[1]));
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700784 return 0;
785 }
786 return -1;
787}
788
Ken Sumrallc5c51032011-03-08 17:01:29 -0800789int do_load_persist_props(int nargs, char **args) {
790 if (nargs == 1) {
791 load_persist_props();
792 return 0;
793 }
794 return -1;
795}
796
Colin Crosscd0f1732010-04-19 17:10:24 -0700797int do_wait(int nargs, char **args)
798{
799 if (nargs == 2) {
800 return wait_for_file(args[1], COMMAND_RETRY_TIMEOUT);
801 }
802 return -1;
803}