source: MondoRescue/branches/3.3/mindi-busybox/e2fsprogs/chattr.c@ 3625

Last change on this file since 3625 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 5.0 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * chattr.c - Change file attributes on an ext2 file system
4 *
5 * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
6 * Laboratoire MASI, Institut Blaise Pascal
7 * Universite Pierre et Marie Curie (Paris VI)
8 *
9 * This file can be redistributed under the terms of the GNU General
10 * Public License
11 */
12//config:config CHATTR
13//config: bool "chattr"
14//config: default y
15//config: help
16//config: chattr changes the file attributes on a second extended file system.
17
18//applet:IF_CHATTR(APPLET(chattr, BB_DIR_BIN, BB_SUID_DROP))
19
20//kbuild:lib-$(CONFIG_CHATTR) += chattr.o e2fs_lib.o
21
22//usage:#define chattr_trivial_usage
23//usage: "[-R] [-+=AacDdijsStTu] [-v VERSION] [FILE]..."
24//usage:#define chattr_full_usage "\n\n"
25//usage: "Change ext2 file attributes\n"
26//usage: "\nModifiers:"
27//usage: "\n -,+,= Remove/add/set attributes"
28//usage: "\nAttributes:"
29//usage: "\n A Don't track atime"
30//usage: "\n a Append mode only"
31//usage: "\n c Enable compress"
32//usage: "\n D Write dir contents synchronously"
33//usage: "\n d Don't backup with dump"
34//usage: "\n i Cannot be modified (immutable)"
35//usage: "\n j Write all data to journal first"
36//usage: "\n s Zero disk storage when deleted"
37//usage: "\n S Write synchronously"
38//usage: "\n t Disable tail-merging of partial blocks with other files"
39//usage: "\n u Allow file to be undeleted"
40//usage: "\n -R Recurse"
41//usage: "\n -v VER Set version/generation number"
42
43#include "libbb.h"
44#include "e2fs_lib.h"
45
46#define OPT_ADD 1
47#define OPT_REM 2
48#define OPT_SET 4
49#define OPT_SET_VER 8
50
51struct globals {
52 unsigned long version;
53 unsigned long af;
54 unsigned long rf;
55 smallint flags;
56 smallint recursive;
57};
58
59static unsigned long get_flag(char c)
60{
61 const char *fp = strchr(e2attr_flags_sname_chattr, c);
62 if (fp)
63 return e2attr_flags_value_chattr[fp - e2attr_flags_sname_chattr];
64 bb_show_usage();
65}
66
67static int decode_arg(const char *arg, struct globals *gp)
68{
69 unsigned long *fl;
70 char opt = *arg++;
71
72 fl = &gp->af;
73 if (opt == '-') {
74 gp->flags |= OPT_REM;
75 fl = &gp->rf;
76 } else if (opt == '+') {
77 gp->flags |= OPT_ADD;
78 } else if (opt == '=') {
79 gp->flags |= OPT_SET;
80 } else
81 return 0;
82
83 while (*arg)
84 *fl |= get_flag(*arg++);
85
86 return 1;
87}
88
89static void change_attributes(const char *name, struct globals *gp);
90
91static int FAST_FUNC chattr_dir_proc(const char *dir_name, struct dirent *de, void *gp)
92{
93 char *path = concat_subpath_file(dir_name, de->d_name);
94 /* path is NULL if de->d_name is "." or "..", else... */
95 if (path) {
96 change_attributes(path, gp);
97 free(path);
98 }
99 return 0;
100}
101
102static void change_attributes(const char *name, struct globals *gp)
103{
104 unsigned long fsflags;
105 struct stat st;
106
107 if (lstat(name, &st) != 0) {
108 bb_perror_msg("stat %s", name);
109 return;
110 }
111 if (S_ISLNK(st.st_mode) && gp->recursive)
112 return;
113
114 /* Don't try to open device files, fifos etc. We probably
115 * ought to display an error if the file was explicitly given
116 * on the command line (whether or not recursive was
117 * requested). */
118 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) && !S_ISDIR(st.st_mode))
119 return;
120
121 if (gp->flags & OPT_SET_VER)
122 if (fsetversion(name, gp->version) != 0)
123 bb_perror_msg("setting version on %s", name);
124
125 if (gp->flags & OPT_SET) {
126 fsflags = gp->af;
127 } else {
128 if (fgetflags(name, &fsflags) != 0) {
129 bb_perror_msg("reading flags on %s", name);
130 goto skip_setflags;
131 }
132 /*if (gp->flags & OPT_REM) - not needed, rf is zero otherwise */
133 fsflags &= ~gp->rf;
134 /*if (gp->flags & OPT_ADD) - not needed, af is zero otherwise */
135 fsflags |= gp->af;
136 /* What is this? And why it's not done for SET case? */
137 if (!S_ISDIR(st.st_mode))
138 fsflags &= ~EXT2_DIRSYNC_FL;
139 }
140 if (fsetflags(name, fsflags) != 0)
141 bb_perror_msg("setting flags on %s", name);
142
143 skip_setflags:
144 if (gp->recursive && S_ISDIR(st.st_mode))
145 iterate_on_dir(name, chattr_dir_proc, gp);
146}
147
148int chattr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
149int chattr_main(int argc UNUSED_PARAM, char **argv)
150{
151 struct globals g;
152 char *arg;
153
154 memset(&g, 0, sizeof(g));
155
156 /* parse the args */
157 while ((arg = *++argv)) {
158 /* take care of -R and -v <version> */
159 if (arg[0] == '-'
160 && (arg[1] == 'R' || arg[1] == 'v')
161 && !arg[2]
162 ) {
163 if (arg[1] == 'R') {
164 g.recursive = 1;
165 continue;
166 }
167 /* arg[1] == 'v' */
168 if (!*++argv)
169 bb_show_usage();
170 g.version = xatoul(*argv);
171 g.flags |= OPT_SET_VER;
172 continue;
173 }
174
175 if (!decode_arg(arg, &g))
176 break;
177 }
178
179 /* run sanity checks on all the arguments given us */
180 if (!*argv)
181 bb_show_usage();
182 if ((g.flags & OPT_SET) && (g.flags & (OPT_ADD|OPT_REM)))
183 bb_error_msg_and_die("= is incompatible with - and +");
184 if (g.rf & g.af)
185 bb_error_msg_and_die("can't set and unset a flag");
186 if (!g.flags)
187 bb_error_msg_and_die("must use '-v', =, - or +");
188
189 /* now run chattr on all the files passed to us */
190 do change_attributes(*argv, &g); while (*++argv);
191
192 return EXIT_SUCCESS;
193}
Note: See TracBrowser for help on using the repository browser.