]> git.ipfire.org Git - people/ms/pakfire.git/blame - src/libpakfire/mount.c
mount: Remove the legacy logger
[people/ms/pakfire.git] / src / libpakfire / mount.c
CommitLineData
bf5f9c24
MT
1/*#############################################################################
2# #
3# Pakfire - The IPFire package management system #
4# Copyright (C) 2022 Pakfire development team #
5# #
6# This program is free software: you can redistribute it and/or modify #
7# it under the terms of the GNU General Public License as published by #
8# the Free Software Foundation, either version 3 of the License, or #
9# (at your option) any later version. #
10# #
11# This program is distributed in the hope that it will be useful, #
12# but WITHOUT ANY WARRANTY; without even the implied warranty of #
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14# GNU General Public License for more details. #
15# #
16# You should have received a copy of the GNU General Public License #
17# along with this program. If not, see <http://www.gnu.org/licenses/>. #
18# #
19#############################################################################*/
20
21#include <errno.h>
22#include <linux/limits.h>
bf5f9c24
MT
23#include <stddef.h>
24#include <sys/mount.h>
25#include <sys/stat.h>
f71c82d8 26#include <sys/sysmacros.h>
bf5f9c24
MT
27#include <sys/types.h>
28
660120b6 29#include <pakfire/arch.h>
bf5f9c24
MT
30#include <pakfire/logging.h>
31#include <pakfire/pakfire.h>
bc0b24a7 32#include <pakfire/parse.h>
729827f7 33#include <pakfire/path.h>
bf5f9c24 34#include <pakfire/mount.h>
d973a13d 35#include <pakfire/string.h>
bf5f9c24
MT
36#include <pakfire/util.h>
37
38static const struct pakfire_mountpoint {
b2ccb363 39 pakfire_mntns_t ns;
bf5f9c24
MT
40 const char* source;
41 const char* target;
42 const char* fstype;
43 int flags;
44 const char* options;
bf5f9c24 45} mountpoints[] = {
9ab7dd21 46 // Mount a new instance of /proc
b2ccb363
MT
47 {
48 PAKFIRE_MNTNS_INNER|PAKFIRE_MNTNS_OUTER,
49 "pakfire_proc",
50 "proc",
51 "proc",
52 MS_NOSUID|MS_NOEXEC|MS_NODEV,
53 NULL,
54 },
bf5f9c24 55
0d9e0714
MT
56 /*
57 XXX it is kind of problematic to mount /proc twice as a process inside the
58 jail can umount /proc and will then see the host's /proc.
59 */
60
9ab7dd21 61 // Make /proc/sys read-only (except /proc/sys/net)
b2ccb363
MT
62 {
63 PAKFIRE_MNTNS_INNER,
64 "/proc/sys",
65 "proc/sys",
66 "bind",
67 MS_BIND|MS_REC,
68 NULL,
69 },
70 {
71 PAKFIRE_MNTNS_INNER,
72 "/proc/sys/net",
73 "proc/sys/net",
74 "bind",
75 MS_BIND|MS_REC,
76 NULL,
77 },
78 {
79 PAKFIRE_MNTNS_INNER,
80 "/proc/sys",
81 "proc/sys",
82 "bind",
83 MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT,
84 NULL,
85 },
bf5f9c24 86
9ab7dd21 87 // Deny write access to /proc/sysrq-trigger (can be used to restart the host)
b2ccb363
MT
88 {
89 PAKFIRE_MNTNS_INNER,
90 "/proc/sysrq-trigger",
91 "proc/sysrq-trigger",
92 "bind",
93 MS_BIND|MS_REC,
94 NULL,
95 },
96 {
97 PAKFIRE_MNTNS_INNER,
98 "/proc/sysrq-trigger",
99 "proc/sysrq-trigger",
100 "bind",
101 MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT,
102 NULL,
103 },
9ab7dd21
MT
104
105 // Make /proc/irq read-only
b2ccb363
MT
106 {
107 PAKFIRE_MNTNS_INNER,
108 "/proc/irq",
109 "proc/irq",
110 "bind",
111 MS_BIND|MS_REC,
112 NULL,
113 },
114 {
115 PAKFIRE_MNTNS_INNER,
116 "/proc/irq",
117 "proc/irq",
118 "bind",
119 MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT,
120 NULL,
121 },
9ab7dd21
MT
122
123 // Make /proc/bus read-only
b2ccb363
MT
124 {
125 PAKFIRE_MNTNS_INNER,
126 "/proc/bus",
127 "proc/bus",
128 "bind",
129 MS_BIND|MS_REC,
130 NULL,
131 },
132 {
133 PAKFIRE_MNTNS_INNER,
134 "/proc/bus",
135 "proc/bus",
136 "bind",
137 MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT,
138 NULL,
139 },
9ab7dd21
MT
140
141 // Bind-Mount /sys ready-only
b2ccb363
MT
142 {
143 PAKFIRE_MNTNS_OUTER,
144 "/sys",
145 "sys",
146 "bind",
147 MS_BIND|MS_REC,
148 NULL,
149 },
150 {
151 PAKFIRE_MNTNS_OUTER,
152 "/sys",
153 "sys",
154 "bind",
155 MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT,
156 NULL,
157 },
bf5f9c24
MT
158
159 // Create a new /dev
b2ccb363
MT
160 {
161 PAKFIRE_MNTNS_OUTER,
162 "pakfire_dev",
163 "dev",
164 "tmpfs",
165 MS_NOSUID|MS_NOEXEC,
166 "mode=0755,size=4m,nr_inodes=64k",
167 },
168 {
169 PAKFIRE_MNTNS_OUTER,
170 "pakfire_dev_pts",
171 "dev/pts",
172 "devpts",
173 MS_NOSUID|MS_NOEXEC,
174 "newinstance,ptmxmode=0666,mode=620",
175 },
cc752ada 176
99affb62 177 // Create a new /dev/shm
b2ccb363
MT
178 {
179 PAKFIRE_MNTNS_OUTER,
180 "pakfire_dev_shm",
181 "dev/shm",
182 "tmpfs",
183 MS_NOSUID|MS_NODEV|MS_STRICTATIME,
184 "mode=1777,size=1024m",
185 },
99affb62 186
cc752ada 187 // Mount /dev/mqueue
b2ccb363
MT
188 {
189 PAKFIRE_MNTNS_INNER,
190 "mqueue",
191 "dev/mqueue",
192 "mqueue",
193 MS_NOSUID|MS_NOEXEC|MS_NODEV,
194 NULL,
195 },
bf5f9c24
MT
196
197 // Create a new /run
b2ccb363
MT
198 {
199 PAKFIRE_MNTNS_OUTER,
200 "pakfire_run",
201 "run",
202 "tmpfs",
203 MS_NOSUID|MS_NOEXEC|MS_NODEV,
204 "mode=755,size=256m,nr_inodes=1k",
205 },
b1a6d98c
MT
206
207 // Create a new /tmp
b2ccb363
MT
208 {
209 PAKFIRE_MNTNS_OUTER,
210 "pakfire_tmp",
211 "tmp",
212 "tmpfs",
213 MS_NOSUID|MS_NODEV|MS_STRICTATIME,
214 "mode=1777,size=4096m",
215 },
bf5f9c24 216
bf5f9c24 217 // The end
b2ccb363 218 {},
bf5f9c24
MT
219};
220
f71c82d8
MT
221static const struct pakfire_devnode {
222 const char* path;
223 int major;
224 int minor;
225 mode_t mode;
282b732a 226 int flags;
f71c82d8 227} devnodes[] = {
282b732a
MT
228 { "/dev/null", 1, 3, S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, 0 },
229 { "/dev/zero", 1, 5, S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, 0 },
230 { "/dev/full", 1, 7, S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, 0 },
231 { "/dev/random", 1, 8, S_IFCHR|S_IRUSR|S_IRGRP|S_IROTH, 0 },
232 { "/dev/urandom", 1, 9, S_IFCHR|S_IRUSR|S_IRGRP|S_IROTH, 0 },
233 { "/dev/kmsg", 1, 11, S_IFCHR|S_IRUSR|S_IRGRP|S_IROTH, 0 },
234 { "/dev/tty", 5, 0, S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, 0 },
282b732a
MT
235 { "/dev/rtc0", 252, 0, S_IFCHR|S_IRUSR|S_IWUSR, 0 },
236
237 // Loop Devices
238 { "/dev/loop-control", 10, 237, S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, PAKFIRE_MOUNT_LOOP_DEVICES },
239 { "/dev/loop0", 7, 0, S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, PAKFIRE_MOUNT_LOOP_DEVICES },
240 { "/dev/loop1", 7, 1, S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, PAKFIRE_MOUNT_LOOP_DEVICES },
241 { "/dev/loop2", 7, 2, S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, PAKFIRE_MOUNT_LOOP_DEVICES },
242 { "/dev/loop3", 7, 3, S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, PAKFIRE_MOUNT_LOOP_DEVICES },
243 { "/dev/loop4", 7, 4, S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, PAKFIRE_MOUNT_LOOP_DEVICES },
244 { "/dev/loop5", 7, 5, S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, PAKFIRE_MOUNT_LOOP_DEVICES },
245 { "/dev/loop6", 7, 6, S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, PAKFIRE_MOUNT_LOOP_DEVICES },
246 { "/dev/loop7", 7, 7, S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, PAKFIRE_MOUNT_LOOP_DEVICES },
247
f71c82d8
MT
248 { NULL },
249};
dc01afb6 250
f71c82d8
MT
251static const struct pakfire_symlink {
252 const char* target;
253 const char* path;
254} symlinks[] = {
0675c514 255 { "/dev/pts/ptmx", "/dev/ptmx", },
f71c82d8
MT
256 { "/proc/self/fd", "/dev/fd", },
257 { "/proc/self/fd/0", "/dev/stdin" },
258 { "/proc/self/fd/1", "/dev/stdout" },
259 { "/proc/self/fd/2", "/dev/stderr" },
260 { "/proc/kcore", "/dev/core" },
261 { NULL },
262};
dc01afb6 263
719e2e3e
MT
264int pakfire_mount_change_propagation(struct pakfire_ctx* ctx, const char* path, int propagation) {
265 CTX_DEBUG(ctx, "Changing mount propagation on %s\n", path);
9f558f7d
MT
266
267 int r = mount(NULL, path, NULL, propagation|MS_REC, NULL);
268 if (r)
719e2e3e 269 CTX_ERROR(ctx, "Failed to change mount propagation on %s: %m\n", path);
9f558f7d
MT
270
271 return r;
272}
273
14df7388
MT
274static int pakfire_mount_is_mountpoint(struct pakfire* pakfire, const char* path) {
275 // XXX THIS STILL NEEDS TO BE IMPLEMENTED
276 return 1;
277}
278
d6ad46d9
MT
279int pakfire_mount_make_mounpoint(struct pakfire_ctx* ctx, struct pakfire* pakfire,
280 const char* path) {
14df7388
MT
281 int r;
282
283 // Check if path already is a mountpoint
284 r = pakfire_mount_is_mountpoint(pakfire, path);
285 switch (r) {
286 // Already is a mountpoint
287 case 0:
288 return 0;
289
290 // Is not a mountpoint
291 case 1:
292 break;
293
294 default:
d6ad46d9 295 CTX_ERROR(ctx, "Could not determine whether %s is a mountpoint: %m\n", path);
14df7388
MT
296 return r;
297 }
298
299 // Bind-mount to self
300 r = mount(path, path, NULL, MS_BIND|MS_REC, NULL);
301 if (r) {
d6ad46d9 302 CTX_ERROR(ctx, "Could not make %s a mountpoint: %m\n", path);
14df7388
MT
303 return r;
304 }
305
306 return 0;
307}
308
d6ad46d9
MT
309static int pakfire_mount(struct pakfire_ctx* ctx, struct pakfire* pakfire, const char* source,
310 const char* target, const char* fstype, unsigned long mflags, const void* data) {
bf5f9c24 311 const char* options = (const char*)data;
bf5f9c24
MT
312
313 // Check for some basic inputs
314 if (!source || !target) {
315 errno = EINVAL;
316 return 1;
317 }
318
d6ad46d9 319 CTX_DEBUG(ctx, "Mounting %s from %s (%s - %s)\n", target, source, fstype, options);
bf5f9c24 320
7f970e6e
MT
321 // Perform mount()
322 int r = mount(source, target, fstype, mflags, data);
bf5f9c24 323 if (r) {
d6ad46d9 324 CTX_ERROR(ctx, "Could not mount %s: %m\n", target);
bf5f9c24
MT
325 }
326
bf5f9c24
MT
327 return r;
328}
329
bc0b24a7
MT
330static int __pakfire_mount_list(char* line, size_t length, void* data) {
331 struct pakfire_ctx* ctx = data;
bf5f9c24 332
bc0b24a7
MT
333 // Send the line to the logger
334 CTX_DEBUG(ctx, " %.*s", (int)length, line);
335
336 return 0;
337}
338
339int pakfire_mount_list(struct pakfire_ctx* ctx) {
340 CTX_DEBUG(ctx, "Mountpoints:\n");
341
342 return pakfire_parse_file("/proc/self/mounts", __pakfire_mount_list, ctx);
f71c82d8
MT
343}
344
d6ad46d9 345int pakfire_populate_dev(struct pakfire_ctx* ctx, struct pakfire* pakfire, int flags) {
f71c82d8
MT
346 char path[PATH_MAX];
347
348 // Create device nodes
349 for (const struct pakfire_devnode* devnode = devnodes; devnode->path; devnode++) {
d6ad46d9 350 CTX_DEBUG(ctx, "Creating device node %s\n", devnode->path);
f71c82d8 351
282b732a
MT
352 // Check if flags match
353 if (devnode->flags && !(flags & devnode->flags))
354 continue;
355
77e26129
MT
356 int r = pakfire_path(pakfire, path, "%s", devnode->path);
357 if (r)
358 return r;
f71c82d8
MT
359
360 dev_t dev = makedev(devnode->major, devnode->minor);
361
362 r = mknod(path, devnode->mode, dev);
8f1003a3
MT
363
364 // Continue if mknod was successful
365 if (r == 0)
366 continue;
367
368 // If we could not create the device node because of permission issues,
369 // it might be likely that we are running in a user namespace where creating
370 // device nodes is not permitted. Try bind-mounting them.
371 if (errno == EPERM)
372 goto MOUNT;
373
374 // Otherwise log an error and end
d6ad46d9 375 CTX_ERROR(ctx, "Could not create %s: %m\n", devnode->path);
8f1003a3
MT
376 return r;
377
378MOUNT:
379 // Create an empty file
380 r = pakfire_touch(path, 0444);
f71c82d8 381 if (r) {
d6ad46d9 382 CTX_ERROR(ctx, "Could not create %s: %m\n", path);
f71c82d8
MT
383 return r;
384 }
8f1003a3
MT
385
386 // Create a bind-mount over the file
d6ad46d9 387 r = pakfire_mount(ctx, pakfire, devnode->path, path, "bind", MS_BIND, NULL);
8f1003a3
MT
388 if (r)
389 return r;
f71c82d8
MT
390 }
391
392 // Create symlinks
393 for (const struct pakfire_symlink* s = symlinks; s->target; s++) {
d6ad46d9 394 CTX_DEBUG(ctx, "Creating symlink %s -> %s\n", s->path, s->target);
f71c82d8 395
77e26129
MT
396 int r = pakfire_path(pakfire, path, "%s", s->path);
397 if (r)
398 return r;
f71c82d8
MT
399
400 r = symlink(s->target, path);
401 if (r) {
d6ad46d9 402 CTX_ERROR(ctx, "Could not create symlink %s: %m\n", s->path);
f71c82d8
MT
403 return r;
404 }
405 }
406
407 return 0;
bf5f9c24
MT
408}
409
d6ad46d9 410int pakfire_mount_interpreter(struct pakfire_ctx* ctx, struct pakfire* pakfire) {
660120b6
MT
411 char target[PATH_MAX];
412
413 // Fetch the target architecture
652f2a99 414 const char* arch = pakfire_get_effective_arch(pakfire);
660120b6
MT
415
416 // Can we emulate this architecture?
417 char* interpreter = pakfire_arch_find_interpreter(arch);
418
419 // No interpreter required
420 if (!interpreter)
421 return 0;
422
d6ad46d9 423 CTX_DEBUG(ctx, "Mounting interpreter %s for %s\n", interpreter, arch);
660120b6
MT
424
425 // Where to mount this?
77e26129
MT
426 int r = pakfire_path(pakfire, target, "%s", interpreter);
427 if (r)
660120b6
MT
428 return r;
429
430 // Create directory
520ce66c 431 r = pakfire_mkparentdir(target, 0755);
660120b6
MT
432 if (r)
433 return r;
434
435 // Create an empty file
436 FILE* f = fopen(target, "w");
437 if (!f)
438 return 1;
439 fclose(f);
440
d6ad46d9 441 r = pakfire_mount(ctx, pakfire, interpreter, target, NULL, MS_BIND|MS_RDONLY, NULL);
660120b6 442 if (r)
d6ad46d9 443 CTX_ERROR(ctx, "Could not mount interpreter %s to %s: %m\n", interpreter, target);
660120b6
MT
444
445 return r;
446}
447
d6ad46d9 448int pakfire_mount_all(struct pakfire_ctx* ctx, struct pakfire* pakfire, pakfire_mntns_t ns, int flags) {
bf5f9c24 449 char target[PATH_MAX];
bf5f9c24
MT
450 int r;
451
b2ccb363
MT
452 const char* root = "/";
453
bf5f9c24 454 // Fetch Pakfire's root directory
b2ccb363
MT
455 if (ns == PAKFIRE_MNTNS_OUTER)
456 root = pakfire_get_path(pakfire);
bf5f9c24 457
bf5f9c24 458 for (const struct pakfire_mountpoint* mp = mountpoints; mp->source; mp++) {
b2ccb363
MT
459 if (!(mp->ns & ns))
460 continue;
461
bf5f9c24 462 // Figure out where to mount
819232d6 463 r = pakfire_path_append(target, root, mp->target);
56796f84 464 if (r)
bf5f9c24
MT
465 return r;
466
a685a503
MT
467 // Create target if it doesn't exist
468 if (!pakfire_path_exists(target)) {
469 r = pakfire_mkdir(target, 0755);
470 if (r) {
d6ad46d9 471 CTX_ERROR(ctx, "Could not create %s: %m\n", target);
a685a503
MT
472 return r;
473 }
474 }
bf5f9c24 475
bf5f9c24 476 // Perform mount()
d6ad46d9
MT
477 r = pakfire_mount(ctx, pakfire, mp->source, target,
478 mp->fstype, mp->flags, mp->options);
a685a503 479 if (r)
bf5f9c24 480 return r;
bf5f9c24
MT
481 }
482
bf5f9c24
MT
483 return 0;
484}
485
d6ad46d9
MT
486int pakfire_make_ramdisk(struct pakfire_ctx* ctx, struct pakfire* pakfire,
487 char* path, const char* args) {
06d741c6
MT
488 int r;
489
490 // Create a new temporary directory
491 char* p = pakfire_mkdtemp(path);
492 if (!p)
493 return -errno;
494
495 // Mount the ramdisk
d6ad46d9 496 r = pakfire_mount(ctx, pakfire, "pakfire_ramdisk", p, "tmpfs", 0, args);
06d741c6 497 if (r) {
d6ad46d9
MT
498 CTX_ERROR(ctx, "Could not mount ramdisk at %s (%s): %s\n",
499 p, args, strerror(errno));
06d741c6
MT
500 return r;
501 }
502
d6ad46d9 503 CTX_DEBUG(ctx, "Ramdisk mounted at %s (%s)\n", p, args);
06d741c6
MT
504
505 return 0;
506}
507
d6ad46d9
MT
508int pakfire_bind(struct pakfire_ctx* ctx, struct pakfire* pakfire,
509 const char* src, const char* dst, int flags) {
163851bc
MT
510 struct stat st;
511 char mountpoint[PATH_MAX];
512
513 if (!dst)
514 dst = src;
515
77e26129
MT
516 int r = pakfire_path(pakfire, mountpoint, "%s", dst);
517 if (r)
518 return r;
163851bc 519
d6ad46d9 520 CTX_DEBUG(ctx, "Bind-mounting %s to %s\n", src, mountpoint);
163851bc
MT
521
522 r = stat(src, &st);
523 if (r < 0) {
d6ad46d9 524 CTX_ERROR(ctx, "Could not stat %s: %m\n", src);
163851bc
MT
525 return 1;
526 }
527
528 // Make sure the mountpoint exists
529 switch (st.st_mode & S_IFMT) {
530 case S_IFDIR:
520ce66c 531 r = pakfire_mkdir(mountpoint, st.st_mode);
163851bc
MT
532 if (r && errno != EEXIST)
533 return r;
534 break;
535
536 case S_IFREG:
537 case S_IFLNK:
538 // Make parent directory
520ce66c 539 r = pakfire_mkparentdir(mountpoint, 0755);
163851bc
MT
540 if (r)
541 return r;
542
543 // Create a file
544 FILE* f = fopen(mountpoint, "w");
545 if (!f)
546 return 1;
547 fclose(f);
548 break;
549
550 default:
551 errno = ENOTSUP;
552 return 1;
553 }
554
976fbbc8
MT
555 // The Linux kernel seems to be quite funny when trying to bind-mount something
556 // as read-only and requires us to mount the source first, and then remount it
557 // again using MS_RDONLY.
558 if (flags & MS_RDONLY) {
d6ad46d9 559 r = pakfire_mount(ctx, pakfire, src, mountpoint, "bind", MS_BIND|MS_REC, NULL);
976fbbc8
MT
560 if (r)
561 return r;
562
563 // Add the remount flag
564 flags |= MS_REMOUNT;
565 }
566
163851bc 567 // Perform mount
d6ad46d9 568 return pakfire_mount(ctx, pakfire, src, mountpoint, "bind", flags|MS_BIND|MS_REC, NULL);
163851bc 569}