1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 28*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 29*7c478bd9Sstevel@tonic-gate 30*7c478bd9Sstevel@tonic-gate /* 31*7c478bd9Sstevel@tonic-gate * Portions of this source code were derived from Berkeley 4.3 BSD 32*7c478bd9Sstevel@tonic-gate * under license from the Regents of the University of California. 33*7c478bd9Sstevel@tonic-gate */ 34*7c478bd9Sstevel@tonic-gate 35*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 36*7c478bd9Sstevel@tonic-gate 37*7c478bd9Sstevel@tonic-gate /* 38*7c478bd9Sstevel@tonic-gate * chown [-fhR] uid [:gid] file ... 39*7c478bd9Sstevel@tonic-gate * chown -R [-f] [-H|-L|-P] uid [:gid] file ... 40*7c478bd9Sstevel@tonic-gate */ 41*7c478bd9Sstevel@tonic-gate 42*7c478bd9Sstevel@tonic-gate #include <stdio.h> 43*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 44*7c478bd9Sstevel@tonic-gate #include <ctype.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 46*7c478bd9Sstevel@tonic-gate #include <dirent.h> 47*7c478bd9Sstevel@tonic-gate #include <string.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/avl.h> 50*7c478bd9Sstevel@tonic-gate #include <pwd.h> 51*7c478bd9Sstevel@tonic-gate #include <grp.h> 52*7c478bd9Sstevel@tonic-gate #include <unistd.h> 53*7c478bd9Sstevel@tonic-gate #include <locale.h> 54*7c478bd9Sstevel@tonic-gate #include <errno.h> 55*7c478bd9Sstevel@tonic-gate #include <libcmdutils.h> 56*7c478bd9Sstevel@tonic-gate 57*7c478bd9Sstevel@tonic-gate static struct passwd *pwd; 58*7c478bd9Sstevel@tonic-gate static struct group *grp; 59*7c478bd9Sstevel@tonic-gate static struct stat stbuf; 60*7c478bd9Sstevel@tonic-gate static uid_t uid = -1; 61*7c478bd9Sstevel@tonic-gate static gid_t gid = -1; 62*7c478bd9Sstevel@tonic-gate static int status = 0; /* total number of errors received */ 63*7c478bd9Sstevel@tonic-gate static int hflag = 0, 64*7c478bd9Sstevel@tonic-gate rflag = 0, 65*7c478bd9Sstevel@tonic-gate fflag = 0, 66*7c478bd9Sstevel@tonic-gate Hflag = 0, 67*7c478bd9Sstevel@tonic-gate Lflag = 0, 68*7c478bd9Sstevel@tonic-gate Pflag = 0; 69*7c478bd9Sstevel@tonic-gate static avl_tree_t *tree; 70*7c478bd9Sstevel@tonic-gate 71*7c478bd9Sstevel@tonic-gate static int Perror(char *); 72*7c478bd9Sstevel@tonic-gate static int isnumber(char *); 73*7c478bd9Sstevel@tonic-gate static void chownr(char *, uid_t, gid_t); 74*7c478bd9Sstevel@tonic-gate static void usage(); 75*7c478bd9Sstevel@tonic-gate 76*7c478bd9Sstevel@tonic-gate #ifdef XPG4 77*7c478bd9Sstevel@tonic-gate /* 78*7c478bd9Sstevel@tonic-gate * Check to see if we are to follow symlinks specified on the command line. 79*7c478bd9Sstevel@tonic-gate * This assumes we've already checked to make sure neither -h or -P was 80*7c478bd9Sstevel@tonic-gate * specified, so we are just looking to see if -R -H, or -R -L was specified, 81*7c478bd9Sstevel@tonic-gate * or, since -R has the same behavior as -R -L, if -R was specified by itself. 82*7c478bd9Sstevel@tonic-gate * Therefore, all we really need to check for is if -R was specified. 83*7c478bd9Sstevel@tonic-gate */ 84*7c478bd9Sstevel@tonic-gate #define FOLLOW_CL_LINKS (rflag) 85*7c478bd9Sstevel@tonic-gate #else 86*7c478bd9Sstevel@tonic-gate /* 87*7c478bd9Sstevel@tonic-gate * Check to see if we are to follow symlinks specified on the command line. 88*7c478bd9Sstevel@tonic-gate * This assumes we've already checked to make sure neither -h or -P was 89*7c478bd9Sstevel@tonic-gate * specified, so we are just looking to see if -R -H, or -R -L was specified. 90*7c478bd9Sstevel@tonic-gate * Note: -R by itself will change the ownership of a directory referenced by a 91*7c478bd9Sstevel@tonic-gate * symlink however it will now follow the symlink to any other part of the 92*7c478bd9Sstevel@tonic-gate * file hierarchy. 93*7c478bd9Sstevel@tonic-gate */ 94*7c478bd9Sstevel@tonic-gate #define FOLLOW_CL_LINKS (rflag && (Hflag || Lflag)) 95*7c478bd9Sstevel@tonic-gate #endif 96*7c478bd9Sstevel@tonic-gate 97*7c478bd9Sstevel@tonic-gate #ifdef XPG4 98*7c478bd9Sstevel@tonic-gate /* 99*7c478bd9Sstevel@tonic-gate * Follow symlinks when traversing directories. Since -R behaves the 100*7c478bd9Sstevel@tonic-gate * same as -R -L, we always want to follow symlinks to other parts 101*7c478bd9Sstevel@tonic-gate * of the file hierarchy unless -H was specified. 102*7c478bd9Sstevel@tonic-gate */ 103*7c478bd9Sstevel@tonic-gate #define FOLLOW_D_LINKS (!Hflag) 104*7c478bd9Sstevel@tonic-gate #else 105*7c478bd9Sstevel@tonic-gate /* 106*7c478bd9Sstevel@tonic-gate * Follow symlinks when traversing directories. Only follow symlinks 107*7c478bd9Sstevel@tonic-gate * to other parts of the file hierarchy if -L was specified. 108*7c478bd9Sstevel@tonic-gate */ 109*7c478bd9Sstevel@tonic-gate #define FOLLOW_D_LINKS (Lflag) 110*7c478bd9Sstevel@tonic-gate #endif 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate #define CHOWN(f, u, g) if (chown(f, u, g) < 0) { \ 113*7c478bd9Sstevel@tonic-gate status += Perror(f); \ 114*7c478bd9Sstevel@tonic-gate } 115*7c478bd9Sstevel@tonic-gate #define LCHOWN(f, u, g) if (lchown(f, u, g) < 0) { \ 116*7c478bd9Sstevel@tonic-gate status += Perror(f); \ 117*7c478bd9Sstevel@tonic-gate } 118*7c478bd9Sstevel@tonic-gate 119*7c478bd9Sstevel@tonic-gate 120*7c478bd9Sstevel@tonic-gate int 121*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 122*7c478bd9Sstevel@tonic-gate { 123*7c478bd9Sstevel@tonic-gate int c; 124*7c478bd9Sstevel@tonic-gate int ch; 125*7c478bd9Sstevel@tonic-gate char *grpp; /* pointer to group name arg */ 126*7c478bd9Sstevel@tonic-gate extern int optind; 127*7c478bd9Sstevel@tonic-gate int errflg = 0; 128*7c478bd9Sstevel@tonic-gate 129*7c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 130*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 131*7c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 132*7c478bd9Sstevel@tonic-gate #endif 133*7c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 134*7c478bd9Sstevel@tonic-gate 135*7c478bd9Sstevel@tonic-gate while ((ch = getopt(argc, argv, "hRfHLP")) != EOF) { 136*7c478bd9Sstevel@tonic-gate switch (ch) { 137*7c478bd9Sstevel@tonic-gate case 'h': 138*7c478bd9Sstevel@tonic-gate hflag++; 139*7c478bd9Sstevel@tonic-gate break; 140*7c478bd9Sstevel@tonic-gate 141*7c478bd9Sstevel@tonic-gate case 'R': 142*7c478bd9Sstevel@tonic-gate rflag++; 143*7c478bd9Sstevel@tonic-gate break; 144*7c478bd9Sstevel@tonic-gate 145*7c478bd9Sstevel@tonic-gate case 'f': 146*7c478bd9Sstevel@tonic-gate fflag++; 147*7c478bd9Sstevel@tonic-gate break; 148*7c478bd9Sstevel@tonic-gate 149*7c478bd9Sstevel@tonic-gate case 'H': 150*7c478bd9Sstevel@tonic-gate /* 151*7c478bd9Sstevel@tonic-gate * If more than one of -H, -L, and -P 152*7c478bd9Sstevel@tonic-gate * are specified, only the last option 153*7c478bd9Sstevel@tonic-gate * specified determines the behavior of 154*7c478bd9Sstevel@tonic-gate * chown. 155*7c478bd9Sstevel@tonic-gate */ 156*7c478bd9Sstevel@tonic-gate Lflag = Pflag = 0; 157*7c478bd9Sstevel@tonic-gate Hflag++; 158*7c478bd9Sstevel@tonic-gate break; 159*7c478bd9Sstevel@tonic-gate 160*7c478bd9Sstevel@tonic-gate case 'L': 161*7c478bd9Sstevel@tonic-gate Hflag = Pflag = 0; 162*7c478bd9Sstevel@tonic-gate Lflag++; 163*7c478bd9Sstevel@tonic-gate break; 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate case 'P': 166*7c478bd9Sstevel@tonic-gate Hflag = Lflag = 0; 167*7c478bd9Sstevel@tonic-gate Pflag++; 168*7c478bd9Sstevel@tonic-gate break; 169*7c478bd9Sstevel@tonic-gate 170*7c478bd9Sstevel@tonic-gate default: 171*7c478bd9Sstevel@tonic-gate errflg++; 172*7c478bd9Sstevel@tonic-gate break; 173*7c478bd9Sstevel@tonic-gate } 174*7c478bd9Sstevel@tonic-gate } 175*7c478bd9Sstevel@tonic-gate 176*7c478bd9Sstevel@tonic-gate /* 177*7c478bd9Sstevel@tonic-gate * Check for sufficient arguments 178*7c478bd9Sstevel@tonic-gate * or a usage error. 179*7c478bd9Sstevel@tonic-gate */ 180*7c478bd9Sstevel@tonic-gate 181*7c478bd9Sstevel@tonic-gate argc -= optind; 182*7c478bd9Sstevel@tonic-gate argv = &argv[optind]; 183*7c478bd9Sstevel@tonic-gate 184*7c478bd9Sstevel@tonic-gate if (errflg || (argc < 2) || 185*7c478bd9Sstevel@tonic-gate ((Hflag || Lflag || Pflag) && !rflag) || 186*7c478bd9Sstevel@tonic-gate ((Hflag || Lflag || Pflag) && hflag)) { 187*7c478bd9Sstevel@tonic-gate usage(); 188*7c478bd9Sstevel@tonic-gate } 189*7c478bd9Sstevel@tonic-gate 190*7c478bd9Sstevel@tonic-gate /* 191*7c478bd9Sstevel@tonic-gate * POSIX.2 192*7c478bd9Sstevel@tonic-gate * Check for owner[:group] 193*7c478bd9Sstevel@tonic-gate */ 194*7c478bd9Sstevel@tonic-gate if ((grpp = strchr(argv[0], ':')) != NULL) { 195*7c478bd9Sstevel@tonic-gate *grpp++ = 0; 196*7c478bd9Sstevel@tonic-gate 197*7c478bd9Sstevel@tonic-gate if (isnumber(grpp)) { 198*7c478bd9Sstevel@tonic-gate errno = 0; 199*7c478bd9Sstevel@tonic-gate gid = (gid_t)strtol(grpp, NULL, 10); 200*7c478bd9Sstevel@tonic-gate if (errno != 0) { 201*7c478bd9Sstevel@tonic-gate if (errno == ERANGE) { 202*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 203*7c478bd9Sstevel@tonic-gate "chown: group id too large\n")); 204*7c478bd9Sstevel@tonic-gate exit(2); 205*7c478bd9Sstevel@tonic-gate } else { 206*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 207*7c478bd9Sstevel@tonic-gate "chown: invalid group id\n")); 208*7c478bd9Sstevel@tonic-gate exit(2); 209*7c478bd9Sstevel@tonic-gate } 210*7c478bd9Sstevel@tonic-gate } 211*7c478bd9Sstevel@tonic-gate } else if ((grp = getgrnam(grpp)) == NULL) { 212*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 213*7c478bd9Sstevel@tonic-gate "chown: unknown group id %s\n"), grpp); 214*7c478bd9Sstevel@tonic-gate exit(2); 215*7c478bd9Sstevel@tonic-gate } else 216*7c478bd9Sstevel@tonic-gate gid = grp->gr_gid; 217*7c478bd9Sstevel@tonic-gate } 218*7c478bd9Sstevel@tonic-gate 219*7c478bd9Sstevel@tonic-gate if (isnumber(argv[0])) { 220*7c478bd9Sstevel@tonic-gate errno = 0; 221*7c478bd9Sstevel@tonic-gate uid = (uid_t)strtol(argv[0], NULL, 10); 222*7c478bd9Sstevel@tonic-gate if (errno != 0) { 223*7c478bd9Sstevel@tonic-gate if (errno == ERANGE) { 224*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 225*7c478bd9Sstevel@tonic-gate "chown: user id too large\n")); 226*7c478bd9Sstevel@tonic-gate exit(2); 227*7c478bd9Sstevel@tonic-gate } else { 228*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 229*7c478bd9Sstevel@tonic-gate "chown: invalid user id\n")); 230*7c478bd9Sstevel@tonic-gate exit(2); 231*7c478bd9Sstevel@tonic-gate } 232*7c478bd9Sstevel@tonic-gate } 233*7c478bd9Sstevel@tonic-gate } else if ((pwd = getpwnam(argv[0])) == NULL) { 234*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 235*7c478bd9Sstevel@tonic-gate "chown: unknown user id %s\n"), argv[0]); 236*7c478bd9Sstevel@tonic-gate exit(2); 237*7c478bd9Sstevel@tonic-gate } else 238*7c478bd9Sstevel@tonic-gate uid = pwd->pw_uid; 239*7c478bd9Sstevel@tonic-gate 240*7c478bd9Sstevel@tonic-gate for (c = 1; c < argc; c++) { 241*7c478bd9Sstevel@tonic-gate tree = NULL; 242*7c478bd9Sstevel@tonic-gate if (lstat(argv[c], &stbuf) < 0) { 243*7c478bd9Sstevel@tonic-gate status += Perror(argv[c]); 244*7c478bd9Sstevel@tonic-gate continue; 245*7c478bd9Sstevel@tonic-gate } 246*7c478bd9Sstevel@tonic-gate if (rflag && ((stbuf.st_mode & S_IFMT) == S_IFLNK)) { 247*7c478bd9Sstevel@tonic-gate if (hflag || Pflag) { 248*7c478bd9Sstevel@tonic-gate /* 249*7c478bd9Sstevel@tonic-gate * Change the ownership of the symlink 250*7c478bd9Sstevel@tonic-gate * specified on the command line. 251*7c478bd9Sstevel@tonic-gate * Don't follow the symbolic link to 252*7c478bd9Sstevel@tonic-gate * any other part of the file hierarchy. 253*7c478bd9Sstevel@tonic-gate */ 254*7c478bd9Sstevel@tonic-gate LCHOWN(argv[c], uid, gid); 255*7c478bd9Sstevel@tonic-gate } else { 256*7c478bd9Sstevel@tonic-gate struct stat stbuf2; 257*7c478bd9Sstevel@tonic-gate if (stat(argv[c], &stbuf2) < 0) { 258*7c478bd9Sstevel@tonic-gate status += Perror(argv[c]); 259*7c478bd9Sstevel@tonic-gate continue; 260*7c478bd9Sstevel@tonic-gate } 261*7c478bd9Sstevel@tonic-gate /* 262*7c478bd9Sstevel@tonic-gate * We know that we are to change the 263*7c478bd9Sstevel@tonic-gate * ownership of the file referenced by the 264*7c478bd9Sstevel@tonic-gate * symlink specified on the command line. 265*7c478bd9Sstevel@tonic-gate * Now check to see if we are to follow 266*7c478bd9Sstevel@tonic-gate * the symlink to any other part of the 267*7c478bd9Sstevel@tonic-gate * file hierarchy. 268*7c478bd9Sstevel@tonic-gate */ 269*7c478bd9Sstevel@tonic-gate if (FOLLOW_CL_LINKS) { 270*7c478bd9Sstevel@tonic-gate if ((stbuf2.st_mode & S_IFMT) 271*7c478bd9Sstevel@tonic-gate == S_IFDIR) { 272*7c478bd9Sstevel@tonic-gate /* 273*7c478bd9Sstevel@tonic-gate * We are following symlinks so 274*7c478bd9Sstevel@tonic-gate * traverse into the directory. 275*7c478bd9Sstevel@tonic-gate * Add this node to the search 276*7c478bd9Sstevel@tonic-gate * tree so we don't get into an 277*7c478bd9Sstevel@tonic-gate * endless loop. 278*7c478bd9Sstevel@tonic-gate */ 279*7c478bd9Sstevel@tonic-gate if (add_tnode(&tree, 280*7c478bd9Sstevel@tonic-gate stbuf2.st_dev, 281*7c478bd9Sstevel@tonic-gate stbuf2.st_ino) == 1) { 282*7c478bd9Sstevel@tonic-gate chownr(argv[c], 283*7c478bd9Sstevel@tonic-gate uid, gid); 284*7c478bd9Sstevel@tonic-gate } else { 285*7c478bd9Sstevel@tonic-gate /* 286*7c478bd9Sstevel@tonic-gate * Error occurred. 287*7c478bd9Sstevel@tonic-gate * rc can't be 0 288*7c478bd9Sstevel@tonic-gate * as this is the first 289*7c478bd9Sstevel@tonic-gate * node to be added to 290*7c478bd9Sstevel@tonic-gate * the search tree. 291*7c478bd9Sstevel@tonic-gate */ 292*7c478bd9Sstevel@tonic-gate status += Perror( 293*7c478bd9Sstevel@tonic-gate argv[c]); 294*7c478bd9Sstevel@tonic-gate } 295*7c478bd9Sstevel@tonic-gate } else { 296*7c478bd9Sstevel@tonic-gate /* 297*7c478bd9Sstevel@tonic-gate * Change the user ID of the 298*7c478bd9Sstevel@tonic-gate * file referenced by the 299*7c478bd9Sstevel@tonic-gate * symlink. 300*7c478bd9Sstevel@tonic-gate */ 301*7c478bd9Sstevel@tonic-gate CHOWN(argv[c], uid, gid); 302*7c478bd9Sstevel@tonic-gate } 303*7c478bd9Sstevel@tonic-gate } else { 304*7c478bd9Sstevel@tonic-gate /* 305*7c478bd9Sstevel@tonic-gate * Change the user ID of the file 306*7c478bd9Sstevel@tonic-gate * referenced by the symbolic link. 307*7c478bd9Sstevel@tonic-gate */ 308*7c478bd9Sstevel@tonic-gate CHOWN(argv[c], uid, gid); 309*7c478bd9Sstevel@tonic-gate } 310*7c478bd9Sstevel@tonic-gate } 311*7c478bd9Sstevel@tonic-gate } else if (rflag && ((stbuf.st_mode & S_IFMT) == S_IFDIR)) { 312*7c478bd9Sstevel@tonic-gate /* 313*7c478bd9Sstevel@tonic-gate * Add this node to the search tree so we don't 314*7c478bd9Sstevel@tonic-gate * get into a endless loop. 315*7c478bd9Sstevel@tonic-gate */ 316*7c478bd9Sstevel@tonic-gate if (add_tnode(&tree, stbuf.st_dev, 317*7c478bd9Sstevel@tonic-gate stbuf.st_ino) == 1) { 318*7c478bd9Sstevel@tonic-gate chownr(argv[c], uid, gid); 319*7c478bd9Sstevel@tonic-gate } else { 320*7c478bd9Sstevel@tonic-gate /* 321*7c478bd9Sstevel@tonic-gate * An error occurred while trying 322*7c478bd9Sstevel@tonic-gate * to add the node to the tree. 323*7c478bd9Sstevel@tonic-gate * Continue on with next file 324*7c478bd9Sstevel@tonic-gate * specified. Note: rc shouldn't 325*7c478bd9Sstevel@tonic-gate * be 0 as this was the first node 326*7c478bd9Sstevel@tonic-gate * being added to the search tree. 327*7c478bd9Sstevel@tonic-gate */ 328*7c478bd9Sstevel@tonic-gate status += Perror(argv[c]); 329*7c478bd9Sstevel@tonic-gate } 330*7c478bd9Sstevel@tonic-gate } else if (hflag || Pflag) { 331*7c478bd9Sstevel@tonic-gate LCHOWN(argv[c], uid, gid); 332*7c478bd9Sstevel@tonic-gate } else { 333*7c478bd9Sstevel@tonic-gate CHOWN(argv[c], uid, gid); 334*7c478bd9Sstevel@tonic-gate } 335*7c478bd9Sstevel@tonic-gate } 336*7c478bd9Sstevel@tonic-gate return (status); 337*7c478bd9Sstevel@tonic-gate } 338*7c478bd9Sstevel@tonic-gate 339*7c478bd9Sstevel@tonic-gate /* 340*7c478bd9Sstevel@tonic-gate * chownr() - recursive chown() 341*7c478bd9Sstevel@tonic-gate * 342*7c478bd9Sstevel@tonic-gate * Recursively chowns the input directory then its contents. rflag must 343*7c478bd9Sstevel@tonic-gate * have been set if chownr() is called. The input directory should not 344*7c478bd9Sstevel@tonic-gate * be a sym link (this is handled in the calling routine). In 345*7c478bd9Sstevel@tonic-gate * addition, the calling routine should have already added the input 346*7c478bd9Sstevel@tonic-gate * directory to the search tree so we do not get into endless loops. 347*7c478bd9Sstevel@tonic-gate * Note: chownr() doesn't need a return value as errors are reported 348*7c478bd9Sstevel@tonic-gate * through the global "status" variable. 349*7c478bd9Sstevel@tonic-gate */ 350*7c478bd9Sstevel@tonic-gate static void 351*7c478bd9Sstevel@tonic-gate chownr(char *dir, uid_t uid, gid_t gid) 352*7c478bd9Sstevel@tonic-gate { 353*7c478bd9Sstevel@tonic-gate DIR *dirp; 354*7c478bd9Sstevel@tonic-gate struct dirent *dp; 355*7c478bd9Sstevel@tonic-gate struct stat st, st2; 356*7c478bd9Sstevel@tonic-gate char savedir[1024]; 357*7c478bd9Sstevel@tonic-gate 358*7c478bd9Sstevel@tonic-gate if (getcwd(savedir, 1024) == (char *)0) { 359*7c478bd9Sstevel@tonic-gate (void) Perror("getcwd"); 360*7c478bd9Sstevel@tonic-gate exit(255); 361*7c478bd9Sstevel@tonic-gate } 362*7c478bd9Sstevel@tonic-gate 363*7c478bd9Sstevel@tonic-gate /* 364*7c478bd9Sstevel@tonic-gate * Attempt to chown the directory, however don't return if we 365*7c478bd9Sstevel@tonic-gate * can't as we still may be able to chown the contents of the 366*7c478bd9Sstevel@tonic-gate * directory. Note: the calling routine resets the SUID bits 367*7c478bd9Sstevel@tonic-gate * on this directory so we don't have to perform an extra 'stat'. 368*7c478bd9Sstevel@tonic-gate */ 369*7c478bd9Sstevel@tonic-gate CHOWN(dir, uid, gid); 370*7c478bd9Sstevel@tonic-gate 371*7c478bd9Sstevel@tonic-gate if (chdir(dir) < 0) { 372*7c478bd9Sstevel@tonic-gate status += Perror(dir); 373*7c478bd9Sstevel@tonic-gate return; 374*7c478bd9Sstevel@tonic-gate } 375*7c478bd9Sstevel@tonic-gate if ((dirp = opendir(".")) == NULL) { 376*7c478bd9Sstevel@tonic-gate status += Perror(dir); 377*7c478bd9Sstevel@tonic-gate return; 378*7c478bd9Sstevel@tonic-gate } 379*7c478bd9Sstevel@tonic-gate dp = readdir(dirp); 380*7c478bd9Sstevel@tonic-gate dp = readdir(dirp); /* read "." and ".." */ 381*7c478bd9Sstevel@tonic-gate for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { 382*7c478bd9Sstevel@tonic-gate if (lstat(dp->d_name, &st) < 0) { 383*7c478bd9Sstevel@tonic-gate status += Perror(dp->d_name); 384*7c478bd9Sstevel@tonic-gate continue; 385*7c478bd9Sstevel@tonic-gate } 386*7c478bd9Sstevel@tonic-gate if ((st.st_mode & S_IFMT) == S_IFLNK) { 387*7c478bd9Sstevel@tonic-gate if (hflag || Pflag) { 388*7c478bd9Sstevel@tonic-gate /* 389*7c478bd9Sstevel@tonic-gate * Change the ownership of the symbolic link 390*7c478bd9Sstevel@tonic-gate * encountered while traversing the 391*7c478bd9Sstevel@tonic-gate * directory. Don't follow the symbolic 392*7c478bd9Sstevel@tonic-gate * link to any other part of the file 393*7c478bd9Sstevel@tonic-gate * hierarchy. 394*7c478bd9Sstevel@tonic-gate */ 395*7c478bd9Sstevel@tonic-gate LCHOWN(dp->d_name, uid, gid); 396*7c478bd9Sstevel@tonic-gate } else { 397*7c478bd9Sstevel@tonic-gate if (stat(dp->d_name, &st2) < 0) { 398*7c478bd9Sstevel@tonic-gate status += Perror(dp->d_name); 399*7c478bd9Sstevel@tonic-gate continue; 400*7c478bd9Sstevel@tonic-gate } 401*7c478bd9Sstevel@tonic-gate /* 402*7c478bd9Sstevel@tonic-gate * We know that we are to change the 403*7c478bd9Sstevel@tonic-gate * ownership of the file referenced by the 404*7c478bd9Sstevel@tonic-gate * symlink encountered while traversing 405*7c478bd9Sstevel@tonic-gate * the directory. Now check to see if we 406*7c478bd9Sstevel@tonic-gate * are to follow the symlink to any other 407*7c478bd9Sstevel@tonic-gate * part of the file hierarchy. 408*7c478bd9Sstevel@tonic-gate */ 409*7c478bd9Sstevel@tonic-gate if (FOLLOW_D_LINKS) { 410*7c478bd9Sstevel@tonic-gate if ((st2.st_mode & S_IFMT) == S_IFDIR) { 411*7c478bd9Sstevel@tonic-gate /* 412*7c478bd9Sstevel@tonic-gate * We are following symlinks so 413*7c478bd9Sstevel@tonic-gate * traverse into the directory. 414*7c478bd9Sstevel@tonic-gate * Add this node to the search 415*7c478bd9Sstevel@tonic-gate * tree so we don't get into an 416*7c478bd9Sstevel@tonic-gate * endless loop. 417*7c478bd9Sstevel@tonic-gate */ 418*7c478bd9Sstevel@tonic-gate int rc; 419*7c478bd9Sstevel@tonic-gate if ((rc = add_tnode(&tree, 420*7c478bd9Sstevel@tonic-gate st2.st_dev, 421*7c478bd9Sstevel@tonic-gate st2.st_ino)) == 1) { 422*7c478bd9Sstevel@tonic-gate chownr(dp->d_name, 423*7c478bd9Sstevel@tonic-gate uid, gid); 424*7c478bd9Sstevel@tonic-gate } else if (rc == 0) { 425*7c478bd9Sstevel@tonic-gate /* already visited */ 426*7c478bd9Sstevel@tonic-gate continue; 427*7c478bd9Sstevel@tonic-gate } else { 428*7c478bd9Sstevel@tonic-gate /* 429*7c478bd9Sstevel@tonic-gate * An error occurred 430*7c478bd9Sstevel@tonic-gate * while trying to add 431*7c478bd9Sstevel@tonic-gate * the node to the tree. 432*7c478bd9Sstevel@tonic-gate */ 433*7c478bd9Sstevel@tonic-gate status += Perror( 434*7c478bd9Sstevel@tonic-gate dp->d_name); 435*7c478bd9Sstevel@tonic-gate continue; 436*7c478bd9Sstevel@tonic-gate } 437*7c478bd9Sstevel@tonic-gate } else { 438*7c478bd9Sstevel@tonic-gate /* 439*7c478bd9Sstevel@tonic-gate * Change the user id of the 440*7c478bd9Sstevel@tonic-gate * file referenced by the 441*7c478bd9Sstevel@tonic-gate * symbolic link. 442*7c478bd9Sstevel@tonic-gate */ 443*7c478bd9Sstevel@tonic-gate CHOWN(dp->d_name, uid, gid); 444*7c478bd9Sstevel@tonic-gate } 445*7c478bd9Sstevel@tonic-gate } else { 446*7c478bd9Sstevel@tonic-gate /* 447*7c478bd9Sstevel@tonic-gate * Change the user id of the file 448*7c478bd9Sstevel@tonic-gate * referenced by the symbolic link. 449*7c478bd9Sstevel@tonic-gate */ 450*7c478bd9Sstevel@tonic-gate CHOWN(dp->d_name, uid, gid); 451*7c478bd9Sstevel@tonic-gate } 452*7c478bd9Sstevel@tonic-gate } 453*7c478bd9Sstevel@tonic-gate } else if ((st.st_mode & S_IFMT) == S_IFDIR) { 454*7c478bd9Sstevel@tonic-gate /* 455*7c478bd9Sstevel@tonic-gate * Add this node to the search tree so we don't 456*7c478bd9Sstevel@tonic-gate * get into a endless loop. 457*7c478bd9Sstevel@tonic-gate */ 458*7c478bd9Sstevel@tonic-gate int rc; 459*7c478bd9Sstevel@tonic-gate if ((rc = add_tnode(&tree, st.st_dev, 460*7c478bd9Sstevel@tonic-gate st.st_ino)) == 1) { 461*7c478bd9Sstevel@tonic-gate chownr(dp->d_name, uid, gid); 462*7c478bd9Sstevel@tonic-gate } else if (rc == 0) { 463*7c478bd9Sstevel@tonic-gate /* already visited */ 464*7c478bd9Sstevel@tonic-gate continue; 465*7c478bd9Sstevel@tonic-gate } else { 466*7c478bd9Sstevel@tonic-gate /* 467*7c478bd9Sstevel@tonic-gate * An error occurred while trying 468*7c478bd9Sstevel@tonic-gate * to add the node to the search tree. 469*7c478bd9Sstevel@tonic-gate */ 470*7c478bd9Sstevel@tonic-gate status += Perror(dp->d_name); 471*7c478bd9Sstevel@tonic-gate continue; 472*7c478bd9Sstevel@tonic-gate } 473*7c478bd9Sstevel@tonic-gate } else { 474*7c478bd9Sstevel@tonic-gate CHOWN(dp->d_name, uid, gid); 475*7c478bd9Sstevel@tonic-gate } 476*7c478bd9Sstevel@tonic-gate } 477*7c478bd9Sstevel@tonic-gate 478*7c478bd9Sstevel@tonic-gate (void) closedir(dirp); 479*7c478bd9Sstevel@tonic-gate if (chdir(savedir) < 0) { 480*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 481*7c478bd9Sstevel@tonic-gate "chown: can't change back to %s\n"), savedir); 482*7c478bd9Sstevel@tonic-gate exit(255); 483*7c478bd9Sstevel@tonic-gate } 484*7c478bd9Sstevel@tonic-gate } 485*7c478bd9Sstevel@tonic-gate 486*7c478bd9Sstevel@tonic-gate static int 487*7c478bd9Sstevel@tonic-gate isnumber(char *s) 488*7c478bd9Sstevel@tonic-gate { 489*7c478bd9Sstevel@tonic-gate int c; 490*7c478bd9Sstevel@tonic-gate 491*7c478bd9Sstevel@tonic-gate while ((c = *s++) != '\0') 492*7c478bd9Sstevel@tonic-gate if (!isdigit(c)) 493*7c478bd9Sstevel@tonic-gate return (0); 494*7c478bd9Sstevel@tonic-gate return (1); 495*7c478bd9Sstevel@tonic-gate } 496*7c478bd9Sstevel@tonic-gate 497*7c478bd9Sstevel@tonic-gate static int 498*7c478bd9Sstevel@tonic-gate Perror(char *s) 499*7c478bd9Sstevel@tonic-gate { 500*7c478bd9Sstevel@tonic-gate if (!fflag) { 501*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "chown: "); 502*7c478bd9Sstevel@tonic-gate perror(s); 503*7c478bd9Sstevel@tonic-gate } 504*7c478bd9Sstevel@tonic-gate return (!fflag); 505*7c478bd9Sstevel@tonic-gate } 506*7c478bd9Sstevel@tonic-gate 507*7c478bd9Sstevel@tonic-gate static void 508*7c478bd9Sstevel@tonic-gate usage() 509*7c478bd9Sstevel@tonic-gate { 510*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 511*7c478bd9Sstevel@tonic-gate "usage:\n" 512*7c478bd9Sstevel@tonic-gate "\tchown [-fhR] owner[:group] file...\n" 513*7c478bd9Sstevel@tonic-gate "\tchown -R [-f] [-H|-L|-P] owner[:group] file...\n")); 514*7c478bd9Sstevel@tonic-gate exit(2); 515*7c478bd9Sstevel@tonic-gate } 516