/* * Copyright (C) NGINX, Inc. */ #include #if (NXT_HAVE_FREEBSD_NMOUNT) #include #include #endif static nxt_int_t nxt_fs_mkdir(const u_char *dir, mode_t mode); #if (NXT_HAVE_LINUX_MOUNT) nxt_int_t nxt_fs_mount(nxt_task_t *task, nxt_fs_mount_t *mnt) { int rc; const char *fsname; unsigned long flags; flags = 0; switch (mnt->type) { case NXT_FS_BIND: if (nxt_slow_path(mnt->flags != 0)) { nxt_log(task, NXT_LOG_WARN, "bind mount ignores additional flags"); } fsname = "bind"; flags = MS_BIND | MS_REC; break; case NXT_FS_PROC: fsname = "proc"; goto getflags; case NXT_FS_TMP: fsname = "tmpfs"; goto getflags; default: fsname = (const char *) mnt->name; getflags: if (mnt->flags & NXT_FS_FLAGS_NODEV) { flags |= MS_NODEV; } if (mnt->flags & NXT_FS_FLAGS_NOEXEC) { flags |= MS_NOEXEC; } if (mnt->flags & NXT_FS_FLAGS_NOSUID) { flags |= MS_NOSUID; } if (!(mnt->flags & NXT_FS_FLAGS_NOTIME)) { flags |= MS_RELATIME; } } rc = mount((const char *) mnt->src, (const char *) mnt->dst, fsname, flags, mnt->data); if (nxt_slow_path(rc < 0)) { nxt_alert(task, "mount(\"%s\", \"%s\", \"%s\", %ul, \"%s\") %E", mnt->src, mnt->dst, fsname, flags, mnt->data, nxt_errno); return NXT_ERROR; } return NXT_OK; } #elif (NXT_HAVE_FREEBSD_NMOUNT) nxt_int_t nxt_fs_mount(nxt_task_t *task, nxt_fs_mount_t *mnt) { int flags; u_char *data, *p, *end; size_t iovlen; nxt_int_t ret; const char *fsname; struct iovec iov[128]; char errmsg[256]; if (nxt_slow_path((mnt->flags & NXT_FS_FLAGS_NODEV) && !mnt->builtin)) { nxt_alert(task, "nmount(2) doesn't support \"nodev\" option"); return NXT_ERROR; } flags = 0; switch (mnt->type) { case NXT_FS_BIND: fsname = "nullfs"; break; case NXT_FS_PROC: fsname = "procfs"; goto getflags; case NXT_FS_TMP: fsname = "tmpfs"; goto getflags; default: fsname = (const char *) mnt->name; getflags: if (mnt->flags & NXT_FS_FLAGS_NOEXEC) { flags |= MNT_NOEXEC; } if (mnt->flags & NXT_FS_FLAGS_NOSUID) { flags |= MNT_NOSUID; } if (mnt->flags & NXT_FS_FLAGS_NOTIME) { flags |= MNT_NOATIME; } if (mnt->flags & NXT_FS_FLAGS_RDONLY) { flags |= MNT_RDONLY; } } iov[0].iov_base = (void *) "fstype"; iov[0].iov_len = 7; iov[1].iov_base = (void *) fsname; iov[1].iov_len = nxt_strlen(fsname) + 1; iov[2].iov_base = (void *) "fspath"; iov[2].iov_len = 7; iov[3].iov_base = (void *) mnt->dst; iov[3].iov_len = nxt_strlen(mnt->dst) + 1; iov[4].iov_base = (void *) "target"; iov[4].iov_len = 7; iov[5].iov_base = (void *) mnt->src; iov[5].iov_len = nxt_strlen(mnt->src) + 1; iov[6].iov_base = (void *) "errmsg"; iov[6].iov_len = 7; iov[7].iov_base = (void *) errmsg; iov[7].iov_len = sizeof(errmsg); iovlen = 8; data = NULL; if (mnt->data != NULL) { data = (u_char *) nxt_strdup(mnt->data); if (nxt_slow_path(data == NULL)) { return NXT_ERROR; } end = data - 1; do { p = end + 1; end = nxt_strchr(p, '='); if (end == NULL) { break; } *end = '\0'; iov[iovlen++].iov_base = (void *) p; iov[iovlen++].iov_len = (end - p) + 1; p = end + 1; end = nxt_strchr(p, ','); if (end != NULL) { *end = '\0'; } iov[iovlen++].iov_base = (void *) p; iov[iovlen++].iov_len = nxt_strlen(p) + 1; } while (end != NULL && nxt_nitems(iov) > (iovlen + 2)); } ret = NXT_OK; if (nxt_slow_path(nmount(iov, iovlen, flags) < 0)) { nxt_alert(task, "nmount(%p, %d, 0) %s", iov, iovlen, errmsg); ret = NXT_ERROR; } if (data != NULL) { free(data); } return ret; } #endif #if (NXT_HAVE_LINUX_UMOUNT2) void nxt_fs_unmount(const u_char *path) { if (nxt_slow_path(umount2((const char *) path, MNT_DETACH) < 0)) { nxt_thread_log_error(NXT_LOG_WARN, "umount2(%s, MNT_DETACH) %E", path, nxt_errno); } } #elif (NXT_HAVE_UNMOUNT) void nxt_fs_unmount(const u_char *path) { if (nxt_slow_path(unmount((const char *) path, MNT_FORCE) < 0)) { nxt_thread_log_error(NXT_LOG_WARN, "unmount(%s) %E", path, nxt_errno); } } #endif nxt_int_t nxt_fs_mkdir_all(const u_char *dir, mode_t mode) { char *start, *end, *dst; size_t dirlen; char path[PATH_MAX]; dirlen = nxt_strlen(dir); nxt_assert(dirlen < PATH_MAX && dirlen > 1 && dir[0] == '/'); dst = path; start = end = (char *) dir; while (*start != '\0') { if (*start == '/') { *dst++ = *start++; } end = strchr(start, '/'); if (end == NULL) { end = ((char *)dir + dirlen); } dst = nxt_cpymem(dst, start, end - start); *dst = '\0'; if (nxt_slow_path(nxt_fs_mkdir((u_char *) path, mode) != NXT_OK && nxt_errno != EEXIST)) { return NXT_ERROR; } start = end; } return NXT_OK; } static nxt_int_t nxt_fs_mkdir(const u_char *dir, mode_t mode) { if (nxt_fast_path(mkdir((const char *) dir, mode) == 0)) { return NXT_OK; } return NXT_ERROR; }