f072a5b |
Jamozed |
2021-02-16 14:28:04 |
0
|
// chmod.c, version 1.0.2 |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
1
|
// OMKOV coreutils implementation of POSIX chmod |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
2
|
// Copyright (C) 2020, Jakob Wakeling |
e2140ec |
Jamozed |
2022-03-06 15:27:45 |
3
|
// MIT Licence |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
4
|
|
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
5
|
/* |
72364dd |
Jamozed |
2020-11-17 01:23:57 |
6
|
TODO Don't recursively change symlink permissions |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
7
|
TODO Handle copying permission |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
8
|
*/ |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
9
|
|
b181413 |
Jamozed |
2022-02-05 22:32:00 |
10
|
#include "util/error.h" |
b181413 |
Jamozed |
2022-02-05 22:32:00 |
11
|
#include "util/mode.h" |
b181413 |
Jamozed |
2022-02-05 22:32:00 |
12
|
#include "util/optget.h" |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
13
|
|
72364dd |
Jamozed |
2020-11-17 01:23:57 |
14
|
#include <dirent.h> |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
15
|
#include <sys/stat.h> |
72364dd |
Jamozed |
2020-11-17 01:23:57 |
16
|
#include <unistd.h> |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
17
|
|
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
18
|
#include <errno.h> |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
19
|
#include <stdbool.h> |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
20
|
#include <stdio.h> |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
21
|
#include <stdlib.h> |
72364dd |
Jamozed |
2020-11-17 01:23:57 |
22
|
#include <string.h> |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
23
|
|
f072a5b |
Jamozed |
2021-02-16 14:28:04 |
24
|
#define VERSION "1.0.2" |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
25
|
|
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
26
|
static struct lop lops[] = { |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
27
|
{ "help", ARG_NUL, 256 }, |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
28
|
{ "version", ARG_NUL, 257 }, |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
29
|
{ NULL, 0, 0 } |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
30
|
}; |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
31
|
|
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
32
|
static bool Rflag; |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
33
|
|
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
34
|
static mode_t mask; |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
35
|
|
72364dd |
Jamozed |
2020-11-17 01:23:57 |
36
|
static inline int setmode(const char *path, chmod_t *m); |
72364dd |
Jamozed |
2020-11-17 01:23:57 |
37
|
static inline char *mkpath(const char *path, const char *file); |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
38
|
|
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
39
|
static void hlp(void); |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
40
|
static void ver(void); |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
41
|
|
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
42
|
int main(int ac, char *av[]) { A0 = av[0]; |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
43
|
struct opt opt = OPTGET_INIT; opt.str = "R"; opt.lops = lops; |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
44
|
for (int o; (o = optget(&opt, av, 1)) != -1;) switch (o) { |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
45
|
case 'R': { Rflag = true; break; } |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
46
|
case 256: { hlp(); return 0; } |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
47
|
case 257: { ver(); return 0; } |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
48
|
default: { return 1; } |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
49
|
} |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
50
|
|
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
51
|
if (opt.ind >= ac - 1) { error(1, "missing operand"); } |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
52
|
|
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
53
|
mask = umask(0); chmod_t *m = strmode(av[opt.ind]); |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
54
|
if (!m) { error(1, "%s: invalid mode", av[opt.ind]); } |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
55
|
|
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
56
|
for (char **p = &av[opt.ind + 1]; *p; ++p) { |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
57
|
if (setmode(*p, m)) { warn("%s: %s", *p, serr()); warned = true; } |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
58
|
} |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
59
|
|
72364dd |
Jamozed |
2020-11-17 01:23:57 |
60
|
free(m); return warned; |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
61
|
} |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
62
|
|
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
63
|
/* Set the mode of the specified file */ |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
64
|
static inline int setmode(const char *path, chmod_t *m) { |
72364dd |
Jamozed |
2020-11-17 01:23:57 |
65
|
struct stat st; register bool ln = false; |
72364dd |
Jamozed |
2020-11-17 01:23:57 |
66
|
|
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
67
|
// Get current permissions of file |
72364dd |
Jamozed |
2020-11-17 01:23:57 |
68
|
if (lstat(path, &st)) { return 1; }; |
72364dd |
Jamozed |
2020-11-17 01:23:57 |
69
|
if (S_ISLNK(st.st_mode)) { if (stat(path, &st)) { return 1; } ln = true; } |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
70
|
mode_t mode = st.st_mode; |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
71
|
|
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
72
|
// Handle each chmod_t |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
73
|
for (int i = 0;; ++i) switch (m[i].flag) { |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
74
|
case MF_NORM: case MF_XIFX: { |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
75
|
// If ref is null, use the file mode creation mask |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
76
|
if (!m[i].ref) { m[i].ref = M_ALL & ~mask; } |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
77
|
|
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
78
|
switch (m[i].op) { |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
79
|
case '+': { mode |= m[i].ref & m[i].mod; break; } |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
80
|
case '-': { mode &= (~(m[i].ref & m[i].mod) & 07777); break; } |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
81
|
case '=': { mode &= ~m[i].ref; mode |= m[i].ref & m[i].mod; break; } |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
82
|
} |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
83
|
|
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
84
|
// If the XIFX flag is set, set execute permission accordingly |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
85
|
if (m[i].flag == MF_XIFX) { |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
86
|
if (S_ISDIR(mode) || mode & M_EX) { mode |= m[i].ref & M_EX; } |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
87
|
} break; |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
88
|
} |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
89
|
case MF_COPY: { /* TODO */ } |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
90
|
case MF_NULL: { goto end; } |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
91
|
} end:; |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
92
|
|
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
93
|
// Set permissions of the file to the calculated mode |
72364dd |
Jamozed |
2020-11-17 01:23:57 |
94
|
if (chmod(path, mode)) { return 1; } |
72364dd |
Jamozed |
2020-11-17 01:23:57 |
95
|
|
72364dd |
Jamozed |
2020-11-17 01:23:57 |
96
|
// Recurse into directories if R flag is set |
72364dd |
Jamozed |
2020-11-17 01:23:57 |
97
|
if (Rflag && !ln && S_ISDIR(st.st_mode)) { |
72364dd |
Jamozed |
2020-11-17 01:23:57 |
98
|
DIR *di; if (!(di = opendir(path))) { return 1; } |
72364dd |
Jamozed |
2020-11-17 01:23:57 |
99
|
|
72364dd |
Jamozed |
2020-11-17 01:23:57 |
100
|
// For each entry in directory, recursively call setmode |
72364dd |
Jamozed |
2020-11-17 01:23:57 |
101
|
for (struct dirent *de; (de = readdir(di));) { |
72364dd |
Jamozed |
2020-11-17 01:23:57 |
102
|
if (de->d_name[0] == '.' && (de->d_name[1] == 0 || |
72364dd |
Jamozed |
2020-11-17 01:23:57 |
103
|
(de->d_name[1] == '.' && de->d_name[2] == 0))) { continue; } |
72364dd |
Jamozed |
2020-11-17 01:23:57 |
104
|
|
72364dd |
Jamozed |
2020-11-17 01:23:57 |
105
|
char *s = mkpath(path, de->d_name); |
72364dd |
Jamozed |
2020-11-17 01:23:57 |
106
|
if (setmode(s, m)) { warn("%s: %s", s, serr()); warned = true; } |
72364dd |
Jamozed |
2020-11-17 01:23:57 |
107
|
|
72364dd |
Jamozed |
2020-11-17 01:23:57 |
108
|
free(s); |
72364dd |
Jamozed |
2020-11-17 01:23:57 |
109
|
} |
72364dd |
Jamozed |
2020-11-17 01:23:57 |
110
|
|
72364dd |
Jamozed |
2020-11-17 01:23:57 |
111
|
closedir(di); |
72364dd |
Jamozed |
2020-11-17 01:23:57 |
112
|
} |
72364dd |
Jamozed |
2020-11-17 01:23:57 |
113
|
|
72364dd |
Jamozed |
2020-11-17 01:23:57 |
114
|
return 0; |
72364dd |
Jamozed |
2020-11-17 01:23:57 |
115
|
} |
72364dd |
Jamozed |
2020-11-17 01:23:57 |
116
|
|
72364dd |
Jamozed |
2020-11-17 01:23:57 |
117
|
/* Allocate and make path from two components */ |
72364dd |
Jamozed |
2020-11-17 01:23:57 |
118
|
static inline char *mkpath(const char *path, const char *file) { |
72364dd |
Jamozed |
2020-11-17 01:23:57 |
119
|
register size_t pl = strlen(path); char *s; |
72364dd |
Jamozed |
2020-11-17 01:23:57 |
120
|
s = (char *)malloc((pl + strlen(file) + 2) * sizeof (*s)); |
72364dd |
Jamozed |
2020-11-17 01:23:57 |
121
|
strcpy(s, path); if (s[pl - 1] != '/') { s[pl] = '/'; s[++pl] = 0; } |
72364dd |
Jamozed |
2020-11-17 01:23:57 |
122
|
strcat(s, file); return s; |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
123
|
} |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
124
|
|
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
125
|
/* Print help information */ |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
126
|
static void hlp(void) { |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
127
|
puts("chmod - change the file modes\n"); |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
128
|
puts("usage: chmod [-R] mode file...\n"); |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
129
|
puts("options:"); |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
130
|
puts(" -R Recursively change file mode bits"); |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
131
|
puts(" --help Display help information"); |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
132
|
puts(" --version Display version information"); |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
133
|
} |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
134
|
|
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
135
|
/* Print version information */ |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
136
|
static void ver(void) { |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
137
|
puts("OMKOV coreutils chmod, version " VERSION); |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
138
|
puts("Copyright (C) 2020, Jakob Wakeling"); |
e2140ec |
Jamozed |
2022-03-06 15:27:45 |
139
|
puts("MIT Licence (https://opensource.org/licenses/MIT)"); |
70ce5b0 |
Jamozed |
2020-11-13 00:17:34 |
140
|
} |
|
|
|
141
|
|