chown, chmod
This commit is contained in:
parent
d8f2c10b71
commit
c6446e178b
7 changed files with 457 additions and 20 deletions
232
command/chmod.c
Normal file
232
command/chmod.c
Normal file
|
@ -0,0 +1,232 @@
|
|||
#include "args.h"
|
||||
#include "command.h"
|
||||
#include "lslib.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
enum method {
|
||||
ADD,
|
||||
SUB,
|
||||
SET
|
||||
};
|
||||
|
||||
static struct {
|
||||
bool recurse;
|
||||
bool list_changed;
|
||||
bool verbose;
|
||||
bool quiet;
|
||||
enum method method;
|
||||
mode_t mode;
|
||||
} flags;
|
||||
|
||||
static void help (void) {
|
||||
printf("Usage: chmod [-Rcvf] MODE[,MODE]... FILE...\n\n");
|
||||
printf("MODE is octal number (bit pattern sstrwxrwxrwx) or [ugoa]{+|-|=}[rwxXst]\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;
|
||||
case 'r':
|
||||
case 'w':
|
||||
case 'x':
|
||||
case 'X':
|
||||
case 't':
|
||||
case 's':
|
||||
return ARG_IGNORE;
|
||||
default:
|
||||
return ARG_INVALID;
|
||||
}
|
||||
return ARG_UNUSED;
|
||||
}
|
||||
|
||||
static void chmod_file(char* path) {
|
||||
int save;
|
||||
struct stat s;
|
||||
DIR* d;
|
||||
struct dirent* file;
|
||||
mode_t mode = 0;
|
||||
|
||||
save = push_path_buffer(path);
|
||||
|
||||
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 (flags.method == SET) {
|
||||
mode = flags.mode;;
|
||||
} else if (flags.method == ADD) {
|
||||
mode = s.st_mode | flags.mode;
|
||||
} else if (flags.method == SUB) {
|
||||
mode = s.st_mode & ~flags.mode;
|
||||
}
|
||||
|
||||
if (chmod(get_path_buffer(), mode) < 0) {
|
||||
if (!flags.quiet) {
|
||||
error_s("cannot chmod '%s': %s", get_path_buffer(), strerror(errno));
|
||||
}
|
||||
pop_path_buffer(save);
|
||||
return;
|
||||
} else if (flags.list_changed) {
|
||||
printf("chmod: changed '%s' to %o\n", get_path_buffer(), mode);
|
||||
}
|
||||
|
||||
if (!flags.recurse) {
|
||||
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;
|
||||
chmod_file(file->d_name);
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
pop_path_buffer(save);
|
||||
}
|
||||
|
||||
static mode_t parse_mode(char** input) {
|
||||
mode_t mode = 00000;
|
||||
char* str = *input;
|
||||
|
||||
switch (*str) {
|
||||
case '=':
|
||||
flags.method = SET;
|
||||
break;
|
||||
case '+':
|
||||
flags.method = ADD;
|
||||
break;
|
||||
case '-':
|
||||
flags.method = SUB;
|
||||
break;
|
||||
default:
|
||||
flags.method = SET;
|
||||
mode = get_mode(str);
|
||||
goto end;
|
||||
}
|
||||
|
||||
next:
|
||||
str++;
|
||||
switch (*str) {
|
||||
case 'r':
|
||||
mode |= 00444;
|
||||
goto next;
|
||||
case 'w':
|
||||
mode |= 00200;
|
||||
goto next;
|
||||
case 'x':
|
||||
mode |= 00111;
|
||||
goto next;
|
||||
case 'X':
|
||||
mode |= 00000;
|
||||
goto next;
|
||||
case 's':
|
||||
mode |= 06000;
|
||||
goto next;
|
||||
case 't':
|
||||
mode |= 01000;
|
||||
goto next;
|
||||
case '\0':
|
||||
case ',':
|
||||
goto end;
|
||||
default:
|
||||
error("invalid option: %c", *str);
|
||||
}
|
||||
|
||||
end:
|
||||
while (true) {
|
||||
|
||||
if (*str == '\0') {
|
||||
*input = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (*str == ',') {
|
||||
*input = ++str;
|
||||
break;
|
||||
}
|
||||
|
||||
str++;
|
||||
}
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
COMMAND(chmod_cmd) {
|
||||
|
||||
int start, i;
|
||||
|
||||
flags.recurse = false;
|
||||
flags.list_changed = false;
|
||||
flags.verbose = false;
|
||||
flags.quiet = false;
|
||||
flags.mode = 0;
|
||||
|
||||
start = parse_args(argc, argv, help, short_arg, NULL);
|
||||
|
||||
if (argc - start < 1) {
|
||||
if (!flags.quiet) {
|
||||
error("no mode provided");
|
||||
} else {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
flags.mode |= parse_mode(&argv[start]);
|
||||
} while (argv[start] != NULL);
|
||||
|
||||
if (argc - start < 2) {
|
||||
if (!flags.quiet) {
|
||||
error("no files passed");
|
||||
} else {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = start + 1; i < argc; i++) {
|
||||
chmod_file(argv[i]);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
187
command/chown.c
Normal file
187
command/chown.c
Normal file
|
@ -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;
|
||||
}
|
33
command/ls.c
33
command/ls.c
|
@ -133,35 +133,46 @@ static bool get_file_info(const char* file_name, struct FileInfo* info) {
|
|||
|
||||
info->mode[1] = (s.st_mode & S_IRUSR) ? 'r' : '-';
|
||||
info->mode[2] = (s.st_mode & S_IWUSR) ? 'w' : '-';
|
||||
if (s.st_mode & S_IXUSR) {
|
||||
if (s.st_mode & S_ISUID) {
|
||||
if (s.st_mode & S_IXUSR && s.st_mode & S_ISUID) {
|
||||
info->mode[3] = 's';
|
||||
info->set_uid = true;
|
||||
} else {
|
||||
if (!info->exec) info->exec = info->usr->pw_uid == uid;
|
||||
} else if (s.st_mode & S_ISUID) {
|
||||
info->mode[3] = 'S';
|
||||
info->set_uid = true;
|
||||
} else if (s.st_mode & S_IXUSR) {
|
||||
info->mode[3] = 'x';
|
||||
}
|
||||
if (!info->exec) info->exec = s.st_uid == uid;
|
||||
if (!info->exec) info->exec = info->usr->pw_uid == uid;
|
||||
} else {
|
||||
info->mode[3] = '-';
|
||||
}
|
||||
|
||||
info->mode[4] = (s.st_mode & S_IRGRP) ? 'r' : '-';
|
||||
info->mode[5] = (s.st_mode & S_IWGRP) ? 'w' : '-';
|
||||
if (s.st_mode & S_IXGRP) {
|
||||
if (s.st_mode & S_ISGID) {
|
||||
if (s.st_mode & S_IXGRP && s.st_mode & S_ISGID) {
|
||||
info->mode[6] = 's';
|
||||
info->set_gid = true;
|
||||
} else {
|
||||
if (!info->exec) info->exec = info->grp->gr_gid == gid;
|
||||
} else if (s.st_mode & S_ISGID) {
|
||||
info->mode[6] = 'S';
|
||||
info->set_gid = true;
|
||||
} else if (s.st_mode & S_IXGRP) {
|
||||
info->mode[6] = 'x';
|
||||
}
|
||||
if (!info->exec) info->exec = s.st_gid == gid;
|
||||
if (!info->exec) info->exec = info->grp->gr_gid == gid;
|
||||
} else {
|
||||
info->mode[6] = '-';
|
||||
}
|
||||
|
||||
info->mode[7] = (s.st_mode & S_IROTH) ? 'r' : '-';
|
||||
info->mode[8] = (s.st_mode & S_IWOTH) ? 'w' : '-';
|
||||
if (s.st_mode & S_IXOTH) {
|
||||
if (s.st_mode & S_IXOTH && s.st_mode & S_ISVTX) {
|
||||
info->mode[9] = 't';
|
||||
info->set_gid = true;
|
||||
info->exec = true;
|
||||
} else if (s.st_mode & S_ISVTX) {
|
||||
info->mode[9] = 'T';
|
||||
info->set_gid = true;
|
||||
} else if (s.st_mode & S_IXOTH) {
|
||||
info->mode[9] = 'x';
|
||||
info->exec = true;
|
||||
} else {
|
||||
|
|
|
@ -46,7 +46,7 @@ mode_t get_mode(const char* next) {
|
|||
mode_t mode = (mode_t)strtol(next, &end, 8);
|
||||
if (!end) return 0;
|
||||
while(isspace(*end)) end++;
|
||||
if (*end != '\0' || (unsigned) mode < 010000) {
|
||||
if (*end != '\0' || (unsigned) mode >= 010000) {
|
||||
error("invalid file mode: `%s`", next);
|
||||
}
|
||||
return mode;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
A terrible busybox/gnu coreutils clone.
|
||||
|
||||
Currently the only supported commands are:
|
||||
`dd`, `cat`, `yes`, `echo`, `printf`, `id`, `groups`, `ls`, `tail`, `head`, `ed`, `tee`, `true`, `false`, `tee`, `whoami`, `wc`, `xargs`, `tac`, `rm`, `cp`, `mkdir`, `mv`, `grep`
|
||||
`dd`, `cat`, `yes`, `echo`, `printf`, `id`, `groups`, `ls`, `tail`, `head`, `ed`, `tee`, `true`, `false`, `tee`, `whoami`, `wc`, `xargs`, `tac`, `rm`, `cp`, `mkdir`, `mv`, `grep`, `chown`, `chmod`
|
||||
|
||||
## How to
|
||||
|
||||
|
|
|
@ -26,5 +26,7 @@ COMMAND(cp);
|
|||
COMMAND(makedir);
|
||||
COMMAND(mv);
|
||||
COMMAND(grep);
|
||||
COMMAND(chown_cmd);
|
||||
COMMAND(chmod_cmd);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "command.h"
|
||||
#include "convert.h"
|
||||
#include "lslib.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
@ -22,7 +23,7 @@ int main (ARGUMENTS) {
|
|||
if (argc < 2) {
|
||||
printf("usage: lazysphere [function [arguments]...]\n\n");
|
||||
printf("currently defined functions:\n");
|
||||
printf("\tdd, cat, yes, echo, printf, id, groups, ls, tail, head, ed, tee, true, false, tee, whoami, wc, xargs, tac, rm, cp, mkdir, mv, grep\n");
|
||||
printf("\tdd, cat, yes, echo, printf, id, groups, ls, tail, head, ed, tee, true, false, tee, whoami, wc, xargs, tac, rm, cp, mkdir, mv, grep, chown, chmod\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
argc--;
|
||||
|
@ -84,6 +85,10 @@ int main (ARGUMENTS) {
|
|||
return mv(NEXT_ARGS);
|
||||
} else if (streql(cmd, "grep")) {
|
||||
return grep(NEXT_ARGS);
|
||||
} else if (streql(cmd, "chown")) {
|
||||
return chown_cmd(NEXT_ARGS);
|
||||
} else if (streql(cmd, "chmod")) {
|
||||
return chmod_cmd(NEXT_ARGS);
|
||||
} else {
|
||||
fprintf(stderr, "lazysphere: invalid command %s\n", cmd);
|
||||
return EXIT_FAILURE;
|
||||
|
|
Loading…
Reference in a new issue