diff options
author | Paul Crowley <paulcrowley@google.com> | 2019-08-27 02:26:25 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2019-08-27 02:26:25 +0000 |
commit | 309d6dde312fc279da11c3b77d93d3e8177e830f (patch) | |
tree | cb873e3924181bff7c3ab3d8117f9a47632aa2fa /init/builtins.cpp | |
parent | 8d168c3321a81f11f8fc0d52e6cfbb760238b69c (diff) | |
parent | 1b4e7328ad8ddb6b67c637c14b36fe581c047c98 (diff) |
Merge changes I1c1445ba,Ic0c8b163
* changes:
Straighten out do_mkdir
Convert fscrypt_set_directory_policy to C++
Diffstat (limited to 'init/builtins.cpp')
-rw-r--r-- | init/builtins.cpp | 81 |
1 files changed, 47 insertions, 34 deletions
diff --git a/init/builtins.cpp b/init/builtins.cpp index ed240267b..7c66de5f8 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -356,51 +356,64 @@ static Result<void> do_interface_stop(const BuiltinArguments& args) { // mkdir <path> [mode] [owner] [group] static Result<void> do_mkdir(const BuiltinArguments& args) { mode_t mode = 0755; - if (args.size() >= 3) { - mode = std::strtoul(args[2].c_str(), 0, 8); - } - - if (!make_dir(args[1], mode)) { - /* chmod in case the directory already exists */ - if (errno == EEXIST) { - if (fchmodat(AT_FDCWD, args[1].c_str(), mode, AT_SYMLINK_NOFOLLOW) == -1) { - return ErrnoError() << "fchmodat() failed"; - } - } else { - return ErrnoErrorIgnoreEnoent() << "mkdir() failed"; - } - } - - if (args.size() >= 4) { - auto uid = DecodeUid(args[3]); - if (!uid) { - return Error() << "Unable to decode UID for '" << args[3] << "': " << uid.error(); - } - Result<gid_t> gid = -1; + Result<uid_t> uid = -1; + Result<gid_t> gid = -1; - if (args.size() == 5) { + switch (args.size()) { + case 5: gid = DecodeUid(args[4]); if (!gid) { return Error() << "Unable to decode GID for '" << args[4] << "': " << gid.error(); } + FALLTHROUGH_INTENDED; + case 4: + uid = DecodeUid(args[3]); + if (!uid) { + return Error() << "Unable to decode UID for '" << args[3] << "': " << uid.error(); + } + FALLTHROUGH_INTENDED; + case 3: + mode = std::strtoul(args[2].c_str(), 0, 8); + FALLTHROUGH_INTENDED; + case 2: + break; + default: + return Error() << "Unexpected argument count: " << args.size(); + } + std::string target = args[1]; + struct stat mstat; + if (lstat(target.c_str(), &mstat) != 0) { + if (errno != ENOENT) { + return ErrnoError() << "lstat() failed on " << target; } - - if (lchown(args[1].c_str(), *uid, *gid) == -1) { - return ErrnoError() << "lchown failed"; + if (!make_dir(target, mode)) { + return ErrnoErrorIgnoreEnoent() << "mkdir() failed on " << target; } - - /* chown may have cleared S_ISUID and S_ISGID, chmod again */ - if (mode & (S_ISUID | S_ISGID)) { - if (fchmodat(AT_FDCWD, args[1].c_str(), mode, AT_SYMLINK_NOFOLLOW) == -1) { - return ErrnoError() << "fchmodat failed"; - } + if (lstat(target.c_str(), &mstat) != 0) { + return ErrnoError() << "lstat() failed on new " << target; + } + } + if (!S_ISDIR(mstat.st_mode)) { + return Error() << "Not a directory on " << target; + } + bool needs_chmod = (mstat.st_mode & ~S_IFMT) != mode; + if ((*uid != static_cast<uid_t>(-1) && *uid != mstat.st_uid) || + (*gid != static_cast<gid_t>(-1) && *gid != mstat.st_gid)) { + if (lchown(target.c_str(), *uid, *gid) == -1) { + return ErrnoError() << "lchown failed on " << target; + } + // chown may have cleared S_ISUID and S_ISGID, chmod again + needs_chmod = true; + } + if (needs_chmod) { + if (fchmodat(AT_FDCWD, target.c_str(), mode, AT_SYMLINK_NOFOLLOW) == -1) { + return ErrnoError() << "fchmodat() failed on " << target; } } - if (fscrypt_is_native()) { - if (fscrypt_set_directory_policy(args[1].c_str())) { + if (fscrypt_set_directory_policy(target)) { return reboot_into_recovery( - {"--prompt_and_wipe_data", "--reason=set_policy_failed:"s + args[1]}); + {"--prompt_and_wipe_data", "--reason=set_policy_failed:"s + target}); } } return {}; |