[net.sources.bugs] lln - a routine to list all links to a file

dennis@rlgvax.UUCP (Dennis Bednar) (01/06/87)

I have added a couple of #ifdef's so that the lln.c tool posted
to net.sources should work on 4.2 machines in addition to Sys 5
machines.  Theoretically, all you have to do is define one of
USG, BSD4X, or CCI632, and it should work.  I haved tested it
on the cci632, but have not tried it on a pure 4.2 or 4.3 system.
If you have problems with it, I also added some #ifdef DEBUG code,
which may be enabled by changing the "#undef DEBUG" to "#define
DEBUG 1".

In summary, the changes I made were:

	- the cci632 uses <mtab.h> and /etc/mtab instead of <mnttab.h>
	  and /etc/mnttab.  I assume that the former is 4.2, and the
	  later is pure S5. (Our machine is a Sys5/4.2 hybrid,
	  Sys 5 at the cmd(1) level, some 4.2'isms still hiding under
	  the hood in the kernel.)

	- the cci632 uses 4.2 filesystem with variable length directory
	  entries, instead of 14 char fixed length entries.

	- the cci632 has symbolic links, normally found in 4.2.

Below is only the lln.c file.  Don't forget to remove the trailer
(USENET trailer decapsulation protocol :-) )

------ CUT HERE ---------
/* define your OS type:
 * USG			S3 or S5
 * BSD4X		V7 or 4.2 or 4.3
 * CCI632		Sys5 r2 on CCI Power 6/32
 */
#define CCI632	1

/* the OS type, in turn, defines the lower level #defines that
 * are typical for that system.  If your system is usual,
 * add its type either alongside USG or BSD4X, otherwise if
 * your machine is weird, add it near last #else.
 */
#ifdef USG
#	undef MTAB	/* use /etc/mnttab and mnttab.h */
#	undef BSD_FILESYS	/* use 14 char fix len dir entries */
#	undef BSD_SYMLINK	/* don't have symbolic links */
#else	/* !USG */
/* CCI632 Sys5r2 really has a 4.2 engine under the hood :-) */
#if defined(BSD4X) || defined(CCI632)
#	define MTAB 1		/* have /etc/mtab and mtab.h instead of /etc/mnttab and mnttab.h */
#	define BSD_FILESYS 1	/* have BSD4_2 file system */
#else	/* !BSD4X && !CCI632 && !USG */
	Unknown System.  This causes a compiler error.
#endif /* BSD4X */
#endif /* USG */

#undef DEBUG		/* enables debug code */
#include <sys/types.h>
#include <sys/dir.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
#if defined(MTAB)
#include <fstab.h>
#include <sys/param.h>	/* NMOUNT */
#include <mtab.h>
#define	MNTTAB	mtab
#define MT_FILSYS	m_path
/* MT_FILSYS is field in mtab with directory name */
#else
#include <mnttab.h>
#define MNTTAB	mnttab
#define MT_FILSYS	mt_filsys
#endif
#ifdef BSD_SYMLINK
#define	STAT	lstat
	/* special stat() to handle regular and symbolically linked files */
#else
#define STAT	stat	/* regular old stat() sys call */
#endif
#define BOOL	char


/*
	lln: list links for files

	not (c) 1986 Paul Heffner @ AT&T-IS Altamonte Springs, FL.
		 use it however you wish.

	rlgvax!dennis 01 06 86 Added MTAB, and BSD_FILESYS,
	and BSD_SYMLINK #ifdefs to work on CCI632.
	Enquiries, advice, and calm criticism to:

	ihnp4   \
	akgua   - bsdpkh!heff
	attmail /
*/

#ifdef MTAB
#define MTE_SIZE	sizeof(struct mtab)
#else
#define MTE_SIZE	sizeof(struct mnttab)
#endif
#define DIRESIZ		sizeof(struct direct)
#define PATHMAX	512
#define STR_SAME	!strcmp
#if defined(BSD_FILESYS)
#if !defined(DEBUG)
#define OPENDIR	opendir
#define CLOSEDIR closedir
#else /* debug */
/* use OPENDIR(), CLOSEDIR() debug routines that are default */
/* don't redefine OPENDIR as OPENDIR, because macro recursion expansion */
DIR	*OPENDIR();	/* fw ref */
void	CLOSEDIR();	/* fw ref */
#endif
#endif
char	*u_errmesg();	/* fw ref - return perror() like string */

extern int errno;

/*
	program globals
*/
static int inn;		/* inode number of file being searched for... */
static int found;	/* count of found directory entries.. */
static int need;	/* count of directory entries to find.. */
static int curdev;	/* device # of disk holding fs of objective file. */
static char pathbuf[PATHMAX];	/* holds current search path */

main(argc,argv)
int argc;
char **argv;
{
#ifdef MTAB
static char *mtfil = "/etc/mtab";
#else
static char *mtfil = "/etc/mnttab";
#endif
	struct stat ssfil, junk1, junk2, ssfs;
	/* junk1, junk2 are dummy vars because lstat() would write
	 * past end of ssfil into ssfs, and corrupt it otherwise.
	 * lstat(2) bug on rlgvax!!!
	 */
	struct MNTTAB mte;
	int i, mth, x;
#ifdef	BSD_FILESYS
	DIR	*dirfd;
#else
	int	dirfd;		/* 14 char fixed length directory entries */
#endif

	if (argc < 2) exit(0);

	fclose(stdin);	/* free up an extra fd (just in case) */

	if ((mth = open(mtfil,O_RDONLY)) == -1)
	{	fprintf(stderr,"%s: errno %d, cannot open %s\n",argv[0],errno,mtfil);
		exit(16);
	}
#ifdef DEBUG
	printf("opened mount table file okay\n");
#endif
	for (i = 1; i < argc; ++i)
	{
		if (STAT(argv[i],&ssfil))
		{	fprintf(stderr,"%s:errno %d can not access %s\n",argv[0],errno,argv[i]);
			continue;
		}
		if ((ssfil.st_mode & S_IFMT) == S_IFDIR)
		{	fprintf(stderr,"%s: %s is a directory file.\n",argv[0],argv[i]);
			continue;
		}
		inn = ssfil.st_ino;	/* establish search inode number */
		found = 0;		/* set count of # found */
		need = ssfil.st_nlink;	/* set count of # of links */
		curdev = ssfil.st_dev;	/* # of device holding file */
#ifdef DEBUG
		printf("lln: debug: dev = %d, inode = %d, links = %d\n",
		curdev, inn, need);
#endif

/*
	Scratch through mount table looking for fs hosting file
	seeking a match on device number...
*/

		for (x = 0; x < NMOUNT; ++x)
		{	if (read(mth,&mte,MTE_SIZE) != MTE_SIZE)
			{	fprintf(stderr,"%s: errno %d reading mnttab\n",argv[0],errno);
				exit(32);
			}
			STAT(mte.MT_FILSYS,&ssfs);	/* name of directory mounted as */
#ifdef DEBUG
			printf("lln: debug: Looking at mounted dir %s\n", mte.MT_FILSYS);
			printf(" st_dev=%d, st_rdev=%d, want dev # = %d\n", ssfs.st_dev, ssfs.st_rdev, curdev);
#endif	/* debug */
			if (ssfs.st_dev == ssfil.st_dev) break;
#ifdef DEBUG
			else printf("debug: wrong dir (%d != %d)\n", 
			ssfs.st_dev, ssfil.st_dev);
#endif
		}

#ifdef DEBUG
		printf("lln: debug: found mounted dir starting point\n");
#endif

/*
	The path name is constructed in 'pathbuf'.
	We start with mounted directory from /etc/mnttab entry...
*/
#ifdef BSD_FILESYS
		strncpy(pathbuf,mte.MT_FILSYS,strlen(mte.MT_FILSYS)+1);
#else
		strncpy(pathbuf,mte.MT_FILSYS,14);
#endif
#ifdef DEBUG
		printf("lln: debug: search starting at mounted dir %s\n", pathbuf);
#endif
		if (pathbuf[1] == '\0') pathbuf[0] = '\0';	/* special case for root fs (avoids // at front of path) */
		if (chdir(mte.MT_FILSYS) == -1)
			{
			fprintf(stderr, "lln: chdir(%s) failed\n", mte.MT_FILSYS);
			exit(1);
			}
#ifdef BSD_FILESYS
		if ((dirfd = OPENDIR(mte.MT_FILSYS)) == (DIR *)NULL)
#else
		if ((dirfd = open(mte.MT_FILSYS,O_RDONLY)) == -1)
#endif
		{	fprintf(stderr,"%s: errno %d opening %s\n",argv[0],errno,mte.MT_FILSYS);
			exit(-1);
		}
		if (lnsrch(dirfd))
			fprintf(stderr,"%s incomplete list: only %d of %d links were found.\n",argv[0],found,need);
#ifdef BSD_FILESYS
		CLOSEDIR(dirfd);
#else
		close(dirfd);
#endif
		lseek(mth,0L,0);	/* reset to beginning of mnttab */
	}
	close(mth);
	exit(0);
}

lnsrch(dirfd)
#ifdef BSD_FILESYS
	DIR	*dirfd;
#else
int dirfd;
#endif
{	struct stat curf;
#ifdef BSD_FILESYS
	struct direct *cd;
	DIR	*newdfd;
#else
	struct direct cd;
	int newdfd;
#endif
	char *pathend;
	BOOL	isdir;
#ifdef BSD_SYMLINK
	BOOL	issymlink;
#endif

#ifdef BSD_FILESYS
	/* skip over . and .. in read loop of directory */
#else
	lseek(dirfd,(long) (DIRESIZ << 1),0);	/* go past . and .. */
	/* BUG FIX (long) added for mchs with diff size int & long. rlgvax!dennis */
#endif
#ifdef BSD_FILESYS
	while (cd = readdir(dirfd) )
	{
		if (STR_SAME(cd->d_name, ".") || STR_SAME(cd->d_name, "..") )
			continue;	/* skip . and .. entries */
		if (STAT(cd->d_name,&curf))
		{	fprintf(stderr,"lln: stat error %s/%s\n",pathbuf,cd->d_name);
#else
	while (read(dirfd,&cd,DIRESIZ) == DIRESIZ)	/* bug fix - don't let -1 be okay, rlgvax!dennis */
	{
	if (!cd.d_ino) continue;	/* skip empty entries (i = 0) */
		if (STAT(cd.d_name,&curf))
		{	fprintf(stderr,"lln: stat error %s/%s\n",pathbuf,cd.d_name);
#endif
			continue;
		}
		isdir =  ((curf.st_mode & S_IFMT) == S_IFDIR);
#ifdef BSD_SYMLINK
		issymlink = ((curf.st_mode & S_IFMT) == S_IFLNK);
		if (isdir && issymlink)
			continue;	/* avoid infinite recursion */
		/* recursion when /a/b/c symlinked to /a */
#endif
		if ( isdir )		/* sub-dir?? */
		{
/*
	ignore MT directories and keep search to objective fs (dev)
*/
#ifdef BSD_FILSYS
			if (curf.st_dev != curdev) continue; /* diff mount point */
#else
			if (curf.st_size == (2*DIRESIZ) || /* . && .. ie dir empty */
			    curf.st_dev != curdev) continue; /* wrong mount pt */
#endif

#ifdef BSD_FILESYS
#ifdef DEBUG
			/* track down cannot visit problem */
			printf("Will OPENDIR(%s) Current directory is ", cd->d_name);
			fflush(stdout);
			system("pwd");
#endif
			if ((newdfd = OPENDIR(cd->d_name)) == (DIR *)NULL)
			{	fprintf(stderr,"lln: Can't open %s/%s: %s\n",pathbuf,cd->d_name, u_errmesg());
#else
			if ((newdfd = open(cd.d_name,O_RDONLY)) == -1)
			{	fprintf(stderr,"lln: Can't open %s/%s\n",pathbuf,cd.d_name);
#endif
				continue;
			}
/*
	Maintain current path in pathbuf global area
*/
			for (pathend = pathbuf; *pathend; ++pathend) ;
			*pathend = '/';
#ifdef BSD_FILESYS
			strncpy(pathend + 1,cd->d_name,cd->d_namlen + 1);
			chdir(cd->d_name);
#else /* !bsd_filsys */
			strncpy(pathend + 1,cd.d_name,14);
			chdir(cd.d_name);
#endif
#ifdef DEBUG
			printf("lln: debug: visiting %s\n", pathbuf);
#endif /* debug */
			if (!lnsrch(newdfd))
				{
#ifdef BSD_FILESYS
#ifdef DEBUG
				printf("WILL CLOSEDIR\n");
#endif
				CLOSEDIR(newdfd);
#else
				close(newdfd);
#endif
				return 0;	/* recursively return 0 if all were found */
				}
#ifdef BSD_FILESYS
#ifdef DEBUG
			printf("WILL CLOSEDIR()!\n");
#endif
			CLOSEDIR(newdfd);
#else
			close(newdfd);
#endif
			chdir("..");
			*pathend = '\0';
			continue;
		}

#ifdef DEBUG
		else
			printf("debug: reg file: %s/%s\n", pathbuf,
#ifdef BSD_FILESYS
			cd->d_name);
#else
			cd.d_name);
#endif /* bsd */
#endif /* debug */

#ifdef BSD_FILESYS
		if (cd->d_ino == inn)	/* Print out path on match!! */
		{	printf("%s/%.14s\n",pathbuf,cd->d_name);
#else
		if (cd.d_ino == inn)	/* Print out path on match!! */
		{	printf("%s/%.14s\n",pathbuf,cd.d_name);
#endif
			if (++found == need) return 0;
		}
	}
	return -1;
}


#if defined(BSD_FILESYS) && defined(DEBUG)
/*
 * OPENDIR and CLOSEDIR are debug routines instead of the
 * regular OPENDIR(), CLOSEDIR() routines.  It is used
 * to help track down a problem that I think is "too many
 * files open".
 */

static	open_count = 0;		/* number of open files */
#define MAXFILES _NFILE+1	/* one extra for precaution */
static	char	*fname[MAXFILES];	/* file names, fname[0] is first file name */
static	DIR	*fptr[MAXFILES];	/* store DIR * ptrs in parellel w fname[] */

/*
 * the array fname[] is needed since we cannot derive the directory
 * name when we are closing it.
 */

DIR *
OPENDIR(name)
	char	*name;
{
	DIR	*dirp;
	char	*str_malloc();	/* fw ref */

	fname[open_count] = str_malloc(name);
	dirp = opendir(name);
	fptr[ open_count ] = dirp;
	++open_count;
	printf("OPENDIR(%s) %d\n", name, open_count);	/* number open *after* open */
	return (dirp);
}

void
CLOSEDIR( dirp )
	DIR	*dirp;
{
	int	i;
	if (open_count < 1 )	/* nothing open now */
		error("CLOSEDIR without OPENDIR");

	/* must check all slots, not just first open_count,
	 * because of "holes" in middle!!! */
	for (i = 0; i < MAXFILES; ++i)
		if (dirp == fptr[i])
			break;	/* found ptr */
	if (i >= MAXFILES)
		error("not found in table");
	--open_count;
	printf("CLOSEDIR(%s) %d\n", fname[i], open_count);
	free( fname[i]);
	return;
}

/*
 * malloc space for a string and copy it in
 * return ptr to malloc'd string
 */
char	*
str_malloc( s )
	char	*s;
{
	extern	char	*malloc();
	char	*cp;
	cp = malloc( strlen(s) + 1);
	if (!cp )
		error("out of space");
	strcpy( cp, s );
	return cp;
}

error(msg)
	char	*msg;
{
	fprintf(stderr, "%s\n", msg);
	exit (1);
}
#endif /* bsd && debug */

/*
 * return UNIX error message associated with errno
 * more flexible than perror(3)
 */

char *
u_errmesg()
{
	extern	int	errno;
	extern	int	sys_nerr;
	extern	char	*sys_errlist[];
static	char	buffer[50];	/* don't loose it !!! */

	if (errno < 0 || errno >= sys_nerr)
		{
		sprintf( buffer, "errno %d undefined (%d=max)", errno, sys_nerr);
		return(buffer);
		}

	return( sys_errlist[errno] );
}
-- 
-Dennis Bednar
{decvax,ihnp4,harpo,allegra}!seismo!rlgvax!dennis	UUCP

tim@dciem.UUCP (Tim Pointing) (01/08/87)

Despite the comment near the top of the source for the new version on lln.c
recently posted, lln does not run under V7. Below is a patch to allow lln
to run under V7. It will also allow lln to find files on the root filesystem
on systems which do not have an entry for the root filesystem in the
mount table. There are also some fixes which cause lln to gracefully bypass
directories which allow read (i.e. open) but not search (i.e. chdir).

-------------CUT-HERE------------------------------CUT-HERE---------------
*** lln.c.dist	Thu Jan  8 09:02:23 1987
--- lln.c	Thu Jan  8 10:33:04 1987
***************
*** 1,6
  /* define your OS type:
   * USG			S3 or S5
!  * BSD4X		V7 or 4.2 or 4.3
   * CCI632		Sys5 r2 on CCI Power 6/32
   */
  #define CCI632	1

--- 1,7 -----
  /* define your OS type:
   * USG			S3 or S5
!  * BSD4X		4.2 or 4.3
!  * V7			V7
   * CCI632		Sys5 r2 on CCI Power 6/32
   */
  
***************
*** 3,9
   * BSD4X		V7 or 4.2 or 4.3
   * CCI632		Sys5 r2 on CCI Power 6/32
   */
- #define CCI632	1
  
  /* the OS type, in turn, defines the lower level #defines that
   * are typical for that system.  If your system is usual,

--- 4,9 -----
   * V7			V7
   * CCI632		Sys5 r2 on CCI Power 6/32
   */
  
  /* the OS type, in turn, defines the lower level #defines that
   * are typical for that system.  If your system is usual,
***************
*** 20,25
  #	define MTAB 1		/* have /etc/mtab and mtab.h instead of /etc/mnttab and mnttab.h */
  #	define BSD_FILESYS 1	/* have BSD4_2 file system */
  #else	/* !BSD4X && !CCI632 && !USG */
  	Unknown System.  This causes a compiler error.
  #endif /* BSD4X */
  #endif /* USG */

--- 20,28 -----
  #	define MTAB 1		/* have /etc/mtab and mtab.h instead of /etc/mnttab and mnttab.h */
  #	define BSD_FILESYS 1	/* have BSD4_2 file system */
  #else	/* !BSD4X && !CCI632 && !USG */
+ #if defined(V7)
+ #	define MTAB 1		/* have /etc/mtab but no mtab.h */
+ #else	/* !BSD4X && !CCI632 && !USG && !V7 */
  	Unknown System.  This causes a compiler error.
  #endif /* V7 */
  #endif /* BSD4X */
***************
*** 21,26
  #	define BSD_FILESYS 1	/* have BSD4_2 file system */
  #else	/* !BSD4X && !CCI632 && !USG */
  	Unknown System.  This causes a compiler error.
  #endif /* BSD4X */
  #endif /* USG */
  

--- 24,30 -----
  #	define MTAB 1		/* have /etc/mtab but no mtab.h */
  #else	/* !BSD4X && !CCI632 && !USG && !V7 */
  	Unknown System.  This causes a compiler error.
+ #endif /* V7 */
  #endif /* BSD4X */
  #endif /* USG */
  
***************
*** 29,34
  #include <sys/dir.h>
  #include <sys/stat.h>
  #include <stdio.h>
  #include <fcntl.h>
  #if defined(MTAB)
  #include <fstab.h>

--- 33,39 -----
  #include <sys/dir.h>
  #include <sys/stat.h>
  #include <stdio.h>
+ #if !defined(V7)
  #include <fcntl.h>
  #else
  #define O_RDONLY	(0)
***************
*** 30,35
  #include <sys/stat.h>
  #include <stdio.h>
  #include <fcntl.h>
  #if defined(MTAB)
  #include <fstab.h>
  #include <sys/param.h>	/* NMOUNT */

--- 35,43 -----
  #include <stdio.h>
  #if !defined(V7)
  #include <fcntl.h>
+ #else
+ #define O_RDONLY	(0)
+ #endif /* V7 */
  #if defined(MTAB)
  #if !defined(V7)
  #include <fstab.h>
***************
*** 31,36
  #include <stdio.h>
  #include <fcntl.h>
  #if defined(MTAB)
  #include <fstab.h>
  #include <sys/param.h>	/* NMOUNT */
  #include <mtab.h>

--- 39,45 -----
  #define O_RDONLY	(0)
  #endif /* V7 */
  #if defined(MTAB)
+ #if !defined(V7)
  #include <fstab.h>
  #include <sys/param.h>	/* NMOUNT */
  #include <mtab.h>
***************
*** 34,39
  #include <fstab.h>
  #include <sys/param.h>	/* NMOUNT */
  #include <mtab.h>
  #define	MNTTAB	mtab
  #define MT_FILSYS	m_path
  /* MT_FILSYS is field in mtab with directory name */

--- 43,56 -----
  #include <fstab.h>
  #include <sys/param.h>	/* NMOUNT */
  #include <mtab.h>
+ #else /* V7 */
+ #	define NAMSIZ	32
+ #	define NMOUNT	16
+ struct mtab {
+ 	char m_path[NAMSIZ];
+ 	char m_dev[NAMSIZ];
+ };
+ #endif /* V7 */
  #define	MNTTAB	mtab
  #define MT_FILSYS	m_path
  /* MT_FILSYS is field in mtab with directory name */
***************
*** 119,124
  #else
  	int	dirfd;		/* 14 char fixed length directory entries */
  #endif
  
  	if (argc < 2) exit(0);
  

--- 136,142 -----
  #else
  	int	dirfd;		/* 14 char fixed length directory entries */
  #endif
+ 	int nread, mount_found;
  
  	if (argc < 2) exit(0);
  
***************
*** 155,160
  	seeking a match on device number...
  */
  
  		for (x = 0; x < NMOUNT; ++x)
  		{	if (read(mth,&mte,MTE_SIZE) != MTE_SIZE)
  			{	fprintf(stderr,"%s: errno %d reading mnttab\n",argv[0],errno);

--- 173,180 -----
  	seeking a match on device number...
  */
  
+ 		mount_found = 0;	/* haven't fount the mount dir yet */
+ 
  		for (x = 0; x < NMOUNT; ++x)
  		{	nread = read(mth,&mte,MTE_SIZE);
  			if (nread != MTE_SIZE && nread != 0)
***************
*** 156,163
  */
  
  		for (x = 0; x < NMOUNT; ++x)
! 		{	if (read(mth,&mte,MTE_SIZE) != MTE_SIZE)
! 			{	fprintf(stderr,"%s: errno %d reading mnttab\n",argv[0],errno);
  				exit(32);
  			}
  			STAT(mte.MT_FILSYS,&ssfs);	/* name of directory mounted as */

--- 176,185 -----
  		mount_found = 0;	/* haven't fount the mount dir yet */
  
  		for (x = 0; x < NMOUNT; ++x)
! 		{	nread = read(mth,&mte,MTE_SIZE);
! 			if (nread != MTE_SIZE && nread != 0)
! 			{
! 				fprintf(stderr,"%s: errno %d reading mnttab\n",argv[0],errno);
  				exit(32);
  			}
  			STAT(mte.MT_FILSYS,&ssfs);	/* name of directory mounted as */
***************
*** 165,171
  			printf("lln: debug: Looking at mounted dir %s\n", mte.MT_FILSYS);
  			printf(" st_dev=%d, st_rdev=%d, want dev # = %d\n", ssfs.st_dev, ssfs.st_rdev, curdev);
  #endif	/* debug */
! 			if (ssfs.st_dev == ssfil.st_dev) break;
  #ifdef DEBUG
  			else printf("debug: wrong dir (%d != %d)\n", 
  			ssfs.st_dev, ssfil.st_dev);

--- 187,197 -----
  			printf("lln: debug: Looking at mounted dir %s\n", mte.MT_FILSYS);
  			printf(" st_dev=%d, st_rdev=%d, want dev # = %d\n", ssfs.st_dev, ssfs.st_rdev, curdev);
  #endif	/* debug */
! 			if (ssfs.st_dev == ssfil.st_dev)
! 			{
! 				mount_found = 1;
! 				break;
! 			}
  #ifdef DEBUG
  			else printf("debug: wrong dir (%d != %d)\n", 
  			ssfs.st_dev, ssfil.st_dev);
***************
*** 171,176
  			ssfs.st_dev, ssfil.st_dev);
  #endif
  		}
  
  #ifdef DEBUG
  		printf("lln: debug: found mounted dir starting point\n");

--- 197,218 -----
  			ssfs.st_dev, ssfil.st_dev);
  #endif
  		}
+ 		if (!mount_found)
+ 		{
+ 			strcpy(mte.MT_FILSYS, "/");
+ 			STAT(mte.MT_FILSYS,&ssfs);
+ #ifdef DEBUG
+ 			printf("lln: debug: Looking at mounted dir %s\n", mte.MT_FILSYS);
+ 			printf(" st_dev=%d, st_rdev=%d, want dev # = %d\n", ssfs.st_dev, ssfs.st_rdev, curdev);
+ #endif	/* debug */
+ 			if (ssfs.st_dev == ssfil.st_dev)
+ 			{
+ 				mount_found = 1;
+ 			}
+ #ifdef DEBUG
+ 			else printf("debug: wrong dir (%d != %d)\n", 
+ 			ssfs.st_dev, ssfil.st_dev);
+ #endif
  
  		}
  		if (!mount_fount)
***************
*** 172,177
  #endif
  		}
  
  #ifdef DEBUG
  		printf("lln: debug: found mounted dir starting point\n");
  #endif

--- 214,226 -----
  			ssfs.st_dev, ssfil.st_dev);
  #endif
  
+ 		}
+ 		if (!mount_fount)
+ 		{
+ 			fprintf(stderr, "lln: cannot find mount point of file system containing file '%s'\n", argv[i]);
+ 			continue;
+ 		}
+ 
  #ifdef DEBUG
  		printf("lln: debug: found mounted dir starting point\n");
  #endif
***************
*** 298,304
  			*pathend = '/';
  #ifdef BSD_FILESYS
  			strncpy(pathend + 1,cd->d_name,cd->d_namlen + 1);
! 			chdir(cd->d_name);
  #else /* !bsd_filsys */
  			strncpy(pathend + 1,cd.d_name,14);
  			chdir(cd.d_name);

--- 347,353 -----
  			*pathend = '/';
  #ifdef BSD_FILESYS
  			strncpy(pathend + 1,cd->d_name,cd->d_namlen + 1);
! 			if (chdir(cd->d_name) < 0)
  #else /* !bsd_filsys */
  			strncpy(pathend + 1,cd.d_name,14);
  			if (chdir(cd.d_name))
***************
*** 301,307
  			chdir(cd->d_name);
  #else /* !bsd_filsys */
  			strncpy(pathend + 1,cd.d_name,14);
! 			chdir(cd.d_name);
  #endif
  #ifdef DEBUG
  			printf("lln: debug: visiting %s\n", pathbuf);

--- 350,356 -----
  			if (chdir(cd->d_name) < 0)
  #else /* !bsd_filsys */
  			strncpy(pathend + 1,cd.d_name,14);
! 			if (chdir(cd.d_name))
  #endif
  			{
  				fprintf(stderr, "lln: cannot chdir to %s\n",
***************
*** 303,308
  			strncpy(pathend + 1,cd.d_name,14);
  			chdir(cd.d_name);
  #endif
  #ifdef DEBUG
  			printf("lln: debug: visiting %s\n", pathbuf);
  #endif /* debug */

--- 352,367 -----
  			strncpy(pathend + 1,cd.d_name,14);
  			if (chdir(cd.d_name))
  #endif
+ 			{
+ 				fprintf(stderr, "lln: cannot chdir to %s\n",
+ 				pathbuf);
+ #ifdef BSD_FILESYS
+ 				CLOSEDIR(newdfd);
+ #else
+ 				close(newdfd);
+ #endif
+ 				continue;
+ 			}
  #ifdef DEBUG
  			printf("lln: debug: visiting %s\n", pathbuf);
  #endif /* debug */
-- 
	Tim Pointing, DCIEM
	   {decvax|ihnp4|watmath}!utzoo!dciem!tim
	or uw-beaver!utcsri!dciem!tim
        or seismo!mnetor!lsuc!dciem!tim