Work on `id`. Still missing some functionality.
[lab.git] / chmod.c
blobedd27488b41074d2f06daed802ac9b85ebad3120
1 /* `chmod.c` - change the file modes
2 Copyright (c) 2022, Alan Potteiger
3 See `LICENSE` for copyright and license details */
5 #define _POSIX_C_SOURCE 200809L
7 #include <stdio.h>
8 #include <unistd.h>
9 #include <errno.h>
10 #include <string.h>
11 #include <sys/stat.h>
12 #include <ftw.h>
14 #include "lab.h"
16 static const char *usage = {
17 "usage: chmod [-R] mode file...\n"
20 static char *modestr; /* mode string */
22 /* callback for ftw(3) to traverse directory tree */
23 static int
24 recurse(const char *path, const struct stat *sb, int flag)
26 mode_t m;
27 switch (flag) {
28 case FTW_D:
29 m = sb->st_mode;
30 modeset(modestr, &m);
31 if (chmod(path, m) != 0)
32 fprintf(stderr, "chmod: %s: %s\n", path,
33 strerror(errno));
34 return 0;
35 case FTW_F: case FTW_SL: case FTW_SLN:
36 m = sb->st_mode;
37 modeset(modestr, &m);
38 if (chmod(path, m) != 0)
39 fprintf(stderr, "chmod: %s: %s\n", path,
40 strerror(errno));
41 return 0;
42 default:
43 return 0;
47 int
48 main(int argc, char *argv[])
50 struct stat st;
51 int status, Rflag;
52 char ch;
53 mode_t mode;
55 status = 0;
56 Rflag = 0;
58 argc--;
59 argv++;
61 if (argc < 2) {
62 fputs(usage, stderr);
63 return 1;
66 if (argv[0][0] == '-' && argv[0][1] == 'R') {
67 Rflag = 1;
68 argc--;
69 argv++;
72 if (argc < 2) {
73 fputs(usage, stderr);
74 return 1;
77 modestr = argv[0];
78 argc--; argv++;
80 for (; argc > 0; argc-- && argv++) {
81 if (stat(argv[0], &st) != 0) {
82 fprintf(stderr, "chmod: %s: %s\n", argv[0],
83 strerror(errno));
84 status = 1;
85 continue;
88 mode = st.st_mode;
89 if (modeset(modestr, &mode) != 0) {
90 fprintf(stderr, "chmod: invalid mode");
91 return 1;
94 if (Rflag)
95 ftw(argv[0], recurse, 1);
97 if (chmod(argv[0], mode) != 0) {
98 fprintf(stderr, "chmod: %s: %s\n", argv[0],
99 strerror(errno));
100 status = 1;
101 continue;
105 return status;