c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering/***
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering This file is part of systemd.
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering Copyright 2010 Lennart Poettering
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering systemd is free software; you can redistribute it and/or modify it
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering under the terms of the GNU Lesser General Public License as published by
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering (at your option) any later version.
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering systemd is distributed in the hope that it will be useful, but
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering Lesser General Public License for more details.
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering You should have received a copy of the GNU Lesser General Public License
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering***/
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering
11c3a36649e5e5e77db499c92f3cdcbd619efd3aThomas Hindoe Paaboel Andersen#include <errno.h>
11c3a36649e5e5e77db499c92f3cdcbd619efd3aThomas Hindoe Paaboel Andersen#include <fcntl.h>
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering#include <sys/ioctl.h>
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering#include <sys/stat.h>
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering#include <linux/fs.h>
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering#include "chattr-util.h"
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering#include "fd-util.h"
11c3a36649e5e5e77db499c92f3cdcbd619efd3aThomas Hindoe Paaboel Andersen#include "macro.h"
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poetteringint chattr_fd(int fd, unsigned value, unsigned mask) {
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering unsigned old_attr, new_attr;
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering struct stat st;
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering assert(fd >= 0);
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering if (fstat(fd, &st) < 0)
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering return -errno;
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering /* Explicitly check whether this is a regular file or
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering * directory. If it is anything else (such as a device node or
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering * fifo), then the ioctl will not hit the file systems but
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering * possibly drivers, where the ioctl might have different
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering * effects. Notably, DRM is using the same ioctl() number. */
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode))
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering return -ENOTTY;
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering if (mask == 0)
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering return 0;
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering if (ioctl(fd, FS_IOC_GETFLAGS, &old_attr) < 0)
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering return -errno;
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering new_attr = (old_attr & ~mask) | (value & mask);
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering if (new_attr == old_attr)
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering return 0;
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering if (ioctl(fd, FS_IOC_SETFLAGS, &new_attr) < 0)
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering return -errno;
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering return 1;
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering}
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poetteringint chattr_path(const char *p, unsigned value, unsigned mask) {
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering _cleanup_close_ int fd = -1;
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering assert(p);
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering if (mask == 0)
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering return 0;
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering if (fd < 0)
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering return -errno;
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering return chattr_fd(fd, value, mask);
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering}
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poetteringint read_attr_fd(int fd, unsigned *ret) {
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering struct stat st;
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering assert(fd >= 0);
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering if (fstat(fd, &st) < 0)
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering return -errno;
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode))
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering return -ENOTTY;
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering if (ioctl(fd, FS_IOC_GETFLAGS, ret) < 0)
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering return -errno;
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering return 0;
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering}
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poetteringint read_attr_path(const char *p, unsigned *ret) {
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering _cleanup_close_ int fd = -1;
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering assert(p);
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering assert(ret);
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering if (fd < 0)
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering return -errno;
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering return read_attr_fd(fd, ret);
c8b3094de58e3b1e37d06f3d56c9346cffbe320aLennart Poettering}