summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--init/builtins.c42
-rw-r--r--init/readme.txt4
2 files changed, 44 insertions, 2 deletions
diff --git a/init/builtins.c b/init/builtins.c
index ba7fe3f..de067ce 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -35,6 +35,7 @@
#include <cutils/partition_utils.h>
#include <sys/system_properties.h>
#include <fs_mgr.h>
+#include <fts.h>
#ifdef HAVE_SELINUX
#include <selinux/selinux.h>
@@ -804,6 +805,47 @@ int do_chown(int nargs, char **args) {
} else if (nargs == 4) {
if (_chown(args[3], decode_uid(args[1]), decode_uid(args[2])) < 0)
return -errno;
+ } else if (nargs == 5) {
+ int ret = 0;
+ int ftsflags = FTS_PHYSICAL;
+ FTS *fts;
+ FTSENT *ftsent;
+ char *options = args[1];
+ uid_t uid = decode_uid(args[2]);
+ uid_t gid = decode_uid(args[3]);
+ char * path_argv[] = {args[4], NULL};
+ if (strcmp(options, "-R")) {
+ ERROR("do_chown: Invalid argument: %s\n", args[1]);
+ return -EINVAL;
+ }
+ fts = fts_open(path_argv, ftsflags, NULL);
+ if (!fts) {
+ ERROR("do_chown: Error traversing hierarchy starting at %s\n", path_argv[0]);
+ return -errno;
+ }
+ while ((ftsent = fts_read(fts))) {
+ switch (ftsent->fts_info) {
+ case FTS_DP:
+ case FTS_SL:
+ break;
+ case FTS_DNR:
+ case FTS_ERR:
+ case FTS_NS:
+ ERROR("do_chown: Could not access %s\n", ftsent->fts_path);
+ fts_set(fts, ftsent, FTS_SKIP);
+ ret = -errno;
+ break;
+ default:
+ if (_chown(ftsent->fts_accpath, uid, gid) < 0) {
+ ret = -errno;
+ fts_set(fts, ftsent, FTS_SKIP);
+ }
+ break;
+ }
+ }
+ fts_close(fts);
+ if (ret)
+ return ret;
} else {
return -1;
}
diff --git a/init/readme.txt b/init/readme.txt
index fe0d15d..f674db8 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -151,8 +151,8 @@ chdir <directory>
chmod <octal-mode> <path>
Change file access permissions.
-chown <owner> <group> <path>
- Change file owner and group.
+chown [-R] <owner> <group> <path>
+ Change file owner and group. "-R" is for recursive chown.
chroot <directory>
Change process root directory.