training

Code I wrote during training
git clone git://git.bitsmanent.org/training
Log | Files | Refs | README

ex-4.12.c (3644B)


      1 /*
      2  * Advanced Programming in the UNIX(r) Environment
      3  *
      4  * Exercise 4.12
      5 */
      6 
      7 #include	<sys/types.h>
      8 #include	<sys/stat.h>
      9 #include	<dirent.h>
     10 #include	<limits.h>
     11 
     12 #include	"ourhdr.h"
     13 
     14 typedef	int	Myfunc(const char *, const struct stat *, int);
     15 				/* function type that's called for each filename */
     16 
     17 static Myfunc	myfunc;
     18 static int	myftw(char *filename, Myfunc* func);
     19 
     20 static long	nreg, ndir, nblk, nchr, nfifo, nslink, nsock, ntot;
     21 
     22 int
     23 main(int argc, char *argv[])
     24 {
     25 	int		ret;
     26 
     27 	if (argc != 2)
     28 		err_quit("usage:  ftw  <starting-pathname>");
     29 
     30 	ret = myftw(argv[1], myfunc);		/* does it all */
     31 
     32 	if ( (ntot = nreg + ndir + nblk + nchr + nfifo + nslink + nsock) == 0)
     33 		ntot = 1;		/* avoid divide by 0; print 0 for all counts */
     34 	printf("regular files  = %7ld, %5.2f %%\n", nreg,  nreg*100.0/ntot);
     35 	printf("directories    = %7ld, %5.2f %%\n", ndir,  ndir*100.0/ntot);
     36 	printf("block special  = %7ld, %5.2f %%\n", nblk,  nblk*100.0/ntot);
     37 	printf("char special   = %7ld, %5.2f %%\n", nchr,  nchr*100.0/ntot);
     38 	printf("FIFOs          = %7ld, %5.2f %%\n", nfifo, nfifo*100.0/ntot);
     39 	printf("symbolic links = %7ld, %5.2f %%\n", nslink,nslink*100.0/ntot);
     40 	printf("sockets        = %7ld, %5.2f %%\n", nsock, nsock*100.0/ntot);
     41 
     42 	exit(ret);
     43 }
     44 
     45 /*
     46  * Descend through the hierarchy, starting at "pathname".
     47  * The caller's func() is called for every file.
     48  */
     49 
     50 #define	FTW_F	1		/* file other than directory */
     51 #define	FTW_D	2		/* directory */
     52 #define	FTW_DNR	3		/* directory that can't be read */
     53 #define	FTW_NS	4		/* file that we can't stat */
     54 
     55 /*
     56  * Descend through the hierarchy, starting at "filename".
     57  * If "filename" is anything other than a directory, we lstat() it,
     58  * call func(), and return.  For a directory, we call ourself
     59  * recursively for each name in the directory.
     60  */
     61 static int					/* we return whatever func() returns */
     62 myftw(char *filename, Myfunc* func)
     63 {
     64 	struct stat		statbuf;
     65 	struct dirent		*dirp;
     66 	DIR			*dp;
     67 	int			ret;
     68 
     69 	if (lstat(filename, &statbuf) < 0)
     70 		return(func(filename, NULL, FTW_NS));	/* stat error */
     71 
     72 	if (S_ISDIR(statbuf.st_mode) == 0)
     73 		return(func(filename, &statbuf, FTW_F));	/* not a directory */
     74 
     75 	/*
     76 	 * It's a directory.  First call func() for the directory,
     77 	 * then process each filename in the directory.
     78 	 */
     79 
     80 	if ( (ret = func(filename, NULL, FTW_D)) != 0)
     81 		return(ret);
     82 
     83 	if ( (dp = opendir(filename)) == NULL)
     84 		return(func(filename, NULL, FTW_DNR));
     85 
     86 	if( chdir(filename) == -1 ) /* enter the directory */
     87 		return(func(filename, NULL, FTW_DNR));
     88 
     89 	while ( (dirp = readdir(dp)) != NULL) {
     90 		if (strcmp(dirp->d_name, ".") == 0  ||
     91 		    strcmp(dirp->d_name, "..") == 0)
     92 				continue;		/* ignore dot and dot-dot */
     93 
     94 		if ( (ret = myftw(dirp->d_name, func)) != 0) 	/* recursive */
     95 	  		break;	/* time to leave */
     96 
     97 	}
     98 
     99 	if (closedir(dp) < 0)
    100 		err_ret("can't close directory %s", filename);
    101 
    102 	chdir(".."); /* back to the parent directory */
    103 
    104 	return(ret);
    105 }
    106 
    107 static int
    108 myfunc(const char *pathname, const struct stat *statptr, int type)
    109 {
    110 	switch (type) {
    111 	case FTW_F:
    112 		switch (statptr->st_mode & S_IFMT) {
    113 		case S_IFREG:	nreg++;		break;
    114 		case S_IFBLK:	nblk++;		break;
    115 		case S_IFCHR:	nchr++;		break;
    116 		case S_IFIFO:	nfifo++;	break;
    117 		case S_IFLNK:	nslink++;	break;
    118 		case S_IFSOCK:	nsock++;	break;
    119 		case S_IFDIR:
    120 			err_dump("for S_IFDIR for %s", pathname);
    121 					/* directories should have type = FTW_D */
    122 		}
    123 		break;
    124 
    125 	case FTW_D:
    126 		ndir++;
    127 		break;
    128 
    129 	case FTW_DNR:
    130 		err_ret("can't read directory %s", pathname);
    131 		break;
    132 
    133 	case FTW_NS:
    134 		err_ret("stat error for %s", pathname);
    135 		break;
    136 
    137 	default:
    138 		err_dump("unknown type %d for pathname %s", type, pathname);
    139 	}
    140 
    141 	return(0);
    142 }