blob: 76c0a18874fe81803913010b7241a2212b4d9037 [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 Kralevich5535b052013-09-17 14:43:12 -070062 fd = open(path, O_WRONLY|O_CREAT|O_NOFOLLOW, 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
102 fd = open("/dev/tty0", O_RDWR | O_SYNC);
103 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
208int do_export(int nargs, char **args)
209{
James Morrissey381341f2014-05-16 11:36:36 +0100210 return add_environment(args[1], args[2]);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700211}
212
213int do_hostname(int nargs, char **args)
214{
215 return write_file("/proc/sys/kernel/hostname", args[1]);
216}
217
218int do_ifup(int nargs, char **args)
219{
220 return __ifupdown(args[1], 1);
221}
222
The Android Open Source Project35237d12008-12-17 18:08:08 -0800223
224static int do_insmod_inner(int nargs, char **args, int opt_len)
225{
226 char options[opt_len + 1];
227 int i;
228
229 options[0] = '\0';
230 if (nargs > 2) {
231 strcpy(options, args[2]);
232 for (i = 3; i < nargs; ++i) {
233 strcat(options, " ");
234 strcat(options, args[i]);
235 }
236 }
237
238 return insmod(args[1], options);
239}
240
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700241int do_insmod(int nargs, char **args)
242{
The Android Open Source Project35237d12008-12-17 18:08:08 -0800243 int i;
244 int size = 0;
245
246 if (nargs > 2) {
247 for (i = 2; i < nargs; ++i)
248 size += strlen(args[i]) + 1;
249 }
250
251 return do_insmod_inner(nargs, args, size);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700252}
253
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700254int do_mkdir(int nargs, char **args)
255{
256 mode_t mode = 0755;
Chia-chi Yeh27164dc2011-07-08 12:57:36 -0700257 int ret;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700258
259 /* mkdir <path> [mode] [owner] [group] */
260
261 if (nargs >= 3) {
262 mode = strtoul(args[2], 0, 8);
263 }
264
Stephen Smalleye096e362012-06-11 13:37:39 -0400265 ret = make_dir(args[1], mode);
Chia-chi Yeh27164dc2011-07-08 12:57:36 -0700266 /* chmod in case the directory already exists */
267 if (ret == -1 && errno == EEXIST) {
Nick Kralevichbc609542015-01-31 21:39:46 -0800268 ret = fchmodat(AT_FDCWD, args[1], mode, AT_SYMLINK_NOFOLLOW);
Chia-chi Yeh27164dc2011-07-08 12:57:36 -0700269 }
270 if (ret == -1) {
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700271 return -errno;
272 }
273
274 if (nargs >= 4) {
275 uid_t uid = decode_uid(args[3]);
276 gid_t gid = -1;
277
278 if (nargs == 5) {
279 gid = decode_uid(args[4]);
280 }
281
Nick Kralevichbc609542015-01-31 21:39:46 -0800282 if (lchown(args[1], uid, gid) == -1) {
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700283 return -errno;
284 }
Benoit Goby5c8574b2012-08-14 15:43:46 -0700285
286 /* chown may have cleared S_ISUID and S_ISGID, chmod again */
287 if (mode & (S_ISUID | S_ISGID)) {
Nick Kralevichbc609542015-01-31 21:39:46 -0800288 ret = fchmodat(AT_FDCWD, args[1], mode, AT_SYMLINK_NOFOLLOW);
Benoit Goby5c8574b2012-08-14 15:43:46 -0700289 if (ret == -1) {
290 return -errno;
291 }
292 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700293 }
294
295 return 0;
296}
297
298static struct {
299 const char *name;
300 unsigned flag;
301} mount_flags[] = {
302 { "noatime", MS_NOATIME },
Lars Svenssonb6ee25e2011-07-14 13:39:09 +0200303 { "noexec", MS_NOEXEC },
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700304 { "nosuid", MS_NOSUID },
305 { "nodev", MS_NODEV },
306 { "nodiratime", MS_NODIRATIME },
307 { "ro", MS_RDONLY },
308 { "rw", 0 },
309 { "remount", MS_REMOUNT },
Jeff Sharkeye50ac5f2012-08-14 11:34:34 -0700310 { "bind", MS_BIND },
311 { "rec", MS_REC },
312 { "unbindable", MS_UNBINDABLE },
313 { "private", MS_PRIVATE },
314 { "slave", MS_SLAVE },
315 { "shared", MS_SHARED },
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700316 { "defaults", 0 },
317 { 0, 0 },
318};
319
Ken Sumrall752923c2010-12-03 16:33:31 -0800320#define DATA_MNT_POINT "/data"
321
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700322/* mount <type> <device> <path> <flags ...> <options> */
323int do_mount(int nargs, char **args)
324{
325 char tmp[64];
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000326 char *source, *target, *system;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700327 char *options = NULL;
328 unsigned flags = 0;
329 int n, i;
Colin Crosscd0f1732010-04-19 17:10:24 -0700330 int wait = 0;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700331
332 for (n = 4; n < nargs; n++) {
333 for (i = 0; mount_flags[i].name; i++) {
334 if (!strcmp(args[n], mount_flags[i].name)) {
335 flags |= mount_flags[i].flag;
336 break;
337 }
338 }
339
Colin Crosscd0f1732010-04-19 17:10:24 -0700340 if (!mount_flags[i].name) {
341 if (!strcmp(args[n], "wait"))
342 wait = 1;
343 /* if our last argument isn't a flag, wolf it up as an option string */
344 else if (n + 1 == nargs)
345 options = args[n];
346 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700347 }
348
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000349 system = args[1];
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700350 source = args[2];
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000351 target = args[3];
352
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700353 if (!strncmp(source, "mtd@", 4)) {
354 n = mtd_name_to_number(source + 4);
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000355 if (n < 0) {
356 return -1;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700357 }
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000358
359 sprintf(tmp, "/dev/block/mtdblock%d", n);
360
Colin Crosscd0f1732010-04-19 17:10:24 -0700361 if (wait)
362 wait_for_file(tmp, COMMAND_RETRY_TIMEOUT);
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000363 if (mount(tmp, target, system, flags, options) < 0) {
364 return -1;
365 }
366
Ken Sumralldd4d7862011-02-17 18:09:47 -0800367 goto exit_success;
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000368 } else if (!strncmp(source, "loop@", 5)) {
369 int mode, loop, fd;
370 struct loop_info info;
371
372 mode = (flags & MS_RDONLY) ? O_RDONLY : O_RDWR;
373 fd = open(source + 5, mode);
374 if (fd < 0) {
375 return -1;
376 }
377
378 for (n = 0; ; n++) {
379 sprintf(tmp, "/dev/block/loop%d", n);
380 loop = open(tmp, mode);
381 if (loop < 0) {
Tomasz Kondelbfdcc402014-02-06 08:57:27 +0100382 close(fd);
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000383 return -1;
384 }
385
386 /* if it is a blank loop device */
387 if (ioctl(loop, LOOP_GET_STATUS, &info) < 0 && errno == ENXIO) {
388 /* if it becomes our loop device */
389 if (ioctl(loop, LOOP_SET_FD, fd) >= 0) {
390 close(fd);
391
392 if (mount(tmp, target, system, flags, options) < 0) {
393 ioctl(loop, LOOP_CLR_FD, 0);
394 close(loop);
395 return -1;
396 }
397
398 close(loop);
Ken Sumralldd4d7862011-02-17 18:09:47 -0800399 goto exit_success;
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000400 }
401 }
402
403 close(loop);
404 }
405
406 close(fd);
407 ERROR("out of loopback devices");
408 return -1;
409 } else {
Colin Crosscd0f1732010-04-19 17:10:24 -0700410 if (wait)
411 wait_for_file(source, COMMAND_RETRY_TIMEOUT);
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000412 if (mount(source, target, system, flags, options) < 0) {
Ken Sumrall0e9dd902012-04-17 17:20:16 -0700413 return -1;
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000414 }
415
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700416 }
Ken Sumralldd4d7862011-02-17 18:09:47 -0800417
418exit_success:
Ken Sumralldd4d7862011-02-17 18:09:47 -0800419 return 0;
420
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700421}
422
JP Abgrallcee20682014-07-02 14:26:54 -0700423static int wipe_data_via_recovery()
424{
425 mkdir("/cache/recovery", 0700);
426 int fd = open("/cache/recovery/command", O_RDWR|O_CREAT|O_TRUNC, 0600);
427 if (fd >= 0) {
Jeff Sharkeyd26135b2014-09-24 11:46:36 -0700428 write(fd, "--wipe_data\n", strlen("--wipe_data\n") + 1);
429 write(fd, "--reason=wipe_data_via_recovery\n", strlen("--reason=wipe_data_via_recovery\n") + 1);
JP Abgrallcee20682014-07-02 14:26:54 -0700430 close(fd);
431 } else {
432 ERROR("could not open /cache/recovery/command\n");
433 return -1;
434 }
435 android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
436 while (1) { pause(); } // never reached
437}
438
439
440/*
441 * This function might request a reboot, in which case it will
442 * not return.
443 */
Ken Sumrall0e9dd902012-04-17 17:20:16 -0700444int do_mount_all(int nargs, char **args)
445{
446 pid_t pid;
447 int ret = -1;
448 int child_ret = -1;
449 int status;
Ken Sumrallab6b8522013-02-13 12:58:40 -0800450 struct fstab *fstab;
Ken Sumrall0e9dd902012-04-17 17:20:16 -0700451
452 if (nargs != 2) {
453 return -1;
454 }
455
456 /*
457 * Call fs_mgr_mount_all() to mount all filesystems. We fork(2) and
458 * do the call in the child to provide protection to the main init
459 * process if anything goes wrong (crash or memory leak), and wait for
460 * the child to finish in the parent.
461 */
462 pid = fork();
463 if (pid > 0) {
464 /* Parent. Wait for the child to return */
Paul Lawrence40af0922014-09-16 14:31:23 -0700465 int wp_ret = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
466 if (wp_ret < 0) {
467 /* Unexpected error code. We will continue anyway. */
468 NOTICE("waitpid failed rc=%d, errno=%d\n", wp_ret, errno);
469 }
470
Ken Sumrall0e9dd902012-04-17 17:20:16 -0700471 if (WIFEXITED(status)) {
472 ret = WEXITSTATUS(status);
473 } else {
474 ret = -1;
475 }
476 } else if (pid == 0) {
477 /* child, call fs_mgr_mount_all() */
478 klog_set_level(6); /* So we can see what fs_mgr_mount_all() does */
Ken Sumrallab6b8522013-02-13 12:58:40 -0800479 fstab = fs_mgr_read_fstab(args[1]);
480 child_ret = fs_mgr_mount_all(fstab);
481 fs_mgr_free_fstab(fstab);
Ken Sumrall0e9dd902012-04-17 17:20:16 -0700482 if (child_ret == -1) {
483 ERROR("fs_mgr_mount_all returned an error\n");
484 }
JP Abgrallf22b7452014-07-02 13:16:04 -0700485 _exit(child_ret);
Ken Sumrall0e9dd902012-04-17 17:20:16 -0700486 } else {
487 /* fork failed, return an error */
488 return -1;
489 }
490
JP Abgrallf22b7452014-07-02 13:16:04 -0700491 if (ret == FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION) {
Paul Lawrence166fa3d2014-02-03 13:27:49 -0800492 property_set("vold.decrypt", "trigger_encryption");
JP Abgrallf22b7452014-07-02 13:16:04 -0700493 } else if (ret == FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED) {
Ken Sumrall0e9dd902012-04-17 17:20:16 -0700494 property_set("ro.crypto.state", "encrypted");
Paul Lawrence13d5bb42014-01-30 10:43:52 -0800495 property_set("vold.decrypt", "trigger_default_encryption");
JP Abgrallf22b7452014-07-02 13:16:04 -0700496 } else if (ret == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
Ken Sumrall0e9dd902012-04-17 17:20:16 -0700497 property_set("ro.crypto.state", "unencrypted");
498 /* If fs_mgr determined this is an unencrypted device, then trigger
499 * that action.
500 */
501 action_for_each_trigger("nonencrypted", action_add_queue_tail);
JP Abgrallcee20682014-07-02 14:26:54 -0700502 } else if (ret == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) {
503 /* Setup a wipe via recovery, and reboot into recovery */
504 ERROR("fs_mgr_mount_all suggested recovery, so wiping data via recovery.\n");
505 ret = wipe_data_via_recovery();
506 /* If reboot worked, there is no return. */
507 } else if (ret > 0) {
508 ERROR("fs_mgr_mount_all returned unexpected error %d\n", ret);
Ken Sumrall0e9dd902012-04-17 17:20:16 -0700509 }
JP Abgrallf22b7452014-07-02 13:16:04 -0700510 /* else ... < 0: error */
Ken Sumrall0e9dd902012-04-17 17:20:16 -0700511
512 return ret;
513}
514
Ken Sumralla76baaa2013-07-09 18:42:09 -0700515int do_swapon_all(int nargs, char **args)
516{
517 struct fstab *fstab;
518 int ret;
519
520 fstab = fs_mgr_read_fstab(args[1]);
521 ret = fs_mgr_swapon_all(fstab);
522 fs_mgr_free_fstab(fstab);
523
524 return ret;
525}
526
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500527int do_setcon(int nargs, char **args) {
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500528 if (is_selinux_enabled() <= 0)
529 return 0;
530 if (setcon(args[1]) < 0) {
531 return -errno;
532 }
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500533 return 0;
534}
535
536int do_setenforce(int nargs, char **args) {
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500537 if (is_selinux_enabled() <= 0)
538 return 0;
539 if (security_setenforce(atoi(args[1])) < 0) {
540 return -errno;
541 }
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500542 return 0;
543}
544
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700545int do_setkey(int nargs, char **args)
546{
547 struct kbentry kbe;
548 kbe.kb_table = strtoul(args[1], 0, 0);
549 kbe.kb_index = strtoul(args[2], 0, 0);
550 kbe.kb_value = strtoul(args[3], 0, 0);
551 return setkey(&kbe);
552}
553
554int do_setprop(int nargs, char **args)
555{
Mike Lockwood1f0bd322011-06-08 17:31:27 -0700556 const char *name = args[1];
557 const char *value = args[2];
Dima Zavin84bf9af2011-12-20 13:44:41 -0800558 char prop_val[PROP_VALUE_MAX];
559 int ret;
Mike Lockwood1f0bd322011-06-08 17:31:27 -0700560
Dima Zavin84bf9af2011-12-20 13:44:41 -0800561 ret = expand_props(prop_val, value, sizeof(prop_val));
562 if (ret) {
563 ERROR("cannot expand '%s' while assigning to '%s'\n", value, name);
564 return -EINVAL;
Mike Lockwood1f0bd322011-06-08 17:31:27 -0700565 }
Dima Zavin84bf9af2011-12-20 13:44:41 -0800566 property_set(name, prop_val);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700567 return 0;
568}
569
570int do_setrlimit(int nargs, char **args)
571{
572 struct rlimit limit;
573 int resource;
574 resource = atoi(args[1]);
575 limit.rlim_cur = atoi(args[2]);
576 limit.rlim_max = atoi(args[3]);
577 return setrlimit(resource, &limit);
578}
579
580int do_start(int nargs, char **args)
581{
582 struct service *svc;
583 svc = service_find_by_name(args[1]);
584 if (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_stop(int nargs, char **args)
591{
592 struct service *svc;
593 svc = service_find_by_name(args[1]);
594 if (svc) {
595 service_stop(svc);
596 }
597 return 0;
598}
599
600int do_restart(int nargs, char **args)
601{
602 struct service *svc;
603 svc = service_find_by_name(args[1]);
604 if (svc) {
Mike Kasickb54f39f2012-01-25 23:48:46 -0500605 service_restart(svc);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700606 }
607 return 0;
608}
609
Nick Kralevichca8e66a2013-04-18 12:20:02 -0700610int do_powerctl(int nargs, char **args)
611{
612 char command[PROP_VALUE_MAX];
613 int res;
614 int len = 0;
615 int cmd = 0;
616 char *reboot_target;
617
618 res = expand_props(command, args[1], sizeof(command));
619 if (res) {
620 ERROR("powerctl: cannot expand '%s'\n", args[1]);
621 return -EINVAL;
622 }
623
624 if (strncmp(command, "shutdown", 8) == 0) {
625 cmd = ANDROID_RB_POWEROFF;
626 len = 8;
627 } else if (strncmp(command, "reboot", 6) == 0) {
628 cmd = ANDROID_RB_RESTART2;
629 len = 6;
630 } else {
631 ERROR("powerctl: unrecognized command '%s'\n", command);
632 return -EINVAL;
633 }
634
635 if (command[len] == ',') {
636 reboot_target = &command[len + 1];
637 } else if (command[len] == '\0') {
638 reboot_target = "";
639 } else {
640 ERROR("powerctl: unrecognized reboot target '%s'\n", &command[len]);
641 return -EINVAL;
642 }
643
644 return android_reboot(cmd, 0, reboot_target);
645}
646
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700647int do_trigger(int nargs, char **args)
648{
Jay Freeman (saurik)11e1c422008-11-17 06:35:08 +0000649 action_for_each_trigger(args[1], action_add_queue_tail);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700650 return 0;
651}
652
653int do_symlink(int nargs, char **args)
654{
655 return symlink(args[1], args[2]);
656}
657
Ken Sumrall203bad52011-01-18 17:37:41 -0800658int do_rm(int nargs, char **args)
659{
660 return unlink(args[1]);
661}
662
663int do_rmdir(int nargs, char **args)
664{
665 return rmdir(args[1]);
666}
667
The Android Open Source Project35237d12008-12-17 18:08:08 -0800668int do_sysclktz(int nargs, char **args)
669{
670 struct timezone tz;
671
672 if (nargs != 2)
673 return -1;
674
675 memset(&tz, 0, sizeof(tz));
676 tz.tz_minuteswest = atoi(args[1]);
677 if (settimeofday(NULL, &tz))
678 return -1;
679 return 0;
680}
681
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700682int do_write(int nargs, char **args)
683{
Mike Lockwood1f0bd322011-06-08 17:31:27 -0700684 const char *path = args[1];
685 const char *value = args[2];
Dima Zavin84bf9af2011-12-20 13:44:41 -0800686 char prop_val[PROP_VALUE_MAX];
687 int ret;
Mike Lockwood2c4d5dc2011-06-07 17:30:11 -0700688
Dima Zavin84bf9af2011-12-20 13:44:41 -0800689 ret = expand_props(prop_val, value, sizeof(prop_val));
690 if (ret) {
691 ERROR("cannot expand '%s' while writing to '%s'\n", value, path);
692 return -EINVAL;
693 }
694 return write_file(path, prop_val);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700695}
696
San Mehat7c44fe52009-08-26 16:39:25 -0700697int do_copy(int nargs, char **args)
698{
699 char *buffer = NULL;
700 int rc = 0;
701 int fd1 = -1, fd2 = -1;
702 struct stat info;
703 int brtw, brtr;
704 char *p;
705
706 if (nargs != 3)
707 return -1;
708
709 if (stat(args[1], &info) < 0)
710 return -1;
711
712 if ((fd1 = open(args[1], O_RDONLY)) < 0)
713 goto out_err;
714
Tom Zhu4833d9f2009-09-28 19:53:12 -0500715 if ((fd2 = open(args[2], O_WRONLY|O_CREAT|O_TRUNC, 0660)) < 0)
San Mehat7c44fe52009-08-26 16:39:25 -0700716 goto out_err;
717
718 if (!(buffer = malloc(info.st_size)))
719 goto out_err;
720
721 p = buffer;
722 brtr = info.st_size;
723 while(brtr) {
724 rc = read(fd1, p, brtr);
725 if (rc < 0)
726 goto out_err;
727 if (rc == 0)
728 break;
729 p += rc;
730 brtr -= rc;
731 }
732
733 p = buffer;
734 brtw = info.st_size;
735 while(brtw) {
736 rc = write(fd2, p, brtw);
737 if (rc < 0)
738 goto out_err;
739 if (rc == 0)
740 break;
741 p += rc;
742 brtw -= rc;
743 }
744
745 rc = 0;
746 goto out;
747out_err:
748 rc = -1;
749out:
750 if (buffer)
751 free(buffer);
752 if (fd1 >= 0)
753 close(fd1);
754 if (fd2 >= 0)
755 close(fd2);
756 return rc;
757}
758
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700759int do_chown(int nargs, char **args) {
760 /* GID is optional. */
761 if (nargs == 3) {
Nick Kralevichbc609542015-01-31 21:39:46 -0800762 if (lchown(args[2], decode_uid(args[1]), -1) == -1)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700763 return -errno;
764 } else if (nargs == 4) {
Nick Kralevichbc609542015-01-31 21:39:46 -0800765 if (lchown(args[3], decode_uid(args[1]), decode_uid(args[2])) == -1)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700766 return -errno;
767 } else {
768 return -1;
769 }
770 return 0;
771}
772
773static mode_t get_mode(const char *s) {
774 mode_t mode = 0;
775 while (*s) {
776 if (*s >= '0' && *s <= '7') {
777 mode = (mode<<3) | (*s-'0');
778 } else {
779 return -1;
780 }
781 s++;
782 }
783 return mode;
784}
785
786int do_chmod(int nargs, char **args) {
787 mode_t mode = get_mode(args[1]);
Nick Kralevichbc609542015-01-31 21:39:46 -0800788 if (fchmodat(AT_FDCWD, args[2], mode, AT_SYMLINK_NOFOLLOW) < 0) {
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700789 return -errno;
790 }
791 return 0;
792}
793
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500794int do_restorecon(int nargs, char **args) {
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500795 int i;
Stephen Smalley726e8f72013-10-09 16:02:09 -0400796 int ret = 0;
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500797
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500798 for (i = 1; i < nargs; i++) {
Stephen Smalleye096e362012-06-11 13:37:39 -0400799 if (restorecon(args[i]) < 0)
Stephen Smalley726e8f72013-10-09 16:02:09 -0400800 ret = -errno;
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500801 }
Stephen Smalley726e8f72013-10-09 16:02:09 -0400802 return ret;
803}
804
805int do_restorecon_recursive(int nargs, char **args) {
806 int i;
807 int ret = 0;
808
809 for (i = 1; i < nargs; i++) {
810 if (restorecon_recursive(args[i]) < 0)
811 ret = -errno;
812 }
813 return ret;
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500814}
815
816int do_setsebool(int nargs, char **args) {
Stephen Smalley0e23fee2012-11-28 13:52:12 -0500817 const char *name = args[1];
818 const char *value = args[2];
819 SELboolean b;
820 int ret;
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500821
822 if (is_selinux_enabled() <= 0)
823 return 0;
824
Stephen Smalley0e23fee2012-11-28 13:52:12 -0500825 b.name = name;
826 if (!strcmp(value, "1") || !strcasecmp(value, "true") || !strcasecmp(value, "on"))
827 b.value = 1;
828 else if (!strcmp(value, "0") || !strcasecmp(value, "false") || !strcasecmp(value, "off"))
829 b.value = 0;
830 else {
831 ERROR("setsebool: invalid value %s\n", value);
832 return -EINVAL;
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500833 }
834
Stephen Smalley0e23fee2012-11-28 13:52:12 -0500835 if (security_set_boolean_list(1, &b, 0) < 0) {
836 ret = -errno;
837 ERROR("setsebool: could not set %s to %s\n", name, value);
838 return ret;
839 }
Kenny Rootb5982bf2012-10-16 23:07:05 -0700840
Stephen Smalleye46f9d52012-01-13 08:48:47 -0500841 return 0;
842}
843
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700844int do_loglevel(int nargs, char **args) {
Riley Andrews1bbef882014-06-26 13:55:03 -0700845 int log_level;
846 char log_level_str[PROP_VALUE_MAX] = "";
847 if (nargs != 2) {
848 ERROR("loglevel: missing argument\n");
849 return -EINVAL;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700850 }
Riley Andrews1bbef882014-06-26 13:55:03 -0700851
852 if (expand_props(log_level_str, args[1], sizeof(log_level_str))) {
853 ERROR("loglevel: cannot expand '%s'\n", args[1]);
854 return -EINVAL;
855 }
856 log_level = atoi(log_level_str);
857 if (log_level < KLOG_ERROR_LEVEL || log_level > KLOG_DEBUG_LEVEL) {
858 ERROR("loglevel: invalid log level'%d'\n", log_level);
859 return -EINVAL;
860 }
861 klog_set_level(log_level);
862 return 0;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700863}
864
Ken Sumrallc5c51032011-03-08 17:01:29 -0800865int do_load_persist_props(int nargs, char **args) {
866 if (nargs == 1) {
867 load_persist_props();
868 return 0;
869 }
870 return -1;
871}
872
Riley Andrewse4b7b292014-06-16 15:06:21 -0700873int do_load_all_props(int nargs, char **args) {
874 if (nargs == 1) {
875 load_all_props();
876 return 0;
877 }
878 return -1;
879}
880
Colin Crosscd0f1732010-04-19 17:10:24 -0700881int do_wait(int nargs, char **args)
882{
883 if (nargs == 2) {
884 return wait_for_file(args[1], COMMAND_RETRY_TIMEOUT);
Patrick McCormick96d0a4d2011-02-04 10:51:39 -0800885 } else if (nargs == 3) {
886 return wait_for_file(args[1], atoi(args[2]));
887 } else
888 return -1;
Colin Crosscd0f1732010-04-19 17:10:24 -0700889}