• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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>
32 #include <sys/wait.h>
33 #include <linux/loop.h>
34 #include <cutils/partition_utils.h>
35 #include <cutils/android_reboot.h>
36 #include <fs_mgr.h>
37 
38 #include <selinux/selinux.h>
39 #include <selinux/label.h>
40 
41 #include "init.h"
42 #include "keywords.h"
43 #include "property_service.h"
44 #include "devices.h"
45 #include "init_parser.h"
46 #include "util.h"
47 #include "log.h"
48 
49 #include <private/android_filesystem_config.h>
50 
51 int add_environment(const char *name, const char *value);
52 
53 extern int init_module(void *, unsigned long, const char *);
54 
write_file(const char * path,const char * value)55 static int write_file(const char *path, const char *value)
56 {
57     int fd, ret, len;
58 
59     fd = open(path, O_WRONLY|O_CREAT|O_NOFOLLOW, 0600);
60 
61     if (fd < 0)
62         return -errno;
63 
64     len = strlen(value);
65 
66     do {
67         ret = write(fd, value, len);
68     } while (ret < 0 && errno == EINTR);
69 
70     close(fd);
71     if (ret < 0) {
72         return -errno;
73     } else {
74         return 0;
75     }
76 }
77 
_open(const char * path)78 static int _open(const char *path)
79 {
80     int fd;
81 
82     fd = open(path, O_RDONLY | O_NOFOLLOW);
83     if (fd < 0)
84         fd = open(path, O_WRONLY | O_NOFOLLOW);
85 
86     return fd;
87 }
88 
_chown(const char * path,unsigned int uid,unsigned int gid)89 static int _chown(const char *path, unsigned int uid, unsigned int gid)
90 {
91     int fd;
92     int ret;
93 
94     fd = _open(path);
95     if (fd < 0) {
96         return -1;
97     }
98 
99     ret = fchown(fd, uid, gid);
100     if (ret < 0) {
101         int errno_copy = errno;
102         close(fd);
103         errno = errno_copy;
104         return -1;
105     }
106 
107     close(fd);
108 
109     return 0;
110 }
111 
_chmod(const char * path,mode_t mode)112 static int _chmod(const char *path, mode_t mode)
113 {
114     int fd;
115     int ret;
116 
117     fd = _open(path);
118     if (fd < 0) {
119         return -1;
120     }
121 
122     ret = fchmod(fd, mode);
123     if (ret < 0) {
124         int errno_copy = errno;
125         close(fd);
126         errno = errno_copy;
127         return -1;
128     }
129 
130     close(fd);
131 
132     return 0;
133 }
134 
insmod(const char * filename,char * options)135 static int insmod(const char *filename, char *options)
136 {
137     void *module;
138     unsigned size;
139     int ret;
140 
141     module = read_file(filename, &size);
142     if (!module)
143         return -1;
144 
145     ret = init_module(module, size, options);
146 
147     free(module);
148 
149     return ret;
150 }
151 
setkey(struct kbentry * kbe)152 static int setkey(struct kbentry *kbe)
153 {
154     int fd, ret;
155 
156     fd = open("/dev/tty0", O_RDWR | O_SYNC);
157     if (fd < 0)
158         return -1;
159 
160     ret = ioctl(fd, KDSKBENT, kbe);
161 
162     close(fd);
163     return ret;
164 }
165 
__ifupdown(const char * interface,int up)166 static int __ifupdown(const char *interface, int up)
167 {
168     struct ifreq ifr;
169     int s, ret;
170 
171     strlcpy(ifr.ifr_name, interface, IFNAMSIZ);
172 
173     s = socket(AF_INET, SOCK_DGRAM, 0);
174     if (s < 0)
175         return -1;
176 
177     ret = ioctl(s, SIOCGIFFLAGS, &ifr);
178     if (ret < 0) {
179         goto done;
180     }
181 
182     if (up)
183         ifr.ifr_flags |= IFF_UP;
184     else
185         ifr.ifr_flags &= ~IFF_UP;
186 
187     ret = ioctl(s, SIOCSIFFLAGS, &ifr);
188 
189 done:
190     close(s);
191     return ret;
192 }
193 
service_start_if_not_disabled(struct service * svc)194 static void service_start_if_not_disabled(struct service *svc)
195 {
196     if (!(svc->flags & SVC_DISABLED)) {
197         service_start(svc, NULL);
198     } else {
199         svc->flags |= SVC_DISABLED_START;
200     }
201 }
202 
do_chdir(int nargs,char ** args)203 int do_chdir(int nargs, char **args)
204 {
205     chdir(args[1]);
206     return 0;
207 }
208 
do_chroot(int nargs,char ** args)209 int do_chroot(int nargs, char **args)
210 {
211     chroot(args[1]);
212     return 0;
213 }
214 
do_class_start(int nargs,char ** args)215 int do_class_start(int nargs, char **args)
216 {
217         /* Starting a class does not start services
218          * which are explicitly disabled.  They must
219          * be started individually.
220          */
221     service_for_each_class(args[1], service_start_if_not_disabled);
222     return 0;
223 }
224 
do_class_stop(int nargs,char ** args)225 int do_class_stop(int nargs, char **args)
226 {
227     service_for_each_class(args[1], service_stop);
228     return 0;
229 }
230 
do_class_reset(int nargs,char ** args)231 int do_class_reset(int nargs, char **args)
232 {
233     service_for_each_class(args[1], service_reset);
234     return 0;
235 }
236 
do_domainname(int nargs,char ** args)237 int do_domainname(int nargs, char **args)
238 {
239     return write_file("/proc/sys/kernel/domainname", args[1]);
240 }
241 
do_enable(int nargs,char ** args)242 int do_enable(int nargs, char **args)
243 {
244     struct service *svc;
245     svc = service_find_by_name(args[1]);
246     if (svc) {
247         svc->flags &= ~(SVC_DISABLED | SVC_RC_DISABLED);
248         if (svc->flags & SVC_DISABLED_START) {
249             service_start(svc, NULL);
250         }
251     } else {
252         return -1;
253     }
254     return 0;
255 }
256 
do_exec(int nargs,char ** args)257 int do_exec(int nargs, char **args)
258 {
259     return -1;
260 }
261 
do_export(int nargs,char ** args)262 int do_export(int nargs, char **args)
263 {
264     return add_environment(args[1], args[2]);
265 }
266 
do_hostname(int nargs,char ** args)267 int do_hostname(int nargs, char **args)
268 {
269     return write_file("/proc/sys/kernel/hostname", args[1]);
270 }
271 
do_ifup(int nargs,char ** args)272 int do_ifup(int nargs, char **args)
273 {
274     return __ifupdown(args[1], 1);
275 }
276 
277 
do_insmod_inner(int nargs,char ** args,int opt_len)278 static int do_insmod_inner(int nargs, char **args, int opt_len)
279 {
280     char options[opt_len + 1];
281     int i;
282 
283     options[0] = '\0';
284     if (nargs > 2) {
285         strcpy(options, args[2]);
286         for (i = 3; i < nargs; ++i) {
287             strcat(options, " ");
288             strcat(options, args[i]);
289         }
290     }
291 
292     return insmod(args[1], options);
293 }
294 
do_insmod(int nargs,char ** args)295 int do_insmod(int nargs, char **args)
296 {
297     int i;
298     int size = 0;
299 
300     if (nargs > 2) {
301         for (i = 2; i < nargs; ++i)
302             size += strlen(args[i]) + 1;
303     }
304 
305     return do_insmod_inner(nargs, args, size);
306 }
307 
do_mkdir(int nargs,char ** args)308 int do_mkdir(int nargs, char **args)
309 {
310     mode_t mode = 0755;
311     int ret;
312 
313     /* mkdir <path> [mode] [owner] [group] */
314 
315     if (nargs >= 3) {
316         mode = strtoul(args[2], 0, 8);
317     }
318 
319     ret = make_dir(args[1], mode);
320     /* chmod in case the directory already exists */
321     if (ret == -1 && errno == EEXIST) {
322         ret = _chmod(args[1], mode);
323     }
324     if (ret == -1) {
325         return -errno;
326     }
327 
328     if (nargs >= 4) {
329         uid_t uid = decode_uid(args[3]);
330         gid_t gid = -1;
331 
332         if (nargs == 5) {
333             gid = decode_uid(args[4]);
334         }
335 
336         if (_chown(args[1], uid, gid) < 0) {
337             return -errno;
338         }
339 
340         /* chown may have cleared S_ISUID and S_ISGID, chmod again */
341         if (mode & (S_ISUID | S_ISGID)) {
342             ret = _chmod(args[1], mode);
343             if (ret == -1) {
344                 return -errno;
345             }
346         }
347     }
348 
349     return 0;
350 }
351 
352 static struct {
353     const char *name;
354     unsigned flag;
355 } mount_flags[] = {
356     { "noatime",    MS_NOATIME },
357     { "noexec",     MS_NOEXEC },
358     { "nosuid",     MS_NOSUID },
359     { "nodev",      MS_NODEV },
360     { "nodiratime", MS_NODIRATIME },
361     { "ro",         MS_RDONLY },
362     { "rw",         0 },
363     { "remount",    MS_REMOUNT },
364     { "bind",       MS_BIND },
365     { "rec",        MS_REC },
366     { "unbindable", MS_UNBINDABLE },
367     { "private",    MS_PRIVATE },
368     { "slave",      MS_SLAVE },
369     { "shared",     MS_SHARED },
370     { "defaults",   0 },
371     { 0,            0 },
372 };
373 
374 #define DATA_MNT_POINT "/data"
375 
376 /* mount <type> <device> <path> <flags ...> <options> */
do_mount(int nargs,char ** args)377 int do_mount(int nargs, char **args)
378 {
379     char tmp[64];
380     char *source, *target, *system;
381     char *options = NULL;
382     unsigned flags = 0;
383     int n, i;
384     int wait = 0;
385 
386     for (n = 4; n < nargs; n++) {
387         for (i = 0; mount_flags[i].name; i++) {
388             if (!strcmp(args[n], mount_flags[i].name)) {
389                 flags |= mount_flags[i].flag;
390                 break;
391             }
392         }
393 
394         if (!mount_flags[i].name) {
395             if (!strcmp(args[n], "wait"))
396                 wait = 1;
397             /* if our last argument isn't a flag, wolf it up as an option string */
398             else if (n + 1 == nargs)
399                 options = args[n];
400         }
401     }
402 
403     system = args[1];
404     source = args[2];
405     target = args[3];
406 
407     if (!strncmp(source, "mtd@", 4)) {
408         n = mtd_name_to_number(source + 4);
409         if (n < 0) {
410             return -1;
411         }
412 
413         sprintf(tmp, "/dev/block/mtdblock%d", n);
414 
415         if (wait)
416             wait_for_file(tmp, COMMAND_RETRY_TIMEOUT);
417         if (mount(tmp, target, system, flags, options) < 0) {
418             return -1;
419         }
420 
421         goto exit_success;
422     } else if (!strncmp(source, "loop@", 5)) {
423         int mode, loop, fd;
424         struct loop_info info;
425 
426         mode = (flags & MS_RDONLY) ? O_RDONLY : O_RDWR;
427         fd = open(source + 5, mode);
428         if (fd < 0) {
429             return -1;
430         }
431 
432         for (n = 0; ; n++) {
433             sprintf(tmp, "/dev/block/loop%d", n);
434             loop = open(tmp, mode);
435             if (loop < 0) {
436                 return -1;
437             }
438 
439             /* if it is a blank loop device */
440             if (ioctl(loop, LOOP_GET_STATUS, &info) < 0 && errno == ENXIO) {
441                 /* if it becomes our loop device */
442                 if (ioctl(loop, LOOP_SET_FD, fd) >= 0) {
443                     close(fd);
444 
445                     if (mount(tmp, target, system, flags, options) < 0) {
446                         ioctl(loop, LOOP_CLR_FD, 0);
447                         close(loop);
448                         return -1;
449                     }
450 
451                     close(loop);
452                     goto exit_success;
453                 }
454             }
455 
456             close(loop);
457         }
458 
459         close(fd);
460         ERROR("out of loopback devices");
461         return -1;
462     } else {
463         if (wait)
464             wait_for_file(source, COMMAND_RETRY_TIMEOUT);
465         if (mount(source, target, system, flags, options) < 0) {
466             return -1;
467         }
468 
469     }
470 
471 exit_success:
472     return 0;
473 
474 }
475 
wipe_data_via_recovery()476 static int wipe_data_via_recovery()
477 {
478     mkdir("/cache/recovery", 0700);
479     int fd = open("/cache/recovery/command", O_RDWR|O_CREAT|O_TRUNC, 0600);
480     if (fd >= 0) {
481         write(fd, "--wipe_data\n", strlen("--wipe_data\n") + 1);
482         write(fd, "--reason=wipe_data_via_recovery\n", strlen("--reason=wipe_data_via_recovery\n") + 1);
483         close(fd);
484     } else {
485         ERROR("could not open /cache/recovery/command\n");
486         return -1;
487     }
488     android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
489     while (1) { pause(); }  // never reached
490 }
491 
492 
493 /*
494  * This function might request a reboot, in which case it will
495  * not return.
496  */
do_mount_all(int nargs,char ** args)497 int do_mount_all(int nargs, char **args)
498 {
499     pid_t pid;
500     int ret = -1;
501     int child_ret = -1;
502     int status;
503     const char *prop;
504     struct fstab *fstab;
505 
506     if (nargs != 2) {
507         return -1;
508     }
509 
510     /*
511      * Call fs_mgr_mount_all() to mount all filesystems.  We fork(2) and
512      * do the call in the child to provide protection to the main init
513      * process if anything goes wrong (crash or memory leak), and wait for
514      * the child to finish in the parent.
515      */
516     pid = fork();
517     if (pid > 0) {
518         /* Parent.  Wait for the child to return */
519         int wp_ret = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
520         if (wp_ret < 0) {
521             /* Unexpected error code. We will continue anyway. */
522             NOTICE("waitpid failed rc=%d, errno=%d\n", wp_ret, errno);
523         }
524 
525         if (WIFEXITED(status)) {
526             ret = WEXITSTATUS(status);
527         } else {
528             ret = -1;
529         }
530     } else if (pid == 0) {
531         /* child, call fs_mgr_mount_all() */
532         klog_set_level(6);  /* So we can see what fs_mgr_mount_all() does */
533         fstab = fs_mgr_read_fstab(args[1]);
534         child_ret = fs_mgr_mount_all(fstab);
535         fs_mgr_free_fstab(fstab);
536         if (child_ret == -1) {
537             ERROR("fs_mgr_mount_all returned an error\n");
538         }
539         _exit(child_ret);
540     } else {
541         /* fork failed, return an error */
542         return -1;
543     }
544 
545     if (ret == FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION) {
546         property_set("vold.decrypt", "trigger_encryption");
547     } else if (ret == FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED) {
548         property_set("ro.crypto.state", "encrypted");
549         property_set("vold.decrypt", "trigger_default_encryption");
550     } else if (ret == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
551         property_set("ro.crypto.state", "unencrypted");
552         /* If fs_mgr determined this is an unencrypted device, then trigger
553          * that action.
554          */
555         action_for_each_trigger("nonencrypted", action_add_queue_tail);
556     } else if (ret == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) {
557         /* Setup a wipe via recovery, and reboot into recovery */
558         ERROR("fs_mgr_mount_all suggested recovery, so wiping data via recovery.\n");
559         ret = wipe_data_via_recovery();
560         /* If reboot worked, there is no return. */
561     } else if (ret > 0) {
562         ERROR("fs_mgr_mount_all returned unexpected error %d\n", ret);
563     }
564     /* else ... < 0: error */
565 
566     return ret;
567 }
568 
do_swapon_all(int nargs,char ** args)569 int do_swapon_all(int nargs, char **args)
570 {
571     struct fstab *fstab;
572     int ret;
573 
574     fstab = fs_mgr_read_fstab(args[1]);
575     ret = fs_mgr_swapon_all(fstab);
576     fs_mgr_free_fstab(fstab);
577 
578     return ret;
579 }
580 
do_setcon(int nargs,char ** args)581 int do_setcon(int nargs, char **args) {
582     if (is_selinux_enabled() <= 0)
583         return 0;
584     if (setcon(args[1]) < 0) {
585         return -errno;
586     }
587     return 0;
588 }
589 
do_setenforce(int nargs,char ** args)590 int do_setenforce(int nargs, char **args) {
591     if (is_selinux_enabled() <= 0)
592         return 0;
593     if (security_setenforce(atoi(args[1])) < 0) {
594         return -errno;
595     }
596     return 0;
597 }
598 
do_setkey(int nargs,char ** args)599 int do_setkey(int nargs, char **args)
600 {
601     struct kbentry kbe;
602     kbe.kb_table = strtoul(args[1], 0, 0);
603     kbe.kb_index = strtoul(args[2], 0, 0);
604     kbe.kb_value = strtoul(args[3], 0, 0);
605     return setkey(&kbe);
606 }
607 
do_setprop(int nargs,char ** args)608 int do_setprop(int nargs, char **args)
609 {
610     const char *name = args[1];
611     const char *value = args[2];
612     char prop_val[PROP_VALUE_MAX];
613     int ret;
614 
615     ret = expand_props(prop_val, value, sizeof(prop_val));
616     if (ret) {
617         ERROR("cannot expand '%s' while assigning to '%s'\n", value, name);
618         return -EINVAL;
619     }
620     property_set(name, prop_val);
621     return 0;
622 }
623 
do_setrlimit(int nargs,char ** args)624 int do_setrlimit(int nargs, char **args)
625 {
626     struct rlimit limit;
627     int resource;
628     resource = atoi(args[1]);
629     limit.rlim_cur = atoi(args[2]);
630     limit.rlim_max = atoi(args[3]);
631     return setrlimit(resource, &limit);
632 }
633 
do_start(int nargs,char ** args)634 int do_start(int nargs, char **args)
635 {
636     struct service *svc;
637     svc = service_find_by_name(args[1]);
638     if (svc) {
639         service_start(svc, NULL);
640     }
641     return 0;
642 }
643 
do_stop(int nargs,char ** args)644 int do_stop(int nargs, char **args)
645 {
646     struct service *svc;
647     svc = service_find_by_name(args[1]);
648     if (svc) {
649         service_stop(svc);
650     }
651     return 0;
652 }
653 
do_restart(int nargs,char ** args)654 int do_restart(int nargs, char **args)
655 {
656     struct service *svc;
657     svc = service_find_by_name(args[1]);
658     if (svc) {
659         service_restart(svc);
660     }
661     return 0;
662 }
663 
do_powerctl(int nargs,char ** args)664 int do_powerctl(int nargs, char **args)
665 {
666     char command[PROP_VALUE_MAX];
667     int res;
668     int len = 0;
669     int cmd = 0;
670     char *reboot_target;
671 
672     res = expand_props(command, args[1], sizeof(command));
673     if (res) {
674         ERROR("powerctl: cannot expand '%s'\n", args[1]);
675         return -EINVAL;
676     }
677 
678     if (strncmp(command, "shutdown", 8) == 0) {
679         cmd = ANDROID_RB_POWEROFF;
680         len = 8;
681     } else if (strncmp(command, "reboot", 6) == 0) {
682         cmd = ANDROID_RB_RESTART2;
683         len = 6;
684     } else {
685         ERROR("powerctl: unrecognized command '%s'\n", command);
686         return -EINVAL;
687     }
688 
689     if (command[len] == ',') {
690         reboot_target = &command[len + 1];
691     } else if (command[len] == '\0') {
692         reboot_target = "";
693     } else {
694         ERROR("powerctl: unrecognized reboot target '%s'\n", &command[len]);
695         return -EINVAL;
696     }
697 
698     return android_reboot(cmd, 0, reboot_target);
699 }
700 
do_trigger(int nargs,char ** args)701 int do_trigger(int nargs, char **args)
702 {
703     action_for_each_trigger(args[1], action_add_queue_tail);
704     return 0;
705 }
706 
do_symlink(int nargs,char ** args)707 int do_symlink(int nargs, char **args)
708 {
709     return symlink(args[1], args[2]);
710 }
711 
do_rm(int nargs,char ** args)712 int do_rm(int nargs, char **args)
713 {
714     return unlink(args[1]);
715 }
716 
do_rmdir(int nargs,char ** args)717 int do_rmdir(int nargs, char **args)
718 {
719     return rmdir(args[1]);
720 }
721 
do_sysclktz(int nargs,char ** args)722 int do_sysclktz(int nargs, char **args)
723 {
724     struct timezone tz;
725 
726     if (nargs != 2)
727         return -1;
728 
729     memset(&tz, 0, sizeof(tz));
730     tz.tz_minuteswest = atoi(args[1]);
731     if (settimeofday(NULL, &tz))
732         return -1;
733     return 0;
734 }
735 
do_write(int nargs,char ** args)736 int do_write(int nargs, char **args)
737 {
738     const char *path = args[1];
739     const char *value = args[2];
740     char prop_val[PROP_VALUE_MAX];
741     int ret;
742 
743     ret = expand_props(prop_val, value, sizeof(prop_val));
744     if (ret) {
745         ERROR("cannot expand '%s' while writing to '%s'\n", value, path);
746         return -EINVAL;
747     }
748     return write_file(path, prop_val);
749 }
750 
do_copy(int nargs,char ** args)751 int do_copy(int nargs, char **args)
752 {
753     char *buffer = NULL;
754     int rc = 0;
755     int fd1 = -1, fd2 = -1;
756     struct stat info;
757     int brtw, brtr;
758     char *p;
759 
760     if (nargs != 3)
761         return -1;
762 
763     if (stat(args[1], &info) < 0)
764         return -1;
765 
766     if ((fd1 = open(args[1], O_RDONLY)) < 0)
767         goto out_err;
768 
769     if ((fd2 = open(args[2], O_WRONLY|O_CREAT|O_TRUNC, 0660)) < 0)
770         goto out_err;
771 
772     if (!(buffer = malloc(info.st_size)))
773         goto out_err;
774 
775     p = buffer;
776     brtr = info.st_size;
777     while(brtr) {
778         rc = read(fd1, p, brtr);
779         if (rc < 0)
780             goto out_err;
781         if (rc == 0)
782             break;
783         p += rc;
784         brtr -= rc;
785     }
786 
787     p = buffer;
788     brtw = info.st_size;
789     while(brtw) {
790         rc = write(fd2, p, brtw);
791         if (rc < 0)
792             goto out_err;
793         if (rc == 0)
794             break;
795         p += rc;
796         brtw -= rc;
797     }
798 
799     rc = 0;
800     goto out;
801 out_err:
802     rc = -1;
803 out:
804     if (buffer)
805         free(buffer);
806     if (fd1 >= 0)
807         close(fd1);
808     if (fd2 >= 0)
809         close(fd2);
810     return rc;
811 }
812 
do_chown(int nargs,char ** args)813 int do_chown(int nargs, char **args) {
814     /* GID is optional. */
815     if (nargs == 3) {
816         if (_chown(args[2], decode_uid(args[1]), -1) < 0)
817             return -errno;
818     } else if (nargs == 4) {
819         if (_chown(args[3], decode_uid(args[1]), decode_uid(args[2])) < 0)
820             return -errno;
821     } else {
822         return -1;
823     }
824     return 0;
825 }
826 
get_mode(const char * s)827 static mode_t get_mode(const char *s) {
828     mode_t mode = 0;
829     while (*s) {
830         if (*s >= '0' && *s <= '7') {
831             mode = (mode<<3) | (*s-'0');
832         } else {
833             return -1;
834         }
835         s++;
836     }
837     return mode;
838 }
839 
do_chmod(int nargs,char ** args)840 int do_chmod(int nargs, char **args) {
841     mode_t mode = get_mode(args[1]);
842     if (_chmod(args[2], mode) < 0) {
843         return -errno;
844     }
845     return 0;
846 }
847 
do_restorecon(int nargs,char ** args)848 int do_restorecon(int nargs, char **args) {
849     int i;
850     int ret = 0;
851 
852     for (i = 1; i < nargs; i++) {
853         if (restorecon(args[i]) < 0)
854             ret = -errno;
855     }
856     return ret;
857 }
858 
do_restorecon_recursive(int nargs,char ** args)859 int do_restorecon_recursive(int nargs, char **args) {
860     int i;
861     int ret = 0;
862 
863     for (i = 1; i < nargs; i++) {
864         if (restorecon_recursive(args[i]) < 0)
865             ret = -errno;
866     }
867     return ret;
868 }
869 
do_setsebool(int nargs,char ** args)870 int do_setsebool(int nargs, char **args) {
871     const char *name = args[1];
872     const char *value = args[2];
873     SELboolean b;
874     int ret;
875 
876     if (is_selinux_enabled() <= 0)
877         return 0;
878 
879     b.name = name;
880     if (!strcmp(value, "1") || !strcasecmp(value, "true") || !strcasecmp(value, "on"))
881         b.value = 1;
882     else if (!strcmp(value, "0") || !strcasecmp(value, "false") || !strcasecmp(value, "off"))
883         b.value = 0;
884     else {
885         ERROR("setsebool: invalid value %s\n", value);
886         return -EINVAL;
887     }
888 
889     if (security_set_boolean_list(1, &b, 0) < 0) {
890         ret = -errno;
891         ERROR("setsebool: could not set %s to %s\n", name, value);
892         return ret;
893     }
894 
895     return 0;
896 }
897 
do_loglevel(int nargs,char ** args)898 int do_loglevel(int nargs, char **args) {
899     int log_level;
900     char log_level_str[PROP_VALUE_MAX] = "";
901     if (nargs != 2) {
902         ERROR("loglevel: missing argument\n");
903         return -EINVAL;
904     }
905 
906     if (expand_props(log_level_str, args[1], sizeof(log_level_str))) {
907         ERROR("loglevel: cannot expand '%s'\n", args[1]);
908         return -EINVAL;
909     }
910     log_level = atoi(log_level_str);
911     if (log_level < KLOG_ERROR_LEVEL || log_level > KLOG_DEBUG_LEVEL) {
912         ERROR("loglevel: invalid log level'%d'\n", log_level);
913         return -EINVAL;
914     }
915     klog_set_level(log_level);
916     return 0;
917 }
918 
do_load_persist_props(int nargs,char ** args)919 int do_load_persist_props(int nargs, char **args) {
920     if (nargs == 1) {
921         load_persist_props();
922         return 0;
923     }
924     return -1;
925 }
926 
do_load_all_props(int nargs,char ** args)927 int do_load_all_props(int nargs, char **args) {
928     if (nargs == 1) {
929         load_all_props();
930         return 0;
931     }
932     return -1;
933 }
934 
do_wait(int nargs,char ** args)935 int do_wait(int nargs, char **args)
936 {
937     if (nargs == 2) {
938         return wait_for_file(args[1], COMMAND_RETRY_TIMEOUT);
939     } else if (nargs == 3) {
940         return wait_for_file(args[1], atoi(args[2]));
941     } else
942         return -1;
943 }
944