| /* |
| * nfs-server-generator: |
| * systemd generator to create ordering dependencies between |
| * nfs-server and various filesystem mounts |
| * |
| * 1/ nfs-server should start Before any 'nfs' mountpoints are |
| * mounted, in case they are loop-back mounts. This ordering is particularly |
| * important for the shutdown side, so the nfs-server is stopped |
| * after the filesystems are unmounted. |
| * 2/ nfs-server should start After all exported filesystems are mounted |
| * so there is no risk of exporting the underlying directory. |
| * This is particularly important for _net mounts which |
| * are not caught by "local-fs.target". |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif |
| |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <ctype.h> |
| #include <stdio.h> |
| #include <mntent.h> |
| #include <alloca.h> |
| |
| #include "misc.h" |
| #include "nfslib.h" |
| #include "exportfs.h" |
| #include "systemd.h" |
| |
| /* A simple "set of strings" to remove duplicates |
| * found in /etc/exports |
| */ |
| struct list { |
| struct list *next; |
| char *name; |
| }; |
| static int is_unique(struct list **lp, char *path) |
| { |
| struct list *l = *lp; |
| |
| while (l) { |
| if (strcmp(l->name, path) == 0) |
| return 0; |
| l = l->next; |
| } |
| l = malloc(sizeof(*l)); |
| if (l == NULL) |
| return 0; |
| l->name = path; |
| l->next = *lp; |
| *lp = l; |
| return 1; |
| } |
| |
| static int has_noauto_flag(char *path) |
| { |
| FILE *fstab; |
| struct mntent *mnt; |
| |
| fstab = setmntent("/etc/fstab", "r"); |
| if (!fstab) |
| return 0; |
| |
| while ((mnt = getmntent(fstab)) != NULL) { |
| int l = strlen(mnt->mnt_dir); |
| if (strncmp(mnt->mnt_dir, path, l) != 0) |
| continue; |
| if (path[l] && path[l] != '/') |
| continue; |
| if (hasmntopt(mnt, "noauto")) |
| break; |
| } |
| fclose(fstab); |
| return mnt != NULL; |
| } |
| |
| int main(int argc, char *argv[]) |
| { |
| char *path, *spath; |
| char dirbase[] = "/nfs-server.service.d"; |
| char filebase[] = "/order-with-mounts.conf"; |
| nfs_export *exp; |
| int i; |
| struct list *list = NULL; |
| FILE *f, *fstab; |
| struct mntent *mnt; |
| |
| /* Avoid using any external services */ |
| xlog_syslog(0); |
| |
| if (argc != 4 || argv[1][0] != '/') { |
| fprintf(stderr, "nfs-server-generator: create systemd dependencies for nfs-server\n"); |
| fprintf(stderr, "Usage: normal-dir early-dir late-dir\n"); |
| exit(1); |
| } |
| |
| path = alloca(strlen(argv[1]) + sizeof(dirbase) + sizeof(filebase)); |
| if (!path) |
| exit(2); |
| if (export_read(_PATH_EXPORTS, 1) + |
| export_d_read(_PATH_EXPORTS_D, 1) == 0) |
| /* Nothing is exported, so nothing to do */ |
| exit(0); |
| |
| strcat(strcpy(path, argv[1]), dirbase); |
| mkdir(path, 0755); |
| strcat(path, filebase); |
| f = fopen(path, "w"); |
| if (!f) |
| exit(1); |
| fprintf(f, "# Automatically generated by nfs-server-generator\n\n[Unit]\n"); |
| |
| for (i = 0; i < MCL_MAXTYPES; i++) { |
| for (exp = exportlist[i].p_head; exp; exp = exp->m_next) { |
| if (!is_unique(&list, exp->m_export.e_path)) |
| continue; |
| if (exp->m_export.e_mountpoint) |
| continue; |
| if (has_noauto_flag(exp->m_export.e_path)) |
| continue; |
| if (strchr(exp->m_export.e_path, ' ')) |
| fprintf(f, "RequiresMountsFor=\"%s\"\n", |
| exp->m_export.e_path); |
| else |
| fprintf(f, "RequiresMountsFor=%s\n", |
| exp->m_export.e_path); |
| } |
| } |
| |
| fstab = setmntent("/etc/fstab", "r"); |
| if (!fstab) |
| exit(1); |
| |
| while ((mnt = getmntent(fstab)) != NULL) { |
| if (strcmp(mnt->mnt_type, "nfs") != 0 && |
| strcmp(mnt->mnt_type, "nfs4") != 0) |
| continue; |
| |
| spath = systemd_escape(mnt->mnt_dir, ".mount"); |
| if (!spath) { |
| fprintf(stderr, |
| "nfs-server-generator: convert path failed: %s\n", |
| mnt->mnt_dir); |
| continue; |
| } |
| fprintf(f, "Before=%s\n", spath); |
| } |
| |
| fclose(fstab); |
| fclose(f); |
| |
| exit(0); |
| } |