morpheus-base

morpheus base system
git clone git://git.2f30.org/morpheus-base.git
Log | Files | Refs

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 }