xref: /netbsd-src/usr.bin/chflags/chflags.c (revision da39777e71da2583f9f99e14ec631aa1110387b6)
1*da39777eSkre /*	$NetBSD: chflags.c,v 1.18 2023/05/05 04:14:02 kre Exp $	*/
26e0c4dedSjtc 
39636069cSjtc /*
49636069cSjtc  * Copyright (c) 1992, 1993, 1994
59636069cSjtc  *	The Regents of the University of California.  All rights reserved.
69636069cSjtc  *
79636069cSjtc  * Redistribution and use in source and binary forms, with or without
89636069cSjtc  * modification, are permitted provided that the following conditions
99636069cSjtc  * are met:
109636069cSjtc  * 1. Redistributions of source code must retain the above copyright
119636069cSjtc  *    notice, this list of conditions and the following disclaimer.
129636069cSjtc  * 2. Redistributions in binary form must reproduce the above copyright
139636069cSjtc  *    notice, this list of conditions and the following disclaimer in the
149636069cSjtc  *    documentation and/or other materials provided with the distribution.
1589aaa1bbSagc  * 3. Neither the name of the University nor the names of its contributors
169636069cSjtc  *    may be used to endorse or promote products derived from this software
179636069cSjtc  *    without specific prior written permission.
189636069cSjtc  *
199636069cSjtc  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
209636069cSjtc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
219636069cSjtc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
229636069cSjtc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
239636069cSjtc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
249636069cSjtc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
259636069cSjtc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
269636069cSjtc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
279636069cSjtc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
289636069cSjtc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
299636069cSjtc  * SUCH DAMAGE.
309636069cSjtc  */
319636069cSjtc 
325f18af1fSlukem #include <sys/cdefs.h>
339636069cSjtc #ifndef lint
3498e5374cSlukem __COPYRIGHT("@(#) Copyright (c) 1992, 1993, 1994\
3598e5374cSlukem  The Regents of the University of California.  All rights reserved.");
369636069cSjtc #endif /* not lint */
379636069cSjtc 
389636069cSjtc #ifndef lint
39e0703abaSglass #if 0
40e0703abaSglass static char sccsid[] = "from: @(#)chflags.c	8.5 (Berkeley) 4/1/94";
41e0703abaSglass #else
42*da39777eSkre __RCSID("$NetBSD: chflags.c,v 1.18 2023/05/05 04:14:02 kre Exp $");
43e0703abaSglass #endif
449636069cSjtc #endif /* not lint */
459636069cSjtc 
469636069cSjtc #include <sys/types.h>
479636069cSjtc #include <sys/stat.h>
489636069cSjtc 
499636069cSjtc #include <err.h>
509636069cSjtc #include <errno.h>
519636069cSjtc #include <fts.h>
529636069cSjtc #include <stdio.h>
539636069cSjtc #include <stdlib.h>
549636069cSjtc #include <string.h>
559636069cSjtc #include <unistd.h>
5649444675She #include <util.h>
5714a817a5Smrg 
586e33bec8Sjoerg __dead static void	usage(void);
599636069cSjtc 
609636069cSjtc int
main(int argc,char * argv[])6180a3a079Sxtraeme main(int argc, char *argv[])
629636069cSjtc {
639636069cSjtc 	FTS *ftsp;
649636069cSjtc 	FTSENT *p;
6575015c55Senami 	u_long clear, set, newflags;
669636069cSjtc 	long val;
67*da39777eSkre 	int Hflag, Lflag, Rflag, ch, fts_options, dflag, hflag, oct, rval;
689636069cSjtc 	char *flags, *ep;
69971b39dfSxtraeme 	int (*change_flags)(const char *, u_long);
709636069cSjtc 
71*da39777eSkre 	Hflag = Lflag = Rflag = dflag = hflag = 0;
72*da39777eSkre 	while ((ch = getopt(argc, argv, "HLPRdh")) != -1)
739636069cSjtc 		switch (ch) {
749636069cSjtc 		case 'H':
759636069cSjtc 			Hflag = 1;
7643bbf1aeSenami 			Lflag = 0;
779636069cSjtc 			break;
789636069cSjtc 		case 'L':
799636069cSjtc 			Lflag = 1;
8043bbf1aeSenami 			Hflag = 0;
819636069cSjtc 			break;
829636069cSjtc 		case 'P':
839636069cSjtc 			Hflag = Lflag = 0;
849636069cSjtc 			break;
859636069cSjtc 		case 'R':
869636069cSjtc 			Rflag = 1;
879636069cSjtc 			break;
88*da39777eSkre 		case 'd':
89*da39777eSkre 			dflag = 1;
90*da39777eSkre 			break;
9175015c55Senami 		case 'h':
9275015c55Senami 			hflag = 1;
9375015c55Senami 			break;
949636069cSjtc 		case '?':
959636069cSjtc 		default:
969636069cSjtc 			usage();
979636069cSjtc 		}
989636069cSjtc 	argv += optind;
999636069cSjtc 	argc -= optind;
1009636069cSjtc 
1019636069cSjtc 	if (argc < 2)
1029636069cSjtc 		usage();
1039636069cSjtc 
1049636069cSjtc 	fts_options = FTS_PHYSICAL;
1059636069cSjtc 	if (Rflag) {
1069636069cSjtc 		if (Hflag)
1079636069cSjtc 			fts_options |= FTS_COMFOLLOW;
1089636069cSjtc 		if (Lflag) {
1099636069cSjtc 			fts_options &= ~FTS_PHYSICAL;
1109636069cSjtc 			fts_options |= FTS_LOGICAL;
1119636069cSjtc 		}
112525b0502Sbjh21 	} else if (!hflag)
113525b0502Sbjh21 		fts_options |= FTS_COMFOLLOW;
1149636069cSjtc 
1159636069cSjtc 	flags = *argv;
1169636069cSjtc 	if (*flags >= '0' && *flags <= '7') {
1179636069cSjtc 		errno = 0;
1189636069cSjtc 		val = strtol(flags, &ep, 8);
1199636069cSjtc 		if (val < 0)
1209636069cSjtc 			errno = ERANGE;
1219636069cSjtc 		if (errno)
1229636069cSjtc 			err(1, "invalid flags: %s", flags);
1239636069cSjtc 		if (*ep)
1249636069cSjtc 			errx(1, "invalid flags: %s", flags);
1259636069cSjtc 		set = val;
1269636069cSjtc 		oct = 1;
1279636069cSjtc 	} else {
1289636069cSjtc 		if (string_to_flags(&flags, &set, &clear))
1299636069cSjtc 			errx(1, "invalid flag: %s", flags);
1309636069cSjtc 		clear = ~clear;
1319636069cSjtc 		oct = 0;
1329636069cSjtc 	}
1339636069cSjtc 
13443bbf1aeSenami 	if ((ftsp = fts_open(++argv, fts_options, NULL)) == NULL)
13575015c55Senami 		err(1, "fts_open");
1369636069cSjtc 
1379636069cSjtc 	for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
13875015c55Senami 		change_flags = chflags;
1399636069cSjtc 		switch (p->fts_info) {
1409636069cSjtc 		case FTS_D:
1419636069cSjtc 			if (Rflag)		/* Change it at FTS_DP. */
1429636069cSjtc 				continue;
1439636069cSjtc 			fts_set(ftsp, p, FTS_SKIP);
1449636069cSjtc 			break;
1459636069cSjtc 		case FTS_DNR:			/* Warn, chflag, continue. */
1469636069cSjtc 			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
1479636069cSjtc 			rval = 1;
1489636069cSjtc 			break;
1499636069cSjtc 		case FTS_ERR:			/* Warn, continue. */
1509636069cSjtc 		case FTS_NS:
1519636069cSjtc 			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
1529636069cSjtc 			rval = 1;
1539636069cSjtc 			continue;
15475015c55Senami 		case FTS_SL:			/* Ignore unless -h. */
15575015c55Senami 			/*
15675015c55Senami 			 * All symlinks we found while doing a physical
15775015c55Senami 			 * walk end up here.
15875015c55Senami 			 */
15975015c55Senami 			if (!hflag)
16075015c55Senami 				continue;
16175015c55Senami 			/*
16275015c55Senami 			 * Note that if we follow a symlink, fts_info is
16375015c55Senami 			 * not FTS_SL but FTS_F or whatever.  And we should
16475015c55Senami 			 * use lchflags only for FTS_SL and should use chflags
16575015c55Senami 			 * for others.
16675015c55Senami 			 */
16775015c55Senami 			change_flags = lchflags;
16875015c55Senami 			break;
16975015c55Senami 		case FTS_SLNONE:		/* Ignore. */
1709636069cSjtc 			/*
1719636069cSjtc 			 * The only symlinks that end up here are ones that
17275015c55Senami 			 * don't point to anything.  Note that if we are
1736ef0b3e4Sandvar 			 * doing a physical walk, we never reach here unless
17475015c55Senami 			 * we asked to follow explicitly.
1759636069cSjtc 			 */
1769636069cSjtc 			continue;
1779636069cSjtc 		default:
1789636069cSjtc 			break;
1799636069cSjtc 		}
18075015c55Senami 		if (oct)
18175015c55Senami 			newflags = set;
18275015c55Senami 		else {
18375015c55Senami 			newflags = p->fts_statp->st_flags;
18475015c55Senami 			newflags |= set;
18575015c55Senami 			newflags &= clear;
1869636069cSjtc 		}
187*da39777eSkre 		if (dflag && newflags == p->fts_statp->st_flags)
188*da39777eSkre 			continue;
18975015c55Senami 		if ((*change_flags)(p->fts_accpath, newflags)) {
1909636069cSjtc 			warn("%s", p->fts_path);
1919636069cSjtc 			rval = 1;
1929636069cSjtc 		}
19375015c55Senami 	}
1949636069cSjtc 	if (errno)
1959636069cSjtc 		err(1, "fts_read");
1969636069cSjtc 	exit(rval);
1979636069cSjtc }
1989636069cSjtc 
1996e33bec8Sjoerg static void
usage(void)20080a3a079Sxtraeme usage(void)
2019636069cSjtc {
20275015c55Senami 
2039636069cSjtc 	(void)fprintf(stderr,
204*da39777eSkre 	    "usage: chflags [-R [-H | -L | -P]] [-dh] flags file ...\n");
2059636069cSjtc 	exit(1);
2069636069cSjtc }
207