blob: 9ead340fe04c44102c1d4330e49349aba6df261c [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>
Elliott Hughes3d74d7a2015-01-29 21:31:23 -080032#include <sys/time.h>
Ken Sumrall0e9dd902012-04-17 17:20:16 -070033#include <sys/wait.h>
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +000034#include <linux/loop.h>
Ken Sumrall7bc6e9e2011-05-26 20:01:39 -070035#include <cutils/partition_utils.h>
Nick Kralevichca8e66a2013-04-18 12:20:02 -070036#include <cutils/android_reboot.h>
Ken Sumrall0e9dd902012-04-17 17:20:16 -070037#include <fs_mgr.h>
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070038
Stephen Smalleye46f9d52012-01-13 08:48:47 -050039#include <selinux/selinux.h>
40#include <selinux/label.h>
Stephen Smalleye46f9d52012-01-13 08:48:47 -050041
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070042#include "init.h"
43#include "keywords.h"
44#include "property_service.h"
45#include "devices.h"
Colin Cross6310a822010-04-20 14:29:05 -070046#include "init_parser.h"
Colin Cross3899e9f2010-04-13 20:35:46 -070047#include "util.h"
Colin Crossed8a7d82010-04-19 17:05:34 -070048#include "log.h"
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070049
50#include <private/android_filesystem_config.h>
51
Nick Kralevichbc609542015-01-31 21:39:46 -080052#define chmod DO_NOT_USE_CHMOD_USE_FCHMODAT_SYMLINK_NOFOLLOW
53
James Morrissey381341f2014-05-16 11:36:36 +010054int add_environment(const char *name, const char *value);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070055
Elliott Hughesf3cf4382015-02-03 17:12:07 -080056// System call provided by bionic but not in any header file.
57extern "C" int init_module(void *, unsigned long, const char *);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070058
59static int write_file(const char *path, const char *value)
60{
61 int fd, ret, len;
62
Nick Kralevich45a884f2015-02-02 14:37:22 -080063 fd = open(path, O_WRONLY|O_CREAT|O_NOFOLLOW|O_CLOEXEC, 0600);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070064
65 if (fd < 0)
Mike Chan008abac2009-06-29 20:30:55 -070066 return -errno;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070067
68 len = strlen(value);
69
Elliott Hughes24627902015-02-04 10:25:09 -080070 ret = TEMP_FAILURE_RETRY(write(fd, value, len));
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070071
72 close(fd);
73 if (ret < 0) {
Mike Chan008abac2009-06-29 20:30:55 -070074 return -errno;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070075 } else {
76 return 0;
77 }
78}
79
The Android Open Source Project35237d12008-12-17 18:08:08 -080080static int insmod(const char *filename, char *options)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070081{
82 void *module;
83 unsigned size;
84 int ret;
85
86 module = read_file(filename, &size);
87 if (!module)
88 return -1;
89
The Android Open Source Project35237d12008-12-17 18:08:08 -080090 ret = init_module(module, size, options);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070091
92 free(module);
93
94 return ret;
95}
96
97static int setkey(struct kbentry *kbe)
98{
99 int fd, ret;
100
Nick Kralevich45a884f2015-02-02 14:37:22 -0800101 fd = open("/dev/tty0", O_RDWR | O_SYNC | O_CLOEXEC);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700102 if (fd < 0)
103 return -1;
104
105 ret = ioctl(fd, KDSKBENT, kbe);
106
107 close(fd);
108 return ret;
109}
110
111static int __ifupdown(const char *interface, int up)
112{
113 struct ifreq ifr;
114 int s, ret;
115
116 strlcpy(ifr.ifr_name, interface, IFNAMSIZ);
117
118 s = socket(AF_INET, SOCK_DGRAM, 0);
119 if (s < 0)
120 return -1;
121
122 ret = ioctl(s, SIOCGIFFLAGS, &ifr);
123 if (ret < 0) {
124 goto done;
125 }
126
127 if (up)
128 ifr.ifr_flags |= IFF_UP;
129 else
130 ifr.ifr_flags &= ~IFF_UP;
131
132 ret = ioctl(s, SIOCSIFFLAGS, &ifr);
Elliott Hughes24627902015-02-04 10:25:09 -0800133
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700134done:
135 close(s);
136 return ret;
137}
138
139static void service_start_if_not_disabled(struct service *svc)
140{
141 if (!(svc->flags & SVC_DISABLED)) {
San Mehatf24e2522009-05-19 13:30:46 -0700142 service_start(svc, NULL);
JP Abgrall3beec7e2014-05-02 21:14:29 -0700143 } else {
144 svc->flags |= SVC_DISABLED_START;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700145 }
146}
147
Jay Freeman (saurik)e7cb1372008-11-17 06:41:10 +0000148int do_chdir(int nargs, char **args)
149{
150 chdir(args[1]);
151 return 0;
152}
153
154int do_chroot(int nargs, char **args)
155{
156 chroot(args[1]);
157 return 0;
158}
159
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700160int do_class_start(int nargs, char **args)
161{
162 /* Starting a class does not start services
163 * which are explicitly disabled. They must
164 * be started individually.
165 */
166 service_for_each_class(args[1], service_start_if_not_disabled);
167 return 0;
168}
169
170int do_class_stop(int nargs, char **args)
171{
172 service_for_each_class(args[1], service_stop);
173 return 0;
174}
175
Ken Sumrall752923c2010-12-03 16:33:31 -0800176int do_class_reset(int nargs, char **args)
177{
178 service_for_each_class(args[1], service_reset);
179 return 0;
180}
181
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700182int do_domainname(int nargs, char **args)
183{
184 return write_file("/proc/sys/kernel/domainname", args[1]);
185}
186
JP Abgrall3beec7e2014-05-02 21:14:29 -0700187int do_enable(int nargs, char **args)
188{
189 struct service *svc;
190 svc = service_find_by_name(args[1]);
191 if (svc) {
192 svc->flags &= ~(SVC_DISABLED | SVC_RC_DISABLED);
193 if (svc->flags & SVC_DISABLED_START) {
194 service_start(svc, NULL);
195 }
196 } else {
197 return -1;
198 }
199 return 0;
200}
201
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700202int do_exec(int nargs, char **args)
203{
204 return -1;
205}
206
San Mehat429721c2014-09-23 07:48:47 -0700207int do_execonce(int nargs, char **args)
208{
209 pid_t child;
210 int child_status = 0;
211 static int already_done;
212
213 if (already_done) {
214 return -1;
215 }
216 already_done = 1;
217 if (!(child = fork())) {
218 /*
219 * Child process.
220 */
221 zap_stdio();
222 char *exec_args[100];
Elliott Hughesd3e37d12015-02-02 16:43:32 -0800223 size_t num_process_args = nargs;
San Mehat429721c2014-09-23 07:48:47 -0700224
225 memset(exec_args, 0, sizeof(exec_args));
226 if (num_process_args > ARRAY_SIZE(exec_args) - 1) {
Elliott Hughesd3e37d12015-02-02 16:43:32 -0800227 ERROR("exec called with %zu args, limit is %zu", num_process_args,
San Mehat429721c2014-09-23 07:48:47 -0700228 ARRAY_SIZE(exec_args) - 1);
229 _exit(1);
230 }
Elliott Hughesd3e37d12015-02-02 16:43:32 -0800231 for (size_t i = 1; i < num_process_args; i++)
San Mehat429721c2014-09-23 07:48:47 -0700232 exec_args[i - 1] = args[i];
233
234 if (execv(exec_args[0], exec_args) == -1) {
235 ERROR("Failed to execv '%s' (%s)", exec_args[0], strerror(errno));
236 _exit(1);
237 }
238 ERROR("Returned from execv()!");
239 _exit(1);
240 }
241
242 /*
243 * Parent process.
244 */
245 if (child == -1) {
246 ERROR("Fork failed\n");
247 return -1;
248 }
249
250 if (TEMP_FAILURE_RETRY(waitpid(child, &child_status, 0)) == -1) {
251 ERROR("waitpid(): failed (%s)\n", strerror(errno));
252 return -1;
253 }
254
255 if (WIFSIGNALED(child_status)) {
256 INFO("Child exited due to signal %d\n", WTERMSIG(child_status));
257 return -1;
258 } else if (WIFEXITED(child_status)) {
259 INFO("Child exited normally (exit code %d)\n", WEXITSTATUS(child_status));
260 return WEXITSTATUS(child_status);
261 }
262
263 ERROR("Abnormal child process exit\n");
264
265 return -1;
266}
267
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700268int do_export(int nargs, char **args)
269{
James Morrissey381341f2014-05-16 11:36:36 +0100270 return add_environment(args[1], args[2]);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700271}
272
273int do_hostname(int nargs, char **args)
274{
275 return write_file("/proc/sys/kernel/hostname", args[1]);
276}
277
278int do_ifup(int nargs, char **args)
279{
280 return __ifupdown(args[1], 1);
281}
282
The Android Open Source Project35237d12008-12-17 18:08:08 -0800283
284static int do_insmod_inner(int nargs, char **args, int opt_len)
285{
286 char options[opt_len + 1];
287 int i;
288
289 options[0] = '\0';
290 if (nargs > 2) {
291 strcpy(options, args[2]);
292 for (i = 3; i < nargs; ++i) {
293 strcat(options, " ");
294 strcat(options, args[i]);
295 }
296 }
297
298 return insmod(args[1], options);
299}
300
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700301int do_insmod(int nargs, char **args)
302{
The Android Open Source Project35237d12008-12-17 18:08:08 -0800303 int i;
304 int size = 0;
305
306 if (nargs > 2) {
307 for (i = 2; i < nargs; ++i)
308 size += strlen(args[i]) + 1;
309 }
310
311 return do_insmod_inner(nargs, args, size);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700312}
313
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700314int do_mkdir(int nargs, char **args)
315{
316 mode_t mode = 0755;
Chia-chi Yeh27164dc2011-07-08 12:57:36 -0700317 int ret;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700318
319 /* mkdir <path> [mode] [owner] [group] */
320
321 if (nargs >= 3) {
322 mode = strtoul(args[2], 0, 8);
323 }
324
Stephen Smalleye096e362012-06-11 13:37:39 -0400325 ret = make_dir(args[1], mode);
Chia-chi Yeh27164dc2011-07-08 12:57:36 -0700326 /* chmod in case the directory already exists */
327 if (ret == -1 && errno == EEXIST) {
Nick Kralevichbc609542015-01-31 21:39:46 -0800328 ret = fchmodat(AT_FDCWD, args[1], mode, AT_SYMLINK_NOFOLLOW);
Chia-chi Yeh27164dc2011-07-08 12:57:36 -0700329 }
330 if (ret == -1) {
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700331 return -errno;
332 }
333
334 if (nargs >= 4) {
335 uid_t uid = decode_uid(args[3]);
336 gid_t gid = -1;
337
338 if (nargs == 5) {
339 gid = decode_uid(args[4]);
340 }
341
Nick Kralevichbc609542015-01-31 21:39:46 -0800342 if (lchown(args[1], uid, gid) == -1) {
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700343 return -errno;
344 }
Benoit Goby5c8574b2012-08-14 15:43:46 -0700345
346 /* chown may have cleared S_ISUID and S_ISGID, chmod again */
347 if (mode & (S_ISUID | S_ISGID)) {
Nick Kralevichbc609542015-01-31 21:39:46 -0800348 ret = fchmodat(AT_FDCWD, args[1], mode, AT_SYMLINK_NOFOLLOW);
Benoit Goby5c8574b2012-08-14 15:43:46 -0700349 if (ret == -1) {
350 return -errno;
351 }
352 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700353 }
354
355 return 0;
356}
357
358static struct {
359 const char *name;
360 unsigned flag;
361} mount_flags[] = {
362 { "noatime", MS_NOATIME },
Lars Svenssonb6ee25e2011-07-14 13:39:09 +0200363 { "noexec", MS_NOEXEC },
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700364 { "nosuid", MS_NOSUID },
365 { "nodev", MS_NODEV },
366 { "nodiratime", MS_NODIRATIME },
367 { "ro", MS_RDONLY },
368 { "rw", 0 },
369 { "remount", MS_REMOUNT },
Jeff Sharkeye50ac5f2012-08-14 11:34:34 -0700370 { "bind", MS_BIND },
371 { "rec", MS_REC },
372 { "unbindable", MS_UNBINDABLE },
373 { "private", MS_PRIVATE },
374 { "slave", MS_SLAVE },
375 { "shared", MS_SHARED },
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700376 { "defaults", 0 },
377 { 0, 0 },
378};
379
Ken Sumrall752923c2010-12-03 16:33:31 -0800380#define DATA_MNT_POINT "/data"
381
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700382/* mount <type> <device> <path> <flags ...> <options> */
383int do_mount(int nargs, char **args)
384{
385 char tmp[64];
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000386 char *source, *target, *system;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700387 char *options = NULL;
388 unsigned flags = 0;
389 int n, i;
Colin Crosscd0f1732010-04-19 17:10:24 -0700390 int wait = 0;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700391
392 for (n = 4; n < nargs; n++) {
393 for (i = 0; mount_flags[i].name; i++) {
394 if (!strcmp(args[n], mount_flags[i].name)) {
395 flags |= mount_flags[i].flag;
396 break;
397 }
398 }
399
Colin Crosscd0f1732010-04-19 17:10:24 -0700400 if (!mount_flags[i].name) {
401 if (!strcmp(args[n], "wait"))
402 wait = 1;
403 /* if our last argument isn't a flag, wolf it up as an option string */
404 else if (n + 1 == nargs)
405 options = args[n];
406 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700407 }
408
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000409 system = args[1];
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700410 source = args[2];
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000411 target = args[3];
412
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700413 if (!strncmp(source, "mtd@", 4)) {
414 n = mtd_name_to_number(source + 4);
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000415 if (n < 0) {
416 return -1;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700417 }
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000418
419 sprintf(tmp, "/dev/block/mtdblock%d", n);
420
Colin Crosscd0f1732010-04-19 17:10:24 -0700421 if (wait)
422 wait_for_file(tmp, COMMAND_RETRY_TIMEOUT);
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000423 if (mount(tmp, target, system, flags, options) < 0) {
424 return -1;
425 }
426
Ken Sumralldd4d7862011-02-17 18:09:47 -0800427 goto exit_success;
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000428 } else if (!strncmp(source, "loop@", 5)) {
429 int mode, loop, fd;
430 struct loop_info info;
431
432 mode = (flags & MS_RDONLY) ? O_RDONLY : O_RDWR;
Nick Kralevich45a884f2015-02-02 14:37:22 -0800433 fd = open(source + 5, mode | O_CLOEXEC);
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000434 if (fd < 0) {
435 return -1;
436 }
437
438 for (n = 0; ; n++) {
439 sprintf(tmp, "/dev/block/loop%d", n);
Nick Kralevich45a884f2015-02-02 14:37:22 -0800440 loop = open(tmp, mode | O_CLOEXEC);
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000441 if (loop < 0) {
Tomasz Kondelbfdcc402014-02-06 08:57:27 +0100442 close(fd);
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000443 return -1;
444 }
445
446 /* if it is a blank loop device */
447 if (ioctl(loop, LOOP_GET_STATUS, &info) < 0 && errno == ENXIO) {
448 /* if it becomes our loop device */
449 if (ioctl(loop, LOOP_SET_FD, fd) >= 0) {
450 close(fd);
451
452 if (mount(tmp, target, system, flags, options) < 0) {
453 ioctl(loop, LOOP_CLR_FD, 0);
454 close(loop);
455 return -1;
456 }
457
458 close(loop);
Ken Sumralldd4d7862011-02-17 18:09:47 -0800459 goto exit_success;
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000460 }
461 }
462
463 close(loop);
464 }
465
466 close(fd);
467 ERROR("out of loopback devices");
468 return -1;
469 } else {
Colin Crosscd0f1732010-04-19 17:10:24 -0700470 if (wait)
471 wait_for_file(source, COMMAND_RETRY_TIMEOUT);
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000472 if (mount(source, target, system, flags, options) < 0) {
Ken Sumrall0e9dd902012-04-17 17:20:16 -0700473 return -1;
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000474 }
475
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700476 }
Ken Sumralldd4d7862011-02-17 18:09:47 -0800477
478exit_success:
Ken Sumralldd4d7862011-02-17 18:09:47 -0800479 return 0;
480
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700481}
482
JP Abgrallcee20682014-07-02 14:26:54 -0700483static int wipe_data_via_recovery()
484{
485 mkdir("/cache/recovery", 0700);
Nick Kralevich45a884f2015-02-02 14:37:22 -0800486 int fd = open("/cache/recovery/command", O_RDWR|O_CREAT|O_TRUNC|O_CLOEXEC, 0600);
JP Abgrallcee20682014-07-02 14:26:54 -0700487 if (fd >= 0) {
Jeff Sharkeyd26135b2014-09-24 11:46:36 -0700488 write(fd, "--wipe_data\n", strlen("--wipe_data\n") + 1);
489 write(fd, "--reason=wipe_data_via_recovery\n", strlen("--reason=wipe_data_via_recovery\n") + 1);
JP Abgrallcee20682014-07-02 14:26:54 -0700490 close(fd);
491 } else {
492 ERROR("could not open /cache/recovery/command\n");
493 return -1;
494 }
495 android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
496 while (1) { pause(); } // never reached
497}
498
499
500/*
501 * This function might request a reboot, in which case it will
502 * not return.
503 */
Ken Sumrall0e9dd902012-04-17 17:20:16 -0700504int do_mount_all(int nargs, char **args)
505{
506 pid_t pid;
507 int ret = -1;
508 int child_ret = -1;
509 int status;
Ken Sumrallab6b8522013-02-13 12:58:40 -0800510 struct fstab *fstab;
Ken Sumrall0e9dd902012-04-17 17:20:16 -0700511
512 if (nargs != 2) {
513 return -1;
514 }
515
516 /*
517 * Call fs_mgr_mount_all() to mount all filesystems. We fork(2) and
518 * do the call in the child to provide protection to the main init
519 * process if anything goes wrong (crash or memory leak), and wait for
520 * the child to finish in the parent.
521 */
522 pid = fork();
523 if (pid > 0) {
524 /* Parent. Wait for the child to return */
Paul Lawrence40af0922014-09-16 14:31:23 -0700525 int wp_ret = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
526 if (wp_ret < 0) {
527 /* Unexpected error code. We will continue anyway. */
528 NOTICE("waitpid failed rc=%d, errno=%d\n", wp_ret, errno);
529 }
530
Ken Sumrall0e9dd902012-04-17 17:20:16 -0700531 if (WIFEXITED(status)) {
532 ret = WEXITSTATUS(status);
533 } else {
534 ret = -1;
535 }
536 } else if (pid == 0) {
537 /* child, call fs_mgr_mount_all() */
538 klog_set_level(6); /* So we can see what fs_mgr_mount_all() does */
Ken Sumrallab6b8522013-02-13 12:58:40 -0800539 fstab = fs_mgr_read_fstab(args[1]);
540 child_ret = fs_mgr_mount_all(fstab);
541 fs_mgr_free_fstab(fstab);
Ken Sumrall0e9dd902012-04-17 17:20:16 -0700542 if (child_ret == -1) {
543 ERROR("fs_mgr_mount_all returned an error\n");
544 }
JP Abgrallf22b7452014-07-02 13:16:04 -0700545 _exit(child_ret);
Ken Sumrall0e9dd902012-04-17 17:20:16 -0700546 } else {
547 /* fork failed, return an error */
548 return -1;
549 }
550
JP Abgrallf22b7452014-07-02 13:16:04 -0700551 if (ret == FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION) {
Paul Lawrence166fa3d2014-02-03 13:27:49 -0800552 property_set("vold.decrypt", "trigger_encryption");
JP Abgrallf22b7452014-07-02 13:16:04 -0700553 } else if (ret == FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED) {
Ken Sumrall0e9dd902012-04-17 17:20:16 -0700554 property_set("ro.crypto.state", "encrypted");
Paul Lawrence13d5bb42014-01-30 10:43:52 -0800555 property_set("vold.decrypt", "trigger_default_encryption");
JP Abgrallf22b7452014-07-02 13:16:04 -0700556 } else if (ret == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
Ken Sumrall0e9dd902012-04-17 17:20:16 -0700557 property_set("ro.crypto.state", "unencrypted");
558 /* If fs_mgr determined this is an unencrypted device, then trigger
559 * that action.
560 */
561 action_for_each_trigger("nonencrypted", action_add_queue_tail);
JP Abgrallcee20682014-07-02 14:26:54 -0700562 } else if (ret == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) {
563 /* Setup a wipe via recovery, and reboot into recovery */
564 ERROR("fs_mgr_mount_all suggested recovery, so wiping data via recovery.\n");
565 ret = wipe_data_via_recovery();
566 /* If reboot worked, there is no return. */
567 } else if (ret > 0) {
568 ERROR("fs_mgr_mount_all returned unexpected error %d\n", ret);
Ken Sumrall0e9dd902012-04-17 17:20:16 -0700569 }
JP Abgrallf22b7452014-07-02 13:16:04 -0700570 /* else ... < 0: error */
Ken Sumrall0e9dd902012-04-17 17:20:16 -0700571
572 return ret;
573}
574
Ken Sumralla76baaa2013-07-09 18:42:09 -0700575int do_swapon_all(int nargs, char **args)
576{
577 struct fstab *fstab;
578 int ret;
579
580 fstab = fs_mgr_read_fstab(args[1]);
581 ret = fs_mgr_swapon_all(fstab);
582 fs_mgr_free_fstab(fstab);
583
584 return ret;
585}
586
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500587int do_setcon(int nargs, char **args) {
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500588 if (is_selinux_enabled() <= 0)
589 return 0;
590 if (setcon(args[1]) < 0) {
591 return -errno;
592 }
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500593 return 0;
594}
595
596int do_setenforce(int nargs, char **args) {
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500597 if (is_selinux_enabled() <= 0)
598 return 0;
599 if (security_setenforce(atoi(args[1])) < 0) {
600 return -errno;
601 }
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500602 return 0;
603}
604
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700605int do_setkey(int nargs, char **args)
606{
607 struct kbentry kbe;
608 kbe.kb_table = strtoul(args[1], 0, 0);
609 kbe.kb_index = strtoul(args[2], 0, 0);
610 kbe.kb_value = strtoul(args[3], 0, 0);
611 return setkey(&kbe);
612}
613
614int do_setprop(int nargs, char **args)
615{
Mike Lockwood1f0bd322011-06-08 17:31:27 -0700616 const char *name = args[1];
617 const char *value = args[2];
Dima Zavin84bf9af2011-12-20 13:44:41 -0800618 char prop_val[PROP_VALUE_MAX];
619 int ret;
Mike Lockwood1f0bd322011-06-08 17:31:27 -0700620
Dima Zavin84bf9af2011-12-20 13:44:41 -0800621 ret = expand_props(prop_val, value, sizeof(prop_val));
622 if (ret) {
623 ERROR("cannot expand '%s' while assigning to '%s'\n", value, name);
624 return -EINVAL;
Mike Lockwood1f0bd322011-06-08 17:31:27 -0700625 }
Dima Zavin84bf9af2011-12-20 13:44:41 -0800626 property_set(name, prop_val);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700627 return 0;
628}
629
630int do_setrlimit(int nargs, char **args)
631{
632 struct rlimit limit;
633 int resource;
634 resource = atoi(args[1]);
635 limit.rlim_cur = atoi(args[2]);
636 limit.rlim_max = atoi(args[3]);
637 return setrlimit(resource, &limit);
638}
639
640int do_start(int nargs, char **args)
641{
642 struct service *svc;
643 svc = service_find_by_name(args[1]);
644 if (svc) {
San Mehatf24e2522009-05-19 13:30:46 -0700645 service_start(svc, NULL);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700646 }
647 return 0;
648}
649
650int do_stop(int nargs, char **args)
651{
652 struct service *svc;
653 svc = service_find_by_name(args[1]);
654 if (svc) {
655 service_stop(svc);
656 }
657 return 0;
658}
659
660int do_restart(int nargs, char **args)
661{
662 struct service *svc;
663 svc = service_find_by_name(args[1]);
664 if (svc) {
Mike Kasickb54f39f2012-01-25 23:48:46 -0500665 service_restart(svc);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700666 }
667 return 0;
668}
669
Nick Kralevichca8e66a2013-04-18 12:20:02 -0700670int do_powerctl(int nargs, char **args)
671{
672 char command[PROP_VALUE_MAX];
673 int res;
674 int len = 0;
675 int cmd = 0;
Elliott Hughesf3cf4382015-02-03 17:12:07 -0800676 const char *reboot_target;
Nick Kralevichca8e66a2013-04-18 12:20:02 -0700677
678 res = expand_props(command, args[1], sizeof(command));
679 if (res) {
680 ERROR("powerctl: cannot expand '%s'\n", args[1]);
681 return -EINVAL;
682 }
683
684 if (strncmp(command, "shutdown", 8) == 0) {
685 cmd = ANDROID_RB_POWEROFF;
686 len = 8;
687 } else if (strncmp(command, "reboot", 6) == 0) {
688 cmd = ANDROID_RB_RESTART2;
689 len = 6;
690 } else {
691 ERROR("powerctl: unrecognized command '%s'\n", command);
692 return -EINVAL;
693 }
694
695 if (command[len] == ',') {
696 reboot_target = &command[len + 1];
697 } else if (command[len] == '\0') {
698 reboot_target = "";
699 } else {
700 ERROR("powerctl: unrecognized reboot target '%s'\n", &command[len]);
701 return -EINVAL;
702 }
703
704 return android_reboot(cmd, 0, reboot_target);
705}
706
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700707int do_trigger(int nargs, char **args)
708{
Jay Freeman (saurik)11e1c422008-11-17 06:35:08 +0000709 action_for_each_trigger(args[1], action_add_queue_tail);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700710 return 0;
711}
712
713int do_symlink(int nargs, char **args)
714{
715 return symlink(args[1], args[2]);
716}
717
Ken Sumrall203bad52011-01-18 17:37:41 -0800718int do_rm(int nargs, char **args)
719{
720 return unlink(args[1]);
721}
722
723int do_rmdir(int nargs, char **args)
724{
725 return rmdir(args[1]);
726}
727
The Android Open Source Project35237d12008-12-17 18:08:08 -0800728int do_sysclktz(int nargs, char **args)
729{
730 struct timezone tz;
731
732 if (nargs != 2)
733 return -1;
734
735 memset(&tz, 0, sizeof(tz));
Elliott Hughes24627902015-02-04 10:25:09 -0800736 tz.tz_minuteswest = atoi(args[1]);
The Android Open Source Project35237d12008-12-17 18:08:08 -0800737 if (settimeofday(NULL, &tz))
738 return -1;
739 return 0;
740}
741
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700742int do_write(int nargs, char **args)
743{
Mike Lockwood1f0bd322011-06-08 17:31:27 -0700744 const char *path = args[1];
745 const char *value = args[2];
Dima Zavin84bf9af2011-12-20 13:44:41 -0800746 char prop_val[PROP_VALUE_MAX];
747 int ret;
Mike Lockwood2c4d5dc2011-06-07 17:30:11 -0700748
Dima Zavin84bf9af2011-12-20 13:44:41 -0800749 ret = expand_props(prop_val, value, sizeof(prop_val));
750 if (ret) {
751 ERROR("cannot expand '%s' while writing to '%s'\n", value, path);
752 return -EINVAL;
753 }
754 return write_file(path, prop_val);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700755}
756
San Mehat7c44fe52009-08-26 16:39:25 -0700757int do_copy(int nargs, char **args)
758{
759 char *buffer = NULL;
760 int rc = 0;
761 int fd1 = -1, fd2 = -1;
762 struct stat info;
763 int brtw, brtr;
764 char *p;
765
766 if (nargs != 3)
767 return -1;
768
Elliott Hughes24627902015-02-04 10:25:09 -0800769 if (stat(args[1], &info) < 0)
San Mehat7c44fe52009-08-26 16:39:25 -0700770 return -1;
771
Nick Kralevich45a884f2015-02-02 14:37:22 -0800772 if ((fd1 = open(args[1], O_RDONLY|O_CLOEXEC)) < 0)
San Mehat7c44fe52009-08-26 16:39:25 -0700773 goto out_err;
774
Nick Kralevich45a884f2015-02-02 14:37:22 -0800775 if ((fd2 = open(args[2], O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0660)) < 0)
San Mehat7c44fe52009-08-26 16:39:25 -0700776 goto out_err;
777
Elliott Hughesf3cf4382015-02-03 17:12:07 -0800778 if (!(buffer = (char*) malloc(info.st_size)))
San Mehat7c44fe52009-08-26 16:39:25 -0700779 goto out_err;
780
781 p = buffer;
782 brtr = info.st_size;
783 while(brtr) {
784 rc = read(fd1, p, brtr);
785 if (rc < 0)
786 goto out_err;
787 if (rc == 0)
788 break;
789 p += rc;
790 brtr -= rc;
791 }
792
793 p = buffer;
794 brtw = info.st_size;
795 while(brtw) {
796 rc = write(fd2, p, brtw);
797 if (rc < 0)
798 goto out_err;
799 if (rc == 0)
800 break;
801 p += rc;
802 brtw -= rc;
803 }
804
805 rc = 0;
806 goto out;
807out_err:
808 rc = -1;
809out:
810 if (buffer)
811 free(buffer);
812 if (fd1 >= 0)
813 close(fd1);
814 if (fd2 >= 0)
815 close(fd2);
816 return rc;
817}
818
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700819int do_chown(int nargs, char **args) {
820 /* GID is optional. */
821 if (nargs == 3) {
Nick Kralevichbc609542015-01-31 21:39:46 -0800822 if (lchown(args[2], decode_uid(args[1]), -1) == -1)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700823 return -errno;
824 } else if (nargs == 4) {
Nick Kralevichbc609542015-01-31 21:39:46 -0800825 if (lchown(args[3], decode_uid(args[1]), decode_uid(args[2])) == -1)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700826 return -errno;
827 } else {
828 return -1;
829 }
830 return 0;
831}
832
833static mode_t get_mode(const char *s) {
834 mode_t mode = 0;
835 while (*s) {
836 if (*s >= '0' && *s <= '7') {
837 mode = (mode<<3) | (*s-'0');
838 } else {
839 return -1;
840 }
841 s++;
842 }
843 return mode;
844}
845
846int do_chmod(int nargs, char **args) {
847 mode_t mode = get_mode(args[1]);
Nick Kralevichbc609542015-01-31 21:39:46 -0800848 if (fchmodat(AT_FDCWD, args[2], mode, AT_SYMLINK_NOFOLLOW) < 0) {
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700849 return -errno;
850 }
851 return 0;
852}
853
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500854int do_restorecon(int nargs, char **args) {
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500855 int i;
Stephen Smalley726e8f72013-10-09 16:02:09 -0400856 int ret = 0;
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500857
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500858 for (i = 1; i < nargs; i++) {
Stephen Smalleye096e362012-06-11 13:37:39 -0400859 if (restorecon(args[i]) < 0)
Stephen Smalley726e8f72013-10-09 16:02:09 -0400860 ret = -errno;
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500861 }
Stephen Smalley726e8f72013-10-09 16:02:09 -0400862 return ret;
863}
864
865int do_restorecon_recursive(int nargs, char **args) {
866 int i;
867 int ret = 0;
868
869 for (i = 1; i < nargs; i++) {
870 if (restorecon_recursive(args[i]) < 0)
871 ret = -errno;
872 }
873 return ret;
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500874}
875
876int do_setsebool(int nargs, char **args) {
Stephen Smalley0e23fee2012-11-28 13:52:12 -0500877 const char *name = args[1];
878 const char *value = args[2];
879 SELboolean b;
880 int ret;
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500881
882 if (is_selinux_enabled() <= 0)
883 return 0;
884
Stephen Smalley0e23fee2012-11-28 13:52:12 -0500885 b.name = name;
886 if (!strcmp(value, "1") || !strcasecmp(value, "true") || !strcasecmp(value, "on"))
887 b.value = 1;
888 else if (!strcmp(value, "0") || !strcasecmp(value, "false") || !strcasecmp(value, "off"))
889 b.value = 0;
890 else {
891 ERROR("setsebool: invalid value %s\n", value);
892 return -EINVAL;
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500893 }
894
Stephen Smalley0e23fee2012-11-28 13:52:12 -0500895 if (security_set_boolean_list(1, &b, 0) < 0) {
896 ret = -errno;
897 ERROR("setsebool: could not set %s to %s\n", name, value);
898 return ret;
899 }
Kenny Rootb5982bf2012-10-16 23:07:05 -0700900
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500901 return 0;
902}
903
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700904int do_loglevel(int nargs, char **args) {
Riley Andrews1bbef882014-06-26 13:55:03 -0700905 int log_level;
906 char log_level_str[PROP_VALUE_MAX] = "";
907 if (nargs != 2) {
908 ERROR("loglevel: missing argument\n");
909 return -EINVAL;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700910 }
Riley Andrews1bbef882014-06-26 13:55:03 -0700911
912 if (expand_props(log_level_str, args[1], sizeof(log_level_str))) {
913 ERROR("loglevel: cannot expand '%s'\n", args[1]);
914 return -EINVAL;
915 }
916 log_level = atoi(log_level_str);
917 if (log_level < KLOG_ERROR_LEVEL || log_level > KLOG_DEBUG_LEVEL) {
918 ERROR("loglevel: invalid log level'%d'\n", log_level);
919 return -EINVAL;
920 }
921 klog_set_level(log_level);
922 return 0;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700923}
924
Ken Sumrallc5c51032011-03-08 17:01:29 -0800925int do_load_persist_props(int nargs, char **args) {
926 if (nargs == 1) {
927 load_persist_props();
928 return 0;
929 }
930 return -1;
931}
932
Riley Andrewse4b7b292014-06-16 15:06:21 -0700933int do_load_all_props(int nargs, char **args) {
934 if (nargs == 1) {
935 load_all_props();
936 return 0;
937 }
938 return -1;
939}
940
Colin Crosscd0f1732010-04-19 17:10:24 -0700941int do_wait(int nargs, char **args)
942{
943 if (nargs == 2) {
944 return wait_for_file(args[1], COMMAND_RETRY_TIMEOUT);
Patrick McCormick96d0a4d2011-02-04 10:51:39 -0800945 } else if (nargs == 3) {
946 return wait_for_file(args[1], atoi(args[2]));
947 } else
948 return -1;
Colin Crosscd0f1732010-04-19 17:10:24 -0700949}