master xplshn/aruu / cmd / posix / chown.c
  1/* See LICENSE file for copyright and license details. */
  2
  3#include <errno.h>
  4#include <fcntl.h>
  5#include <grp.h>
  6#include <limits.h>
  7#include <pwd.h>
  8#include <stdlib.h>
  9#include <string.h>
 10#include <unistd.h>
 11
 12#include "fs.h"
 13#include "util.h"
 14
 15static int   hflag = 0;
 16static uid_t uid   = -1;
 17static gid_t gid   = -1;
 18static int   ret   = 0;
 19
 20static void
 21chownpwgr(int dirfd, const char *name, struct stat *st, void *data, struct recursor *r)
 22{
 23  int flags = 0;
 24
 25  (void)data;
 26
 27  if ((r->maxdepth == 0 && r->follow == 'P') || (r->follow == 'H' && r->depth)
 28      || (hflag && !(r->depth)))
 29    flags |= AT_SYMLINK_NOFOLLOW;
 30
 31  if (fchownat(dirfd, name, uid, gid, flags) < 0) {
 32    weprintf("chown %s:", r->path);
 33    ret = 1;
 34  } else if (S_ISDIR(st->st_mode)) {
 35    recurse(dirfd, name, NULL, r);
 36  }
 37}
 38
 39static void
 40usage(void)
 41{
 42  eprintf(
 43      "usage: %s [-h] [-R [-H | -L | -P]] owner[:[group]] file ...\n"
 44      "       %s [-h] [-R [-H | -L | -P]] :group file ...\n",
 45      argv0,
 46      argv0
 47  );
 48}
 49
 50// ?man chown: change ownership
 51// ?man arguments: owner[:[group]] file ...
 52// ?man change the user and group ownership of files and directories
 53int
 54main(int argc, char *argv[])
 55{
 56  struct group   *gr;
 57  struct passwd  *pw;
 58  struct recursor r = {.fn = chownpwgr, .maxdepth = 1, .follow = 'P'};
 59  char           *owner, *group;
 60
 61  ARGBEGIN
 62  {
 63    // ?man -h: affect symbolic links instead of referenced files
 64    case 'h':
 65      hflag = 1;
 66      break;
 67    // ?man -r: operate recursively
 68    case 'r':
 69    // ?man -R: change files and directories recursively
 70    case 'R':
 71      r.maxdepth = 0;
 72      break;
 73    // ?man -H: specify option flag
 74    case 'H':
 75    // ?man -L: specify option flag
 76    case 'L':
 77    // ?man -P: specify option flag
 78    case 'P':
 79      r.follow = ARGC();
 80      break;
 81    default:
 82      usage();
 83  }
 84  ARGEND
 85
 86  if (argc < 2)
 87    usage();
 88
 89  owner = argv[0];
 90  if ((group = strchr(owner, ':')))
 91    *group++ = '\0';
 92
 93  if (owner && *owner) {
 94    errno = 0;
 95    pw    = getpwnam(owner);
 96    if (pw) {
 97      uid = pw->pw_uid;
 98    } else {
 99      if (errno)
100        eprintf("getpwnam %s:", owner);
101      uid = estrtonum(owner, 0, UINT_MAX);
102    }
103  }
104  if (group && *group) {
105    errno = 0;
106    gr    = getgrnam(group);
107    if (gr) {
108      gid = gr->gr_gid;
109    } else {
110      if (errno)
111        eprintf("getgrnam %s:", group);
112      gid = estrtonum(group, 0, UINT_MAX);
113    }
114  }
115  if (uid == (uid_t)-1 && gid == (gid_t)-1)
116    usage();
117
118  for (argc--, argv++; *argv; argc--, argv++)
119    recurse(AT_FDCWD, *argv, NULL, &r);
120
121  return ret || recurse_status;
122}