diff options
Diffstat (limited to 'systemd/nfs-server-generator.c')
-rw-r--r-- | systemd/nfs-server-generator.c | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/systemd/nfs-server-generator.c b/systemd/nfs-server-generator.c new file mode 100644 index 0000000..eec98fd --- /dev/null +++ b/systemd/nfs-server-generator.c @@ -0,0 +1,158 @@ +/* + * 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); +} |