]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
c8b3094d | 2 | |
11c3a366 TA |
3 | #include <errno.h> |
4 | #include <fcntl.h> | |
c8b3094d LP |
5 | #include <sys/ioctl.h> |
6 | #include <sys/stat.h> | |
7 | #include <linux/fs.h> | |
8 | ||
9 | #include "chattr-util.h" | |
10 | #include "fd-util.h" | |
11c3a366 | 11 | #include "macro.h" |
c8b3094d | 12 | |
db9a4254 | 13 | int chattr_fd(int fd, unsigned value, unsigned mask, unsigned *previous) { |
c8b3094d LP |
14 | unsigned old_attr, new_attr; |
15 | struct stat st; | |
16 | ||
17 | assert(fd >= 0); | |
18 | ||
19 | if (fstat(fd, &st) < 0) | |
20 | return -errno; | |
21 | ||
22 | /* Explicitly check whether this is a regular file or | |
23 | * directory. If it is anything else (such as a device node or | |
24 | * fifo), then the ioctl will not hit the file systems but | |
25 | * possibly drivers, where the ioctl might have different | |
26 | * effects. Notably, DRM is using the same ioctl() number. */ | |
27 | ||
28 | if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode)) | |
29 | return -ENOTTY; | |
30 | ||
db9a4254 | 31 | if (mask == 0 && !previous) |
c8b3094d LP |
32 | return 0; |
33 | ||
34 | if (ioctl(fd, FS_IOC_GETFLAGS, &old_attr) < 0) | |
35 | return -errno; | |
36 | ||
37 | new_attr = (old_attr & ~mask) | (value & mask); | |
db9a4254 LP |
38 | if (new_attr == old_attr) { |
39 | if (previous) | |
40 | *previous = old_attr; | |
c8b3094d | 41 | return 0; |
db9a4254 | 42 | } |
c8b3094d LP |
43 | |
44 | if (ioctl(fd, FS_IOC_SETFLAGS, &new_attr) < 0) | |
45 | return -errno; | |
46 | ||
db9a4254 LP |
47 | if (previous) |
48 | *previous = old_attr; | |
49 | ||
c8b3094d LP |
50 | return 1; |
51 | } | |
52 | ||
db9a4254 | 53 | int chattr_path(const char *p, unsigned value, unsigned mask, unsigned *previous) { |
c8b3094d LP |
54 | _cleanup_close_ int fd = -1; |
55 | ||
56 | assert(p); | |
57 | ||
58 | if (mask == 0) | |
59 | return 0; | |
60 | ||
61 | fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); | |
62 | if (fd < 0) | |
63 | return -errno; | |
64 | ||
db9a4254 | 65 | return chattr_fd(fd, value, mask, previous); |
c8b3094d LP |
66 | } |
67 | ||
68 | int read_attr_fd(int fd, unsigned *ret) { | |
69 | struct stat st; | |
70 | ||
71 | assert(fd >= 0); | |
72 | ||
73 | if (fstat(fd, &st) < 0) | |
74 | return -errno; | |
75 | ||
76 | if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode)) | |
77 | return -ENOTTY; | |
78 | ||
79 | if (ioctl(fd, FS_IOC_GETFLAGS, ret) < 0) | |
80 | return -errno; | |
81 | ||
82 | return 0; | |
83 | } | |
84 | ||
85 | int read_attr_path(const char *p, unsigned *ret) { | |
86 | _cleanup_close_ int fd = -1; | |
87 | ||
88 | assert(p); | |
89 | assert(ret); | |
90 | ||
91 | fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); | |
92 | if (fd < 0) | |
93 | return -errno; | |
94 | ||
95 | return read_attr_fd(fd, ret); | |
96 | } |