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}