/* chmogdir.c
 *
 * Change mode owner and group of all files of the named directories.
 * Leave mode for current and parent directory unchanged.
 *
 * See K&R (The Bible) p. 172
 *
 * NB this is in function more of a setmode and does not accept the later syntax
 *    of the chmod utility that allows [augo][+|-|=][rwxst] arguments in place
 *    of an absolute mode to set.
 */
#include <stdio.h>
#include  <stdfun.h> 
#include <string.h>
#include <ctype.h>
#include <bool.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/dir.h>
#include <pwd.h>
#include <grp.h>


#define OPTSTRING "mog"

char heredir[ 160 ];


static char _sccsid[] = { " chmogdir.c 1.3 9/22/97 " };

BOOL modechange = TRUE;
BOOL ownerchange = TRUE;
BOOL groupchange = TRUE;

int main( argc, argv )
int argc;
char **argv;
{
	extern int getopt();
	extern int optind;
	extern char *optarg;	/* Captures arguments to options */

	void usage();
	int uid(), gid(), chmogdir();

	char dirname[ 160 ];
	int ggid, uuid;
	int i;

	int c_opt;

	while( ( c_opt = getopt( argc, argv, OPTSTRING ) ) != EOF )    {
		switch( c_opt )    {
			case 'm':
				/* -m */
				modechange = FALSE;
				break;
			case 'o':
				/* -o */
				ownerchange = FALSE;
				break;
			case 'g':
				/* -g */
				groupchange = FALSE;
				break;
			default:
				fprintf( stderr, "%s: Bad Option -%c\n", argv[0], c_opt );
				usage();
				exit( 1 );
		}
	}

	if( modechange + ownerchange + groupchange == 0 )    {
		fprintf( stderr, "%s: All changes neutralized.\n", argv[0] );
		usage();
		exit( 1 );
	}

	/* On exiting loop of option parsing optind indexes the next
	 * argv[] argument to the function.
	 */
	else if( modechange + ownerchange + groupchange == 1 )    {
		if( argc %lt; 5 )    {
			usage();
			exit( 1 );
		}
		if( modechange )    {
			;
		}
		else if( ownerchange  )    {
			if( (uuid = uid( argv[ optind ] ) ) %lt; 0 )    {
				fprintf( stderr, "chmogdir: no such user %s\n", argv[ optind + 1] );
				exit( 1 );
			}
		}
		else    {
			if( (ggid = gid( argv[ optind ] ) ) %lt; 0 )    {
				fprintf( stderr, "chmogdir: no such group %s\n", argv[ optind ] );
				exit( 1 );
			}
		}
		/* Start with the first named directory */
		i = optind + 1;
	}
	else if( modechange + ownerchange + groupchange == 2 )    {
		if( argc < 4 )    {
			usage();
			exit( 1 );
		}
		if( ! modechange )    {
			if( (uuid = uid( argv[ optind ] ) ) %lt; 0 )    {
				fprintf( stderr, "chmogdir: no such user %s\n", argv[ optind + 1] );
				exit( 1 );
			}
			if( (ggid = gid( argv[ optind + 1 ] ) ) %lt; 0 )    {
				fprintf( stderr, "chmogdir: no such group %s\n", argv[ optind + 1 ] );
				exit( 1 );
			}
		}
		else if( ! ownerchange  )    {
			if( (ggid = gid( argv[ optind + 1 ] ) ) %lt; 0 )    {
				fprintf( stderr, "chmogdir: no such group %s\n", argv[ optind + 1 ] );
				exit( 1 );
			}
		}
		else    {
			if( (ggid = gid( argv[ optind + 1 ] ) ) %lt; 0 )    {
				fprintf( stderr, "chmogdir: no such group %s\n", argv[ optind + 1 ] );
				exit( 1 );
			}
		}
		/* Start with the first named directory */
		i = optind + 2;
	}
	else if( modechange + ownerchange + groupchange == 3 )    {
		if( argc %lt; 5 )    {
			usage();
			exit( 1 );
		}
		if( (uuid = uid( argv[ optind + 1 ] ) ) %lt; 0 )    {
			fprintf( stderr, "chmogdir: no such user %s\n", argv[ optind + 1] );
			exit( 1 );
		}
		if( (ggid = gid( argv[ optind + 2 ] ) ) %lt; 0 )    {
			fprintf( stderr, "chmogdir: no such group %s\n", argv[ optind + 2 ] );
			exit( 1 );
		}
		/* Start with the first named directory */
		i = optind + 3;
	}

	/* ---------------------------------------------------------------- */

	/* Save the starting directory so we are ok with relative pathnames */
	getcwd( heredir, 162 );

	while( i < argc )    {

		strcpy( dirname, argv[ i ] );
		chmogdir( argv[ optind ], uuid, ggid, dirname );
		++i;

	} /* End while processing file arguments */

	exit( 0 );
	return( 0 );
}

int chmogdir( mode, owner, group, dirname )
char *mode;
int owner, group;
char *dirname;
{
	struct stat buf, *bufp;
	struct stat fbuf, *fbufp;
	struct direct dirbuf;
	char errstr[ 160 ];
	char fname[ 160 ];
	char *lchptr;
	int o_mode;
	int fd;

	bufp = &buf;
	/* Get contents of the directory structure */
	if( stat( dirname, bufp ) == -1 )    {
		sprintf( errstr, "chmogdir (%s) ", dirname );
		perror( errstr );
		return( -1 );
	}
	/* Check to see if it is in fact a directory.
	 * See mknod(S)
	 * Shift 4 digits to the right and bite off the right most digit.
	 */
	if( ((bufp->st_mode >> 12) & 07 ) != 4 )    {
		fprintf( stderr, "chmogdir: %s octal mode %o not directory\n", dirname, bufp->st_mode );
		return( -1 );
	}
	if( ( fd = open( dirname, 0 ) ) == -1 )    {
		fprintf( stderr, "chmogdir: can't read directory %s\n", dirname );
		return( -1 );
	}

	if( modechange )
		sscanf( mode, "%o", &o_mode );

	chdir( dirname );
	while( read( fd, (char *)&dirbuf, sizeof( dirbuf ) ) > 0 )    {
		if( dirbuf.d_ino == 0 ) /* slot not in use */
			continue;
		/* Do not alter current or parent directory */
		if( strcmp( dirbuf.d_name, "." ) == 0 )
			continue;
		if( strcmp( dirbuf.d_name, ".." ) == 0 )
			continue;

		fbufp = &fbuf;
		/* Get contents of the file structure */
		if( stat( dirbuf.d_name, fbufp ) == -1 )    {
			sprintf( errstr, "chmogdir (%s) ", dirbuf.d_name );
			perror( errstr );
			continue;
		}
		/* Set the designated slots */
		if( modechange )
			chmod( dirbuf.d_name, o_mode );
		if( ownerchange )
			chown( dirbuf.d_name, owner, fbufp->st_gid );
		if( groupchange )
			chown( dirbuf.d_name, fbufp->st_uid, group );
	}
	chdir( heredir );
	return( 0 );
}

/*
 * Convert logname to uid.
 */

int uid( ulnam )
char *ulnam;
{
	extern struct passwd *getpwnam();
        struct passwd pw, *ppw;

	ppw = getpwnam( ulnam );
	if( ppw == (struct passwd *)0 )    {
		return( -1 );
	}
	else    {
		return( ppw->pw_uid );
	}
	
}

/*
 * Convert logname to gid.
 */

int gid( ulnam )
char *ulnam;
{
	extern struct group *getgrnam();
        struct group gr, *ggr;

	ggr = getgrnam( ulnam );
	if( ggr == (struct group *)0 )    {
		return( -1 );
	}
	else    {
		return( ggr->gr_gid );
	}
	
}

void usage()
{

	fprintf( stderr, "Usage: chmogdir mode owner group directory [directory ...]\n" );
	fprintf( stderr, "       chmogdir -m owner group directory [directory ...]\n" );
	fprintf( stderr, "       chmogdir -o mode group directory [directory ...]\n" );
	fprintf( stderr, "       chmogdir -g mode owner directory [directory ...]\n" );
	fprintf( stderr, "       chmogdir -m -o group directory [directory ...]\n" );
	fprintf( stderr, "       chmogdir -o -g mode directory [directory ...]\n" );
	fprintf( stderr, "       chmogdir -g -m owner directory [directory ...]\n" );

}


Return to Home Page
Return to Metayoga Page
Return to C Language Page


The URL for this document is:
http://graham.main.nc.us/~bhammel/graham/CPROGS/chmogdir.html
Created: 1997
Last Updated: May 28, 2000 Email me, Bill Hammel at
bhammel@graham.main.nc.us
READ WARNING BEFORE SENDING E-MAIL