Skip to content

Commit 315ce8b

Browse files
committed
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 81c17f1 commit 315ce8b

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

2323
#include <linux/vm_sockets.h>
24+
#include <mntent.h>
2425

2526
#include "jsmn.h"
2627

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

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

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

455617
return 0;
456618
}

0 commit comments

Comments
 (0)