home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume9 / chgrp_ar < prev    next >
Text File  |  1989-12-26  |  6KB  |  282 lines

  1. Newsgroups: comp.sources.misc
  2. organization: Math & Computer Science, Emory University, Atlanta, GA
  3. subject: v09i087: Public domain chown/chgrp clone
  4. From: arnold@mathcs.emory.edu (Arnold D. Robbins {EUCC})
  5. Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  6.  
  7. Posting-number: Volume 9, Issue 87
  8. Submitted-by: arnold@mathcs.emory.edu (Arnold D. Robbins {EUCC})
  9. Archive-name: chgrp_ar
  10.  
  11. This is a Chanukah gift for all you System V-ers out there who might
  12. like the BSD chown, which can (a) recursively chown a tree, and (b)
  13. take an option group argument, which saves tarversing a file tree twice.
  14.  
  15. I wrote this because I had the BSD chown at work but not at home, and
  16. sorely missed the functionality.
  17.  
  18. It requires the ftw(3) library routine, but PD versions are available
  19. in the archives.
  20.  
  21. This program is PUBLIC DOMAIN.  No warranties of any sort.
  22.  
  23. Enjoy,
  24.  
  25. Arnold Robbins
  26. --------------------------------------------------
  27. /*
  28.  * chown.c
  29.  *
  30.  * Reimplementation of the 4.3 BSD chown, which can recursively chown
  31.  * a directory, and take a user + group combination argument.
  32.  * If called as chgrp, just do chgrp.
  33.  *
  34.  * Requires System V ftw(3) library routine, but a PD version is in the
  35.  * source archives.
  36.  *
  37.  * Arnold Robbins
  38.  * arnold@skeeve.atl.ga.us
  39.  * skeeve!arnold
  40.  *
  41.  * Usage: chown [ -R ] user[.group] file ...
  42.  * Usage: chgrp [ -R ] group file ...
  43.  *
  44.  * Posted December 1989.
  45.  */
  46.  
  47. #include <stdio.h>
  48. #include <ctype.h>
  49. #include <pwd.h>
  50. #include <grp.h>
  51. #include <ftw.h>
  52. #include <sys/types.h>
  53. #include <sys/stat.h>
  54.  
  55. char chown_name[] = "chown";
  56. char chgrp_name[] = "chgrp";
  57.  
  58. int user;        /* new uid */
  59. int group;        /* new gid */
  60.  
  61. char *myname;        /* for errors, and to decide behavior */
  62.  
  63. #define MAXFDS    17    /* Any Unix will have at least this many */
  64.  
  65. int problems = 0;    /* exit non-zero if problems != 0 */
  66.  
  67. main (argc, argv)
  68. int argc;
  69. char **argv;
  70. {
  71.     extern int optind, getopt ();
  72.     extern char *strchr ();        /* use index if necessary */
  73.     extern char *strrchr ();    /* use rindex if necessary */
  74.     int recursive = 0;
  75.     int c, ret;
  76.     char *username, *groupname;
  77.     struct passwd *pwd, *getpwnam ();
  78.     struct group *grp, *getgrnam ();
  79.     extern int do_chown ();
  80.  
  81.     /* save program name */
  82.     if ((myname = strrchr (argv[0], '/')) != NULL)
  83.         myname++;
  84.     else
  85.         myname = argv[0];
  86.  
  87.     if (strcmp (myname, chown_name) != 0 && strcmp (myname, chgrp_name) != 0) {
  88.         fprintf (stderr, "%s: not called as `chown' or `chgrp'\n", myname);
  89.         exit (1);
  90.     }
  91.  
  92.     /* are we recursive? */
  93.     while ((c = getopt (argc, argv, "R")) != EOF) {
  94.         switch (c) {
  95.         case 'R':
  96.             recursive = 1;
  97.             break;
  98.         default:
  99.             usage ();
  100.             break;
  101.         }
  102.     }
  103.  
  104.     if (optind >= argc)
  105.         usage ();
  106.  
  107.     user = group = -1;
  108.     if (strcmp (myname, chown_name) == 0) {
  109.         /* called as chown, get user and group */
  110.  
  111.         /* first, get user and group names */
  112.         username = argv[optind];
  113.         groupname = strchr (argv[optind], '.');
  114.         if (groupname != NULL)
  115.             *groupname++ = '\0';    /* skip dot */
  116.  
  117.         /* get uid number */
  118.         pwd = getpwnam (username);
  119.         if (pwd == NULL) {
  120.             if (isnumber (username)) {
  121.                 user = atoi (username);
  122.             } else {
  123.                 fprintf (stderr, "%s: %s: no such user\n",
  124.                     myname, username);
  125.                 exit (1);
  126.             }
  127.         } else
  128.             user = pwd -> pw_uid;
  129.         endpwent ();
  130.  
  131.         if (groupname != NULL)
  132.             goto getgroup;
  133.     } else {
  134.         /* just get group name */
  135.         groupname = argv[optind];
  136.  
  137.     getgroup:
  138.         grp = getgrnam (groupname);
  139.         if (grp == NULL) {
  140.             if (isnumber (groupname)) {
  141.                 group = atoi (groupname);
  142.             } else {
  143.                 fprintf (stderr, "%s: %s: no such group\n",
  144.                     myname, groupname);
  145.                 exit (1);
  146.             }
  147.         } else
  148.             group = grp -> gr_gid;
  149.         endgrent ();
  150.     }
  151.  
  152.     if (++optind >= argc)
  153.         usage ();    /* no files specified */
  154.  
  155.     /* actually do something to the files */
  156.     for (; optind < argc; optind++) {
  157.         if (recursive && isdir (argv[optind])) {
  158.             ret = ftw (argv[optind], do_chown, MAXFDS);
  159.             if (ret == -1)
  160.                 perror (myname);    /* no file name */
  161.         } else
  162.             (void) chown1 (argv[optind]);
  163.     }
  164.     exit (problems != 0);
  165. }
  166.  
  167. int
  168. do_chown (path, sbuf, flag)
  169. char *path;
  170. struct stat *sbuf;
  171. int flag;
  172. {
  173.     int u, g;
  174.     char buf[BUFSIZ];
  175.  
  176.     switch (flag) {
  177.     case FTW_F:        /* file */
  178.     case FTW_D:        /* directory */
  179.         u = (user == -1) ? sbuf -> st_uid : user;
  180.         g = (group == -1) ? sbuf -> st_gid : group;
  181.         if (chown (path, u, g) < 0) {
  182.             perror (path);
  183.             problems = 1;
  184.         }
  185.         return 0;    /* so ftw() will continue */
  186.  
  187.     case FTW_DNR:        /* directory not readable */
  188.         sprintf (buf, "%s: directory %s not readable\n", myname, path);
  189.         break;
  190.  
  191.     case FTW_NS:        /* file could not be stat'ed */
  192.         sprintf (buf, "%s: could not stat %s\n", myname, path);
  193.         break;
  194.  
  195.     default:
  196.         sprintf (buf, "%s: impossible value (%d) from FTW\n", myname,
  197.             flag);
  198.         break;
  199.     }
  200.     fputs (buf, stderr);
  201.     problems = 1;
  202.     return 0;
  203. }
  204.  
  205. int
  206. chown1 (path)
  207. char *path;
  208. {
  209.     struct stat buf;
  210.     int u, g;
  211.  
  212.     if (user == -1 || group == -1) {    /* get old info */
  213.         if (stat (path, & buf) < 0) {
  214.             problems = 1;
  215.             fprintf (stderr, "%s: ", path);
  216.             perror ("stat");
  217.             return -1;
  218.         }
  219.     }
  220.  
  221.     u = (user == -1) ? buf.st_uid : user;
  222.     g = (group == -1) ? buf.st_gid : group;
  223.  
  224.     if (chown (path, u, g) < 0) {
  225.         perror (path);
  226.         problems = 1;
  227.     }
  228.     return 0;
  229. }
  230.  
  231. int
  232. isnumber (str)
  233. char *str;
  234. {
  235.     register int ret = 1;
  236.  
  237.     for (; *str; str++) {
  238.         if (! isdigit (*str)) {
  239.             ret = 0;
  240.             break;
  241.         }
  242.     }
  243.     return (ret);
  244. }
  245.  
  246. int
  247. isdir (file)
  248. char *file;
  249. {
  250.     struct stat buf;
  251.  
  252.     return (stat (file, &buf) == 0 &&
  253.         (buf.st_mode & S_IFMT) == S_IFDIR);
  254. }
  255.  
  256. int
  257. usage ()
  258. {
  259.     fprintf (stderr, "usage: %s [ -R ] user%s file ...\n", myname,
  260.         strcmp (myname, chown_name) == 0 ? "[.group]" : "");
  261.     exit (1);
  262. }
  263.  
  264. #ifdef debug
  265. /* for debugging --- delete for real */
  266.  
  267. int
  268. chown (path, user, group)
  269. char *path;
  270. int user, group;
  271. {
  272.     printf ("chown (\"%s\", %d, %d);\n", path, user, group);
  273.     return 0;
  274. }
  275. #endif
  276. -- 
  277. Arnold Robbins -- guest account at Emory Math/CS    | Laundry increases
  278. DOMAIN: arnold@emory.mathcs.emory.edu            | exponentially in the
  279. UUCP: gatech!emory!arnold  PHONE: +1 404 636-7221    | number of children.
  280. BITNET: arnold@emory                       | -- Miriam Hartholz
  281.  
  282.