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