chall, recursive chown, chgrp - (nf)

utzoo!decvax!harpo!eagle!mhuxt!mhuxj!mhuxa!houxm!ihnp4!ixn5c!inuxc!pur-ee!uiucdcs!adams utzoo!decvax!harpo!eagle!mhuxt!mhuxj!mhuxa!houxm!ihnp4!ixn5c!inuxc!pur-ee!uiucdcs!adams
Fri Apr 22 22:39:05 AEST 1983


#N:uiucdcs:12600008:000:8218
uiucdcs!adams    Apr 22 17:58:00 1983


	What follows is the source and man page (in a Bourne RunMe script)
for chall, a recursive chown/chgrp.  Syntax is as follows:

% chall owner group dir1 dir2 ...
E.g.,
% chall uucp bin /usr/lib/uucp /usr/spool/uucp

	The example appropriately changes the ownership (and group ownship)
of /usr/lib/uucp, /usr/spool/uucp and all of their descendants.

	For more info, read the man page.

	Instructions:
		Save this in a file, and get rid of this
		garbage at top

		type /bin/sh RunMe

		type make chall

	Known lacks:
		Reading the directory could be more efficient. 
		(E.g. I could use 4.1aBSD's directory readers, which
		has the side effect of making this work for 4.1c)
		N.b. I don't know if this will work on 4.1c.

		Error recovery is less than gracious.  If ANYTHING goes
		wrong, chall just dies (by design).  I prolly ought
		to have it continue its task.

		It has only been tested on 4.1,4.1aBSD, and one hybrid
		UNIX running on a Cadlinc Sun 68000.  If it does
		not port easily to your machine, please let me know.

		I have one open file for every directory level.  This means
		that you may only go (NOFILE -3) levels deep.  On my machine
		this means I can get to *almost* everything if I execute
		%chall adams bin /   (No, I didn't try it...)

	RCS:
		I use purdue's RCS (Revision Control System), and it
		has left its mark in my code.  To get RCS, contact
		purdue!wft  or Tichy at purdue.

	Distribution:
		I don't care where it goes, but don't sell it, and if
		you find any bugs (in my code?), let me know.


					Rob Adams
					(217) 333 3536
					uiucdcs!adams
	By the way:
		There is a reason I don't just use find(1).  This
		runs (seriously) 100 times as fast.  Really.
============================ RunMe Follows... ========================
# This is the RunMe script for chall, from the University of Illinois
# This Software may be distributed provided 
#	1) It may NOT be sold.
#	2) The recipient agrees to (1).
#
#			Rob Adams
#			decvax!pur-ee!uiucdcs!adams
#			parsec!uiucdcs!adams
#			UofIllinois
echo Extracting Makefile
cat << !EOF!EOF! > Makefile
chall: main.o walk.o assert.o
	cc -o chall main.o walk.o assert.o
clean:
	rm -f *.o  chall core
!EOF!EOF!
echo Extracting main.c
cat << !EOF!EOF! > main.c
static char *RCSid = "$Header: /mnt/staff/adams/Cprogs/Chall/RCS/main.c,v 1.5 83/04/21 07:13:03 adams Exp $";

/* Modification history --
 *
 * $Log:	/mnt/staff/adams/Cprogs/Chall/RCS/main.c,v $
 * Revision 1.5  83/04/21  07:13:03  adams
 * Added multiple directories.
 * 
 * Revision 1.4  83/04/21  06:59:56  adams
 * indented right.
 * R
 * 
 * Revision 1.3  83/04/11  04:52:30  adams
 * Added su-checking.
 * 
 * Revision 1.2  83/04/11  04:47:38  adams
 * changed all the asserts to my new format.
 * 
 * Revision 1.1  83/04/11  03:30:24  adams
 * Initial revision
 * 
 *
 */

/* chall -- change the ownership and group ownership of a directory
 * and all its descendants.  (I wonder if that is spelled right.. hmmm)
 */
/*
 *
 *  The line marked $Header: and the comment marked $Log: are courtesy
 *  RCS, the Revision Control System written and distributed by 
 *  Walter F. Tichy at University of Purdue.  I have found it invaluable
 *  in generating code, and recommend it whole-heartedly.  For more
 *  information, contact the author.  (purdue!wft or Tichy at purdue)
 * 
 */

/* 
 * original work by Rob Adams, (uiucdcs!adams) on 11 April.
 *
 */
#include <stdio.h>
#include <pwd.h>
#include <grp.h>

main (argc, argv)
int     argc;
char   *argv[];


{

 /* some defs here later. */
    int     uid,
            gid;
    int     i;
    int     walked;
    struct passwd  *pswd,
                   *getpwnam ();
    struct group   *grp,
                   *getgrnam ();


 /* Were we called correctly? */
    assert ((argc >= 4), 's', "Usage: chall owner group file");

 /* Am I su?  non-roots fail */
    assert (((getuid () == 0) || (geteuid () == 0)), 's', "You must be SU to run chall");


 /* parse the args, first the name (argv[1]) */

    setpwent ();
    pswd = getpwnam (argv[1]);
    endpwent ();
    assert ((pswd != (struct passwd *) 0), 's', "Cant get user info");
    uid = pswd -> pw_uid;

 /* now comes the group. */

    setgrent ();
    grp = getgrnam (argv[2]);
    endgrent ();
    assert ((grp != (struct group  *) 0), 's', "Cant get group info");
    gid = grp -> gr_gid;

 /* now, lets just pass everything off to the tree walker. */

    for (i = 3; i < argc; i++)
    {
	walked = walk (uid, gid, argv[i]);
	assert (walked == 0, 's', "Something is wrong, but I don't know what");
    }
    exit (walked);			  /* I know, walked is guaranteed to be 0 here */
}
!EOF!EOF!
echo Extracting walk.c
cat << !EOF!EOF! > walk.c
static char *RCSid = "$Header:   RCS/walk.v  Revision 1.2  83/04/11  04:48:28  adams  Exp$";

/*
 * walk()
 *	    This guy does all the recursion.  It should propagate
 *	    errors backwards, but I don't know if I will do that tonight.
 *
 */
#include <sys/types.h>
#include <sys/dir.h>
#include <sys/stat.h>
#include <stdio.h>

walk (uid, gid, filename)
int     uid,
        gid;
char   *filename;
{
    char    file_nullend[2 * DIRSIZ];	  /* better safe, et al... */
    struct stat status;
    struct direct   dirbuf;
    long lseek();	/* for lint */
    int     stated;
    int     isdir;
    int     walked;
    long lseeked;
    int     chowned = 0;
    int     dot;
    int     readed;

 /* see if filename is a non-directory or directory */

    stated = stat (filename, &status);
    assert ((stated == 0),'p',"chall: stat()");
    isdir = ((status.st_mode & S_IFMT) == S_IFDIR);
    if (!isdir)				  /* I know, I really don't need
					     isdir, but I like it */
    {
	chowned = chown(filename, uid, gid);
	assert ((chowned == 0),'p',"chall: chown()");
	return (0);
    }
 /* else */
    chdir (filename);
	chowned = chown(".", uid, gid);
	assert ((chowned == 0),'p',"chall: chown()");
    dot = open (".", 0);		  /* 0 means read-only */
    assert ((dot != (-1)),'p', "chall: read()");
    lseeked = lseek (dot, (long) 2*sizeof (dirbuf),0);
    assert ((lseeked != (-1)),'p',"chall: lseek()");		/* blow off . and .. */
    while (1 == 1)
    {					  /* I suppose I should make a
					     condition in there, but I am
					     lazy.. */

	readed = read (dot, (char *) & dirbuf, sizeof (dirbuf));
	if (readed == 0)		  /* EOF */
	    break;
	assert ((readed == sizeof (dirbuf)),'p', "chall: read()");
	if (dirbuf.d_ino == 0)
	    continue;
    /* I need to terminate filename with a null char. */
	(void) strncpy (file_nullend, dirbuf.d_name, DIRSIZ + 1);
	walked = walk (uid, gid, file_nullend);
	assert ((walked == 0),'s',"Something mysterious just happend");
    }
    close (dot);
    chdir ("..");
    return (0);				  /* just emptied a directory */
}
!EOF!EOF!
echo Extracting assert.c
cat << !EOF!EOF! > assert.c
static char *RCSid = "$Header:   RCS/assert.v  Revision 1.2  83/04/11  04:47:02  adams  Exp$";

/*
 * assert(bool,char,char *)
 *
 * 	program verification...
 *
 *	If bool is true then return, else print a message and exit(-1)
 *	
 *	If char = p then perror(3) is used. 
 *
 */


#include <stdio.h>

assert (bool, c, s)
int     bool;
char    c;
char   *s;
{
    if (bool)
	return;
    if (c == 'p')
	perror (s);
    else
	fprintf (stderr, "%s\n", s);
    exit (-1);
}
!EOF!EOF!
echo Extracting man'(8)' page
cat << !EOF!EOF! > chown.8
.TH CHOWN 8 
.UC 4
.SH NAME
chown, chgrp, chall \- change owner or group
.SH SYNOPSIS
.B /etc/chown
owner file ...
.PP
.B /etc/chgrp
group file ...
.PP
.B chall owner group directory ...
.SH DESCRIPTION
.I Chown
changes the owner of the
.I files
to
.IR owner .
The owner may be either a decimal UID or
a login name found in the password file.
.PP
.I Chgrp
changes the group-ID of the
.I files
to
.IR group .
The group may be either a decimal GID or
a group name found in the group-ID file.
.PP
.I Chall
changes the owner and group, of any file in a directory and
its subdirectories. The owner and group must be logical names,
not decimal UID or GID's.
.PP
Only the super-user can change owner or group,
in order to simplify as yet unimplemented accounting procedures.
.SH FILES
/etc/passwd
.br
/etc/group
.SH "SEE ALSO"
chown(2),
passwd(5), group(5)
!EOF!EOF!



More information about the Comp.sources.unix mailing list