]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/home/homework-quota.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
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
, "Faled 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_devno(QCMD_FIXED(Q_GETQUOTA
, USRQUOTA
), devno
, h
->uid
, &req
);
59 if (ERRNO_IS_NOT_SUPPORTED(r
))
60 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
);
67 /* Shortcut things if everything is set up properly already */
68 if (FLAGS_SET(req
.dqb_valid
, QIF_BLIMITS
) && h
->disk_size
/ QIF_DQBLKSIZE
== req
.dqb_bhardlimit
) {
69 log_info("Configured quota already matches the intended setting, not updating quota.");
74 req
.dqb_valid
= QIF_BLIMITS
;
75 req
.dqb_bsoftlimit
= req
.dqb_bhardlimit
= h
->disk_size
/ QIF_DQBLKSIZE
;
77 r
= quotactl_devno(QCMD_FIXED(Q_SETQUOTA
, USRQUOTA
), devno
, h
->uid
, &req
);
80 return log_error_errno(SYNTHETIC_ERRNO(ENOTTY
), "UID quota not available on %s.", path
);
82 return log_error_errno(r
, "Failed to set disk quota for UID " UID_FMT
": %m", h
->uid
);
85 log_info("Updated per-UID quota.");
90 int home_update_quota_auto(UserRecord
*h
, const char *path
) {
96 if (h
->disk_size
== UINT64_MAX
)
100 path
= user_record_image_path(h
);
102 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Home record lacks image path.");
105 if (statfs(path
, &sfs
) < 0)
106 return log_error_errno(errno
, "Failed to statfs() file system: %m");
108 if (is_fs_type(&sfs
, XFS_SB_MAGIC
) ||
109 is_fs_type(&sfs
, EXT4_SUPER_MAGIC
))
110 return home_update_quota_classic(h
, path
);
112 if (is_fs_type(&sfs
, BTRFS_SUPER_MAGIC
)) {
114 r
= btrfs_is_subvol(path
);
116 return log_error_errno(errno
, "Failed to test if %s is a subvolume: %m", path
);
118 return log_error_errno(SYNTHETIC_ERRNO(ENOTTY
), "Directory %s is not a subvolume, cannot apply quota.", path
);
120 return home_update_quota_btrfs(h
, path
);
123 return log_error_errno(SYNTHETIC_ERRNO(ENOTTY
), "Type of directory %s not known, cannot apply quota.", path
);