summaryrefslogtreecommitdiffstats
path: root/usr/utils/mount_opts.c
blob: bb26c7d08005a8dd5a81faa84fd47f2d61630043 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/*
 * by rmk
 *
 * Decode mount options.
 */
#include <sys/mount.h>
#include <stdlib.h>
#include <string.h>

#include "mount_opts.h"

#define ARRAY_SIZE(x)	(sizeof(x) / sizeof(x[0]))

static const struct mount_opts options[] = {
	/* name         mask            set             noset           */
	{"async", MS_SYNCHRONOUS, 0, MS_SYNCHRONOUS},
	{"atime", MS_NOATIME, 0, MS_NOATIME},
	{"bind", MS_TYPE, MS_BIND, 0,},
	{"dev", MS_NODEV, 0, MS_NODEV},
	{"diratime", MS_NODIRATIME, 0, MS_NODIRATIME},
	{"dirsync", MS_DIRSYNC, MS_DIRSYNC, 0},
	{"exec", MS_NOEXEC, 0, MS_NOEXEC},
	{"move", MS_TYPE, MS_MOVE, 0},
	{"nodev", MS_NODEV, MS_NODEV, 0},
	{"noexec", MS_NOEXEC, MS_NOEXEC, 0},
	{"nosuid", MS_NOSUID, MS_NOSUID, 0},
	{"recurse", MS_REC, MS_REC, 0},
	{"remount", MS_TYPE, MS_REMOUNT, 0},
	{"ro", MS_RDONLY, MS_RDONLY, 0},
	{"rw", MS_RDONLY, 0, MS_RDONLY},
	{"suid", MS_NOSUID, 0, MS_NOSUID},
	{"sync", MS_SYNCHRONOUS, MS_SYNCHRONOUS, 0},
	{"verbose", MS_VERBOSE, MS_VERBOSE, 0},
};

static void add_extra_option(struct extra_opts *extra, char *s)
{
	int len = strlen(s);
	int newlen = extra->used_size + len;

	if (extra->str)
		len++;		/* +1 for ',' */

	if (newlen >= extra->alloc_size) {
		char *new;

		new = realloc(extra->str, newlen + 1);	/* +1 for NUL */
		if (!new)
			return;

		extra->str = new;
		extra->end = extra->str + extra->used_size;
		extra->alloc_size = newlen;
	}

	if (extra->used_size) {
		*extra->end = ',';
		extra->end++;
	}
	strcpy(extra->end, s);
	extra->used_size += len;

}

unsigned long
parse_mount_options(char *arg, unsigned long rwflag, struct extra_opts *extra)
{
	char *s;

	while ((s = strsep(&arg, ",")) != NULL) {
		char *opt = s;
		unsigned int i;
		int res, no = s[0] == 'n' && s[1] == 'o';

		if (no)
			s += 2;

		for (i = 0, res = 1; i < ARRAY_SIZE(options); i++) {
			res = strcmp(s, options[i].str);

			if (res == 0) {
				rwflag &= ~options[i].rwmask;
				if (no)
					rwflag |= options[i].rwnoset;
				else
					rwflag |= options[i].rwset;
			}
			if (res <= 0)
				break;
		}

		if (res != 0 && s[0]) {
			if (!strcmp(opt, "defaults"))
				rwflag &= ~(MS_RDONLY|MS_NOSUID|MS_NODEV|
					    MS_NOEXEC|MS_SYNCHRONOUS);
			else
				add_extra_option(extra, opt);
		}
	}

	return rwflag;
}