]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/home/homework-quota.c
508c0c01b22674095bb0870fc1760bdda6e783ef
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
4 #include "blockdev-util.h"
5 #include "btrfs-util.h"
6 #include "errno-util.h"
7 #include "format-util.h"
8 #include "homework-quota.h"
9 #include "missing_magic.h"
10 #include "quota-util.h"
11 #include "stat-util.h"
12 #include "user-util.h"
14 int home_update_quota_btrfs(UserRecord
*h
, const char *path
) {
20 if (h
->disk_size
== UINT64_MAX
)
23 /* If the user wants quota, enable it */
24 r
= btrfs_quota_enable(path
, true);
26 return log_error_errno(r
, "No btrfs quota support on subvolume %s.", path
);
28 return log_error_errno(r
, "Failed to enable btrfs quota support on %s.", path
);
30 r
= btrfs_qgroup_set_limit(path
, 0, h
->disk_size
);
32 return log_error_errno(r
, "Failed to set disk quota on subvolume %s: %m", path
);
34 log_info("Set btrfs quota.");
39 int home_update_quota_classic(UserRecord
*h
, const char *path
) {
45 assert(uid_is_valid(h
->uid
));
48 if (h
->disk_size
== UINT64_MAX
)
51 r
= get_block_device(path
, &devno
);
53 return log_error_errno(r
, "Failed to determine block device of %s: %m", path
);
55 return log_error_errno(SYNTHETIC_ERRNO(ENODEV
), "File system %s not backed by a block device.", path
);
57 r
= quotactl_devnum(QCMD_FIXED(Q_GETQUOTA
, USRQUOTA
), devno
, h
->uid
, &req
);
60 else if (ERRNO_IS_NEG_NOT_SUPPORTED(r
))
61 return log_error_errno(r
, "No UID quota support on %s.", path
);
63 return log_error_errno(r
, "Failed to query disk quota for UID " UID_FMT
": %m", h
->uid
);
64 else if (FLAGS_SET(req
.dqb_valid
, QIF_BLIMITS
) && h
->disk_size
/ QIF_DQBLKSIZE
== req
.dqb_bhardlimit
) {
65 /* Shortcut things if everything is set up properly already */
66 log_info("Configured quota already matches the intended setting, not updating quota.");
70 req
.dqb_valid
= QIF_BLIMITS
;
71 req
.dqb_bsoftlimit
= req
.dqb_bhardlimit
= h
->disk_size
/ QIF_DQBLKSIZE
;
73 r
= quotactl_devnum(QCMD_FIXED(Q_SETQUOTA
, USRQUOTA
), devno
, h
->uid
, &req
);
75 return log_error_errno(SYNTHETIC_ERRNO(ENOTTY
), "UID quota not available on %s.", path
);
77 return log_error_errno(r
, "Failed to set disk quota for UID " UID_FMT
": %m", h
->uid
);
79 log_info("Updated per-UID quota.");
84 int home_update_quota_auto(UserRecord
*h
, const char *path
) {
90 if (h
->disk_size
== UINT64_MAX
)
94 path
= user_record_image_path(h
);
96 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Home record lacks image path.");
99 if (statfs(path
, &sfs
) < 0)
100 return log_error_errno(errno
, "Failed to statfs() file system: %m");
102 if (is_fs_type(&sfs
, XFS_SB_MAGIC
) ||
103 is_fs_type(&sfs
, EXT4_SUPER_MAGIC
))
104 return home_update_quota_classic(h
, path
);
106 if (is_fs_type(&sfs
, BTRFS_SUPER_MAGIC
)) {
108 r
= btrfs_is_subvol(path
);
110 return log_error_errno(errno
, "Failed to test if %s is a subvolume: %m", path
);
112 return log_error_errno(SYNTHETIC_ERRNO(ENOTTY
), "Directory %s is not a subvolume, cannot apply quota.", path
);
114 return home_update_quota_btrfs(h
, path
);
117 return log_error_errno(SYNTHETIC_ERRNO(ENOTTY
), "Type of directory %s not known, cannot apply quota.", path
);