home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Boot Disc 8
/
boot-disc-1997-04.iso
/
PDA_Soft
/
Psion
/
comms
/
p3nfs
/
nfsd
/
mp_mount.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-03-31
|
14KB
|
529 lines
#include <stdio.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/wait.h>
#ifdef __svr4__
#include <stdlib.h>
#include <unistd.h>
extern int inet_addr(char *);
#define PORTMAP /* I need svcudp_create in rpc/svc_soc.h, sol 2.4 */
#endif
#define PSIONHOSTNAME "localhost"
#include "config.h"
static char nfshost[128];
#define NFSCLIENT
#include <sys/mount.h>
#ifdef linux
# include <linux/fs.h> /* struct nfs_sever for linux/nfs_fs.h */
# include <linux/nfs_fs.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
#include <rpc/rpc.h>
#include "nfs_prot.h"
#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 <string.h> /* strdup */
#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 <rpc/rpc.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 */
static void
doexit()
{
FILE *fpin, *fpout;
#if defined(sun) && defined(__svr4__)
struct mntent entr;
#else
struct mntent *ent;
#endif
struct stat statb;
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, "p3nfsd: exiting.\n");
exit(0);
}
static void
dosystem(str)
char *str;
{
extern fattr root_fattr;
if(vfork()) return;
setgid(root_fattr.gid);
setuid(root_fattr.uid);
execl("/bin/sh", "sh", "-c", str, 0);
perror("/bin/sh");
_exit(1);
}
void
mount_and_run(dir, dev, proc, root_fh)
char *dir, *dev;
nfs_fh *root_fh;
void (*proc)();
{
int sock, port, pid;
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
sprintf(nfshost, "localhost:%s", dev);
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);
}
/*** 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 p3nfsd");
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", 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;
}
#endif /* solaris */
#if (defined(sun) && !defined(__svr4__)) || defined(hpux) || defined(__sgi)
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
#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");
#ifdef __sgi
if(mount("", dir, MS_DATA, "nfs", &nfs_args, sizeof(nfs_args)))
#endif
#ifdef sun
# ifndef __svr4__
if(mount("nfs", dir, M_NEWTYPE, (caddr_t)&nfs_args))
# else /*gec*/
if(mount("", dir, MS_DATA, "nfs", &nfs_args, sizeof(nfs_args)))
/* eventually drop knc-strings now (memory-leak) */
# endif
#endif
#ifdef hpux
if (vfsmount(MOUNT_NFS, dir, 0, &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, "p3nfsd"))
#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 */
}
if(!background)
while(wait(&ret) != pid)
;
exit(0);
}
/*** Third part: let's go */
printf("p3nfsd: to stop the server do \"ls %s/exit\". (pid %d)\n",
mntdir, getpid());
#if defined(sun) && !defined(__svr4__)
dtbsize = _rpc_dtablesize();
if(psionfd >= dtbsize) dtbsize = psionfd+1;
if(masterfd >= dtbsize) dtbsize = masterfd+1;
#else
dtbsize = FD_SETSIZE;
#endif
for(;;)
{
fd_set readfd;
struct timeval tv;
struct cache *cp;
struct dcache *dcp;
readfd = svc_fdset;
FD_SET(psionfd, &readfd);
if(masterfd >= 0)
FD_SET(masterfd, &readfd);
tv.tv_sec = 2; tv.tv_usec = 0;
ret = select(dtbsize, &readfd, 0, 0, &tv);
if(ret > 0)
{
if(FD_ISSET(psionfd, &readfd)) /* Terminal input from the psion */
{
unsigned char c;
read(psionfd, &c, 1);
shell_feed(c);
continue;
}
if(masterfd >=0 && FD_ISSET(masterfd, &readfd)) /* Terminal output */
{
#define PLEN 245 /* to make life easier for the psion */
char buf[PLEN+1];
int len;
len = read(masterfd, buf, PLEN);
buf[len] = 0;
if(len <= 0)
{
close(masterfd);
masterfd = -1;
}
/* not 0-byte clean. :-( but its faster and PREFIX is no problem*/
sendcmd(PFS_OP_TTYDATA, buf, 0, 0);
continue;
}
svc_getreqset(&readfd);
}
if(ret != 0)
continue;
/* Do some housekeeping */
if(exiting)
doexit();
query_cache = 0; /* clear the GETDENTS "cache". */
/* print some warnings about not written blocks */
for(cp = attrcache; cp; cp = cp->next)
for(dcp = cp->dcache; dcp; dcp = dcp->next)
if(!dcp->written)
{
printf("P3NFSD: WARNING, block at offset %d in %s not written\n",
dcp->offset, get_num(cp->inode)->name);
break;
}
clean_cache(&attrcache);
ret = fd_is_still_alive(psionfd, 0);
if(isalive && !ret)
{
if(debug) printf("Disconnected...\n");
if(disconnprog && *disconnprog)
dosystem(disconnprog);
}
else if(!isalive && ret)
{
if(debug) printf("Connected...\n");
if(connprog && *connprog)
dosystem(connprog);
}
isalive = ret;
}
}