1 /*
2 * Copyright (C) NGINX, Inc.
3 */
4
5 #include <nxt_main.h>
6
7 #if (NXT_HAVE_FREEBSD_NMOUNT)
8 #include <sys/param.h>
9 #include <sys/uio.h>
10 #endif
11
12
13 static nxt_int_t nxt_fs_mkdir(const u_char *dir, mode_t mode);
14
15
16 #if (NXT_HAVE_LINUX_MOUNT)
17
18 nxt_int_t
nxt_fs_mount(nxt_task_t * task,nxt_fs_mount_t * mnt)19 nxt_fs_mount(nxt_task_t *task, nxt_fs_mount_t *mnt)
20 {
21 int rc;
22 const char *fsname;
23 unsigned long flags;
24
25 flags = 0;
26
27 switch (mnt->type) {
28 case NXT_FS_BIND:
29 if (nxt_slow_path(mnt->flags != 0)) {
30 nxt_log(task, NXT_LOG_WARN,
31 "bind mount ignores additional flags");
32 }
33
34 fsname = "bind";
35 flags = MS_BIND | MS_REC;
36 break;
37
38 case NXT_FS_PROC:
39 fsname = "proc";
40 goto getflags;
41
42 case NXT_FS_TMP:
43 fsname = "tmpfs";
44 goto getflags;
45
46 default:
47 fsname = (const char *) mnt->name;
48
49 getflags:
50
51 if (mnt->flags & NXT_FS_FLAGS_NODEV) {
52 flags |= MS_NODEV;
53 }
54
55 if (mnt->flags & NXT_FS_FLAGS_NOEXEC) {
56 flags |= MS_NOEXEC;
57 }
58
59 if (mnt->flags & NXT_FS_FLAGS_NOSUID) {
60 flags |= MS_NOSUID;
61 }
62
63 if (!(mnt->flags & NXT_FS_FLAGS_NOTIME)) {
64 flags |= MS_RELATIME;
65 }
66 }
67
68 rc = mount((const char *) mnt->src, (const char *) mnt->dst, fsname, flags,
69 mnt->data);
70
71 if (nxt_slow_path(rc < 0)) {
72 nxt_alert(task, "mount(\"%s\", \"%s\", \"%s\", %ul, \"%s\") %E",
73 mnt->src, mnt->dst, fsname, flags, mnt->data, nxt_errno);
74
75 return NXT_ERROR;
76 }
77
78 return NXT_OK;
79 }
80
81 #elif (NXT_HAVE_FREEBSD_NMOUNT)
82
83 nxt_int_t
nxt_fs_mount(nxt_task_t * task,nxt_fs_mount_t * mnt)84 nxt_fs_mount(nxt_task_t *task, nxt_fs_mount_t *mnt)
85 {
86 int flags;
87 u_char *data, *p, *end;
88 size_t iovlen;
89 nxt_int_t ret;
90 const char *fsname;
91 struct iovec iov[128];
92 char errmsg[256];
93
94 if (nxt_slow_path((mnt->flags & NXT_FS_FLAGS_NODEV) && !mnt->builtin)) {
95 nxt_alert(task, "nmount(2) doesn't support \"nodev\" option");
96
97 return NXT_ERROR;
98 }
99
100 flags = 0;
101
102 switch (mnt->type) {
103 case NXT_FS_BIND:
104 fsname = "nullfs";
105 break;
106
107 case NXT_FS_PROC:
108 fsname = "procfs";
109 goto getflags;
110
111 case NXT_FS_TMP:
112 fsname = "tmpfs";
113 goto getflags;
114
115 default:
116 fsname = (const char *) mnt->name;
117
118 getflags:
119
120 if (mnt->flags & NXT_FS_FLAGS_NOEXEC) {
121 flags |= MNT_NOEXEC;
122 }
123
124 if (mnt->flags & NXT_FS_FLAGS_NOSUID) {
125 flags |= MNT_NOSUID;
126 }
127
128 if (mnt->flags & NXT_FS_FLAGS_NOTIME) {
129 flags |= MNT_NOATIME;
130 }
131
132 if (mnt->flags & NXT_FS_FLAGS_RDONLY) {
133 flags |= MNT_RDONLY;
134 }
135 }
136
137 iov[0].iov_base = (void *) "fstype";
138 iov[0].iov_len = 7;
139 iov[1].iov_base = (void *) fsname;
140 iov[1].iov_len = nxt_strlen(fsname) + 1;
141 iov[2].iov_base = (void *) "fspath";
142 iov[2].iov_len = 7;
143 iov[3].iov_base = (void *) mnt->dst;
144 iov[3].iov_len = nxt_strlen(mnt->dst) + 1;
145 iov[4].iov_base = (void *) "target";
146 iov[4].iov_len = 7;
147 iov[5].iov_base = (void *) mnt->src;
148 iov[5].iov_len = nxt_strlen(mnt->src) + 1;
149 iov[6].iov_base = (void *) "errmsg";
150 iov[6].iov_len = 7;
151 iov[7].iov_base = (void *) errmsg;
152 iov[7].iov_len = sizeof(errmsg);
153
154 iovlen = 8;
155
156 data = NULL;
157
158 if (mnt->data != NULL) {
159 data = (u_char *) nxt_strdup(mnt->data);
160 if (nxt_slow_path(data == NULL)) {
161 return NXT_ERROR;
162 }
163
164 end = data - 1;
165
166 do {
167 p = end + 1;
168 end = nxt_strchr(p, '=');
169 if (end == NULL) {
170 break;
171 }
172
173 *end = '\0';
174
175 iov[iovlen].iov_base = (void *) p;
176 iov[iovlen].iov_len = (end - p) + 1;
177
178 iovlen++;
179
180 p = end + 1;
181
182 end = nxt_strchr(p, ',');
183 if (end != NULL) {
184 *end = '\0';
185 }
186
187 iov[iovlen].iov_base = (void *) p;
188 iov[iovlen].iov_len = nxt_strlen(p) + 1;
189
190 iovlen++;
191
192 } while (end != NULL && nxt_nitems(iov) > (iovlen + 2));
193 }
194
195 ret = NXT_OK;
196
197 if (nxt_slow_path(nmount(iov, iovlen, flags) < 0)) {
198 nxt_alert(task, "nmount(%p, %d, 0) %s", iov, iovlen, errmsg);
199 ret = NXT_ERROR;
200 }
201
202 if (data != NULL) {
203 free(data);
204 }
205
206 return ret;
207 }
208
209 #endif
210
211
212 #if (NXT_HAVE_LINUX_UMOUNT2)
213
214 void
nxt_fs_unmount(const u_char * path)215 nxt_fs_unmount(const u_char *path)
216 {
217 if (nxt_slow_path(umount2((const char *) path, MNT_DETACH) < 0)) {
218 nxt_thread_log_error(NXT_LOG_WARN, "umount2(%s, MNT_DETACH) %E",
219 path, nxt_errno);
220 }
221 }
222
223 #elif (NXT_HAVE_UNMOUNT)
224
225 void
nxt_fs_unmount(const u_char * path)226 nxt_fs_unmount(const u_char *path)
227 {
228 if (nxt_slow_path(unmount((const char *) path, MNT_FORCE) < 0)) {
229 nxt_thread_log_error(NXT_LOG_WARN, "unmount(%s) %E", path, nxt_errno);
230 }
231 }
232
233 #endif
234
235
236 nxt_int_t
nxt_fs_mkdir_all(const u_char * dir,mode_t mode)237 nxt_fs_mkdir_all(const u_char *dir, mode_t mode)
238 {
239 char *start, *end, *dst;
240 size_t dirlen;
241 char path[PATH_MAX];
242
243 dirlen = nxt_strlen(dir);
244
245 nxt_assert(dirlen < PATH_MAX && dirlen > 1 && dir[0] == '/');
246
247 dst = path;
248 start = end = (char *) dir;
249
250 while (*start != '\0') {
251 if (*start == '/') {
252 *dst++ = *start++;
253 }
254
255 end = strchr(start, '/');
256 if (end == NULL) {
257 end = ((char *)dir + dirlen);
258 }
259
260 dst = nxt_cpymem(dst, start, end - start);
261 *dst = '\0';
262
263 if (nxt_slow_path(nxt_fs_mkdir((u_char *) path, mode) != NXT_OK
264 && nxt_errno != EEXIST))
265 {
266 return NXT_ERROR;
267 }
268
269 start = end;
270 }
271
272 return NXT_OK;
273 }
274
275
276 static nxt_int_t
nxt_fs_mkdir(const u_char * dir,mode_t mode)277 nxt_fs_mkdir(const u_char *dir, mode_t mode)
278 {
279 if (nxt_fast_path(mkdir((const char *) dir, mode) == 0)) {
280 return NXT_OK;
281 }
282
283 return NXT_ERROR;
284 }
285