Files
Arquivotheca.SunOS-4.1.4/usr.etc/rexd/mount_nfs.c
seta75D ff309bfe1c Init
2021-10-11 18:37:13 -03:00

440 lines
9.9 KiB
C

# ifdef lint
static char sccsid[] = "@(#)mount_nfs.c 1.1 94/10/31 Copyr 1985 Sun Micro";
# endif lint
/*
* mount_nfs.c - procedural interface to the NFS mount operation
*
* Copyright (c) 1985 Sun Microsystems, Inc.
*/
# define NFSCLIENT
/** # define OLDMOUNT /** for 2.0 systems only **/
#include <sys/param.h>
#include <rpc/rpc.h>
#include <rpc/pmap_prot.h>
#include <sys/errno.h>
#include <sys/time.h>
#include <nfs/nfs.h>
# ifndef OLDMOUNT
#include <sys/mount.h>
# endif OLDMOUNT
#include <rpcsvc/mount.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netdb.h>
#include <stdio.h>
#include <mntent.h>
#include <sys/vfs.h>
#define MAXSLEEP 1 /* in seconds */
char *sys_errlist[];
int sys_nerr;
/*
* mount_nfs - mount a file system using NFS
*
* Returns: 0 if OK, 1 if error.
* The "error" string returns the error message.
*/
mount_nfs(fsname, dir, error)
char *fsname;
char *dir;
char *error;
{
struct sockaddr_in sin;
struct hostent *hp;
struct fhstatus fhs;
char host[256];
char *path;
char opts[32];
struct stat st;
int s = -1;
struct timeval timeout;
CLIENT *client;
enum clnt_stat rpc_stat;
int printed1 = 0;
int printed2 = 0;
unsigned winks = 0; /* seconds of sleep time */
extern errno;
struct mntent mnt;
char *index();
FILE *mnted;
# ifndef OLDMOUNT
struct nfs_args args;
# endif OLDMOUNT
path = index(fsname, ':');
if (path==NULL) {
errprintf(error,"No host name in %s\n", fsname);
return(1);
}
*path++ = '\0';
strcpy(host,fsname);
path[-1] = ':';
if (*path == '\0') {
/*
* handle the special case of importing a root file system
*/
strcpy(path,"/");
}
/*
* Get server's address
*/
if ((hp = gethostbyname(host)) == NULL) {
errprintf(error,
"mount %s: %s not in hosts database\n", fsname, host);
return (1);
}
/*
* get fhandle of remote path from server's mountd.
* We have to use short timeouts since otherwise our incoming
* RPC call will time out.
*/
do {
bzero(&sin, sizeof(sin));
bcopy(hp->h_addr, (char *) & sin.sin_addr, hp->h_length);
sin.sin_family = AF_INET;
timeout.tv_usec = 0;
timeout.tv_sec = 5;
s = -1;
do {
if (sin.sin_port==0) {
/*
* Ask portmapper for port number since
* the standard pmap_getport has too long a timeout
*/
int ps = -1;
struct pmap parms;
short port;
sin.sin_port = htons(PMAPPORT);
client = clntudp_create(&sin, PMAPPROG, PMAPVERS,
timeout, &ps);
if (client==NULL) {
if (winks < MAXSLEEP)
winks++;
else {
errprintf(error,
"can not map port for %s\n", host);
return(1);
}
sleep(winks);
sin.sin_port = 0;
continue;
}
parms.pm_prog = MOUNTPROG;
parms.pm_vers = MOUNTVERS;
parms.pm_prot = IPPROTO_UDP;
parms.pm_port = 0;
if (clnt_call(client, PMAPPROC_GETPORT, xdr_pmap,
&parms, xdr_u_short, &port, timeout)
!= RPC_SUCCESS) {
if (winks < MAXSLEEP)
winks++;
else {
errprintf(error,
"%s not responding to port map request\n",
host);
clnt_destroy(client);
return(1);
}
if (!printed1++) {
fprintf(stderr,
"rexd portmap: %s not responding", host);
clnt_perror(client,"");
fprintf(stderr,"\r");
}
sleep(winks);
clnt_destroy(client);
client = NULL;
close(ps);
sin.sin_port = 0;
continue;
}
sin.sin_port = ntohs(port);
clnt_destroy(client);
close(ps);
}
if ((client = clntudp_create(&sin,
MOUNTPROG, MOUNTVERS, timeout, &s)) == NULL) {
if (winks < MAXSLEEP)
winks++;
else {
if (rpc_createerr.cf_stat == RPC_PROGNOTREGISTERED)
errprintf(error,
"%s is not running a mount daemon\n", host);
else
errprintf(error,
"%s not responding to mount request\n",
host);
return(1);
}
sleep(winks);
if (!printed1++) {
fprintf(stderr,
"rexd mount: %s not responding", host);
clnt_pcreateerror("");
fprintf(stderr,"\r");
}
}
} while (client == NULL);
client->cl_auth = authunix_create_default();
timeout.tv_usec = 0;
timeout.tv_sec = 25;
rpc_stat = clnt_call(client, MOUNTPROC_MNT, xdr_path, &path,
xdr_fhstatus, &fhs, timeout);
if (rpc_stat != RPC_SUCCESS) {
if (!printed2++) {
fprintf(stderr,
"rexd mount: %s not responding", host);
clnt_perror(client, "");
fprintf(stderr,"\r");
}
}
close(s);
clnt_destroy(client);
} while (rpc_stat == RPC_TIMEDOUT || fhs.fhs_status == ETIMEDOUT);
if (rpc_stat != RPC_SUCCESS || fhs.fhs_status) {
errno = fhs.fhs_status;
if (errno == EACCES) {
errprintf(error,
"rexd mount: not in export list for %s\n",
fsname);
}
return (1);
}
if (printed1 || printed2) {
fprintf(stderr, "rexd mount: %s OK\n", host);
fprintf(stderr,"\r");
}
/*
* remote mount the fhandle on the local path.
*/
# ifdef OLDMOUNT
if (nfsmount(&sin, &fhs.fhs_fh, dir, 0, 0, 0) <0) {
# else OLDMOUNT
sin.sin_port = htons(NFS_PORT);
args.addr = &sin;
args.fh = (caddr_t) &fhs.fhs_fh;
args.flags = NFSMNT_HOSTNAME | NFSMNT_INT;
args.hostname = host;
if (mount("nfs", dir, M_NOSUID | M_NEWTYPE, &args) < 0) {
# endif OLDMOUNT
errprintf(error,"unable to mount %s on %s: %s\n",
fsname, dir,
errno > sys_nerr ? "unknown error" :
sys_errlist[errno]);
return (1);
}
/*
* stat the new mount and get its dev
*/
if (stat(dir, &st) < 0) {
errprintf(error, "couldn't stat %s\n", dir);
return (1);
}
(void) sprintf(opts, "rw,noquota,hard,intr,%s=%04x",
MNTINFO_DEV, (st.st_dev & 0xFFFF));
/*
* update /etc/mtab
*/
mnt.mnt_fsname = fsname;
mnt.mnt_dir = dir;
mnt.mnt_type = MNTTYPE_NFS;
mnt.mnt_opts = opts;
mnt.mnt_freq = 0;
mnt.mnt_passno = 0;
newmtab(&mnt, (char *)NULL);
return (0);
}
#define UNMOUNTTRIES 6
/*
* umount_nfs - unmount a file system when finished
*/
umount_nfs(fsname, dir)
char *fsname, *dir;
{
char *p, *index();
struct sockaddr_in sin;
struct hostent *hp;
int s = -1;
struct timeval timeout;
CLIENT *client;
enum clnt_stat rpc_stat;
int count = 0;
/*
* Give the filesystem time to become un-busy when unmounting.
* If child aborted and is takes a core dump, we may receive the
* SIGCHLD before the core dump is completed.
*/
while (unmount(dir) == -1) {
if (errno != EBUSY) {
perror(dir);
return (1);
}
if (++count > UNMOUNTTRIES)
return (1);
sleep (10);
}
newmtab((struct mntent *)NULL, dir);
if ((p = index(fsname, ':')) == NULL)
return(1);
*p++ = 0;
if ((hp = gethostbyname(fsname)) == NULL) {
fprintf(stderr, "%s not in hosts database\n", fsname);
return(1);
}
bzero(&sin, sizeof(sin));
bcopy(hp->h_addr, (char *) & sin.sin_addr, hp->h_length);
sin.sin_family = AF_INET;
timeout.tv_usec = 0;
timeout.tv_sec = 10;
if ((client = clntudp_create(&sin, MOUNTPROG, MOUNTVERS,
timeout, &s)) == NULL) {
clnt_pcreateerror("Warning on umount create:");
fprintf(stderr,"\r");
return(1);
}
client->cl_auth = authunix_create_default();
timeout.tv_usec = 0;
timeout.tv_sec = 25;
rpc_stat = clnt_call(client, MOUNTPROC_UMNT, xdr_path, &p,
xdr_void, NULL, timeout);
if (rpc_stat != RPC_SUCCESS) {
clnt_perror(client, "Warning: umount:");
fprintf(stderr,"\r");
return(1);
}
return(0);
}
#define MAXTRIES 300
newmtab(addmnt, deldir)
struct mntent *addmnt;
char *deldir;
{
char *from = "/etc/omtabXXXXXX";
char *to = "/etc/nmtabXXXXXX";
FILE *fromp, *top;
int count = 0;
struct mntent *mnt;
struct stat statbuf;
mktemp(from);
while (rename(MOUNTED, from)) {
if (++count > MAXTRIES) {
fprintf(stderr, "newmtab: cat get %s lock\r\n", MOUNTED);
return;
}
sleep(1);
}
fromp = setmntent(from, "r");
mktemp(to);
top = setmntent(to, "w");
if (fromp == NULL || top == NULL) {
rename(from, MOUNTED);
fprintf(stderr, "newmtab: can't open %s or %s\r\n", from, to);
return;
}
while ((mnt = getmntent(fromp)) != NULL)
if (deldir == NULL || strcmp(mnt->mnt_dir, deldir) != 0)
addmntent(top, mnt);
if (addmnt)
addmntent(top, addmnt);
if (!fstat (fileno (fromp), &statbuf))
(void) fchmod (fileno (top), statbuf.st_mode);
endmntent(fromp);
endmntent(top);
if (rename(to, MOUNTED)) {
fprintf(stderr, "newmtab can not rename %s to %s\r\n",
to, MOUNTED);
rename(from, MOUNTED);
}
unlink(from);
}
/*
* parsefs - given a name of the form host:/path/name/for/file
* connect to the give host and look for the exported file system
* that matches.
* Returns: pointer to string containing the part of the pathname
* within the exported directory.
* Returns NULL on errors.
*/
char *
parsefs(fullname,error)
char *fullname;
char *error;
{
char *dir, *subdir;
struct exports *ex = NULL;
int err;
int bestlen = 0;
int len, dirlen;
dir = index(fullname, ':');
if (dir == NULL) {
errprintf(error,"No host name in %s\n",fullname);
return(NULL);
}
*dir++ = '\0';
if (err = callrpc(fullname, MOUNTPROG, MOUNTVERS, MOUNTPROC_EXPORT,
xdr_void, 0, xdr_exports, &ex)) {
if (err== (int)RPC_TIMEDOUT)
errprintf(error, "Host %s is not running mountd\n",
fullname);
else
errprintf(error,"RPC error %d with host %s\n",
err,fullname);
return(NULL);
}
dirlen = strlen(dir);
for (; ex; ex = ex->ex_next) {
len = strlen(ex->ex_name);
if (len > bestlen && len <= dirlen &&
strncmp(dir, ex->ex_name, len) == 0 &&
(dir[len] == '/' || dir[len] == '\0'))
bestlen = len;
}
if (bestlen == 0) {
errprintf(error, "%s not exported by %s\n",
dir, fullname);
return(NULL);
}
if (dir[bestlen] == '\0')
subdir = &dir[bestlen];
else {
dir[bestlen] = '\0';
subdir = &dir[bestlen+1];
}
*--dir = ':';
return (subdir);
}
/*
* errprintf will print a message to standard error channel,
* and return the same string in the given message buffer.
* We add an extra return character in case the console is in raw mode.
*/
errprintf(s,p1,p2,p3,p4,p5,p6,p7)
char *s;
{
sprintf(s,p1,p2,p3,p4,p5,p6,p7);
fprintf(stderr,"%s\r",s);
}