arnold@skeeve.UUCP (Arnold D. Robbins) (03/16/88)
The following piece of code has been doanted to the Free Software Foundation (aka the GNU project) and should be considered copyright by them, even though I wrote it. I use a BSD machine at work. One of the nice things about the 4.3 chown(1) command is that you can say chown [ -R ] user[.group] file .... The -R means recursive; do the chown on any directories, and subdirectory trees. The optional .group says chgrp the files to the specified group too. User and Group may both be numeric or identifiers looked up in the respective file. I missed the above features badly on my 3B1, and since System V makes the recursive part real easy via ftw(3), I decided to reimplement the command. It was pretty easy. I hope the rest of the Unix-pc net finds this of interest too. --------------------- /* * chown.c * * Reimplementation of the 4.3 BSD chown, which can recursively chown * a directory, and take a user + group combination argument. * * Requires System V ftw(3) library routine, but a PD version is in the * source archives. * * Arnold Robbins * skeeve!arnold * * Usage: chown [ -R ] user[.group] file ... * * This program belongs to the Free Software Foundation, their copyright * and copying rules apply. */ #include <stdio.h> #include <ctype.h> #include <pwd.h> #include <grp.h> #include <ftw.h> #include <sys/types.h> #include <sys/stat.h> int user; /* new uid */ int group; /* new gid */ char *myname; /* for errors */ #define MAXFDS 17 /* Any Unix will have at least this many */ int problems = 0; /* exit non-zero if problems != 0 */ main (argc, argv) int argc; char **argv; { extern int optind, getopt (); extern char *strchr (); /* use index if necessary */ extern char *strrchr (); /* use rindex if necessary */ int recursive = 0; int c, ret; char *cp; struct passwd *pwd, *getpwnam (); struct group *grp, *getgrnam (); extern int do_chown (); /* save program name */ if ((myname = strrchr (argv[0], '/')) != NULL) myname++; else myname = argv[0]; /* are we recursive? */ while ((c = getopt (argc, argv, "R")) != EOF) { switch (c) { case 'R': recursive = 1; break; default: usage (); break; } } if (optind >= argc) usage (); /* check if group supplied too */ if ((cp = strchr (argv[optind], '.')) != NULL) { *cp++ = '\0'; grp = getgrnam (cp); if (grp == NULL) { if (isnumber (cp)) { group = atoi (cp); } else { fprintf (stderr, "%s: %s: no such group\n", myname, cp); exit (1); } } else group = grp -> gr_gid; } else group = -1; /* get user to chown to */ pwd = getpwnam (argv[optind]); if (pwd == NULL) { if (isnumber (argv[optind])) { user = atoi (argv[optind]); } else { fprintf (stderr, "%s: %s: no such user\n", myname, argv[optind]); exit (1); } } else user = pwd -> pw_uid; if (++optind >= argc) usage (); /* no files specified */ /* actually do something to the files */ for (; optind < argc; optind++) { if (recursive && isdir (argv[optind])) { ret = ftw (argv[optind], do_chown, MAXFDS); if (ret == -1) perror (myname); /* no file name */ } else (void) chown1 (argv[optind]); } exit (problems != 0); } int do_chown (path, sbuf, flag) char *path; struct stat *sbuf; int flag; { int g; char buf[BUFSIZ]; switch (flag) { case FTW_F: /* file */ case FTW_D: /* directory */ g = (group == -1) ? sbuf -> st_gid : group; if (chown (path, user, g) < 0) perror (path); return 0; /* so ftw() will continue */ case FTW_DNR: /* directory not readable */ sprintf (buf, "%s: directory %s not readable\n", myname, path); break; case FTW_NS: /* file could not be stat'ed */ sprintf (buf, "%s: could not stat %s\n", myname, path); break; default: sprintf (buf, "%s: impossible value (%d) from FTW\n", myname, flag); break; } fprintf (stderr, "%s", buf); problems = 1; return 0; } int chown1 (path) char *path; { struct stat buf; int g; if (group == -1) { /* get old group */ if (stat (path, & buf) < 0) { problems = 1; fprintf (stderr, "%s: ", path); perror ("stat"); return -1; } else g = buf.st_gid; } else g = group; if (chown (path, user, g) < 0) { perror (path); problems = 1; } return 0; } int isnumber (str) char *str; { register int ret = 1; for (; *str; str++) { if (! isdigit (*str)) { ret = 0; break; } } return (ret); } int isdir (file) char *file; { struct stat buf; return (stat (file, &buf) == 0 && (buf.st_mode & S_IFMT) == S_IFDIR); } int usage () { fprintf (stderr, "usage: %s [ -R ] user[.group] file ...\n", myname); exit (1); } -- Arnold Robbins -- The Basement Computer UUCP: { gatech, emory, gt-eedsp, bakerst, gladys }!skeeve!arnold /bin/csh: Just Say NO!
arnold@skeeve.UUCP (Arnold D. Robbins) (03/21/88)
In article <125@skeeve.UUCP> I wrote: >The following piece of code has been doanted to the Free Software Foundation >(aka the GNU project) and should be considered copyright by them, even though >I wrote it. > > [ stuff deleted ... ] >/* > * chown.c > * [ more deleted ] > * > * This program belongs to the Free Software Foundation, their copyright > * and copying rules apply. > */ After some email correspondence with the Free Software Foundation, it turns out I did not do this correctly. Therefore, I am explicitly abandoning any copyrights to the source code posted in <125@skeeve.UUCP> and labeling that program completely Public Domain. Anyone who wants to may do anything they please with the code. I will be working with FSF to get it included as part of GNU. Meanwhile, the code is completely Public Domain. If you wish to contribute code to the GNU project, be sure to contact them first. DO NOT post it or do anything else with it until they've had a chance to take it and put their copyright on it. [ inews filler ! ] [ inews filler ! ] [ inews filler ! ] [ inews filler ! ] [ inews filler ! ] [ inews filler ! ] [ inews filler ! ] [ inews filler ! ] [ inews filler ! ] [ inews filler ! ] -- Arnold Robbins -- The Basement Computer UUCP: { gatech, emory, gt-eedsp, bakerst, gladys }!skeeve!arnold /bin/csh: Just Say NO!