Path: utzoo!utgpu!watserv1!watmath!att!linac!pacific.mps.ohio-state.edu!zaphod.mps.ohio-state.edu!wuarchive!uunet!mcsun!ukc!edcastle!aiai!richard From: richard@aiai.ed.ac.uk (Richard Tobin) Newsgroups: comp.protocols.nfs Subject: Re: Avoiding resource waits on unavailable hard mounted fs Message-ID: <4139@skye.ed.ac.uk> Date: 15 Feb 91 14:15:50 GMT References: <1991Feb14.035507.28805@massey.ac.nz> Reply-To: richard@aiai.UUCP (Richard Tobin) Organization: AIAI, University of Edinburgh, Scotland Lines: 309 In article thurlow@convex.com (Robert Thurlow) writes: >Our df(1) does this now. I can't recall where the idea came from, > signal(SIGALRM, timedout); > alarm(TIMEOUT); > > if(setjmp(env) == 0) { > stat = callrpc(host, NFS_PROGRAM, NFS_VERSION, RFS_NULL, > xdr_void, 0, xdr_void, 0); > alarm(0); /* unimportant race condition here */ > if (stat == 0) > return 0; > } This code appears to be from a version of df I posted to Sun-spots some time ago. A better version uses explicit timeouts in the RPC call. The new code is below. Note that it assumes the NFS server is on port 2049 to avoid having to deal with hanging while waiting for the portmapper. -- Richard /* df.c * A replacement for df that trys not to hang if a fileserver doesn't respond. * Copyright Richard Tobin (R.Tobin@uk.ac.ed) 1989. * May be freely redistributed if this comment remains intact. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern int errno; #define MTAB "/etc/mtab" #define TIMEOUT 5 struct mntent *findmntent(); void printline(), usage(); int nfscheck(); main(argc, argv) int argc; char **argv; { int c, aflag=0, iflag=0, tflag=0, errs = 0; char *type, *file; extern char *optarg; extern int optind, opterr; while((c = getopt(argc, argv, "ait:")) != EOF) switch(c) { case 'a': /* report even boring filesystems */ aflag++; break; case 'i': /* report inode use */ iflag++; break; case 't': /* only report on one type of filesystem */ tflag++; type = optarg; break; case '?': usage(); } if(tflag && optind != argc) usage(); if(iflag) printf("Filesystem iused ifree %%iused Mounted on\n"); else printf("Filesystem kbytes used avail capacity Mounted on\n"); if(optind < argc) { /* report on listed filesystems */ for(file = argv[optind]; optind < argc; file = argv[++optind]) { struct statfs filebuf; struct mntent *mntbuf; if(statfs(file, &filebuf) != 0) { perror(file); errs++; continue; } if(!aflag && filebuf.f_blocks == 0) continue; mntbuf = findmntent(filebuf.f_fsid); if(!mntbuf) { fprintf(stderr, "can't find filesystem for %s\n", file); errs++; continue; } printline(&filebuf, mntbuf, iflag); } } else { /* report on all mounted filesystems */ struct statfs filebuf; struct mntent *mntbuf; FILE *f; errno = 0; f = setmntent(MTAB, "r"); if(!f) { fprintf(stderr, "can't open %s\n", MTAB); if(errno) perror("setmntent"); exit(1); } while(mntbuf = getmntent(f)) { if(tflag && strcmp(mntbuf->mnt_type, type) != 0) continue; if(nfscheck(mntbuf) != 0) { errs++; continue; } if(statfs(mntbuf->mnt_dir, &filebuf) != 0) { perror(mntbuf->mnt_dir); errs++; continue; } if(!aflag && filebuf.f_blocks == 0) continue; printline(&filebuf, mntbuf, iflag); } endmntent(f); } exit(errs > 0 ? 1 : 0); } /* findmntent finds the filesystem in mtab with the specified id. */ struct mntent *findmntent(id) fsid_t id; { FILE *f; struct mntent *fs; errno = 0; f = setmntent(MTAB, "r"); if(!f) { fprintf(stderr, "can't open %s\n", MTAB); if(errno) perror("setmntent"); exit(1); } while(fs = getmntent(f)) { struct statfs buf; if(nfscheck(fs) != 0) continue; if(statfs(fs->mnt_dir, &buf) != 0) continue; if(bcmp(&buf.f_fsid, &id, sizeof(fsid_t)) == 0) { endmntent(f); return fs; } } endmntent(f); return (struct mntent *)0; } void printline(buf, mntbuf, iflag) struct statfs *buf; struct mntent *mntbuf; int iflag; { printf("%-20s", mntbuf->mnt_fsname); if(strlen(mntbuf->mnt_fsname) > 20) printf("\n%20s", ""); if(iflag) printf(" %7d %7d %3d%% %s\n", buf->f_files - buf->f_ffree, buf->f_ffree, ((buf->f_files - buf->f_ffree) * 100 + buf->f_files / 2) / buf->f_files, mntbuf->mnt_dir); else printf(" %7d %7d %7d %3d%% %s\n", (buf->f_blocks * buf->f_bsize + 512) / 1024, ((buf->f_blocks - buf->f_bfree) * buf->f_bsize + 512) / 1024, (buf->f_bavail * buf->f_bsize + 512) / 1024, ((buf->f_blocks - buf->f_bfree) * 100 + buf->f_blocks / 2) / ((buf->f_blocks * 9)/10), mntbuf->mnt_dir); } void usage() { fprintf(stderr, "usage: df [ -i ] [ -a ] [ -t type | file... ]\n"); exit(2); } static jmp_buf env; /* * nfscheck checks that the host supplying the filesystem described * by mntbuf is responding, by calling the null nfs procedure. */ int nfscheck(mntbuf) struct mntent *mntbuf; { int stat, sock= RPC_ANYSOCK; char host[50], *p; struct hostent *server; struct sockaddr_in sin; CLIENT *client; struct timeval try, total; if(strcmp(mntbuf->mnt_type, "nfs") != 0) return 0; p = index(mntbuf->mnt_fsname, ':'); if(!p || p - mntbuf->mnt_fsname >= sizeof(host)) return 0; strncpy(host, mntbuf->mnt_fsname, p - mntbuf->mnt_fsname); host[p - mntbuf->mnt_fsname] = '\0'; server = gethostbyname(host); if(!server) { fprintf(stderr, "%s: unknown host %s\n", mntbuf->mnt_dir, 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) { fprintf(stderr, "%s: can't create connection to %s\n", mntbuf->mnt_dir, host); 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) { fprintf(stderr, "%s: nfs server %s not responding\n", mntbuf->mnt_dir, host); 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