diff options
author | Tyler Murphy <tylerm@tylerm.dev> | 2023-05-12 17:38:41 -0400 |
---|---|---|
committer | Tyler Murphy <tylerm@tylerm.dev> | 2023-05-12 17:38:41 -0400 |
commit | c6446e178bf8f4a53511e5ae1e0f3feeb921197c (patch) | |
tree | f13384c1d4f6f085d0856c253996c7b9000bcb7b /command/chown.c | |
parent | refactor (diff) | |
download | lazysphere-c6446e178bf8f4a53511e5ae1e0f3feeb921197c.tar.gz lazysphere-c6446e178bf8f4a53511e5ae1e0f3feeb921197c.tar.bz2 lazysphere-c6446e178bf8f4a53511e5ae1e0f3feeb921197c.zip |
chown, chmod
Diffstat (limited to 'command/chown.c')
-rw-r--r-- | command/chown.c | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/command/chown.c b/command/chown.c new file mode 100644 index 0000000..164e3b4 --- /dev/null +++ b/command/chown.c @@ -0,0 +1,187 @@ +#include "command.h" +#include "lslib.h" + +#include <dirent.h> +#include <grp.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <pwd.h> + +static struct { + bool recurse; + bool list_changed; + bool verbose; + bool quiet; + uid_t uid; + gid_t gid; +} flags; + +static void help (void) { + printf("Usage: chown [-Rcvf]... USER[:[GRP]] FILE...\n\n"); + printf("Change the owner and/or group of FILEs to USER and/or GRP\n\n"); + printf("\t-R\tRecurse\n"); + printf("\t-c\tList changed files\n"); + printf("\t-v\tVerbose\n"); + printf("\t-f\tHide errors\n"); +} + +static int short_arg(char c, char* next) { + UNUSED(next); + switch (c) { + case 'R': + flags.recurse = true; + break; + case 'c': + flags.list_changed = true; + break; + case 'v': + flags.verbose = true; + break; + case 'f': + flags.quiet = true; + break; + default: + return ARG_INVALID; + } + return ARG_UNUSED; +} + +static void chown_file(char* path) { + int save; + struct stat s; + DIR* d; + struct dirent* file; + + save = push_path_buffer(path); + + if (chown(get_path_buffer(), flags.uid, flags.gid) < 0) { + if (!flags.quiet) { + error_s("cannot chown '%s': %s", get_path_buffer(), strerror(errno)); + } + pop_path_buffer(save); + return; + } else if (flags.list_changed) { + printf("chown: changed '%s' to %u:%u\n", get_path_buffer(), flags.uid, flags.gid); + } + + if (!flags.recurse) { + pop_path_buffer(save); + return; + } + + if (lstat(get_path_buffer(), &s) < 0) { + if (!flags.quiet) { + error_s("cannot stat '%s': %s", get_path_buffer(), strerror(errno)); + } + pop_path_buffer(save); + return; + } + + if (!S_ISDIR(s.st_mode)) { + pop_path_buffer(save); + return; + } + + d = opendir(get_path_buffer()); + if (d == NULL) { + if (!flags.quiet) { + error_s("cannot open dir '%s': %s", get_path_buffer(), strerror(errno)); + } + pop_path_buffer(save); + return; + } + + while ((file = readdir(d)) != NULL) { + if (is_dot_dir(file->d_name)) continue; + chown_file(file->d_name); + } + + closedir(d); + pop_path_buffer(save); +} + +static void parse_ownership(char* str) { + char* user = str; + char* group = NULL; + char* end = NULL; + unsigned long i; + struct passwd* p = NULL; + struct group* g = NULL; + + for (i = 0; i < strlen(str); i++) { + if (str[i] == ':') { + str[i] = '\0'; + group = &str[i] + 1; + break; + } + } + + flags.uid = strtol(user, &end, 10); + if (end != user) goto group; + + if ((p = getpwnam(user)) == NULL) { + error("invalid user '%s'", user); + } else { + flags.uid = p->pw_uid; + } + +group: + + if (group == NULL) { + if (p == NULL) { + flags.gid = flags.uid; + } else { + flags.gid = p->pw_gid; + } + return; + } + + flags.gid = strtol(group, &end, 10); + if (end != group) return; + + if ((g = getgrnam(group)) == NULL) { + error("invalid group '%s'", group); + } else { + flags.gid = g->gr_gid; + } +} + +COMMAND(chown_cmd) { + + int start, i; + + flags.recurse = false; + flags.list_changed = false; + flags.verbose = false; + flags.quiet = false; + + start = parse_args(argc, argv, help, short_arg, NULL); + + if (argc - start < 1) { + if (!flags.quiet) { + error("no onwership passed"); + } else { + return EXIT_FAILURE; + } + } + + parse_ownership(argv[start]); + + if (argc - start < 1) { + if (!flags.quiet) { + error("no files passed"); + } else { + return EXIT_FAILURE; + } + } + + for (i = start + 1; i < argc; i++) { + chown_file(argv[i]); + } + + return EXIT_SUCCESS; +} |