aboutsummaryrefslogtreecommitdiffstats
path: root/plpnfsd/mp_mount.c
diff options
context:
space:
mode:
Diffstat (limited to 'plpnfsd/mp_mount.c')
-rw-r--r--plpnfsd/mp_mount.c601
1 files changed, 601 insertions, 0 deletions
diff --git a/plpnfsd/mp_mount.c b/plpnfsd/mp_mount.c
new file mode 100644
index 0000000..d13dea5
--- /dev/null
+++ b/plpnfsd/mp_mount.c
@@ -0,0 +1,601 @@
+#if defined(__SVR4) || defined(__sgi) || defined(linux)
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h> /* strdup */
+#ifndef linux
+extern int inet_addr(char *);
+#endif
+#define PORTMAP /* I need svcudp_create in rpc/svc_soc.h, sol 2.4 */
+#endif
+
+#include <OSdefs.h>
+#include <stdio.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+
+#ifdef __sgi
+#include <bstring.h>
+#endif
+
+#if defined(__NetBSD__) || defined(__FreeBSD__)
+#include <sys/param.h> /* Needs NGROUPS for mount.h */
+#define umount(dir) unmount(dir, 1)
+#endif
+
+#if defined(__NeXT__)
+#include <libc.h>
+#include <unistd.h>
+#include <nfs/nfs_mount.h>
+#define umount(dir) unmount(dir)
+#endif
+
+#include "defs.h"
+
+static char nfshost[128];
+
+#define NFSCLIENT
+#ifdef __FreeBSD__
+#define NFS
+#endif /* __FreeBSD__ */
+#include <sys/mount.h>
+
+#ifdef __FreeBSD__
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <rpc/rpc.h>
+#include <nfs/rpcv2.h>
+#if __FreeBSD_version >= 300001
+#include <nfs/nfs.h>
+#endif
+#endif /* __FreeBSD__ */
+
+#include <rpc/rpc.h>
+#include "nfs_prot.h"
+
+#ifdef linux
+#ifndef __GLIBC__
+#include <linux/fs.h> /* struct nfs_mount_data */
+#endif
+#include <linux/nfs_mount.h> /* struct nfs_mount_data */
+#include <arpa/inet.h> /* inet_addr() */
+#endif
+#ifdef _IBMR2
+#include "os-aix3.h"
+#include "misc-aix3.h"
+#include <sys/vmount.h>
+#endif
+
+
+#ifndef DONT_UPDATE_MTAB
+#if defined(sun) && defined(__SVR4)
+#include <sys/mnttab.h>
+#else
+#include <mntent.h>
+#endif
+#endif
+
+#if defined(sun) && defined(__SVR4) /*gec */
+#include <nfs/mount.h>
+#include <sys/fstyp.h>
+#include <sys/fsid.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#define PORTMAP
+#endif
+
+#if defined(sun) && !defined(__SVR4)
+extern int _rpc_dtablesize();
+#define umount unmount
+#endif
+
+#include <sys/socket.h>
+#include <netdb.h>
+
+#include "mp.h"
+
+#ifdef __sgi
+#define vfork fork
+#define NFSMNT_NOCTO 0
+#endif
+
+#if defined(sun) && defined(__SVR4)
+#define setmntent fopen
+#define endmntent fclose
+#define addmntent putmntent
+#define mntent mnttab
+#endif
+
+
+static char *mntdir; /* where we mounted the psion */
+
+#ifdef __STDC__
+static void doexit(void);
+#endif
+
+static void
+usr1_handler SIGARG
+{
+ debug = (debug + 1) & 3;
+ printf("Set debug level to %d\n", debug);
+};
+
+static void
+hup_handler SIGARG
+{
+ if (debug > 1)
+ printf("Got HUP signal\n");
+ exiting = 5;
+};
+
+static void
+doexit()
+{
+#ifndef DONT_UPDATE_MTAB
+ FILE *fpin, *fpout;
+#if defined(sun) && defined(__SVR4)
+ struct mntent entr;
+#else
+ struct mntent *ent;
+#endif
+#endif
+#ifndef __FreeBSD__
+ struct stat statb;
+#endif
+
+ exiting--;
+
+ if (debug)
+ printf("Doing exit\n");
+
+#ifdef _IBMR2
+ if (stat(mntdir, &statb)) {
+ perror("stat");
+ return;
+ }
+ if (debug)
+ printf("Next call: uvmount(%d, 0)\n", statb.st_vfs);
+ if (uvmount(statb.st_vfs, 0)) {
+ perror("uvmount");
+ return;
+ }
+#else
+ if (umount(mntdir)) {
+ perror(mntdir);
+ return;
+ }
+#endif
+
+#ifndef DONT_UPDATE_MTAB
+ if (debug)
+ printf("unmount succeeded, trying to fix mtab.\n");
+
+ if (!(fpout = setmntent(MTAB_TMP, "w"))) {
+ perror(MTAB_TMP);
+ return;
+ }
+ if (!(fpin = setmntent(MTAB_PATH, "r"))) {
+ endmntent(fpout);
+ unlink(MTAB_TMP);
+ perror(MTAB_PATH);
+ exit(0);
+ }
+ if (fstat(fileno(fpin), &statb))
+ perror("fstat");
+ else
+ fchmod(fileno(fpout), statb.st_mode);
+
+#if defined(sun) && defined(__SVR4)
+ while (!getmntent(fpin, &entr))
+ if (strcmp(entr.mnt_special, nfshost) || strcmp(entr.mnt_mountp, mntdir))
+ putmntent(fpout, &entr);
+#else
+ while ((ent = getmntent(fpin)))
+ if (strcmp(ent->mnt_fsname, nfshost) || strcmp(ent->mnt_dir, mntdir))
+ addmntent(fpout, ent);
+#endif
+ endmntent(fpin);
+ endmntent(fpout);
+
+ if (rename(MTAB_TMP, MTAB_PATH)) {
+ perror(MTAB_PATH);
+ unlink(MTAB_TMP);
+ }
+#else
+ if (debug)
+ printf("no mtab fixing needed\n");
+#endif
+ fprintf(stderr, "plpnfsd: exiting.\n");
+
+ exit(0);
+}
+
+void
+mount_and_run(char *dir, void (*proc)(), nfs_fh *root_fh)
+{
+ int sock, port, pid, doclean;
+ struct sockaddr_in sain;
+ int isalive = 0, ret, dtbsize;
+ SVCXPRT *nfsxprt;
+ int bufsiz = 0xc000; /* room for a few biods */
+#ifdef linux
+ struct nfs_mount_data nfs_mount_data;
+ int mount_flags;
+ int ksock, kport;
+ struct sockaddr_in kaddr;
+#else
+ struct nfs_args nfs_args;
+#endif
+#ifdef __FreeBSD__
+ int mount_flags;
+#endif
+
+ sprintf(nfshost, "localhost:/psion");
+ bzero((char *) &sain, sizeof(struct sockaddr_in));
+#ifdef linux
+ bzero(&nfs_mount_data, sizeof(struct nfs_mount_data));
+#else
+ bzero((char *) &nfs_args, sizeof(struct nfs_args));
+#endif
+
+/*** First part: set up the rpc service */
+ /* Create udp socket */
+ sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *) &bufsiz, sizeof(bufsiz)))
+ perror("setsockopt");
+
+ /* Bind it to a reserved port */
+ sain.sin_family = AF_INET;
+ sain.sin_addr.s_addr = inet_addr("127.0.0.1");
+ for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) {
+ sain.sin_port = htons(port);
+ if (bind(sock, (struct sockaddr *) &sain, sizeof(sain)) >= 0)
+ break;
+ }
+ if (port <= IPPORT_RESERVED / 2) {
+ perror("bind to reserved port");
+ exit(1);
+ }
+ if ((nfsxprt = svcudp_create(sock)) == 0) {
+ perror("svcudp_create");
+ exit(1);
+ }
+ if (!svc_register(nfsxprt, NFS_PROGRAM, NFS_VERSION, proc, 0)) {
+ perror("svc_register");
+ exit(1);
+ }
+ if (debug)
+ printf("created svc PROG=%d, VER=%d port=%d\n",
+ NFS_PROGRAM, NFS_VERSION, port);
+
+
+/*** Second part: mount the directory */
+#ifdef linux
+ /*
+ * Hold your hat! Another odd internet socket coming up. The linux
+ * kernel needs the socket to talk to the nfs daemon.
+ */
+ ksock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (ksock < 0) {
+ perror("Cannot create kernel socket.");
+ exit(1);
+ }
+ kaddr.sin_family = AF_INET;
+ kaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
+ for (kport = IPPORT_RESERVED - 1; kport > IPPORT_RESERVED / 2; kport--) {
+ kaddr.sin_port = htons(kport);
+ if (bind(ksock, (struct sockaddr *) &kaddr, sizeof(kaddr)) >= 0)
+ break;
+ }
+ if (kport <= IPPORT_RESERVED / 2) {
+ perror("bind to reserved port");
+ exit(1);
+ }
+ nfs_mount_data.version = NFS_MOUNT_VERSION;
+ nfs_mount_data.fd = ksock;
+ nfs_mount_data.root = *root_fh; /* structure copy */
+ nfs_mount_data.flags = NFS_MOUNT_INTR | NFS_MOUNT_NOCTO;
+ /* NFS_MOUNT_SECURE | NFS_MOUNT_POSIX | NFS_MOUNT_SOFT | NFS_MOUNT_NOAC */
+ nfs_mount_data.rsize = PBUFSIZE;
+ nfs_mount_data.wsize = PBUFSIZE;
+ nfs_mount_data.timeo = 600;
+ nfs_mount_data.retrans = 10; /* default 3 */
+ nfs_mount_data.acregmin = 3; /* default 3 seconds */
+ nfs_mount_data.acregmax = 60; /* default 60 seconds */
+ nfs_mount_data.acdirmin = 30; /* default 30 seconds */
+ nfs_mount_data.acdirmax = 60; /* default 60 seconds */
+ nfs_mount_data.addr = sain; /* structure copy */
+ strcpy(nfs_mount_data.hostname, PSIONHOSTNAME);
+
+ if (connect(ksock, (struct sockaddr *) &nfs_mount_data.addr, sizeof(nfs_mount_data.addr)) < 0) {
+ perror("Cannot connect to plpnfsd");
+ exit(1);
+ }
+ mount_flags = MS_MGC_VAL; /* | MS_SYNC | MS_RDONLY | MS_NOEXEC | MS_NODEV | MS_NOSUID */
+
+#endif
+
+#if defined(sun) && defined (__SVR4)
+ { /*gec */
+ struct netbuf myaddr;
+ struct stat stb;
+ struct knetconfig knc;
+ struct netconfig *nc = getnetconfigent("udp");
+ if (!nc) {
+ extern int errno;
+ fprintf(stderr, "getnetconfigent \"udp\": (errno %d) ", errno);
+ perror("");
+ exit(1);
+ }
+ knc.knc_semantics = nc->nc_semantics;
+ knc.knc_protofmly = strdup(nc->nc_protofmly);
+ knc.knc_proto = strdup(nc->nc_proto);
+
+ if (stat(nc->nc_device, &stb)) {
+ extern int errno;
+ fprintf(stderr, "stat \"%s\": (errno %d) ", nc->nc_device, errno);
+ perror("");
+ exit(1);
+ }
+ knc.knc_rdev = stb.st_rdev;
+
+ /*freenetconfigent(nc) has the struct been allocated, or is it static ?!? */
+
+ if (debug)
+ printf("%d,%s,%s,%lx (1,inet,udp,0x002c0029)\n", (int) knc.knc_semantics,
+ knc.knc_protofmly, knc.knc_proto, knc.knc_rdev);
+
+ myaddr.maxlen = myaddr.len = sizeof(sain);
+ myaddr.buf = (char *) &sain;
+
+ nfs_args.knconf = &knc;
+ nfs_args.wsize = PBUFSIZE;
+ nfs_args.rsize = PBUFSIZE;
+ nfs_args.addr = &myaddr;
+ nfs_args.fh = (char *) root_fh;
+ nfs_args.retrans = 10;
+ /* 1 minute timeout - see below */
+ nfs_args.timeo = 600;
+ nfs_args.hostname = PSIONHOSTNAME;
+ nfs_args.flags = NFSMNT_INT | NFSMNT_HOSTNAME | NFSMNT_NOCTO |
+ NFSMNT_RETRANS | NFSMNT_TIMEO | NFSMNT_WSIZE |
+ NFSMNT_RSIZE | NFSMNT_KNCONF /* | NFSMNT_NOAC */ ;
+ /* eventually drop knc-strings now (memory-leak) */
+ }
+#endif /* solaris */
+
+/* BSD Derived systems */
+#if (defined(sun) && !defined(__SVR4)) || defined(hpux) || defined(__sgi) || defined(__NeXT__)
+ nfs_args.addr = &sain;
+ nfs_args.fh = (void *) root_fh;
+ nfs_args.wsize = PBUFSIZE;
+ nfs_args.rsize = PBUFSIZE;
+ nfs_args.retrans = 10;
+ /* 1 minute timeout - means that we receive double requests in worst case,
+ if the file is longer than 100k. So long for the theory. Since SunOS uses
+ dynamic retransmission (hardwired), nfs_args.timeo is only a hint. :-( */
+ nfs_args.timeo = 600;
+ nfs_args.hostname = PSIONHOSTNAME;
+ nfs_args.flags = NFSMNT_INT | NFSMNT_HOSTNAME | NFSMNT_NOCTO |
+ NFSMNT_RETRANS | NFSMNT_TIMEO | NFSMNT_WSIZE | NFSMNT_RSIZE;
+#endif
+
+#ifdef __FreeBSD__
+#if __FreeBSD_version >= 300001
+ nfs_args.version = NFS_ARGSVERSION;
+#endif
+ nfs_args.addr = (struct sockaddr *) &sain;
+ nfs_args.addrlen = sizeof(sain);
+ nfs_args.sotype = SOCK_DGRAM;
+ nfs_args.fh = (void *) root_fh;
+ nfs_args.fhsize = sizeof(*root_fh);
+ nfs_args.wsize = PBUFSIZE;
+ nfs_args.rsize = PBUFSIZE;
+ nfs_args.retrans = 10;
+ /* 1 minute timeout - see below */
+ nfs_args.timeo = 600;
+ nfs_args.hostname = PSIONHOSTNAME;
+ nfs_args.flags =
+ NFSMNT_INT |
+ NFSMNT_SOFT |
+ NFSMNT_RETRANS |
+ NFSMNT_TIMEO |
+ NFSMNT_WSIZE |
+ NFSMNT_RSIZE;
+ mount_flags = MNT_NOSUID | MNT_NODEV | MNT_NOEXEC | MNT_NOATIME;
+#endif
+
+#ifdef __NetBSD__
+ nfs_args.addrlen = sizeof(sain);
+ nfs_args.sotype = SOCK_DGRAM;
+ nfs_args.maxgrouplist = NGROUPS;
+ nfs_args.readahead = 1;
+ nfs_args.addr = (struct sockaddr *) &sain;
+ nfs_args.fh = (void *) root_fh;
+ nfs_args.wsize = PBUFSIZE;
+ nfs_args.rsize = PBUFSIZE;
+ nfs_args.retrans = 10;
+ nfs_args.timeo = 600;
+ nfs_args.hostname = PSIONHOSTNAME;
+ nfs_args.flags = NFSMNT_INT | NFSMNT_RETRANS | NFSMNT_TIMEO
+ | NFSMNT_NOCONN | NFSMNT_DUMBTIMR | NFSMNT_MYWRITE
+ | NFSMNT_WSIZE | NFSMNT_RSIZE;
+#endif
+
+#if defined(_IBMR2)
+ nfs_args.addr = sain;
+ nfs_args.fh = *(fhandle_t *) root_fh;
+ nfs_args.wsize = PBUFSIZE;
+ nfs_args.rsize = PBUFSIZE;
+ nfs_args.retrans = 0; /* Shouldn't need bigger retrans since there is
+ only one biod. Somebody prove it ? Nice feature. */
+ nfs_args.biods = 1;
+ nfs_args.timeo = 150;
+ nfs_args.hostname = PSIONHOSTNAME;
+ nfs_args.flags = NFSMNT_INT | NFSMNT_HOSTNAME | NFSMNT_BIODS |
+ NFSMNT_RETRANS | NFSMNT_TIMEO | NFSMNT_WSIZE | NFSMNT_RSIZE;
+#endif
+
+ mntdir = dir;
+ switch (pid = fork()) {
+ case 0:
+ break;
+ case -1:
+ perror("fork");
+ exit(1);
+ default:
+ if (debug)
+ printf("Going to mount...\n");
+
+#if defined(__sgi) || (defined(sun) && defined(__SVR4))
+ if (mount("", dir, MS_DATA, "nfs", &nfs_args, sizeof(nfs_args)))
+#endif
+#if defined(__NetBSD__) || defined(__NeXT__)
+ if (mount(MOUNT_NFS, dir, 0, (caddr_t) & nfs_args))
+#endif
+#ifdef hpux
+ if (vfsmount(MOUNT_NFS, dir, 0, &nfs_args))
+#endif
+#if defined(sun) && !defined(__SVR4)
+ if (mount("nfs", dir, M_NEWTYPE, (caddr_t) & nfs_args))
+#endif
+#ifdef linux
+ if (mount("nfs", dir, "nfs", mount_flags, &nfs_mount_data))
+#endif
+#ifdef _IBMR2
+ if (aix3_mount("psion:loc", dir, 0, MOUNT_TYPE_NFS, &nfs_args, "plpnfsd"))
+#endif
+
+#ifdef __FreeBSD__
+#if __FreeBSD_version >= 300001
+ if (mount("nfs", dir, mount_flags, &nfs_args))
+#else
+ if (mount(MOUNT_NFS, dir, mount_flags, &nfs_args))
+#endif
+#endif
+
+ {
+ extern int errno;
+
+ fprintf(stderr, "nfs mount %s: (errno %d) ", dir, errno);
+ perror("");
+ kill(pid, SIGTERM);
+ exit(0);
+ } else {
+#ifndef DONT_UPDATE_MTAB
+ FILE *mfp;
+ struct mntent mnt;
+#if defined(sun) && defined(__SVR4) /*gec */
+ char tim[32];
+#endif
+
+ if (debug)
+ printf("Mount succeded, making mtab entry.\n");
+
+#if defined(sun) && defined(__SVR4) /*gec */
+ mnt.mnt_special = nfshost;
+ mnt.mnt_mountp = mntdir;
+ mnt.mnt_fstype = "nfs";
+ mnt.mnt_mntopts = "hard,intr"; /* dev=??? */
+ sprintf(tim, "%ld", time(NULL)); /* umount crashes! without this */
+ mnt.mnt_time = tim;
+#else
+ mnt.mnt_fsname = nfshost;
+ mnt.mnt_dir = mntdir;
+ mnt.mnt_type = "nfs";
+ mnt.mnt_opts = "hard,intr";
+ mnt.mnt_freq = mnt.mnt_passno = 0;
+#endif
+
+ if ((mfp = setmntent(MTAB_PATH, "a")))
+ addmntent(mfp, &mnt);
+ else
+ perror(MTAB_PATH);
+ endmntent(mfp);
+#endif /* !DONT_UPDATE_MTAB */
+ }
+ exit(0);
+ }
+
+/*** Third part: let's go */
+ printf("plpnfsd: to stop the server do \"ls %s/exit\". (pid %d)\n",
+ mntdir, (int) getpid());
+
+#if defined(sun) && !defined(__SVR4)
+ dtbsize = _rpc_dtablesize();
+#else
+ dtbsize = FD_SETSIZE;
+#endif
+
+ /*
+ * Signal handling, etc. should only happen in one process, so let's
+ * make it this one (the other one might well go away). We really
+ * ought to block off the other signals, but that's OK...
+ */
+ signal(SIGUSR1, usr1_handler);
+ signal(SIGHUP, hup_handler);
+
+ for (;;) {
+ fd_set readfd;
+ struct timeval tv;
+ struct cache *cp;
+ struct dcache *dcp;
+
+ readfd = svc_fdset;
+ tv.tv_sec = 2;
+ tv.tv_usec = 0;
+
+ ret = select(dtbsize, &readfd, 0, 0, &tv);
+ if (ret > 0)
+ svc_getreqset(&readfd);
+ if (ret != 0)
+ continue;
+
+ /* Do some housekeeping */
+
+ if (exiting)
+ doexit();
+
+ /*
+ * Solaris sends blocks in a way which is not very pleasent
+ * for us. It sends blocks 0,1,2,3,4,5,6, then 9,10,11 and
+ * do on. A little bit later block 7 and 8 arrives. This "bit"
+ * is more that 2 seconds, it is about 6 seconds. It occurs,
+ * if we're rewriting a file. We set MAXWRITE to 15, meaning
+ * that we are waiting for 30 seconds to receive the missing
+ * blocks.
+ */
+
+#define MAXWRITE 15
+ doclean = 1;
+ for (cp = attrcache; cp; cp = cp->next)
+ for (dcp = cp->dcache; dcp; dcp = dcp->next)
+ if (dcp->towrite) {
+ if (debug)
+ printf("\twaiting for block %d in %s to write (%d)\n",
+ dcp->offset, get_num(cp->inode)->name, dcp->towrite);
+ if (++dcp->towrite <= MAXWRITE)
+ doclean = 0; /* Wait with cleaning */
+ }
+ if (doclean) {
+ for (cp = attrcache; cp; cp = cp->next)
+ for (dcp = cp->dcache; dcp; dcp = dcp->next)
+ if (dcp->towrite)
+ printf("PLPNFSD WARNING: file %s block at %d not written\n",
+ get_num(cp->inode)->name, dcp->offset);
+ clean_cache(&attrcache);
+ query_cache = 0; /* clear the GETDENTS "cache". */
+ }
+ ret = 1 /* FRITZ fd_is_still_alive(psionfd, 0) */ ;
+ if (isalive && !ret) {
+ if (debug)
+ printf("Disconnected...\n");
+ } else if (!isalive && ret) {
+ if (debug)
+ printf("Connected...\n");
+ }
+ isalive = ret;
+ }
+}