Skip to content

Commit 5500334

Browse files
authored
feat(init): implement native virtiofs fstab mounting (#14)
Replace system("/bin/mount -a") with direct mounting of virtiofs entries from /etc/fstab. This provides better error handling and eliminates dependency on mount(8) binary. - Add mkdir_p() helper for recursive directory creation - Add is_mounted() to check existing mount points - Add clean_opts() to handle mount options - Add mount_fstab_virtiofs() to process fstab entries - Only mount virtiofs entries, leaving other filesystems unmounted
1 parent 8e0efd3 commit 5500334

File tree

1 file changed

+164
-2
lines changed

1 file changed

+164
-2
lines changed

init/init.c

Lines changed: 164 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <sys/wait.h>
2222
#include <sys/stat.h>
2323
#include <linux/vm_sockets.h>
24+
#include <mntent.h>
2425

2526
#include "jsmn.h"
2627

@@ -389,6 +390,167 @@ static int chroot_luks()
389390
}
390391
#endif
391392

393+
/* mkdir -p (recursively create all parents) */
394+
static int mkdir_p(const char *path, mode_t mode)
395+
{
396+
char tmp[256];
397+
char *p = NULL;
398+
size_t len;
399+
400+
if (!path || !*path) return -1;
401+
len = strnlen(path, sizeof(tmp) - 1);
402+
memcpy(tmp, path, len);
403+
tmp[len] = '\0';
404+
405+
if (tmp[len - 1] == '/')
406+
tmp[len - 1] = '\0';
407+
408+
for (p = tmp + 1; *p; ++p) {
409+
if (*p == '/') {
410+
*p = '\0';
411+
if (mkdir(tmp, mode) < 0 && errno != EEXIST)
412+
return -1;
413+
*p = '/';
414+
}
415+
}
416+
if (mkdir(tmp, mode) < 0 && errno != EEXIST)
417+
return -1;
418+
return 0;
419+
}
420+
421+
/* Return: 1 = same fs already mounted
422+
* -1 = dir busy with different type/tag
423+
* 0 = not mounted yet
424+
*/
425+
static int is_mounted(const char *dir, const char *src, const char *type)
426+
{
427+
FILE *fp = setmntent("/proc/self/mounts", "r");
428+
if (!fp) return 0; /* silent best-effort */
429+
430+
struct mntent *m;
431+
int found = 0;
432+
433+
while ((m = getmntent(fp)) != NULL) {
434+
if (strcmp(m->mnt_dir, dir) == 0) {
435+
if (strcmp(m->mnt_type, type) != 0)
436+
found = -1; /* same dir, other fstype */
437+
else
438+
found = (strcmp(m->mnt_fsname, src) == 0) ? 1 : -1;
439+
break;
440+
}
441+
}
442+
endmntent(fp);
443+
return found;
444+
}
445+
446+
/* Strip the single word "defaults" (and empty commas) from opt string.
447+
* Returns pointer inside `buf`. buf must persist until mount(2) call.
448+
*/
449+
static const char *clean_opts(const char *orig, char *buf, size_t buflen)
450+
{
451+
if (!orig || !*orig) return NULL;
452+
if (strcmp(orig, "defaults") == 0) return NULL;
453+
454+
/* quick path: if the substring "defaults" not present, pass as-is */
455+
if (!strstr(orig, "defaults")) return orig;
456+
457+
/* otherwise build a filtered copy */
458+
char *dst = buf;
459+
const char *tok;
460+
char tmp[256];
461+
strncpy(tmp, orig, sizeof(tmp)-1);
462+
tmp[sizeof(tmp)-1] = '\0';
463+
464+
for (tok = strtok(tmp, ","); tok; tok = strtok(NULL, ",")) {
465+
if (strcmp(tok, "defaults") == 0 || *tok == '\0')
466+
continue;
467+
size_t n = snprintf(dst, buflen - (dst - buf), "%s,", tok);
468+
dst += n;
469+
}
470+
if (dst != buf) *(dst - 1) = '\0'; /* remove trailing comma */
471+
return (dst == buf) ? NULL : buf; /* all stripped? -> NULL */
472+
}
473+
474+
/* Mount every virtiofs entry found in /etc/fstab.
475+
* Idempotent, silent on success, logs only actionable errors. */
476+
static int mount_fstab_virtiofs(void)
477+
{
478+
FILE *fp = setmntent("/etc/fstab", "r");
479+
if (!fp) /* no fstab → nothing to do, not an error */
480+
return 0;
481+
482+
struct mntent *e;
483+
int rc = 0;
484+
485+
while ((e = getmntent(fp)) != NULL) {
486+
/* ─────────── 1. we only care about virtiofs rows ─────────── */
487+
if (strcmp(e->mnt_type, "virtiofs") != 0)
488+
continue;
489+
490+
if (!e->mnt_fsname[0] || !e->mnt_dir[0]) {
491+
fprintf(stderr,
492+
"virtiofs-init: malformed fstab line – skipped\n");
493+
rc = -1;
494+
continue;
495+
}
496+
497+
/* ─────────── 2. make local copies BEFORE is_mounted() ─────── */
498+
char fsname[256], dir[256], opts[256];
499+
strncpy(fsname, e->mnt_fsname, sizeof(fsname) - 1);
500+
strncpy(dir, e->mnt_dir, sizeof(dir) - 1);
501+
strncpy(opts, e->mnt_opts, sizeof(opts) - 1);
502+
fsname[sizeof(fsname) - 1] =
503+
dir[sizeof(dir) - 1] =
504+
opts[sizeof(opts) - 1] = '\0';
505+
506+
/* ─────────── 3. ensure mount‑point exists (mkdir -p) ───────── */
507+
if (mkdir_p(dir, 0755) < 0) {
508+
fprintf(stderr,
509+
"virtiofs-init: cannot create %s: %s\n",
510+
dir, strerror(errno));
511+
rc = -1;
512+
continue;
513+
}
514+
515+
/* ─────────── 4. skip if already mounted / busy ─────────────── */
516+
switch (is_mounted(dir, fsname, "virtiofs")) {
517+
case 1: continue; /* identical mount already there */
518+
case -1: fprintf(stderr,
519+
"virtiofs-init: %s busy – skipped\n", dir);
520+
rc = -1;
521+
continue;
522+
}
523+
524+
/* ─────────── 5. translate common flags BEFORE they vanish ──── */
525+
unsigned long flags = 0;
526+
struct mntent fake = { .mnt_opts = opts };
527+
if (hasmntopt(&fake, "ro")) flags |= MS_RDONLY;
528+
if (hasmntopt(&fake, "nosuid")) flags |= MS_NOSUID;
529+
if (hasmntopt(&fake, "nodev")) flags |= MS_NODEV;
530+
if (hasmntopt(&fake, "noexec")) flags |= MS_NOEXEC;
531+
532+
/* Clean "defaults" out of the option list */
533+
char optbuf[256];
534+
const char *data = clean_opts(opts, optbuf, sizeof(optbuf));
535+
536+
/* ─────────── 6. actual mount attempt ───────────────────────── */
537+
if (mount(fsname, dir, "virtiofs", flags, data) < 0) {
538+
if (errno == ENODEV || errno == ENOENT) {
539+
fprintf(stderr,
540+
"virtiofs-init: tag %s absent – skipped\n", fsname);
541+
} else if (errno != EBUSY) {
542+
fprintf(stderr,
543+
"virtiofs-init: mount %s→%s failed: %s\n",
544+
fsname, dir, strerror(errno));
545+
rc = -1;
546+
}
547+
}
548+
}
549+
550+
endmntent(fp);
551+
return rc;
552+
}
553+
392554
static int mount_filesystems()
393555
{
394556
char *const DIRS_LEVEL1[] = {"/dev", "/proc", "/sys"};
@@ -448,8 +610,8 @@ static int mount_filesystems()
448610
/* May fail if already exists and that's fine. */
449611
symlink("/proc/self/fd", "/dev/fd");
450612

451-
/* Process /etc/fstab to mount additional filesystems, including virtiofs shares */
452-
system("/bin/mount -a");
613+
/* Mount virtiofs shares from /etc/fstab (if any) */
614+
mount_fstab_virtiofs();
453615

454616
return 0;
455617
}

0 commit comments

Comments
 (0)