Path: utzoo!utgpu!water!watmath!uunet!lll-winken!lll-tis!ptsfa!pacbell!gladys!skeeve!arnold From: arnold@skeeve.UUCP (Arnold D. Robbins) Newsgroups: unix-pc.sources Subject: Reimplementation of BSD chown(1) command Keywords: recursive chown, can take group spec Message-ID: <125@skeeve.UUCP> Date: 16 Mar 88 05:10:43 GMT Distribution: unix-pc Organization: The Basement Computer, Atlanta GA Lines: 231 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 #include #include #include #include #include #include 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!