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