1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
9 #include "bus-locator.h"
10 #include "dev-setup.h"
11 #include "format-util.h"
13 #include "label-util.h"
14 #include "limits-util.h"
15 #include "main-func.h"
16 #include "mkdir-label.h"
17 #include "mount-util.h"
18 #include "mountpoint-util.h"
19 #include "path-util.h"
21 #include "selinux-util.h"
22 #include "smack-util.h"
23 #include "stdio-util.h"
24 #include "string-util.h"
26 #include "user-util.h"
28 static int acquire_runtime_dir_properties(uint64_t *size
, uint64_t *inodes
) {
29 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
30 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
33 r
= sd_bus_default_system(&bus
);
35 return log_error_errno(r
, "Failed to connect to system bus: %m");
37 r
= bus_get_property_trivial(bus
, bus_login_mgr
, "RuntimeDirectorySize", &error
, 't', size
);
39 log_warning_errno(r
, "Failed to acquire runtime directory size, ignoring: %s", bus_error_message(&error
, r
));
40 *size
= physical_memory_scale(10U, 100U); /* 10% */
43 r
= bus_get_property_trivial(bus
, bus_login_mgr
, "RuntimeDirectoryInodesMax", &error
, 't', inodes
);
45 log_warning_errno(r
, "Failed to acquire number of inodes for runtime directory, ignoring: %s", bus_error_message(&error
, r
));
46 *inodes
= DIV_ROUND_UP(*size
, 4096);
52 static int user_mkdir_runtime_path(
53 const char *runtime_path
,
56 uint64_t runtime_dir_size
,
57 uint64_t runtime_dir_inodes
) {
62 assert(path_is_absolute(runtime_path
));
63 assert(uid_is_valid(uid
));
64 assert(gid_is_valid(gid
));
66 r
= mkdir_safe_label("/run/user", 0755, 0, 0, MKDIR_WARN_MODE
);
68 return log_error_errno(r
, "Failed to create /run/user: %m");
70 if (path_is_mount_point(runtime_path
, NULL
, 0) >= 0)
71 log_debug("%s is already a mount point", runtime_path
);
73 char options
[sizeof("mode=0700,uid=,gid=,size=,nr_inodes=,smackfsroot=*")
74 + DECIMAL_STR_MAX(uid_t
)
75 + DECIMAL_STR_MAX(gid_t
)
76 + DECIMAL_STR_MAX(uint64_t)
77 + DECIMAL_STR_MAX(uint64_t)];
80 "mode=0700,uid=" UID_FMT
",gid=" GID_FMT
",size=%" PRIu64
",nr_inodes=%" PRIu64
"%s",
81 uid
, gid
, runtime_dir_size
, runtime_dir_inodes
,
82 mac_smack_use() ? ",smackfsroot=*" : "");
84 r
= mkdir_label(runtime_path
, 0700);
85 if (r
< 0 && r
!= -EEXIST
)
86 return log_error_errno(r
, "Failed to create %s: %m", runtime_path
);
88 r
= mount_nofollow_verbose(LOG_DEBUG
, "tmpfs", runtime_path
, "tmpfs", MS_NODEV
|MS_NOSUID
, options
);
90 if (!ERRNO_IS_PRIVILEGE(r
)) {
91 log_error_errno(r
, "Failed to mount per-user tmpfs directory %s: %m", runtime_path
);
96 "Failed to mount per-user tmpfs directory %s.\n"
97 "Assuming containerized execution, ignoring: %m", runtime_path
);
99 r
= chmod_and_chown(runtime_path
, 0700, uid
, gid
);
101 log_error_errno(r
, "Failed to change ownership and mode of \"%s\": %m", runtime_path
);
106 r
= label_fix(runtime_path
, 0);
108 log_warning_errno(r
, "Failed to fix label of \"%s\", ignoring: %m", runtime_path
);
114 /* Try to clean up, but ignore errors */
115 (void) rmdir(runtime_path
);
119 static int user_remove_runtime_path(const char *runtime_path
) {
122 assert(runtime_path
);
123 assert(path_is_absolute(runtime_path
));
125 r
= rm_rf(runtime_path
, 0);
127 log_debug_errno(r
, "Failed to remove runtime directory %s (before unmounting), ignoring: %m", runtime_path
);
129 /* Ignore cases where the directory isn't mounted, as that's quite possible, if we lacked the permissions to
131 r
= umount2(runtime_path
, MNT_DETACH
);
132 if (r
< 0 && !IN_SET(errno
, EINVAL
, ENOENT
))
133 log_debug_errno(errno
, "Failed to unmount user runtime directory %s, ignoring: %m", runtime_path
);
135 r
= rm_rf(runtime_path
, REMOVE_ROOT
);
136 if (r
< 0 && r
!= -ENOENT
)
137 return log_error_errno(r
, "Failed to remove runtime directory %s (after unmounting): %m", runtime_path
);
142 static int do_mount(const char *user
) {
143 char runtime_path
[sizeof("/run/user") + DECIMAL_STR_MAX(uid_t
)];
144 uint64_t runtime_dir_size
, runtime_dir_inodes
;
149 r
= get_user_creds(&user
, &uid
, &gid
, NULL
, NULL
, 0);
151 return log_error_errno(r
,
152 r
== -ESRCH
? "No such user \"%s\"" :
153 r
== -ENOMSG
? "UID \"%s\" is invalid or has an invalid main group"
154 : "Failed to look up user \"%s\": %m",
157 r
= acquire_runtime_dir_properties(&runtime_dir_size
, &runtime_dir_inodes
);
161 xsprintf(runtime_path
, "/run/user/" UID_FMT
, uid
);
163 log_debug("Will mount %s owned by "UID_FMT
":"GID_FMT
, runtime_path
, uid
, gid
);
164 return user_mkdir_runtime_path(runtime_path
, uid
, gid
, runtime_dir_size
, runtime_dir_inodes
);
167 static int do_umount(const char *user
) {
168 char runtime_path
[sizeof("/run/user") + DECIMAL_STR_MAX(uid_t
)];
172 /* The user may be already removed. So, first try to parse the string by parse_uid(),
173 * and if it fails, fall back to get_user_creds(). */
174 if (parse_uid(user
, &uid
) < 0) {
175 r
= get_user_creds(&user
, &uid
, NULL
, NULL
, NULL
, 0);
177 return log_error_errno(r
,
178 r
== -ESRCH
? "No such user \"%s\"" :
179 r
== -ENOMSG
? "UID \"%s\" is invalid or has an invalid main group"
180 : "Failed to look up user \"%s\": %m",
184 xsprintf(runtime_path
, "/run/user/" UID_FMT
, uid
);
186 log_debug("Will remove %s", runtime_path
);
187 return user_remove_runtime_path(runtime_path
);
190 static int run(int argc
, char *argv
[]) {
193 log_parse_environment();
197 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
198 "This program takes two arguments.");
199 if (!STR_IN_SET(argv
[1], "start", "stop"))
200 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
201 "First argument must be either \"start\" or \"stop\".");
209 if (streq(argv
[1], "start"))
210 return do_mount(argv
[2]);
211 if (streq(argv
[1], "stop"))
212 return do_umount(argv
[2]);
213 assert_not_reached();
216 DEFINE_MAIN_FUNCTION(run
);