blob: 2521daf97a034ea4a98fa125f00d084ecc6482a5 [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
56extern int init_module(void *, unsigned long, const char *);
57
58static int write_file(const char *path, const char *value)
59{
60 int fd, ret, len;
61
Nick Kralevich45a884f2015-02-02 14:37:22 -080062 fd = open(path, O_WRONLY|O_CREAT|O_NOFOLLOW|O_CLOEXEC, 0600);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070063
64 if (fd < 0)
Mike Chan008abac2009-06-29 20:30:55 -070065 return -errno;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070066
67 len = strlen(value);
68
69 do {
70 ret = write(fd, value, len);
71 } while (ret < 0 && errno == EINTR);
72
73 close(fd);
74 if (ret < 0) {
Mike Chan008abac2009-06-29 20:30:55 -070075 return -errno;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070076 } else {
77 return 0;
78 }
79}
80
The Android Open Source Project35237d12008-12-17 18:08:08 -080081static int insmod(const char *filename, char *options)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070082{
83 void *module;
84 unsigned size;
85 int ret;
86
87 module = read_file(filename, &size);
88 if (!module)
89 return -1;
90
The Android Open Source Project35237d12008-12-17 18:08:08 -080091 ret = init_module(module, size, options);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070092
93 free(module);
94
95 return ret;
96}
97
98static int setkey(struct kbentry *kbe)
99{
100 int fd, ret;
101
Nick Kralevich45a884f2015-02-02 14:37:22 -0800102 fd = open("/dev/tty0", O_RDWR | O_SYNC | O_CLOEXEC);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700103 if (fd < 0)
104 return -1;
105
106 ret = ioctl(fd, KDSKBENT, kbe);
107
108 close(fd);
109 return ret;
110}
111
112static int __ifupdown(const char *interface, int up)
113{
114 struct ifreq ifr;
115 int s, ret;
116
117 strlcpy(ifr.ifr_name, interface, IFNAMSIZ);
118
119 s = socket(AF_INET, SOCK_DGRAM, 0);
120 if (s < 0)
121 return -1;
122
123 ret = ioctl(s, SIOCGIFFLAGS, &ifr);
124 if (ret < 0) {
125 goto done;
126 }
127
128 if (up)
129 ifr.ifr_flags |= IFF_UP;
130 else
131 ifr.ifr_flags &= ~IFF_UP;
132
133 ret = ioctl(s, SIOCSIFFLAGS, &ifr);
134
135done:
136 close(s);
137 return ret;
138}
139
140static void service_start_if_not_disabled(struct service *svc)
141{
142 if (!(svc->flags & SVC_DISABLED)) {
San Mehatf24e2522009-05-19 13:30:46 -0700143 service_start(svc, NULL);
JP Abgrall3beec7e2014-05-02 21:14:29 -0700144 } else {
145 svc->flags |= SVC_DISABLED_START;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700146 }
147}
148
Jay Freeman (saurik)e7cb1372008-11-17 06:41:10 +0000149int do_chdir(int nargs, char **args)
150{
151 chdir(args[1]);
152 return 0;
153}
154
155int do_chroot(int nargs, char **args)
156{
157 chroot(args[1]);
158 return 0;
159}
160
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700161int do_class_start(int nargs, char **args)
162{
163 /* Starting a class does not start services
164 * which are explicitly disabled. They must
165 * be started individually.
166 */
167 service_for_each_class(args[1], service_start_if_not_disabled);
168 return 0;
169}
170
171int do_class_stop(int nargs, char **args)
172{
173 service_for_each_class(args[1], service_stop);
174 return 0;
175}
176
Ken Sumrall752923c2010-12-03 16:33:31 -0800177int do_class_reset(int nargs, char **args)
178{
179 service_for_each_class(args[1], service_reset);
180 return 0;
181}
182
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700183int do_domainname(int nargs, char **args)
184{
185 return write_file("/proc/sys/kernel/domainname", args[1]);
186}
187
JP Abgrall3beec7e2014-05-02 21:14:29 -0700188int do_enable(int nargs, char **args)
189{
190 struct service *svc;
191 svc = service_find_by_name(args[1]);
192 if (svc) {
193 svc->flags &= ~(SVC_DISABLED | SVC_RC_DISABLED);
194 if (svc->flags & SVC_DISABLED_START) {
195 service_start(svc, NULL);
196 }
197 } else {
198 return -1;
199 }
200 return 0;
201}
202
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700203int do_exec(int nargs, char **args)
204{
205 return -1;
206}
207
San Mehat429721c2014-09-23 07:48:47 -0700208int do_execonce(int nargs, char **args)
209{
210 pid_t child;
211 int child_status = 0;
212 static int already_done;
213
214 if (already_done) {
215 return -1;
216 }
217 already_done = 1;
218 if (!(child = fork())) {
219 /*
220 * Child process.
221 */
222 zap_stdio();
223 char *exec_args[100];
Elliott Hughesd3e37d12015-02-02 16:43:32 -0800224 size_t num_process_args = nargs;
San Mehat429721c2014-09-23 07:48:47 -0700225
226 memset(exec_args, 0, sizeof(exec_args));
227 if (num_process_args > ARRAY_SIZE(exec_args) - 1) {
Elliott Hughesd3e37d12015-02-02 16:43:32 -0800228 ERROR("exec called with %zu args, limit is %zu", num_process_args,
San Mehat429721c2014-09-23 07:48:47 -0700229 ARRAY_SIZE(exec_args) - 1);
230 _exit(1);
231 }
Elliott Hughesd3e37d12015-02-02 16:43:32 -0800232 for (size_t i = 1; i < num_process_args; i++)
San Mehat429721c2014-09-23 07:48:47 -0700233 exec_args[i - 1] = args[i];
234
235 if (execv(exec_args[0], exec_args) == -1) {
236 ERROR("Failed to execv '%s' (%s)", exec_args[0], strerror(errno));
237 _exit(1);
238 }
239 ERROR("Returned from execv()!");
240 _exit(1);
241 }
242
243 /*
244 * Parent process.
245 */
246 if (child == -1) {
247 ERROR("Fork failed\n");
248 return -1;
249 }
250
251 if (TEMP_FAILURE_RETRY(waitpid(child, &child_status, 0)) == -1) {
252 ERROR("waitpid(): failed (%s)\n", strerror(errno));
253 return -1;
254 }
255
256 if (WIFSIGNALED(child_status)) {
257 INFO("Child exited due to signal %d\n", WTERMSIG(child_status));
258 return -1;
259 } else if (WIFEXITED(child_status)) {
260 INFO("Child exited normally (exit code %d)\n", WEXITSTATUS(child_status));
261 return WEXITSTATUS(child_status);
262 }
263
264 ERROR("Abnormal child process exit\n");
265
266 return -1;
267}
268
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700269int do_export(int nargs, char **args)
270{
James Morrissey381341f2014-05-16 11:36:36 +0100271 return add_environment(args[1], args[2]);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700272}
273
274int do_hostname(int nargs, char **args)
275{
276 return write_file("/proc/sys/kernel/hostname", args[1]);
277}
278
279int do_ifup(int nargs, char **args)
280{
281 return __ifupdown(args[1], 1);
282}
283
The Android Open Source Project35237d12008-12-17 18:08:08 -0800284
285static int do_insmod_inner(int nargs, char **args, int opt_len)
286{
287 char options[opt_len + 1];
288 int i;
289
290 options[0] = '\0';
291 if (nargs > 2) {
292 strcpy(options, args[2]);
293 for (i = 3; i < nargs; ++i) {
294 strcat(options, " ");
295 strcat(options, args[i]);
296 }
297 }
298
299 return insmod(args[1], options);
300}
301
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700302int do_insmod(int nargs, char **args)
303{
The Android Open Source Project35237d12008-12-17 18:08:08 -0800304 int i;
305 int size = 0;
306
307 if (nargs > 2) {
308 for (i = 2; i < nargs; ++i)
309 size += strlen(args[i]) + 1;
310 }
311
312 return do_insmod_inner(nargs, args, size);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700313}
314
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700315int do_mkdir(int nargs, char **args)
316{
317 mode_t mode = 0755;
Chia-chi Yeh27164dc2011-07-08 12:57:36 -0700318 int ret;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700319
320 /* mkdir <path> [mode] [owner] [group] */
321
322 if (nargs >= 3) {
323 mode = strtoul(args[2], 0, 8);
324 }
325
Stephen Smalleye096e362012-06-11 13:37:39 -0400326 ret = make_dir(args[1], mode);
Chia-chi Yeh27164dc2011-07-08 12:57:36 -0700327 /* chmod in case the directory already exists */
328 if (ret == -1 && errno == EEXIST) {
Nick Kralevichbc609542015-01-31 21:39:46 -0800329 ret = fchmodat(AT_FDCWD, args[1], mode, AT_SYMLINK_NOFOLLOW);
Chia-chi Yeh27164dc2011-07-08 12:57:36 -0700330 }
331 if (ret == -1) {
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700332 return -errno;
333 }
334
335 if (nargs >= 4) {
336 uid_t uid = decode_uid(args[3]);
337 gid_t gid = -1;
338
339 if (nargs == 5) {
340 gid = decode_uid(args[4]);
341 }
342
Nick Kralevichbc609542015-01-31 21:39:46 -0800343 if (lchown(args[1], uid, gid) == -1) {
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700344 return -errno;
345 }
Benoit Goby5c8574b2012-08-14 15:43:46 -0700346
347 /* chown may have cleared S_ISUID and S_ISGID, chmod again */
348 if (mode & (S_ISUID | S_ISGID)) {
Nick Kralevichbc609542015-01-31 21:39:46 -0800349 ret = fchmodat(AT_FDCWD, args[1], mode, AT_SYMLINK_NOFOLLOW);
Benoit Goby5c8574b2012-08-14 15:43:46 -0700350 if (ret == -1) {
351 return -errno;
352 }
353 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700354 }
355
356 return 0;
357}
358
359static struct {
360 const char *name;
361 unsigned flag;
362} mount_flags[] = {
363 { "noatime", MS_NOATIME },
Lars Svenssonb6ee25e2011-07-14 13:39:09 +0200364 { "noexec", MS_NOEXEC },
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700365 { "nosuid", MS_NOSUID },
366 { "nodev", MS_NODEV },
367 { "nodiratime", MS_NODIRATIME },
368 { "ro", MS_RDONLY },
369 { "rw", 0 },
370 { "remount", MS_REMOUNT },
Jeff Sharkeye50ac5f2012-08-14 11:34:34 -0700371 { "bind", MS_BIND },
372 { "rec", MS_REC },
373 { "unbindable", MS_UNBINDABLE },
374 { "private", MS_PRIVATE },
375 { "slave", MS_SLAVE },
376 { "shared", MS_SHARED },
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700377 { "defaults", 0 },
378 { 0, 0 },
379};
380
Ken Sumrall752923c2010-12-03 16:33:31 -0800381#define DATA_MNT_POINT "/data"
382
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700383/* mount <type> <device> <path> <flags ...> <options> */
384int do_mount(int nargs, char **args)
385{
386 char tmp[64];
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000387 char *source, *target, *system;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700388 char *options = NULL;
389 unsigned flags = 0;
390 int n, i;
Colin Crosscd0f1732010-04-19 17:10:24 -0700391 int wait = 0;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700392
393 for (n = 4; n < nargs; n++) {
394 for (i = 0; mount_flags[i].name; i++) {
395 if (!strcmp(args[n], mount_flags[i].name)) {
396 flags |= mount_flags[i].flag;
397 break;
398 }
399 }
400
Colin Crosscd0f1732010-04-19 17:10:24 -0700401 if (!mount_flags[i].name) {
402 if (!strcmp(args[n], "wait"))
403 wait = 1;
404 /* if our last argument isn't a flag, wolf it up as an option string */
405 else if (n + 1 == nargs)
406 options = args[n];
407 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700408 }
409
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000410 system = args[1];
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700411 source = args[2];
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000412 target = args[3];
413
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700414 if (!strncmp(source, "mtd@", 4)) {
415 n = mtd_name_to_number(source + 4);
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000416 if (n < 0) {
417 return -1;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700418 }
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000419
420 sprintf(tmp, "/dev/block/mtdblock%d", n);
421
Colin Crosscd0f1732010-04-19 17:10:24 -0700422 if (wait)
423 wait_for_file(tmp, COMMAND_RETRY_TIMEOUT);
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000424 if (mount(tmp, target, system, flags, options) < 0) {
425 return -1;
426 }
427
Ken Sumralldd4d7862011-02-17 18:09:47 -0800428 goto exit_success;
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000429 } else if (!strncmp(source, "loop@", 5)) {
430 int mode, loop, fd;
431 struct loop_info info;
432
433 mode = (flags & MS_RDONLY) ? O_RDONLY : O_RDWR;
Nick Kralevich45a884f2015-02-02 14:37:22 -0800434 fd = open(source + 5, mode | O_CLOEXEC);
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000435 if (fd < 0) {
436 return -1;
437 }
438
439 for (n = 0; ; n++) {
440 sprintf(tmp, "/dev/block/loop%d", n);
Nick Kralevich45a884f2015-02-02 14:37:22 -0800441 loop = open(tmp, mode | O_CLOEXEC);
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000442 if (loop < 0) {
Tomasz Kondelbfdcc402014-02-06 08:57:27 +0100443 close(fd);
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000444 return -1;
445 }
446
447 /* if it is a blank loop device */
448 if (ioctl(loop, LOOP_GET_STATUS, &info) < 0 && errno == ENXIO) {
449 /* if it becomes our loop device */
450 if (ioctl(loop, LOOP_SET_FD, fd) >= 0) {
451 close(fd);
452
453 if (mount(tmp, target, system, flags, options) < 0) {
454 ioctl(loop, LOOP_CLR_FD, 0);
455 close(loop);
456 return -1;
457 }
458
459 close(loop);
Ken Sumralldd4d7862011-02-17 18:09:47 -0800460 goto exit_success;
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000461 }
462 }
463
464 close(loop);
465 }
466
467 close(fd);
468 ERROR("out of loopback devices");
469 return -1;
470 } else {
Colin Crosscd0f1732010-04-19 17:10:24 -0700471 if (wait)
472 wait_for_file(source, COMMAND_RETRY_TIMEOUT);
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000473 if (mount(source, target, system, flags, options) < 0) {
Ken Sumrall0e9dd902012-04-17 17:20:16 -0700474 return -1;
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000475 }
476
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700477 }
Ken Sumralldd4d7862011-02-17 18:09:47 -0800478
479exit_success:
Ken Sumralldd4d7862011-02-17 18:09:47 -0800480 return 0;
481
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700482}
483
JP Abgrallcee20682014-07-02 14:26:54 -0700484static int wipe_data_via_recovery()
485{
486 mkdir("/cache/recovery", 0700);
Nick Kralevich45a884f2015-02-02 14:37:22 -0800487 int fd = open("/cache/recovery/command", O_RDWR|O_CREAT|O_TRUNC|O_CLOEXEC, 0600);
JP Abgrallcee20682014-07-02 14:26:54 -0700488 if (fd >= 0) {
Jeff Sharkeyd26135b2014-09-24 11:46:36 -0700489 write(fd, "--wipe_data\n", strlen("--wipe_data\n") + 1);
490 write(fd, "--reason=wipe_data_via_recovery\n", strlen("--reason=wipe_data_via_recovery\n") + 1);
JP Abgrallcee20682014-07-02 14:26:54 -0700491 close(fd);
492 } else {
493 ERROR("could not open /cache/recovery/command\n");
494 return -1;
495 }
496 android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
497 while (1) { pause(); } // never reached
498}
499
500
501/*
502 * This function might request a reboot, in which case it will
503 * not return.
504 */
Ken Sumrall0e9dd902012-04-17 17:20:16 -0700505int do_mount_all(int nargs, char **args)
506{
507 pid_t pid;
508 int ret = -1;
509 int child_ret = -1;
510 int status;
Ken Sumrallab6b8522013-02-13 12:58:40 -0800511 struct fstab *fstab;
Ken Sumrall0e9dd902012-04-17 17:20:16 -0700512
513 if (nargs != 2) {
514 return -1;
515 }
516
517 /*
518 * Call fs_mgr_mount_all() to mount all filesystems. We fork(2) and
519 * do the call in the child to provide protection to the main init
520 * process if anything goes wrong (crash or memory leak), and wait for
521 * the child to finish in the parent.
522 */
523 pid = fork();
524 if (pid > 0) {
525 /* Parent. Wait for the child to return */
Paul Lawrence40af0922014-09-16 14:31:23 -0700526 int wp_ret = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
527 if (wp_ret < 0) {
528 /* Unexpected error code. We will continue anyway. */
529 NOTICE("waitpid failed rc=%d, errno=%d\n", wp_ret, errno);
530 }
531
Ken Sumrall0e9dd902012-04-17 17:20:16 -0700532 if (WIFEXITED(status)) {
533 ret = WEXITSTATUS(status);
534 } else {
535 ret = -1;
536 }
537 } else if (pid == 0) {
538 /* child, call fs_mgr_mount_all() */
539 klog_set_level(6); /* So we can see what fs_mgr_mount_all() does */
Ken Sumrallab6b8522013-02-13 12:58:40 -0800540 fstab = fs_mgr_read_fstab(args[1]);
541 child_ret = fs_mgr_mount_all(fstab);
542 fs_mgr_free_fstab(fstab);
Ken Sumrall0e9dd902012-04-17 17:20:16 -0700543 if (child_ret == -1) {
544 ERROR("fs_mgr_mount_all returned an error\n");
545 }
JP Abgrallf22b7452014-07-02 13:16:04 -0700546 _exit(child_ret);
Ken Sumrall0e9dd902012-04-17 17:20:16 -0700547 } else {
548 /* fork failed, return an error */
549 return -1;
550 }
551
JP Abgrallf22b7452014-07-02 13:16:04 -0700552 if (ret == FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION) {
Paul Lawrence166fa3d2014-02-03 13:27:49 -0800553 property_set("vold.decrypt", "trigger_encryption");
JP Abgrallf22b7452014-07-02 13:16:04 -0700554 } else if (ret == FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED) {
Ken Sumrall0e9dd902012-04-17 17:20:16 -0700555 property_set("ro.crypto.state", "encrypted");
Paul Lawrence13d5bb42014-01-30 10:43:52 -0800556 property_set("vold.decrypt", "trigger_default_encryption");
JP Abgrallf22b7452014-07-02 13:16:04 -0700557 } else if (ret == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
Ken Sumrall0e9dd902012-04-17 17:20:16 -0700558 property_set("ro.crypto.state", "unencrypted");
559 /* If fs_mgr determined this is an unencrypted device, then trigger
560 * that action.
561 */
562 action_for_each_trigger("nonencrypted", action_add_queue_tail);
JP Abgrallcee20682014-07-02 14:26:54 -0700563 } else if (ret == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) {
564 /* Setup a wipe via recovery, and reboot into recovery */
565 ERROR("fs_mgr_mount_all suggested recovery, so wiping data via recovery.\n");
566 ret = wipe_data_via_recovery();
567 /* If reboot worked, there is no return. */
568 } else if (ret > 0) {
569 ERROR("fs_mgr_mount_all returned unexpected error %d\n", ret);
Ken Sumrall0e9dd902012-04-17 17:20:16 -0700570 }
JP Abgrallf22b7452014-07-02 13:16:04 -0700571 /* else ... < 0: error */
Ken Sumrall0e9dd902012-04-17 17:20:16 -0700572
573 return ret;
574}
575
Ken Sumralla76baaa2013-07-09 18:42:09 -0700576int do_swapon_all(int nargs, char **args)
577{
578 struct fstab *fstab;
579 int ret;
580
581 fstab = fs_mgr_read_fstab(args[1]);
582 ret = fs_mgr_swapon_all(fstab);
583 fs_mgr_free_fstab(fstab);
584
585 return ret;
586}
587
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500588int do_setcon(int nargs, char **args) {
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500589 if (is_selinux_enabled() <= 0)
590 return 0;
591 if (setcon(args[1]) < 0) {
592 return -errno;
593 }
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500594 return 0;
595}
596
597int do_setenforce(int nargs, char **args) {
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500598 if (is_selinux_enabled() <= 0)
599 return 0;
600 if (security_setenforce(atoi(args[1])) < 0) {
601 return -errno;
602 }
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500603 return 0;
604}
605
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700606int do_setkey(int nargs, char **args)
607{
608 struct kbentry kbe;
609 kbe.kb_table = strtoul(args[1], 0, 0);
610 kbe.kb_index = strtoul(args[2], 0, 0);
611 kbe.kb_value = strtoul(args[3], 0, 0);
612 return setkey(&kbe);
613}
614
615int do_setprop(int nargs, char **args)
616{
Mike Lockwood1f0bd322011-06-08 17:31:27 -0700617 const char *name = args[1];
618 const char *value = args[2];
Dima Zavin84bf9af2011-12-20 13:44:41 -0800619 char prop_val[PROP_VALUE_MAX];
620 int ret;
Mike Lockwood1f0bd322011-06-08 17:31:27 -0700621
Dima Zavin84bf9af2011-12-20 13:44:41 -0800622 ret = expand_props(prop_val, value, sizeof(prop_val));
623 if (ret) {
624 ERROR("cannot expand '%s' while assigning to '%s'\n", value, name);
625 return -EINVAL;
Mike Lockwood1f0bd322011-06-08 17:31:27 -0700626 }
Dima Zavin84bf9af2011-12-20 13:44:41 -0800627 property_set(name, prop_val);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700628 return 0;
629}
630
631int do_setrlimit(int nargs, char **args)
632{
633 struct rlimit limit;
634 int resource;
635 resource = atoi(args[1]);
636 limit.rlim_cur = atoi(args[2]);
637 limit.rlim_max = atoi(args[3]);
638 return setrlimit(resource, &limit);
639}
640
641int do_start(int nargs, char **args)
642{
643 struct service *svc;
644 svc = service_find_by_name(args[1]);
645 if (svc) {
San Mehatf24e2522009-05-19 13:30:46 -0700646 service_start(svc, NULL);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700647 }
648 return 0;
649}
650
651int do_stop(int nargs, char **args)
652{
653 struct service *svc;
654 svc = service_find_by_name(args[1]);
655 if (svc) {
656 service_stop(svc);
657 }
658 return 0;
659}
660
661int do_restart(int nargs, char **args)
662{
663 struct service *svc;
664 svc = service_find_by_name(args[1]);
665 if (svc) {
Mike Kasickb54f39f2012-01-25 23:48:46 -0500666 service_restart(svc);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700667 }
668 return 0;
669}
670
Nick Kralevichca8e66a2013-04-18 12:20:02 -0700671int do_powerctl(int nargs, char **args)
672{
673 char command[PROP_VALUE_MAX];
674 int res;
675 int len = 0;
676 int cmd = 0;
677 char *reboot_target;
678
679 res = expand_props(command, args[1], sizeof(command));
680 if (res) {
681 ERROR("powerctl: cannot expand '%s'\n", args[1]);
682 return -EINVAL;
683 }
684
685 if (strncmp(command, "shutdown", 8) == 0) {
686 cmd = ANDROID_RB_POWEROFF;
687 len = 8;
688 } else if (strncmp(command, "reboot", 6) == 0) {
689 cmd = ANDROID_RB_RESTART2;
690 len = 6;
691 } else {
692 ERROR("powerctl: unrecognized command '%s'\n", command);
693 return -EINVAL;
694 }
695
696 if (command[len] == ',') {
697 reboot_target = &command[len + 1];
698 } else if (command[len] == '\0') {
699 reboot_target = "";
700 } else {
701 ERROR("powerctl: unrecognized reboot target '%s'\n", &command[len]);
702 return -EINVAL;
703 }
704
705 return android_reboot(cmd, 0, reboot_target);
706}
707
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700708int do_trigger(int nargs, char **args)
709{
Jay Freeman (saurik)11e1c422008-11-17 06:35:08 +0000710 action_for_each_trigger(args[1], action_add_queue_tail);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700711 return 0;
712}
713
714int do_symlink(int nargs, char **args)
715{
716 return symlink(args[1], args[2]);
717}
718
Ken Sumrall203bad52011-01-18 17:37:41 -0800719int do_rm(int nargs, char **args)
720{
721 return unlink(args[1]);
722}
723
724int do_rmdir(int nargs, char **args)
725{
726 return rmdir(args[1]);
727}
728
The Android Open Source Project35237d12008-12-17 18:08:08 -0800729int do_sysclktz(int nargs, char **args)
730{
731 struct timezone tz;
732
733 if (nargs != 2)
734 return -1;
735
736 memset(&tz, 0, sizeof(tz));
737 tz.tz_minuteswest = atoi(args[1]);
738 if (settimeofday(NULL, &tz))
739 return -1;
740 return 0;
741}
742
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700743int do_write(int nargs, char **args)
744{
Mike Lockwood1f0bd322011-06-08 17:31:27 -0700745 const char *path = args[1];
746 const char *value = args[2];
Dima Zavin84bf9af2011-12-20 13:44:41 -0800747 char prop_val[PROP_VALUE_MAX];
748 int ret;
Mike Lockwood2c4d5dc2011-06-07 17:30:11 -0700749
Dima Zavin84bf9af2011-12-20 13:44:41 -0800750 ret = expand_props(prop_val, value, sizeof(prop_val));
751 if (ret) {
752 ERROR("cannot expand '%s' while writing to '%s'\n", value, path);
753 return -EINVAL;
754 }
755 return write_file(path, prop_val);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700756}
757
San Mehat7c44fe52009-08-26 16:39:25 -0700758int do_copy(int nargs, char **args)
759{
760 char *buffer = NULL;
761 int rc = 0;
762 int fd1 = -1, fd2 = -1;
763 struct stat info;
764 int brtw, brtr;
765 char *p;
766
767 if (nargs != 3)
768 return -1;
769
770 if (stat(args[1], &info) < 0)
771 return -1;
772
Nick Kralevich45a884f2015-02-02 14:37:22 -0800773 if ((fd1 = open(args[1], O_RDONLY|O_CLOEXEC)) < 0)
San Mehat7c44fe52009-08-26 16:39:25 -0700774 goto out_err;
775
Nick Kralevich45a884f2015-02-02 14:37:22 -0800776 if ((fd2 = open(args[2], O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0660)) < 0)
San Mehat7c44fe52009-08-26 16:39:25 -0700777 goto out_err;
778
779 if (!(buffer = malloc(info.st_size)))
780 goto out_err;
781
782 p = buffer;
783 brtr = info.st_size;
784 while(brtr) {
785 rc = read(fd1, p, brtr);
786 if (rc < 0)
787 goto out_err;
788 if (rc == 0)
789 break;
790 p += rc;
791 brtr -= rc;
792 }
793
794 p = buffer;
795 brtw = info.st_size;
796 while(brtw) {
797 rc = write(fd2, p, brtw);
798 if (rc < 0)
799 goto out_err;
800 if (rc == 0)
801 break;
802 p += rc;
803 brtw -= rc;
804 }
805
806 rc = 0;
807 goto out;
808out_err:
809 rc = -1;
810out:
811 if (buffer)
812 free(buffer);
813 if (fd1 >= 0)
814 close(fd1);
815 if (fd2 >= 0)
816 close(fd2);
817 return rc;
818}
819
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700820int do_chown(int nargs, char **args) {
821 /* GID is optional. */
822 if (nargs == 3) {
Nick Kralevichbc609542015-01-31 21:39:46 -0800823 if (lchown(args[2], decode_uid(args[1]), -1) == -1)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700824 return -errno;
825 } else if (nargs == 4) {
Nick Kralevichbc609542015-01-31 21:39:46 -0800826 if (lchown(args[3], decode_uid(args[1]), decode_uid(args[2])) == -1)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700827 return -errno;
828 } else {
829 return -1;
830 }
831 return 0;
832}
833
834static mode_t get_mode(const char *s) {
835 mode_t mode = 0;
836 while (*s) {
837 if (*s >= '0' && *s <= '7') {
838 mode = (mode<<3) | (*s-'0');
839 } else {
840 return -1;
841 }
842 s++;
843 }
844 return mode;
845}
846
847int do_chmod(int nargs, char **args) {
848 mode_t mode = get_mode(args[1]);
Nick Kralevichbc609542015-01-31 21:39:46 -0800849 if (fchmodat(AT_FDCWD, args[2], mode, AT_SYMLINK_NOFOLLOW) < 0) {
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700850 return -errno;
851 }
852 return 0;
853}
854
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500855int do_restorecon(int nargs, char **args) {
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500856 int i;
Stephen Smalley726e8f72013-10-09 16:02:09 -0400857 int ret = 0;
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500858
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500859 for (i = 1; i < nargs; i++) {
Stephen Smalleye096e362012-06-11 13:37:39 -0400860 if (restorecon(args[i]) < 0)
Stephen Smalley726e8f72013-10-09 16:02:09 -0400861 ret = -errno;
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500862 }
Stephen Smalley726e8f72013-10-09 16:02:09 -0400863 return ret;
864}
865
866int do_restorecon_recursive(int nargs, char **args) {
867 int i;
868 int ret = 0;
869
870 for (i = 1; i < nargs; i++) {
871 if (restorecon_recursive(args[i]) < 0)
872 ret = -errno;
873 }
874 return ret;
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500875}
876
877int do_setsebool(int nargs, char **args) {
Stephen Smalley0e23fee2012-11-28 13:52:12 -0500878 const char *name = args[1];
879 const char *value = args[2];
880 SELboolean b;
881 int ret;
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500882
883 if (is_selinux_enabled() <= 0)
884 return 0;
885
Stephen Smalley0e23fee2012-11-28 13:52:12 -0500886 b.name = name;
887 if (!strcmp(value, "1") || !strcasecmp(value, "true") || !strcasecmp(value, "on"))
888 b.value = 1;
889 else if (!strcmp(value, "0") || !strcasecmp(value, "false") || !strcasecmp(value, "off"))
890 b.value = 0;
891 else {
892 ERROR("setsebool: invalid value %s\n", value);
893 return -EINVAL;
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500894 }
895
Stephen Smalley0e23fee2012-11-28 13:52:12 -0500896 if (security_set_boolean_list(1, &b, 0) < 0) {
897 ret = -errno;
898 ERROR("setsebool: could not set %s to %s\n", name, value);
899 return ret;
900 }
Kenny Rootb5982bf2012-10-16 23:07:05 -0700901
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500902 return 0;
903}
904
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700905int do_loglevel(int nargs, char **args) {
Riley Andrews1bbef882014-06-26 13:55:03 -0700906 int log_level;
907 char log_level_str[PROP_VALUE_MAX] = "";
908 if (nargs != 2) {
909 ERROR("loglevel: missing argument\n");
910 return -EINVAL;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700911 }
Riley Andrews1bbef882014-06-26 13:55:03 -0700912
913 if (expand_props(log_level_str, args[1], sizeof(log_level_str))) {
914 ERROR("loglevel: cannot expand '%s'\n", args[1]);
915 return -EINVAL;
916 }
917 log_level = atoi(log_level_str);
918 if (log_level < KLOG_ERROR_LEVEL || log_level > KLOG_DEBUG_LEVEL) {
919 ERROR("loglevel: invalid log level'%d'\n", log_level);
920 return -EINVAL;
921 }
922 klog_set_level(log_level);
923 return 0;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700924}
925
Ken Sumrallc5c51032011-03-08 17:01:29 -0800926int do_load_persist_props(int nargs, char **args) {
927 if (nargs == 1) {
928 load_persist_props();
929 return 0;
930 }
931 return -1;
932}
933
Riley Andrewse4b7b292014-06-16 15:06:21 -0700934int do_load_all_props(int nargs, char **args) {
935 if (nargs == 1) {
936 load_all_props();
937 return 0;
938 }
939 return -1;
940}
941
Colin Crosscd0f1732010-04-19 17:10:24 -0700942int do_wait(int nargs, char **args)
943{
944 if (nargs == 2) {
945 return wait_for_file(args[1], COMMAND_RETRY_TIMEOUT);
Patrick McCormick96d0a4d2011-02-04 10:51:39 -0800946 } else if (nargs == 3) {
947 return wait_for_file(args[1], atoi(args[2]));
948 } else
949 return -1;
Colin Crosscd0f1732010-04-19 17:10:24 -0700950}