#include "command.h" #include "lslib.h" #include #include #include #include #include #include #include #include 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'", get_path_buffer()); } 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'", get_path_buffer()); } 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'", get_path_buffer()); } 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; }