]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/chattr-util.c
Merge pull request #1695 from evverx/fix-cap-bounding-merging
[thirdparty/systemd.git] / src / basic / chattr-util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <sys/ioctl.h>
23 #include <sys/stat.h>
24 #include <linux/fs.h>
25
26 #include "chattr-util.h"
27 #include "fd-util.h"
28 #include "util.h"
29
30 int chattr_fd(int fd, unsigned value, unsigned mask) {
31 unsigned old_attr, new_attr;
32 struct stat st;
33
34 assert(fd >= 0);
35
36 if (fstat(fd, &st) < 0)
37 return -errno;
38
39 /* Explicitly check whether this is a regular file or
40 * directory. If it is anything else (such as a device node or
41 * fifo), then the ioctl will not hit the file systems but
42 * possibly drivers, where the ioctl might have different
43 * effects. Notably, DRM is using the same ioctl() number. */
44
45 if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode))
46 return -ENOTTY;
47
48 if (mask == 0)
49 return 0;
50
51 if (ioctl(fd, FS_IOC_GETFLAGS, &old_attr) < 0)
52 return -errno;
53
54 new_attr = (old_attr & ~mask) | (value & mask);
55 if (new_attr == old_attr)
56 return 0;
57
58 if (ioctl(fd, FS_IOC_SETFLAGS, &new_attr) < 0)
59 return -errno;
60
61 return 1;
62 }
63
64 int chattr_path(const char *p, unsigned value, unsigned mask) {
65 _cleanup_close_ int fd = -1;
66
67 assert(p);
68
69 if (mask == 0)
70 return 0;
71
72 fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
73 if (fd < 0)
74 return -errno;
75
76 return chattr_fd(fd, value, mask);
77 }
78
79 int read_attr_fd(int fd, unsigned *ret) {
80 struct stat st;
81
82 assert(fd >= 0);
83
84 if (fstat(fd, &st) < 0)
85 return -errno;
86
87 if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode))
88 return -ENOTTY;
89
90 if (ioctl(fd, FS_IOC_GETFLAGS, ret) < 0)
91 return -errno;
92
93 return 0;
94 }
95
96 int read_attr_path(const char *p, unsigned *ret) {
97 _cleanup_close_ int fd = -1;
98
99 assert(p);
100 assert(ret);
101
102 fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
103 if (fd < 0)
104 return -errno;
105
106 return read_attr_fd(fd, ret);
107 }