From 06bd6e2352af062adf1faed21133e6702708842f Mon Sep 17 00:00:00 2001 From: Matheus Date: Wed, 15 Apr 2026 16:48:59 -0300 Subject: [PATCH] mount: add fstab and mtab support --- tools/mount/main.c | 267 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 257 insertions(+), 10 deletions(-) diff --git a/tools/mount/main.c b/tools/mount/main.c index 7774bb5f..98c7de1d 100644 --- a/tools/mount/main.c +++ b/tools/mount/main.c @@ -3,17 +3,236 @@ #include #include #include +#include +#include -void usage(char *name) { - fprintf(stderr, "%s: usage: %s [-d device] mountpoint filesystem\n", name, name); +struct mtab_list { + struct mtab_list *next; + char line[1000]; + struct mntent mntent; +}; + +static const char *argv0; +static struct mtab_list *mtab_list; + +void usage(void) { + fprintf(stderr, "%s: usage: %s [-a] [-d device] [-t filesystem] [mountpoint]\n", argv0, argv0); exit(EXIT_FAILURE); } +static int mount_filesystem(char *device, char *path, char *filesystem, unsigned long flags, void *opts) { + if (device && strcmp(device, "none") == 0) + device = NULL; + + // check if device already mounted + for (struct mtab_list *it = mtab_list; it; it = it->next) { + if (strcmp(path, it->mntent.mnt_dir) == 0 && strcmp(filesystem, it->mntent.mnt_type) == 0 && strcmp(it->mntent.mnt_fsname, "none") == 0) { + fprintf(stderr, "%s: virtual filesystem %s already mounted at %s\n", argv0, filesystem, path); + return EXIT_SUCCESS; + } + + if (device && strcmp(device, it->mntent.mnt_fsname) == 0 && strcmp(it->mntent.mnt_fsname, "none")) { + fprintf(stderr, "%s: %s already mounted at %s\n", argv0, device, path); + return EXIT_SUCCESS; + } + } + + #ifdef __astral__ + if (mount(device, path, filesystem, flags, opts)) { + fprintf(stderr, "%s: failed to mount filesytem %s on device %s at %s: %s\n", argv0, filesystem, device, path, strerror(errno)); + return EXIT_FAILURE; + } + #else + printf("mount command: mount(%s, %s, %s, 0, NULL)\n", device, path, filesystem); + #endif + + struct mtab_list *entry = malloc(sizeof(struct mtab_list)); + if (entry == NULL) + return EXIT_FAILURE; + + + entry->mntent.mnt_fsname = device ? strdup(device) : "none"; + entry->mntent.mnt_dir = strdup(path); + entry->mntent.mnt_type = strdup(filesystem); + entry->mntent.mnt_opts = "rw"; + entry->mntent.mnt_freq = 0; + entry->mntent.mnt_passno = 0; + entry->next = mtab_list; + mtab_list = entry; + + FILE *mtab = setmntent("/etc/mtab", "a"); + if (mtab) { + addmntent(mtab, &entry->mntent); + endmntent(mtab); + } + + return 0; +} + +static int mount_all(void) { + FILE *fstab = setmntent("/etc/fstab", "r"); + struct mntent mntent; + char buf[1000]; + + if (fstab == NULL) { + fprintf(stderr, "%s: setmntent /etc/fstab: %s\n", argv0, strerror(errno)); + endmntent(fstab); + return EXIT_FAILURE; + } + + for (;;) { + errno = 0; + struct mntent *p = getmntent_r(fstab, &mntent, buf, sizeof(buf)); + if (p == NULL) { + if (errno) { + fprintf(stderr, "%s: getmntent_r: %s\n", argv0, strerror(errno)); + endmntent(fstab); + return EXIT_FAILURE; + } + + break; + } + + if (strcmp(mntent.mnt_type, "auto") == 0) { + fprintf(stderr, "%s: no filesystem autodetection support\n", argv0); + continue; + } + + if (!(hasmntopt(&mntent, "defaults") || hasmntopt(&mntent, "auto")) || hasmntopt(&mntent, "noauto")) + continue; + + mount_filesystem(mntent.mnt_fsname, mntent.mnt_dir, mntent.mnt_type, 0, NULL); + } + + endmntent(fstab); + return 0; +} + +static int print_mounts(void) { + FILE *mtab = setmntent("/etc/mtab", "r"); + struct mntent mntent; + char buf[1000]; + + if (mtab == NULL) { + fprintf(stderr, "%s: setmntent /etc/mtab: %s\n", argv0, strerror(errno)); + return EXIT_FAILURE; + } + + for (;;) { + errno = 0; + struct mntent *p = getmntent_r(mtab, &mntent, buf, sizeof(buf)); + if (p == NULL) { + if (errno) { + fprintf(stderr, "%s: getmntent_r: %s\n", argv0, strerror(errno)); + endmntent(mtab); + return EXIT_FAILURE; + } + + break; + } + + printf("%s on %s type %s (rw)\n", mntent.mnt_fsname, mntent.mnt_dir, mntent.mnt_type); + } + + endmntent(mtab); + return 0; +} + +static int get_fstab_info (const char *mount_point, char **fs, char **dev) { + FILE *fstab = setmntent("/etc/fstab", "r"); + struct mntent mntent; + char buf[1024]; + + if (fstab == NULL) { + fprintf(stderr, "%s: setmntent /etc/fstab: %s\n", argv0, strerror(errno)); + endmntent(fstab); + return EXIT_FAILURE; + } + + for (;;) { + errno = 0; + struct mntent *p = getmntent_r(fstab, &mntent, buf, sizeof(buf)); + if (p == NULL) { + if (errno) + fprintf(stderr, "%s: getmntent_r: %s\n", argv0, strerror(errno)); + else + fprintf(stderr, "%s: no /etc/fstab entry for %s found.\n", argv0, mount_point); + + endmntent(fstab); + return EXIT_FAILURE; + } + + if (strcmp(mntent.mnt_dir, mount_point) == 0) + break; + } + + if (strcmp(mntent.mnt_fsname, "none")) { + *dev = strdup(mntent.mnt_fsname); + if (*dev == NULL) { + fprintf(stderr, "%s: strdup: %s", argv0, strerror(errno)); + endmntent(fstab); + return EXIT_FAILURE; + } + } + + if (strcmp(mntent.mnt_type, "auto") == 0) { + fprintf(stderr, "%s: no filesystem autodetection support\n", argv0); + endmntent(fstab); + return EXIT_FAILURE; + } + + *fs = strdup(mntent.mnt_type); + if (*fs == NULL) { + fprintf(stderr, "%s: strdup: %s", argv0, strerror(errno)); + endmntent(fstab); + return EXIT_FAILURE; + } + + endmntent(fstab); + return EXIT_SUCCESS; +} + +static void scan_mtab() { + FILE *mtab = setmntent("/etc/mtab", "r"); + + if (mtab == NULL) { + fprintf(stderr, "%s: setmntent /etc/mtab: %s\n", argv0, strerror(errno)); + endmntent(mtab); + return; + } + + for (;;) { + errno = 0; + struct mtab_list *entry = malloc(sizeof(struct mtab_list)); + if (!entry) + break; + + struct mntent *p = getmntent_r(mtab, &entry->mntent, entry->line, sizeof(entry->line)); + if (p == NULL) { + if (errno) { + fprintf(stderr, "%s: getmntent_r: %s\n", argv0, strerror(errno)); + endmntent(mtab); + } + + break; + } + + entry->next = mtab_list; + mtab_list = entry; + } + + endmntent(mtab); +} + int main(int argc, char *argv[]) { char *dev = NULL; char *mountp = NULL; char *fs = NULL; bool devnext = false; + bool typenext = false; + bool all = false; + + argv0 = argv[0]; for (int i = 1; i < argc; ++i) { if (strcmp(argv[i], "-d") == 0) { @@ -21,24 +240,52 @@ int main(int argc, char *argv[]) { continue; } + if (strcmp(argv[i], "-t") == 0) { + typenext = true; + continue; + } + + if (strcmp(argv[i], "-a") == 0) { + all = true; + } + if (devnext) { devnext = false; dev = argv[i]; + } else if (typenext) { + typenext = false; + fs = argv[i]; } else if (mountp == NULL) mountp = argv[i]; - else if (fs == NULL) - fs = argv[i]; else - usage(argv[0]); + usage(); } - if (mount == NULL || fs == NULL) - usage(argv[0]); + scan_mtab(); - if (mount(dev, mountp, fs, 0, NULL) == -1) { - perror("mount failed"); + if (all) + return mount_all(); + + if (mountp == NULL && fs == NULL && dev == NULL) + return print_mounts(); + + if (mountp == NULL) + usage(); + + mountp = realpath(mountp, NULL); + if (mountp == NULL) { + fprintf(stderr, "%s: realpath: %s\n", argv0, strerror(errno)); return EXIT_FAILURE; } - return EXIT_SUCCESS; + if (fs == NULL && dev == NULL) { + if (get_fstab_info(mountp, &fs, &dev)) + return EXIT_FAILURE; + } else if (fs == NULL) { + fprintf(stderr, "%s: filesystem autodetection is not supported in the kernel. please provide a filesystem with -t\n", argv[0]); + usage(); + } + + return mount_filesystem(dev, mountp, fs, 0, NULL); } +