URI: 
       mount.c - ubase - suckless linux base utils
  HTML git clone git://git.suckless.org/ubase
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       mount.c (7313B)
       ---
            1 /* See LICENSE file for copyright and license details. */
            2 #include <sys/mount.h>
            3 #include <sys/stat.h>
            4 #include <sys/types.h>
            5 #include <sys/wait.h>
            6 
            7 #include <errno.h>
            8 #include <limits.h>
            9 #include <mntent.h>
           10 #include <stdio.h>
           11 #include <stdlib.h>
           12 #include <string.h>
           13 #include <unistd.h>
           14 
           15 #include "text.h"
           16 #include "util.h"
           17 
           18 #define FSOPTS_MAXLEN 512
           19 
           20 struct {
           21         const char *opt;
           22         const char *notopt;
           23         unsigned long v;
           24 } optnames[] = {
           25         { "defaults",   NULL,           0              },
           26         { "remount",    NULL,           MS_REMOUNT     },
           27         { "ro",         "rw",           MS_RDONLY      },
           28         { "sync",       "async",        MS_SYNCHRONOUS },
           29         { "dirsync",    NULL,           MS_DIRSYNC     },
           30         { "nodev",      "dev",          MS_NODEV       },
           31         { "noatime",    "atime",        MS_NOATIME     },
           32         { "noauto",     "auto",         0              },
           33         { "nodiratime", "diratime",     MS_NODIRATIME  },
           34         { "noexec",     "exec",         MS_NOEXEC      },
           35         { "nosuid",     "suid",         MS_NOSUID      },
           36         { "mand",       "nomand",       MS_MANDLOCK    },
           37         { "relatime",   "norelatime",   MS_RELATIME    },
           38         { "bind",       NULL,           MS_BIND        },
           39         { NULL,         NULL,           0              }
           40 };
           41 
           42 static unsigned long argflags = 0;
           43 static char fsopts[FSOPTS_MAXLEN] = "";
           44 
           45 static char *
           46 findtype(const char *types, const char *t)
           47 {
           48         const char *p;
           49         size_t len;
           50 
           51         for (len = strlen(t); (p = strstr(types, t)); types = p + len) {
           52                 if (!strncmp(p, t, len) && (p[len] == '\0' || p[len] == ','))
           53                         return (char *)p;
           54         }
           55         return NULL;
           56 }
           57 
           58 static void
           59 parseopts(const char *popts, unsigned long *flags, char *data, size_t datasiz)
           60 {
           61         unsigned int i, validopt;
           62         size_t optlen, dlen = 0;
           63         const char *name, *e;
           64 
           65         name = popts;
           66         data[0] = '\0';
           67         do {
           68                 if ((e = strstr(name, ",")))
           69                         optlen = e - name;
           70                 else
           71                         optlen = strlen(name);
           72 
           73                 validopt = 0;
           74                 for (i = 0; optnames[i].opt; i++) {
           75                         if (optnames[i].opt &&
           76                             !strncmp(name, optnames[i].opt, optlen)) {
           77                                 *flags |= optnames[i].v;
           78                                 validopt = 1;
           79                                 break;
           80                         }
           81                         if (optnames[i].notopt &&
           82                             !strncmp(name, optnames[i].notopt, optlen)) {
           83                                 *flags &= ~optnames[i].v;
           84                                 validopt = 1;
           85                                 break;
           86                         }
           87                 }
           88 
           89                 if (!validopt && optlen > 0) {
           90                         /* unknown option, pass as data option to mount() */
           91                         if (dlen + optlen + 2 >= datasiz)
           92                                 return; /* prevent overflow */
           93                         if (dlen)
           94                                 data[dlen++] = ',';
           95                         memcpy(&data[dlen], name, optlen);
           96                         dlen += optlen;
           97                         data[dlen] = '\0';
           98                 }
           99                 name = e + 1;
          100         } while (e);
          101 }
          102 
          103 static int
          104 mounthelper(const char *fsname, const char *dir, const char *fstype)
          105 {
          106         pid_t pid;
          107         char eprog[PATH_MAX];
          108         char const *eargv[10];
          109         int status, i;
          110 
          111         pid = fork();
          112         switch(pid) {
          113         case -1:
          114                 break;
          115         case 0:
          116                 snprintf(eprog, sizeof(eprog), "mount.%s", fstype);
          117 
          118                 i = 0;
          119                 eargv[i++] = eprog;
          120                 if (argflags & MS_BIND)
          121                         eargv[i++] = "-B";
          122                 if (argflags & MS_MOVE)
          123                         eargv[i++] = "-M";
          124                 if (argflags & MS_REC)
          125                         eargv[i++] = "-R";
          126 
          127                 if (fsopts[0]) {
          128                         eargv[i++] = "-o";
          129                         eargv[i++] = fsopts;
          130                 }
          131                 eargv[i++] = fsname;
          132                 eargv[i++] = dir;
          133                 eargv[i] = NULL;
          134 
          135                 execvp(eprog, (char * const *)eargv);
          136                 if (errno == ENOENT)
          137                         _exit(1);
          138                 weprintf("execvp:");
          139                 _exit(1);
          140                 break;
          141         default:
          142                 if (waitpid(pid, &status, 0) < 0) {
          143                         weprintf("waitpid:");
          144                         return -1;
          145                 }
          146                 if (WIFEXITED(status))
          147                         return WEXITSTATUS(status);
          148                 else if (WIFSIGNALED(status))
          149                         return 1;
          150                 break;
          151         }
          152         return 0;
          153 }
          154 
          155 static int
          156 mounted(const char *dir)
          157 {
          158         FILE *fp;
          159         struct mntent *me, mebuf;
          160         struct stat st1, st2;
          161         char linebuf[256];
          162 
          163         if (stat(dir, &st1) < 0) {
          164                 weprintf("stat %s:", dir);
          165                 return 0;
          166         }
          167         if (!(fp = setmntent("/proc/mounts", "r")))
          168                 eprintf("setmntent %s:", "/proc/mounts");
          169 
          170         while ((me = getmntent_r(fp, &mebuf, linebuf, sizeof(linebuf)))) {
          171                 if (stat(me->mnt_dir, &st2) < 0) {
          172                         weprintf("stat %s:", me->mnt_dir);
          173                         continue;
          174                 }
          175                 if (st1.st_dev == st2.st_dev &&
          176                     st1.st_ino == st2.st_ino)
          177                         return 1;
          178         }
          179         endmntent(fp);
          180 
          181         return 0;
          182 }
          183 
          184 static void
          185 usage(void)
          186 {
          187         eprintf("usage: %s [-BMRan] [-t fstype] [-o options] [source] [target]\n",
          188                 argv0);
          189 }
          190 
          191 int
          192 main(int argc, char *argv[])
          193 {
          194         char *types = NULL, data[FSOPTS_MAXLEN] = "", *resolvpath = NULL;
          195         char *files[] = { "/proc/mounts", "/etc/fstab", NULL };
          196         const char *source, *target;
          197         struct mntent *me = NULL;
          198         int aflag = 0, status = 0, i, r;
          199         unsigned long flags = 0;
          200         FILE *fp;
          201 
          202         ARGBEGIN {
          203         case 'B':
          204                 argflags |= MS_BIND;
          205                 break;
          206         case 'M':
          207                 argflags |= MS_MOVE;
          208                 break;
          209         case 'R':
          210                 argflags |= MS_REC;
          211                 break;
          212         case 'a':
          213                 aflag = 1;
          214                 break;
          215         case 'o':
          216                 estrlcat(fsopts, EARGF(usage()), sizeof(fsopts));
          217                 parseopts(fsopts, &flags, data, sizeof(data));
          218                 break;
          219         case 't':
          220                 types = EARGF(usage());
          221                 break;
          222         case 'n':
          223                 break;
          224         default:
          225                 usage();
          226         } ARGEND;
          227 
          228         if (argc < 1 && aflag == 0) {
          229                 if (!(fp = fopen(files[0], "r")))
          230                         eprintf("fopen %s:", files[0]);
          231                 concat(fp, files[0], stdout, "<stdout>");
          232                 fclose(fp);
          233                 return 0;
          234         }
          235 
          236         if (aflag == 1)
          237                 goto mountall;
          238 
          239         source = argv[0];
          240         target = argv[1];
          241 
          242         if (!target) {
          243                 target = argv[0];
          244                 source = NULL;
          245                 if (strcmp(target, "/") != 0) {
          246                         if (!(resolvpath = realpath(target, NULL)))
          247                                 eprintf("realpath %s:", target);
          248                         target = resolvpath;
          249                 }
          250         }
          251 
          252         for (i = 0; files[i]; i++) {
          253                 if (!(fp = setmntent(files[i], "r"))) {
          254                         if (strcmp(files[i], "/proc/mounts") != 0)
          255                                 weprintf("setmntent %s:", files[i]);
          256                         continue;
          257                 }
          258                 while ((me = getmntent(fp))) {
          259                         if (strcmp(me->mnt_dir, target) == 0 ||
          260                            strcmp(me->mnt_fsname, target) == 0 ||
          261                            (source && strcmp(me->mnt_dir, source) == 0) ||
          262                            (source && strcmp(me->mnt_fsname, source) == 0)) {
          263                                 if (!source) {
          264                                         target = me->mnt_dir;
          265                                         source = me->mnt_fsname;
          266                                 }
          267                                 if (!fsopts[0])
          268                                         estrlcat(fsopts, me->mnt_opts, sizeof(fsopts));
          269                                         parseopts(fsopts, &flags, data, sizeof(data));
          270                                 if (!types)
          271                                         types = me->mnt_type;
          272                                 goto mountsingle;
          273                         }
          274                 }
          275                 endmntent(fp);
          276                 fp = NULL;
          277         }
          278         if (!source)
          279                 eprintf("can't find %s in /etc/fstab\n", target);
          280 
          281 mountsingle:
          282         r = mounthelper(source, target, types);
          283         if (r == -1)
          284                 status = 1;
          285         if (r > 0 && mount(source, target, types, argflags | flags, data) < 0) {
          286                 weprintf("mount: %s:", source);
          287                 status = 1;
          288         }
          289         if (fp)
          290                 endmntent(fp);
          291         free(resolvpath);
          292         return status;
          293 
          294 mountall:
          295         if (!(fp = setmntent("/etc/fstab", "r")))
          296                 eprintf("setmntent %s:", "/etc/fstab");
          297         while ((me = getmntent(fp))) {
          298                 /* has "noauto" option or already mounted: skip */
          299                 if (hasmntopt(me, MNTOPT_NOAUTO) || mounted(me->mnt_dir))
          300                         continue;
          301                 flags = 0;
          302                 fsopts[0] = '\0';
          303                 if (strlcat(fsopts, me->mnt_opts, sizeof(fsopts)) >= sizeof(fsopts)) {
          304                         weprintf("%s: option string too long\n", me->mnt_dir);
          305                         status = 1;
          306                         continue;
          307                 }
          308                 parseopts(fsopts, &flags, data, sizeof(data));
          309                 /* if -t types specified:
          310                  * if non-match, skip
          311                  * if match and prefixed with "no", skip */
          312                 if (types &&
          313                     ((types[0] == 'n' && types[1] == 'o' &&
          314                      findtype(types + 2, me->mnt_type)) ||
          315                      (!findtype(types, me->mnt_type))))
          316                         continue;
          317 
          318                 r = mounthelper(me->mnt_fsname, me->mnt_dir, me->mnt_type);
          319                 if (r > 0 && mount(me->mnt_fsname, me->mnt_dir, me->mnt_type,
          320                                    argflags | flags, data) < 0) {
          321                         weprintf("mount: %s:", me->mnt_fsname);
          322                         status = 1;
          323                 }
          324         }
          325         endmntent(fp);
          326 
          327         return status;
          328 }