[alt.sources] [comp.sys.hp...] Re: NFS mounts - hard versus soft - info. wanted

richard@aiai.ed.ac.uk (Richard Tobin) (08/22/90)

Archive-name: nfslink/21-Aug-90
Original-posting-by: richard@aiai.ed.ac.uk (Richard Tobin)
Original-subject: Re: NFS mounts - hard versus soft - info. wanted
Reposted-by: emv@math.lsa.umich.edu (Edward Vielmetti)

[Reposted from comp.sys.hp,comp.unix.questions.
Comments on this service to emv@math.lsa.umich.edu (Edward Vielmetti).]

In article <1990Aug20.204546.15101@anduin.cs.liverpool.ac.uk> dave8@anduin.cs.liverpool.ac.uk writes:
>However, we are frustrated by situations where a cluster server goes down,
>and the workstations on another cluster server hang because the PATH
>environment variable on these includes a directory residing on a
>partition being exported from the machine that has gone down. 

One way to deal with this is to mount the filesystems in some
obscure place, and make symbolic links to them.  You can then remove
the links when the server goes down.

Of course, this doesn't work if you don't have symbolic links.

You should also mount filesystems from different machines in different
directories, so that "pwd" doesn't hang.

You can have a program maintain the links automatically - here's one
I use.  It may need changing for HPs.

-- Richard

/*
 * nfslink [-i interval] [-t timeout] host name mountpt [name mountpt ...]
 *
 * maintain links to mounted file systems, removing them if the
 * remote machine isn't responding.
 *
 * Copyright Richard Tobin / AIAI 1989
 * 
 * May be freely redistributed if this whole notice remains intact.
 */

#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <sys/time.h>
#include <rpc/rpc.h>
#include <rpc/clnt.h>
#include <nfs/nfs.h>
#include <setjmp.h>
#include <sys/stat.h>
#include <netdb.h>
#include <sys/socket.h>

main(argc, argv)
int argc;
char **argv;
{
    int c, interval = 20, timeout = 5, firsttime = 1;
    extern char *optarg;
    extern int optind, opterr;

    while((c = getopt(argc, argv, "i:t:")) != EOF)
	switch(c)
	{
	  case 'i':
	    interval = atoi(optarg);
	    break;

	  case 't':
	    timeout = atoi(optarg);
	    break;

	  case '?':
	    usage();
	    break;
	}

    if((argc - optind) < 3 || ((argc - optind) & 1) == 0)
	usage();

    while(1)
    {
	if(nfscheck(argv[optind], timeout) == 0)
	    makelinks(&argv[optind+1], firsttime);
	else
	    removelinks(&argv[optind+1], firsttime);

	firsttime = 0;
	sleep(interval);
    }
}

void dodate()
{
    char *tim;
    long *clk;

    time(&clk);
    tim = ctime(&clk);
    tim[24] = '\0';		/* lose the linefeed */

    printf("nfslink: %s: ", tim);
}

makelinks(links, verbose)
char **links;
int verbose;
{
    struct stat namestat;
    
    while(*links)
    {
	char *name = *links++;
	char *mountpt = *links++;

	if(lstat(name, &namestat) == -1)
	{
	    if(errno == ENOENT)
	    {
		if(symlink(mountpt, name) == -1)
		{
		    perror("nfslink: symlink");
		    fatal("can't link %s to %s\n", name, mountpt);
		}
		dodate();
		printf("linked %s to %s\n", name, mountpt);
		fflush(stdout);
		continue;
	    }
	    else
	    {
		perror("nfslink: lstat");
		fatal("can't lstat %s\n", name, 0);
	    }
	}

	if((namestat.st_mode & S_IFMT) == S_IFLNK)
	{
	    if(pointsto(name, mountpt))
	    {
		if(verbose)
		{
		    dodate();
		    printf("%s is already linked to %s\n",
			   name, mountpt);
		    fflush(stdout);
		}
	    }
	    else
	    {
		fatal("%s is a link, but not to %s\n", name, mountpt);
	    }
	}
	else
	{
	    fatal("%s exists, but is not a symbolic link\n", name, 0);
	}
    }
}

removelinks(links, verbose)
char **links;
int verbose;
{
    struct stat namestat;
    
    while(*links)
    {
	char *name = *links++;
	char *mountpt = *links++;

	if(lstat(name, &namestat) == -1)
	{
	    if(errno == ENOENT)
	    {
		if(verbose)
		{
		    dodate();
		    printf("link from %s to %s is already removed\n",
			   name, mountpt);
		    fflush(stdout);
		}
		continue;
	    }
	    else
	    {
		perror("nfslink: lstat");
		fatal("can't lstat %s\n", name, 0);
	    }
	}

	if((namestat.st_mode & S_IFMT) == S_IFLNK)
	{
	    if(pointsto(name, mountpt))
	    {
		if(unlink(name) == -1)
		{
		    perror("nfslink: unlink");
		    fatal("can't remove link from %s to %s\n",
			  name, mountpt);
		}
		dodate();
		printf("removed link from %s to %s\n",
		       name, mountpt);
		fflush(stdout);
	    }
	    else
	    {
		fatal("%s is a link, but not to %s\n", name, mountpt);
	    }
	}
	else
	{
	    fatal("%s exists, but is not a symbolic link\n", name, 0);
	}
    }
}

int pointsto(name, target)
char *name, *target;
{
    /* We don't use stat lest it hang, so it's not quite right */

    char buf[200];
    int len;

    len = readlink(name, buf, sizeof(buf)-1);
    if(len == -1)
    {
	perror("nfslink: readlink");
	fatal("can't read link %s\n", name, 0);
    }

    buf[len] = '\0';
    return strcmp(buf, target) == 0;
}

fatal(fmt, arg1, arg2)
char *fmt, *arg1, *arg2;
{
    fprintf(stderr, "nfslink: fatal error: ");
    fprintf(stderr, fmt, arg1, arg2);
    exit(1);
}

usage()
{
    fprintf(stderr, "usage: nfslink [-i interval] [-t timeout] host name mountpt [name mountpt ...]\n");
    exit(2);
}

int nfscheck(host, timeout)
char *host;
int timeout;
{
    int stat, sock= RPC_ANYSOCK;
    struct hostent *server;
    struct sockaddr_in sin;
    CLIENT *client;
    struct timeval try, total;

    server = gethostbyname(host);
    if(!server)
    {
	fprintf(stderr, "nfslink: unknown host %s\n", host);
	return -1;
    }

    bcopy(server->h_addr, &sin.sin_addr, server->h_length);
    sin.sin_family = AF_INET;
    sin.sin_port = 2049;	/* avoid calling portmapper */

    try.tv_sec = 1;
    try.tv_usec = 0;

    client = clntudp_create(&sin, NFS_PROGRAM, NFS_VERSION,
			    try, &sock);
    if(!client)
	return -1;

    total.tv_sec = timeout;
    total.tv_usec = 0;

    stat = clnt_call(client, RFS_NULL, xdr_void, 0, xdr_void, 0, total);

    clnt_destroy(client);

    if(stat != RPC_SUCCESS)
	return -1;

    return 0;
}


-- 
Richard Tobin,                       JANET: R.Tobin@uk.ac.ed             
AI Applications Institute,           ARPA:  R.Tobin%uk.ac.ed@nsfnet-relay.ac.uk
Edinburgh University.                UUCP:  ...!ukc!ed.ac.uk!R.Tobin