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