mount.c (5255B)
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 6 #include <limits.h> 7 #include <mntent.h> 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <string.h> 11 #include <unistd.h> 12 13 #include "util.h" 14 15 struct { 16 const char *opt; 17 const char *notopt; 18 unsigned long v; 19 } optnames[] = { 20 { "defaults", NULL, 0 }, 21 { "remount", NULL, MS_REMOUNT }, 22 { "ro", "rw", MS_RDONLY }, 23 { "sync", "async", MS_SYNCHRONOUS }, 24 { "dirsync", NULL, MS_DIRSYNC }, 25 { "nodev", "dev", MS_NODEV }, 26 { "noatime", "atime", MS_NOATIME }, 27 { "nodiratime", "diratime", MS_NODIRATIME }, 28 { "noexec", "exec", MS_NOEXEC }, 29 { "nosuid", "suid", MS_NOSUID }, 30 { "mand", "nomand", MS_MANDLOCK }, 31 { "relatime", "norelatime", MS_RELATIME }, 32 { "bind", NULL, MS_BIND }, 33 { NULL, NULL, 0 } 34 }; 35 36 static void 37 parseopts(char *popts, unsigned long *flags, char *data, size_t datasiz) 38 { 39 unsigned int i, validopt; 40 size_t optlen, dlen = 0; 41 char *name; 42 43 data[0] = '\0'; 44 for (name = strtok(popts, ","); name; name = strtok(NULL, ",")) { 45 validopt = 0; 46 for (i = 0; optnames[i].opt; i++) { 47 if (optnames[i].opt && strcmp(name, optnames[i].opt) == 0) { 48 *flags |= optnames[i].v; 49 validopt = 1; 50 break; 51 } 52 if (optnames[i].notopt && strcmp(name, optnames[i].notopt) == 0) { 53 *flags &= ~optnames[i].v; 54 validopt = 1; 55 break; 56 } 57 } 58 if (!validopt) { 59 /* unknown option, pass as data option to mount() */ 60 if ((optlen = strlen(name))) { 61 if (dlen + optlen + 2 >= datasiz) 62 return; /* prevent overflow */ 63 if (dlen) 64 data[dlen++] = ','; 65 memcpy(&data[dlen], name, optlen); 66 dlen += optlen; 67 data[dlen] = '\0'; 68 } 69 } 70 } 71 } 72 73 static int 74 mounted(const char *dir) 75 { 76 FILE *fp; 77 struct mntent *me; 78 struct stat st1, st2; 79 80 if (stat(dir, &st1) < 0) { 81 weprintf("stat %s:", dir); 82 return 0; 83 } 84 fp = setmntent("/proc/mounts", "r"); 85 if (!fp) 86 eprintf("setmntent %s:", "/proc/mounts"); 87 while ((me = getmntent(fp)) != NULL) { 88 if (stat(me->mnt_dir, &st2) < 0) { 89 weprintf("stat %s:", me->mnt_dir); 90 continue; 91 } 92 if (st1.st_dev == st2.st_dev && 93 st1.st_ino == st2.st_ino) 94 return 1; 95 } 96 endmntent(fp); 97 return 0; 98 } 99 100 static void 101 usage(void) 102 { 103 eprintf("usage: %s [-BMRan] [-t fstype] [-o options] [source] [target]\n", 104 argv0); 105 } 106 107 static int 108 catfile(FILE *in, FILE *out) 109 { 110 char buf[BUFSIZ]; 111 size_t bytesread; 112 113 while (!feof(in)) { 114 bytesread = fread(buf, 1, sizeof(buf), in); 115 if (ferror(in)) 116 return 0; 117 fwrite(buf, 1, bytesread, out); 118 } 119 return 1; 120 } 121 122 int 123 main(int argc, char *argv[]) 124 { 125 int aflag = 0, oflag = 0, status = 0, i; 126 unsigned long flags = 0; 127 char *types = NULL, data[512] = "", *resolvpath = NULL; 128 char *files[] = { "/proc/mounts", "/etc/fstab", NULL }; 129 size_t datasiz = sizeof(data); 130 const char *source, *target; 131 struct mntent *me = NULL; 132 FILE *fp; 133 134 ARGBEGIN { 135 case 'B': 136 flags |= MS_BIND; 137 break; 138 case 'M': 139 flags |= MS_MOVE; 140 break; 141 case 'R': 142 flags |= MS_REC; 143 break; 144 case 'a': 145 aflag = 1; 146 break; 147 case 'o': 148 oflag = 1; 149 parseopts(EARGF(usage()), &flags, data, datasiz); 150 break; 151 case 't': 152 types = EARGF(usage()); 153 break; 154 case 'n': 155 break; 156 default: 157 usage(); 158 } ARGEND; 159 160 if (argc < 1 && aflag == 0) { 161 if (!(fp = fopen(files[0], "r"))) 162 eprintf("fopen %s:", files[0]); 163 if (catfile(fp, stdout) != 1) { 164 weprintf("error while reading %s:", files[0]); 165 status = 1; 166 } 167 fclose(fp); 168 return status; 169 } 170 171 if (aflag == 1) 172 goto mountall; 173 174 source = argv[0]; 175 target = argv[1]; 176 177 if (!target) { 178 target = argv[0]; 179 source = NULL; 180 if (!(resolvpath = realpath(target, NULL))) 181 eprintf("realpath %s:", target); 182 target = resolvpath; 183 } 184 185 for (i = 0; files[i]; i++) { 186 if (!(fp = setmntent(files[i], "r"))) { 187 if (strcmp(files[i], "/proc/mounts") != 0) 188 weprintf("setmntent %s:", files[i]); 189 continue; 190 } 191 while ((me = getmntent(fp))) { 192 if (strcmp(me->mnt_dir, target) == 0 || 193 strcmp(me->mnt_fsname, target) == 0 || 194 (source && strcmp(me->mnt_dir, source) == 0) || 195 (source && strcmp(me->mnt_fsname, source) == 0)) { 196 if (!source) { 197 target = me->mnt_dir; 198 source = me->mnt_fsname; 199 } 200 if (!oflag) 201 parseopts(me->mnt_opts, &flags, data, datasiz); 202 if (!types) 203 types = me->mnt_type; 204 goto mountsingle; 205 } 206 } 207 endmntent(fp); 208 fp = NULL; 209 } 210 if (!source) 211 eprintf("can't find %s in /etc/fstab\n", target); 212 213 mountsingle: 214 if (mount(source, target, types, flags, data) < 0) { 215 weprintf("mount: %s:", source); 216 status = 1; 217 } 218 if (fp) 219 endmntent(fp); 220 free(resolvpath); 221 return status; 222 223 mountall: 224 if (!(fp = setmntent("/etc/fstab", "r"))) 225 eprintf("setmntent %s:", "/etc/fstab"); 226 while ((me = getmntent(fp))) { 227 flags = 0; 228 parseopts(me->mnt_opts, &flags, data, datasiz); 229 if (mount(me->mnt_fsname, me->mnt_dir, me->mnt_type, flags, data) < 0) { 230 if (mounted(me->mnt_dir) == 0) { 231 weprintf("mount: %s:", me->mnt_fsname); 232 status = 1; 233 } 234 } 235 } 236 endmntent(fp); 237 238 return status; 239 }