From decwrl!sun-barr!cs.utexas.edu!uwm.edu!psuvax1!rutgers!aramis.rutgers.edu!dartagnan.rutgers.edu!mcgrew Sun Dec 10 15:26:12 PST 1989 Article 86 of comp.sources.sun: Path: decwrl!sun-barr!cs.utexas.edu!uwm.edu!psuvax1!rutgers!aramis.rutgers.edu!dartagnan.rutgers.edu!mcgrew From: mcgrew@dartagnan.rutgers.edu (Charles Mcgrew) Newsgroups: comp.sources.sun Subject: v01i084: chknfs-1.1 - Test NFS paths for validity Message-ID: Date: 28 Nov 89 17:26:38 GMT Organization: Rutgers Univ., New Brunswick, N.J. Lines: 853 Approved: mcgrew@aramis.rutgers.edu Submitted-by: aklietz@ncsa.uiuc.edu (Alan Klietz) Posting-number: Volume 1, Issue 84 Archive-name: chknfs-1.1 This program is called cknfs. It checks for dead NFS servers. I wrote it because I was tired of logging into a NFS client workstation, only to find myself hung because one of my twenty-odd execution paths pointed to some obscure NFS server that happened to be dead. Well, this program fixes that problem. It takes a list of execution paths as arguments. Each path is examined for an NFS mount point. If found, the corresponding NFS server is checked. Paths that lead to dead NFS servers are ignored. The remaining paths are printed to stdout. Typical examples: set path = `cknfs /bin /usr/bin /usr/ucb . /usr6/bin /sdg/bin` alias cd 'cknfs -e \!*; if ($status == 0) chdir \!*' The latter example prevents you from hanging if you cd to a directory that leads to a dead NFS server. #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh 'Makefile' <<'END_OF_FILE' X# X# $Header: Makefile,v 1.1 89/06/20 23:29:37 aklietz Exp $ X# X# $Log: Makefile,v $ X# Revision 1.1 89/06/20 23:29:37 aklietz X# Initial revision X# X# XSHELL = /bin/sh X X### Change to -g for debugging XCFLAGS = -O X X### Necessary include dirs, if any XINCLUDES = X#INCLUDES = -I/usr/include/sun -I/usr/include/bsd # for SGI systems X X### Necessary libraries, if any XLFLAGS= X#LFLAGS= -lsun -lbsd # for SGI systems X X### Where executable should be put XDESTDIR = /usr/local/bin X X### Where man page should be put XMANDIR = /usr/man/manl X X### Suffix for man page XMANSUFFIX = 1l X#MANSUFFIX = 1 X#MANSUFFIX = l X#MANSUFFIX = 1local X X### X### End of configuration section X### X XMANPAGE = cknfs.$(MANSUFFIX) XPROG = cknfs X Xall: $(PROG) X Xcknfs: cknfs.c X $(CC) $(CFLAGS) $(INCLUDES) cknfs.c -o cknfs $(LFLAGS) X Xinstall: $(PROG) X rm -f $(DESTDIR)/$(PROG) X cp $(PROG) $(DESTDIR) X chmod 755 $(DESTDIR)/$(PROG) X rm -f $(MANDIR)/$(MANPAGE) X cp cknfs.man $(MANDIR)/$(MANPAGE) X chmod 644 $(MANDIR)/$(MANPAGE) X Xclean: X rm -f *.o core X Xclobber: X rm -f *.o core $(PROG) X Xlint: cknfs.c X lint -ahb $(INCLUDES) cknfs.c END_OF_FILE if test 1092 -ne `wc -c <'Makefile'`; then echo shar: \"'Makefile'\" unpacked with wrong size! fi # end of 'Makefile' fi if test -f 'README' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'README'\" else echo shar: Extracting \"'README'\" \(795 characters\) sed "s/^X//" >'README' <<'END_OF_FILE' XThis program checks for dead NFS servers. X XI wrote it because I was tired of logging into a NFS client workstation, Xonly to find myself hung because one of my twenty-odd execution paths Xpointed to some obscure NFS server that happened to be dead. X XWell, this program fixes that problem. It takes a list of execution Xpaths as arguments. Each path is examined for an NFS mount point. XIf found, the corresponding NFS server is checked. Paths that lead Xto dead NFS servers are ignored. The remaining paths are printed to Xstdout. No more hung logins! X XTypical examples: X X set path = `cknfs /bin /usr/bin /usr/ucb . /usr6/bin /sdg/bin` X alias cd 'cknfs -e \!*; if ($status == 0) chdir \!*' X XThe latter example prevents you from hanging if you cd to a Xdirectory that leads to a dead NFS server. END_OF_FILE if test 795 -ne `wc -c <'README'`; then echo shar: \"'README'\" unpacked with wrong size! fi # end of 'README' fi if test -f 'cknfs.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'cknfs.c'\" else echo shar: Extracting \"'cknfs.c'\" \(13846 characters\) sed "s/^X//" >'cknfs.c' <<'END_OF_FILE' X/* X * cknfs - Check for dead NFS servers X * X * Don't you hate it when you login on an NFS client, only to find X * yourself hung because one of your execution paths points to a dead X * NFS server? X * X * Well, this program fixes that problem. It takes a list of execution X * paths as arguments. Each path is examined for an NFS mount point. X * If found, the corresponding NFS server is checked. Paths that lead X * to dead NFS servers are ignored. The remaining paths are printed to X * stdout. No more hung logins! X * X * Usage: cknfs -e -s -t# -v -D -L paths X * X * -e silent, do not print paths X * -s print paths in sh format (colons) X * -t n timeout interval before assuming an NFS X * server is dead (default 10 seconds) X * -v verbose X * -D debug X * -L expand symbolic links X * X * Typical examples: X * X * set path = `cknfs /bin /usr/bin /usr/ucb . /usr6/bin /sdg/bin` X * alias cd 'cknfs -e \!*; if ($status == 0) chdir \!*' X * X * The latter example prevents you from hanging if you cd to a X * directory that leads to a dead NFS server. X * X * Adminstrative note: You can still get hung if your administator X * mixes NFS mount points from different machines in the same parent X * directory or if your administrator mixes regular directories and X * NFS mount points in the same parent directory. X * X * The best organization is an overall /nfs directory with subdirectories X * for each machine. For example, if you have 3 NFS servers named X * "newton", "bardeen", and "zaphod", a good organization would be X * X * /nfs/bardeen/apps X * /nfs/bardeen/bin X * /nfs/newton/bin X * /nfs/newton/local X * /nfs/zaphod/bin X * /nfs/zaphod/sdg X * X * NEVER MIX MOUNT POINTS FROM DIFFERENT MACHINES IN THE SAME X * PARENT DIRECTORY. X * X * Implementation note: A small amount of system-dependent code is required X * to read the mount table. This is located in mkm_mlist() at bottom of the X * program. It may have to be edited to handle local system dependencies. X * #ifdef'ed versions for SunOs, Ultrix, and SGI are included. X */ X X/* X * Copyright (c) 1989, The Board of Trustees of the University of Illinois X * National Center for Supercomputing Applications. X * X * No warranty is expressed or implied. X * Unlimited redistribution permitted. X * X */ X Xstatic char *RCSid = "$Header: cknfs.c,v 1.6 89/06/21 00:04:15 aklietz Exp $"; X X/* X * $Log: cknfs.c,v $ X * Revision 1.6 89/06/21 00:04:15 aklietz X * Linted. Baseline for release. X * X * Revision 1.5 89/06/20 23:37:59 aklietz X * Restart the parse loop on .. instead of just popping the stack, X * because a/../b need not necessarily == b across a symbolic link. X * Add support for SGI. X * X * Revision 1.4 89/05/31 18:24:49 aklietz X * Fix bug introduced in rev 1.3 that did hangable lstat before X * checking for NFS mount point. X * Add support for Ultrix. X * X * Revision 1.3 89/05/29 03:30:55 aklietz X * Terminate silently if no args in -e mode. X * Fix omission of chdir("/") during parse of symlink to absolute path. X * X * Revision 1.2 89/05/26 14:14:35 aklietz X * Baseline for release X * X * Revision 1.1 89/05/26 13:37:39 aklietz X * Initial revision X * X */ X X#include "sys/param.h" X#include "errno.h" X#include "sys/types.h" X#include "sys/stat.h" X#include "signal.h" X#include "ctype.h" X#include "stdio.h" X#include "sys/time.h" X#include "sys/socket.h" X#include "arpa/inet.h" X#include "netdb.h" X#include "rpc/rpc.h" X#include "rpc/pmap_prot.h" X#include "rpc/pmap_clnt.h" X#ifndef sgi /* sgi is missing nfs.h for some reason */ X#include "nfs/nfs.h" X#else X /* sgi is missing nfs.h, so we must hardcode the RPC values */ X# define NFS_PROGRAM 100003L X# define NFS_VERSION 2L X#endif X X/* X * Make initial program X * May 1989, Alan Klietz (aklietz@ncsa.uiuc.edu) X */ X X#define DEFAULT_TIMEOUT 10 /* Default timeout for checking NFS server */ X Xextern char *realloc(); Xextern char *strchr(), *strrchr(), *strtok(); X Xstruct m_mlist { X int mlist_checked; /* -1 if bad, 0 if not checked, 1 if ok */ X struct m_mlist *mlist_next; X char *mlist_dir; X char *mlist_fsname; X int mlist_isnfs; X}; Xstatic struct m_mlist *firstmnt; X Xstatic int errflg; Xstatic int eflg, sflg, vflg, Dflg, Lflg; Xstatic int timeout = DEFAULT_TIMEOUT; Xstatic char prefix[MAXPATHLEN]; Xstruct m_mlist *isnfsmnt(); Xchar *xalloc(); Xvoid mkm_mlist(); X Xint Xmain(argc, argv) Xint argc; Xchar **argv; X{ X register int n; X register char *s; X int good = 0; X char outbuf[BUFSIZ]; X char errbuf[BUFSIZ]; X extern int optind; X extern char *optarg; X X X /* X * Avoid intermixing stdout and stderr X */ X setvbuf(stdout, outbuf, _IOFBF, sizeof(outbuf)); X setvbuf(stderr, errbuf, _IOLBF, sizeof(errbuf)); X X while ((n = getopt(argc, argv, "est:vDL")) != EOF) X switch(n) { X case 'e': ++eflg; X break; X X case 's': ++sflg; X break; X X case 't': timeout = atoi(optarg); X break; X X case 'v': ++vflg; X break; X X case 'D': ++Dflg; ++vflg; X break; X X case 'L': ++Lflg; X break; X X default: X ++errflg; X } X X if (argc <= optind && !eflg) /* no paths */ X ++errflg; X X if (errflg) { X fprintf(stderr, "Usage: %s -e -s -t# -v -D -L paths\n", argv[0]); X fprintf(stderr, "\tCheck paths for dead NFS servers\n"); X fprintf(stderr, "\tGood paths are printed to stdout\n\n"); X fprintf(stderr, "\t -e\tsilent, do not print paths\n"); X fprintf(stderr, "\t -s\tprint paths in sh format (semicolons)\n"); X fprintf(stderr, "\t -t n\ttimeout interval before assuming an NFS\n"); X fprintf(stderr, "\t\tserver is dead (default 10 seconds)\n"); X fprintf(stderr, "\t -v\tverbose\n"); X fprintf(stderr, "\t -D\tdebug\n"); X fprintf(stderr, "\t -L\texpand symbolic links\n\n"); X exit(1); X } X X for (n = optind; n < argc; ++n) { X s = argv[n]; X if (Dflg) X fprintf(stderr, "chkpath(%s)\n", s); X if (chkpath(s)) { X if (good++ && !eflg) X putchar(sflg ? ':' : ' '); X if (!eflg) X fputs(Lflg ? prefix : s, stdout); X } else X if (vflg) X fprintf(stderr, "path skipped: %s\n", X Lflg ? prefix : s); X } X X if (good && !eflg) X putchar('\n'); X X (void) fflush(stderr); X (void) fflush(stdout); X X exit(good == 0 && optind < argc ); X} X X Xint chkpath(path) X/* X * Check path for accessibility. Return 1 if ok, 0 if error X */ Xchar *path; X{ X extern char *getwd(); X X if (*path != '/') { /* If not absolute path, get initial prefix */ X if (getwd(prefix) == NULL) { X fprintf(stderr, "%s\n", prefix); X return 0; X } X } X return(_chkpath(path)); X} X X X#define NTERMS 256 X Xint X_chkpath(path) Xchar *path; X{ X register char *s, *s2; X register int i, front=0, back=0; X struct stat stb; X struct m_mlist *mlist; X char p[MAXPATHLEN]; X char symlink[MAXPATHLEN]; X char *queue[NTERMS]; X X X /* X * Copy path to working storage X */ X strncpy(p, path, sizeof(p)-1); X X if (*p == '/') { /* If absolute path, start at root */ X *prefix = '\0'; X (void) chdir("/"); X } X X if (Dflg) X fprintf(stderr, "_chkpath(%s) prefix=%s\n", path, prefix); X X /* X * Put directory terms on FIFO queue X */ X for (s = strtok(p, "/"); s != NULL; s = strtok((char *)NULL, "/")) { X if (back >= NTERMS) { X fprintf(stderr, "Too many subdirs: %s\n", path); X goto fail; X } X queue[back++] = s; X } X /* queue[front] = a, queue[front+1] = b, ... queue[back] = null */ X X /* X * Scan queue of directory terms, expanding X * symbolic links recursively. X */ X while (front != back) { X s = queue[front++]; X /* Dot */ X if (s[0] == '.' && s[1] == '\0') X continue; X /* Dot Dot */ X if (s[0] == '.' && s[1] == '.' && s[2] == '\0') { X if (chdir("..") < 0) { X perror("chdir(..)"); X goto fail; X } X /* Remove trailing component of prefix */ X if ((s2 = strrchr(prefix, '/')) != NULL) X *s2 = '\0'; X continue; X } else { X (void) strcat(prefix, "/"); X (void) strcat(prefix, s); X } X X if ((mlist = isnfsmnt(prefix)) != NULL) /* NFS mount? */ X if (chknfsmnt(mlist) <= 0) X return 0; X X /* Check if symlink */ X if (lstat(s, &stb) < 0) { X perror(s); X goto fail; X } X if ((stb.st_mode & S_IFMT) != S_IFLNK) { X /* not symlink */ X if (chdir(s) < 0) { X perror(prefix); X goto fail; X } X continue; X } X X /* Remove symlink from tail of prefix */ X if ((s2 = strrchr(prefix, '/')) != NULL) X *s2 = '\0'; X /* X * Read symlink X */ X if ((i = readlink(s, symlink, MAXPATHLEN-1)) < 0) { X perror(s); X goto fail; X } X symlink[i] = '\0'; /* null terminate */ X X /* X * Recursively check symlink X */ X if (_chkpath(symlink) == 0) X return 0; X } X X return 1; X Xfail: X return 0; X} X X Xstruct m_mlist * Xisnfsmnt(path) X/* X * Return 1 if path is NFS mount point X */ Xchar *path; X{ X register struct m_mlist *mlist; X static int init; X X if (init == 0) { X ++init; X mkm_mlist(); X } X X for (mlist = firstmnt; mlist != NULL; mlist = mlist->mlist_next) { X if (mlist->mlist_isnfs == 0) X continue; X if (strcmp(mlist->mlist_dir, path) == 0) X return(mlist); X } X return NULL; X} X X Xstatic int Xget_inaddr(saddr, host) X/* X * Translate host name to Internet address. X * Return 1 if ok, 0 if error X */ Xstruct sockaddr_in *saddr; Xchar *host; X{ X register struct hostent *hp; X X (void) memset((char *)saddr, 0, sizeof(struct sockaddr_in)); X saddr->sin_family = AF_INET; X if ((saddr->sin_addr.s_addr = inet_addr(host)) == -1) { X if ((hp = gethostbyname(host)) == NULL) { X fprintf(stderr, "%s: unknown host\n", host); X return 0; X } X (void) memcpy((char *)&saddr->sin_addr, hp->h_addr, X hp->h_length); X } X return 1; X} X X Xint Xchknfsmnt(mlist) X/* X * Ping the NFS server indicated by the given mnt entry X */ Xregister struct m_mlist *mlist; X{ X register char *s; X register struct m_mlist *mlist2; X CLIENT *client; X struct sockaddr_in saddr; X int sock, len; X struct timeval tottimeout; X struct timeval interval; X unsigned short port = 0; X struct pmap pmap; X enum clnt_stat rpc_stat; X static char p[MAXPATHLEN]; X X if (Dflg) X fprintf(stderr, "chknfsmnt(%s)\n", mlist->mlist_fsname); X X if (mlist->mlist_checked) /* if already checked this mount point */ X return (mlist->mlist_checked); X X /* X * Save path to working storage and strip colon X */ X (void) strncpy(p, mlist->mlist_fsname, sizeof(p)-1); X if ((s = strchr(p, ':')) != NULL) X *s = '\0'; X len = strlen(p); X X /* X * See if remote host already checked via another mount point X */ X for (mlist2 = firstmnt; mlist2 != NULL; mlist2 = mlist2->mlist_next) X if (strncmp(mlist2->mlist_fsname, p, len) == 0 X && mlist2->mlist_checked) X return(mlist2->mlist_checked); X X mlist->mlist_checked = -1; /* set failed */ X if (vflg) X fprintf(stderr, "Checking %s..\n", p); X interval.tv_sec = 2; /* retry interval */ X interval.tv_usec = 0; X X /* X * Parse internet address X */ X if (get_inaddr(&saddr, p) == 0) X return 0; X /* X * Get socket to remote portmapper X */ X saddr.sin_port = htons(PMAPPORT); X sock = RPC_ANYSOCK; X if ((client = clntudp_create(&saddr, PMAPPROG, PMAPVERS, interval, X &sock)) == NULL) { X clnt_pcreateerror(p); X return 0; X } X /* X * Query portmapper for port # of NFS server X */ X pmap.pm_prog = NFS_PROGRAM; X pmap.pm_vers = NFS_VERSION; X pmap.pm_prot = IPPROTO_UDP; X pmap.pm_port = 0; X tottimeout.tv_sec = timeout; /* total timeout */ X tottimeout.tv_usec = 0; X if ((rpc_stat = clnt_call(client, PMAPPROC_GETPORT, xdr_pmap, &pmap, X xdr_u_short, &port, tottimeout)) != RPC_SUCCESS) { X clnt_perror(client, p); X clnt_destroy(client); X return 0; X } X clnt_destroy(client); X X if (port == 0) { X fprintf(stderr, "%s: NFS server not registered\n", p); X return 0; X } X /* X * Get socket to NFS server X */ X saddr.sin_port = htons(port); X sock = RPC_ANYSOCK; X if ((client = clntudp_create(&saddr, NFS_PROGRAM, NFS_VERSION, X interval, &sock)) == NULL) { X clnt_pcreateerror(p); X return 0; X } X /* X * Ping NFS server X */ X tottimeout.tv_sec = timeout; X tottimeout.tv_usec = 0; X if ((rpc_stat = clnt_call(client, NULLPROC, xdr_void, (char *)NULL, X xdr_void, (char *)NULL, tottimeout)) != RPC_SUCCESS) { X clnt_perror(client, p); X clnt_destroy(client); X return 0; X } X clnt_destroy(client); X mlist->mlist_checked = 1; /* set success */ X if (vflg) X fprintf(stderr, "%s ok\n", p); X return 1; X} X X Xchar * Xxalloc(size) X/* X * Alloc memory with error checks X */ Xint size; X{ X register char *mem; X char *malloc(); X X if ((mem = (char *)malloc((unsigned)size)) == NULL) { X (void) fprintf(stderr, "out of memory\n"); X exit(1); X } X return(mem); X} X X/* X * Begin machine dependent code for mount table X */ X X#if defined(sun) || defined(sgi) X#include Xvoid Xmkm_mlist() X/* X * Build list of mnt entries - Sun version X */ X{ X FILE *mounted; X struct m_mlist *mlist; X struct mntent *mnt; X X if ((mounted = setmntent(MOUNTED, "r"))== NULL) { X perror(MOUNTED); X exit(1); X } X while ((mnt = getmntent(mounted)) != NULL) { X mlist = (struct m_mlist *)xalloc(sizeof(*mlist)); X mlist->mlist_next = firstmnt; X mlist->mlist_checked = 0; X mlist->mlist_dir = xalloc(strlen(mnt->mnt_dir)+1); X (void) strcpy(mlist->mlist_dir, mnt->mnt_dir); X mlist->mlist_fsname = xalloc(strlen(mnt->mnt_fsname)+1); X (void) strcpy(mlist->mlist_fsname, mnt->mnt_fsname); X mlist->mlist_isnfs = !strcmp(mnt->mnt_type, MNTTYPE_NFS); X firstmnt = mlist; X } X (void) endmntent(mounted); X} X#endif X X#if defined(ultrix) X#include X#include Xvoid Xmkm_mlist() X/* X * Build list of mnt entries - Ultrix version X */ X{ X struct m_mlist *mlist; X struct fs_data fs_data; X int start=0, len; X X while ((len = getmnt(&start, &fs_data, sizeof(fs_data), X NOSTAT_MANY, NULL)) > 0) { X mlist = (struct m_mlist *)xalloc(sizeof(*mlist)); X mlist->mlist_next = firstmnt; X mlist->mlist_checked = 0; X mlist->mlist_dir = xalloc(strlen(fs_data.fd_path)+1); X (void) strcpy(mlist->mlist_dir, fs_data.fd_path); X mlist->mlist_fsname = X xalloc(strlen(fs_data.fd_devname)+1); X (void) strcpy(mlist->mlist_fsname, fs_data.fd_devname); X mlist->mlist_isnfs = (fs_data.fd_fstype == GT_NFS); X firstmnt = mlist; X } X if (len < 0) { X perror("getmnt"); X exit(1); X } X} X#endif END_OF_FILE if test 13846 -ne `wc -c <'cknfs.c'`; then echo shar: \"'cknfs.c'\" unpacked with wrong size! fi # end of 'cknfs.c' fi if test -f 'cknfs.man' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'cknfs.man'\" else echo shar: Extracting \"'cknfs.man'\" \(1718 characters\) sed "s/^X//" >'cknfs.man' <<'END_OF_FILE' X.TH CKNFS 1L 06/10/89 NCSA X.SH NAME Xcknfs \- check for dead NFS servers X.SH SYNOPSIS X.B cknfs X[ \fB-esvDL\fR ] [ \fB-t \fItimeout\fR ] [path...] X.SH DESCRIPTION X.I Cknfs Xtakes a list of execution paths. Each path is examined Xfor an NFS mount point. If found, the corresponding NFS server Xis checked. Paths that lead to dead NFS servers are ignored. XThe remaining paths are printed to stdout. X.SS Options X.PP XThe following options are available, X.TP X\fB-e\fR XSilent. Do not print paths. X.TP X\fB-s\fR XPrint paths in X.I sh Xformat, with colons as separators. X.TP X\fB-t \fItimeout\fR XSpecify the timeout interval before assuming an NFS server is dead. XThe default is 10 seconds. X.TP X\fB-v\fR XVerbose. A status message is printed for each NFS server. X.TP X\fB-D\fR XDebug. Messages are printed as the paths are parsed. X.TP X\fB-L\fR XExpand symbolic links on output. This increases the efficiency of shell path Xsearches on machines without a kernel directory name cache. X.sp X.SH EXAMPLES X.sp X.RS Xset path = `/usr/lbin/cknfs /bin /usr/bin /usr/ucb . /usr6/bin /sdg/bin` X.RE X.sp X.RS Xalias cd 'cknfs \-e \e!*; if ($status == 0) chdir \e!*' X.RE X.sp XThe latter example checks the path before performing a X.I chdir Xoperation. X.SH "SEE ALSO" Xnfs(4) X.SH AUTHOR X.nf XAlan Klietz XNational Center for Supercomputing Applications X.fi X.SH BUGS XIn some instances, a Xpath that X.I cknfs Xassumes valid could be vulnerable to hanging if a 3rd party machine Xfails. This happens if your administrator mixes NFS mount points Xand/or regular directories with NFS directories from X3rd party machines. The best organization is an overall X.I /nfs Xdirectory with local subdirectories for each server machine and with Xmount points located therein. END_OF_FILE if test 1718 -ne `wc -c <'cknfs.man'`; then echo shar: \"'cknfs.man'\" unpacked with wrong size! fi # end of 'cknfs.man' fi if test -f 'patchlevel.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'patchlevel.h'\" else echo shar: Extracting \"'patchlevel.h'\" \(190 characters\) sed "s/^X//" >'patchlevel.h' <<'END_OF_FILE' X/* X * $Header: patchlevel.h,v 1.1 89/06/20 21:48:53 aklietz Exp $ X * X * $Log: patchlevel.h,v $ X * Revision 1.1 89/06/20 21:48:53 aklietz X * Initial revision X * X */ X X#define PATCHLEVEL 1 END_OF_FILE if test 190 -ne `wc -c <'patchlevel.h'`; then echo shar: \"'patchlevel.h'\" unpacked with wrong size! fi # end of 'patchlevel.h' fi echo shar: End of shell archive. exit 0