2023-05-12 21:38:41 +00:00
|
|
|
#include "command.h"
|
|
|
|
#include "lslib.h"
|
|
|
|
|
|
|
|
#include <dirent.h>
|
|
|
|
#include <grp.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <unistd.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) {
|
2023-05-15 01:43:02 +00:00
|
|
|
error_s("cannot chown '%s'", get_path_buffer());
|
2023-05-12 21:38:41 +00:00
|
|
|
}
|
|
|
|
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) {
|
2023-05-15 01:43:02 +00:00
|
|
|
error_s("cannot stat '%s'", get_path_buffer());
|
2023-05-12 21:38:41 +00:00
|
|
|
}
|
|
|
|
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) {
|
2023-05-15 01:43:02 +00:00
|
|
|
error_s("cannot open dir '%s'", get_path_buffer());
|
2023-05-12 21:38:41 +00:00
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|