xref: /unit/src/nxt_fs.c (revision 1673:883f2f79c2f6)
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
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
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             p = end + 1;
179 
180             end = nxt_strchr(p, ',');
181             if (end != NULL) {
182                 *end = '\0';
183             }
184 
185             iov[iovlen++].iov_base = (void *) p;
186             iov[iovlen++].iov_len = nxt_strlen(p) + 1;
187 
188         } while (end != NULL && nxt_nitems(iov) > (iovlen + 2));
189     }
190 
191     ret = NXT_OK;
192 
193     if (nxt_slow_path(nmount(iov, iovlen, flags) < 0)) {
194         nxt_alert(task, "nmount(%p, %d, 0) %s", iov, iovlen, errmsg);
195         ret = NXT_ERROR;
196     }
197 
198     if (data != NULL) {
199         free(data);
200     }
201 
202     return ret;
203 }
204 
205 #endif
206 
207 
208 #if (NXT_HAVE_LINUX_UMOUNT2)
209 
210 void
211 nxt_fs_unmount(const u_char *path)
212 {
213     if (nxt_slow_path(umount2((const char *) path, MNT_DETACH) < 0)) {
214         nxt_thread_log_error(NXT_LOG_WARN, "umount2(%s, MNT_DETACH) %E",
215                              path, nxt_errno);
216     }
217 }
218 
219 #elif (NXT_HAVE_UNMOUNT)
220 
221 void
222 nxt_fs_unmount(const u_char *path)
223 {
224     if (nxt_slow_path(unmount((const char *) path, MNT_FORCE) < 0)) {
225         nxt_thread_log_error(NXT_LOG_WARN, "unmount(%s) %E", path, nxt_errno);
226     }
227 }
228 
229 #endif
230 
231 
232 nxt_int_t
233 nxt_fs_mkdir_all(const u_char *dir, mode_t mode)
234 {
235     char    *start, *end, *dst;
236     size_t  dirlen;
237     char    path[PATH_MAX];
238 
239     dirlen = nxt_strlen(dir);
240 
241     nxt_assert(dirlen < PATH_MAX && dirlen > 1 && dir[0] == '/');
242 
243     dst = path;
244     start = end = (char *) dir;
245 
246     while (*start != '\0') {
247         if (*start == '/') {
248             *dst++ = *start++;
249         }
250 
251         end = strchr(start, '/');
252         if (end == NULL) {
253             end = ((char *)dir + dirlen);
254         }
255 
256         dst = nxt_cpymem(dst, start, end - start);
257         *dst = '\0';
258 
259         if (nxt_slow_path(nxt_fs_mkdir((u_char *) path, mode) != NXT_OK
260                           && nxt_errno != EEXIST))
261         {
262             return NXT_ERROR;
263         }
264 
265         start = end;
266     }
267 
268     return NXT_OK;
269 }
270 
271 
272 static nxt_int_t
273 nxt_fs_mkdir(const u_char *dir, mode_t mode)
274 {
275     if (nxt_fast_path(mkdir((const char *) dir, mode) == 0)) {
276         return NXT_OK;
277     }
278 
279     return NXT_ERROR;
280 }
281