/* * support/export/xtab.c * * Interface to the etab/exports file. * * Copyright (C) 1995, 1996 Olaf Kirch */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include "nfslib.h" #include "exportfs.h" #include "xio.h" #include "xlog.h" #include "v4root.h" #include "misc.h" static char state_base_dirname[PATH_MAX] = NFS_STATEDIR; struct state_paths etab; int v4root_needed; static void cond_rename(char *newfile, char *oldfile); static int xtab_read(char *xtab, char *lockfn, int is_export) { /* is_export == 0 => reading /proc/fs/nfs/exports - we know these things are exported to kernel * is_export == 1 => reading /var/lib/nfs/etab - these things are allowed to be exported */ struct exportent *xp; nfs_export *exp; int lockid; if ((lockid = xflock(lockfn, "r")) < 0) return 0; setexportent(xtab, "r"); if (is_export == 1) v4root_needed = 1; while ((xp = getexportent(is_export==0, 0)) != NULL) { if (!(exp = export_lookup(xp->e_hostname, xp->e_path, is_export != 1)) && !(exp = export_create(xp, is_export!=1))) { if(xp->e_hostname) { free(xp->e_hostname); xp->e_hostname=NULL; } if(xp->e_uuid) { free(xp->e_uuid); xp->e_uuid=NULL; } continue; } switch (is_export) { case 0: exp->m_exported = 1; break; case 1: exp->m_xtabent = 1; exp->m_mayexport = 1; if ((xp->e_flags & NFSEXP_FSID) && xp->e_fsid == 0) v4root_needed = 0; break; } if(xp->e_hostname) { free(xp->e_hostname); xp->e_hostname=NULL; } if(xp->e_uuid) { free(xp->e_uuid); xp->e_uuid=NULL; } } endexportent(); xfunlock(lockid); return 0; } int xtab_export_read(void) { return xtab_read(etab.statefn, etab.lockfn, 1); } /* * mountd now keeps an open fd for the etab at all times to make sure that the * inode number changes when the xtab_export_write is done. If you change the * routine below such that the files are edited in place, then you'll need to * fix the auth_reload logic as well... */ static int xtab_write(char *xtab, char *xtabtmp, char *lockfn, int is_export) { struct exportent xe; nfs_export *exp; int lockid, i; if ((lockid = xflock(lockfn, "w")) < 0) { xlog(L_ERROR, "can't lock %s for writing", xtab); return 0; } setexportent(xtabtmp, "w"); for (i = 0; i < MCL_MAXTYPES; i++) { for (exp = exportlist[i].p_head; exp; exp = exp->m_next) { if (is_export && !exp->m_xtabent) continue; if (!is_export && ! exp->m_exported) continue; /* write out the export entry using the FQDN */ xe = exp->m_export; xe.e_hostname = exp->m_client->m_hostname; putexportent(&xe); } } endexportent(); cond_rename(xtabtmp, xtab); xfunlock(lockid); return 1; } int xtab_export_write(void) { return xtab_write(etab.statefn, etab.tmpfn, etab.lockfn, 1); } /* * rename newfile onto oldfile unless * they are identical */ static void cond_rename(char *newfile, char *oldfile) { int nfd, ofd; char nbuf[4096], obuf[4096]; int ncnt, ocnt; nfd = open(newfile, 0); if (nfd < 0) return; ofd = open(oldfile, 0); if (ofd < 0) { close(nfd); rename(newfile, oldfile); return; } do { ncnt = read(nfd, nbuf, sizeof(nbuf)); if (ncnt < 0) break; ocnt = read(ofd, obuf, sizeof(obuf)); if (ocnt < 0) break; if (ncnt != ocnt) break; if (ncnt == 0) { close(nfd); close(ofd); unlink(newfile); return; } } while (memcmp(obuf, nbuf, ncnt) == 0); /* some mis-match */ close(nfd); close(ofd); rename(newfile, oldfile); return; } /* * Returns a dynamically allocated, '\0'-terminated buffer * containing an appropriate pathname, or NULL if an error * occurs. Caller must free the returned result with free(3). */ static char * state_make_pathname(const char *tabname) { return generic_make_pathname(state_base_dirname, tabname); } /** * state_setup_basedir - set up basedir * @progname: C string containing name of program, for error messages * @parentdir: C string containing pathname to on-disk state, or NULL * * This runs before logging is set up, so error messages are directed * to stderr. * * Returns true and sets up our basedir, if @parentdir was valid * and usable; otherwise false is returned. */ _Bool state_setup_basedir(const char *progname, const char *parentdir) { return generic_setup_basedir(progname, parentdir, state_base_dirname, PATH_MAX); } int setup_state_path_names(const char *progname, const char *statefn, const char *tmpfn, const char *lockfn, struct state_paths *paths) { paths->statefn = state_make_pathname(statefn); if (!paths->statefn) { fprintf(stderr, "%s: state_make_pathname(%s) failed\n", progname, statefn); goto out_err; } paths->tmpfn = state_make_pathname(tmpfn); if (!paths->tmpfn) { fprintf(stderr, "%s: state_make_pathname(%s) failed\n", progname, tmpfn); goto out_free_statefn; } paths->lockfn = state_make_pathname(lockfn); if (!paths->lockfn) { fprintf(stderr, "%s: state_make_pathname(%s) failed\n", progname, lockfn); goto out_free_tmpfn; } return 1; out_free_tmpfn: free(paths->tmpfn); out_free_statefn: free(paths->statefn); out_err: return 0; } void free_state_path_names(struct state_paths *paths) { free(paths->statefn); free(paths->tmpfn); free(paths->lockfn); }