]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
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 LP |
12 | |
13 | int chattr_fd(int fd, unsigned value, unsigned mask) { | |
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 | ||
31 | if (mask == 0) | |
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); | |
38 | if (new_attr == old_attr) | |
39 | return 0; | |
40 | ||
41 | if (ioctl(fd, FS_IOC_SETFLAGS, &new_attr) < 0) | |
42 | return -errno; | |
43 | ||
44 | return 1; | |
45 | } | |
46 | ||
47 | int chattr_path(const char *p, unsigned value, unsigned mask) { | |
48 | _cleanup_close_ int fd = -1; | |
49 | ||
50 | assert(p); | |
51 | ||
52 | if (mask == 0) | |
53 | return 0; | |
54 | ||
55 | fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); | |
56 | if (fd < 0) | |
57 | return -errno; | |
58 | ||
59 | return chattr_fd(fd, value, mask); | |
60 | } | |
61 | ||
62 | int read_attr_fd(int fd, unsigned *ret) { | |
63 | struct stat st; | |
64 | ||
65 | assert(fd >= 0); | |
66 | ||
67 | if (fstat(fd, &st) < 0) | |
68 | return -errno; | |
69 | ||
70 | if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode)) | |
71 | return -ENOTTY; | |
72 | ||
73 | if (ioctl(fd, FS_IOC_GETFLAGS, ret) < 0) | |
74 | return -errno; | |
75 | ||
76 | return 0; | |
77 | } | |
78 | ||
79 | int read_attr_path(const char *p, unsigned *ret) { | |
80 | _cleanup_close_ int fd = -1; | |
81 | ||
82 | assert(p); | |
83 | assert(ret); | |
84 | ||
85 | fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); | |
86 | if (fd < 0) | |
87 | return -errno; | |
88 | ||
89 | return read_attr_fd(fd, ret); | |
90 | } |