diff --git a/Makefile b/Makefile index ee6d7cc..d9798c8 100644 --- a/Makefile +++ b/Makefile @@ -21,6 +21,8 @@ all: @make -C head @echo "\x1B[0;1;35m make\x1B[0m utilities/reset" @make -C reset + @echo "\x1B[0;1;35m make\x1B[0m utilities/chmod" + @make -C chmod install: @mkdir -p out @@ -46,6 +48,8 @@ install: @make install -C head @echo "\x1B[0;1;35m make\x1B[0m install utilities/reset" @make install -C reset + @echo "\x1B[0;1;35m make\x1B[0m install utilities/chmod" + @make install -C chmod clean: @echo "\x1B[0;1;35m make\x1B[0m clean utilities/hello" @@ -69,4 +73,6 @@ clean: @echo "\x1B[0;1;35m make\x1B[0m clean utilities/head" @make clean -C head @echo "\x1B[0;1;35m make\x1B[0m clean utilities/reset" - @make clean -C reset \ No newline at end of file + @make clean -C reset + @echo "\x1B[0;1;35m make\x1B[0m clean utilities/chmod" + @make clean -C chmod \ No newline at end of file diff --git a/chmod/Makefile b/chmod/Makefile new file mode 100644 index 0000000..9eb5c13 --- /dev/null +++ b/chmod/Makefile @@ -0,0 +1,23 @@ +PLATFORM=x86_64-lux +CCFLAGS=-Wall -c -O3 +LDFLAGS=-llux +CC=x86_64-lux-gcc +LD=x86_64-lux-gcc +SRC:=$(shell find . -type f -name "*.c") +OBJ:=$(SRC:.c=.o) + +all: chmod + +%.o: %.c + @echo "\x1B[0;1;32m cc \x1B[0m $<" + @$(CC) $(CCFLAGS) -o $@ $< + +chmod: $(OBJ) + @echo "\x1B[0;1;93m ld \x1B[0m chmod" + @$(LD) $(OBJ) -o chmod $(LDFLAGS) + +install: chmod + @cp chmod ../out/ + +clean: + @rm -f chmod $(OBJ) diff --git a/chmod/chmod.c b/chmod/chmod.c new file mode 100644 index 0000000..df24cca --- /dev/null +++ b/chmod/chmod.c @@ -0,0 +1,97 @@ +/* + * luxOS - a unix-like operating system + * Omar Elghoul, 2024 + * + * chmod: Implementation of the chmod command + */ + +#include +#include +#include +#include + +static const mode_t bitmap[] = { + S_IXOTH, + S_IWOTH, + S_IROTH, + S_IXGRP, + S_IWGRP, + S_IRGRP, + S_IXUSR, + S_IWUSR, + S_IRUSR +}; + +int parse(const char *modestr, mode_t *set, mode_t *clear) { + *set = 0; + *clear = 0; + + /* numerical mode setting */ + if(modestr[0] >= '0' && modestr[0] <= '9') { + int num = atoi(modestr); + + for(int i = 0; i < 3; i++) { + int digit = num % 10; + num /= 10; + if(digit > 7) return 1; + + if(digit & 1) { // execute + *set |= bitmap[i * 3]; + } else { + *clear |= bitmap[i * 3]; + } + + if(digit & 2) { // write + *set |= bitmap[(i * 3) + 1]; + } else { + *clear |= bitmap[(i * 3) + 1]; + } + + if(digit & 4) { // read + *set |= bitmap[(i * 3) + 2]; + } else { + *clear |= bitmap[(i * 3) + 2]; + } + } + + return 0; + } + + /* TODO: symbolic mode setting */ + return 1; +} + +int main(int argc, char **argv) { + /* TODO: add support for -R to recursively change file modes */ + + if(argc < 3) { + fprintf(stderr, "usage: %s [-R] mode file...\n", argv[0]); + return EXIT_FAILURE; + } + + mode_t set = 0, clear = 0; + if(parse(argv[1], &set, &clear)) { + fprintf(stderr, "%s: invalid mode -- %s\n", argv[0], argv[1]); + return EXIT_FAILURE; + } + + int errors = 0; + + struct stat st; + for(int i = 2; i < argc; i++) { + if(stat(argv[i], &st)) { + perror(argv[i]); + errors++; + continue; + } + + st.st_mode &= ~clear; + st.st_mode |= set; + if(chmod(argv[i], st.st_mode)) { + perror(argv[i]); + errors++; + } + } + + return errors; +}