Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */ 2 : 3 : #include <errno.h> 4 : #include <fcntl.h> 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" 11 : #include "macro.h" 12 : 13 18 : int chattr_fd(int fd, unsigned value, unsigned mask, unsigned *previous) { 14 : unsigned old_attr, new_attr; 15 : struct stat st; 16 : 17 18 : assert(fd >= 0); 18 : 19 18 : if (fstat(fd, &st) < 0) 20 0 : 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 18 : if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode)) 29 0 : return -ENOTTY; 30 : 31 18 : if (mask == 0 && !previous) 32 0 : return 0; 33 : 34 18 : if (ioctl(fd, FS_IOC_GETFLAGS, &old_attr) < 0) 35 0 : return -errno; 36 : 37 18 : new_attr = (old_attr & ~mask) | (value & mask); 38 18 : if (new_attr == old_attr) { 39 2 : if (previous) 40 0 : *previous = old_attr; 41 2 : return 0; 42 : } 43 : 44 16 : if (ioctl(fd, FS_IOC_SETFLAGS, &new_attr) < 0) 45 16 : return -errno; 46 : 47 0 : if (previous) 48 0 : *previous = old_attr; 49 : 50 0 : return 1; 51 : } 52 : 53 16 : int chattr_path(const char *p, unsigned value, unsigned mask, unsigned *previous) { 54 16 : _cleanup_close_ int fd = -1; 55 : 56 16 : assert(p); 57 : 58 16 : if (mask == 0) 59 0 : return 0; 60 : 61 16 : fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); 62 16 : if (fd < 0) 63 0 : return -errno; 64 : 65 16 : return chattr_fd(fd, value, mask, previous); 66 : } 67 : 68 0 : int read_attr_fd(int fd, unsigned *ret) { 69 : struct stat st; 70 : 71 0 : assert(fd >= 0); 72 : 73 0 : if (fstat(fd, &st) < 0) 74 0 : return -errno; 75 : 76 0 : if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode)) 77 0 : return -ENOTTY; 78 : 79 0 : if (ioctl(fd, FS_IOC_GETFLAGS, ret) < 0) 80 0 : return -errno; 81 : 82 0 : return 0; 83 : } 84 : 85 0 : int read_attr_path(const char *p, unsigned *ret) { 86 0 : _cleanup_close_ int fd = -1; 87 : 88 0 : assert(p); 89 0 : assert(ret); 90 : 91 0 : fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); 92 0 : if (fd < 0) 93 0 : return -errno; 94 : 95 0 : return read_attr_fd(fd, ret); 96 : }