1 /* $NetBSD: extattrctl.c,v 1.4 2011/08/31 13:32:36 joerg Exp $ */
2
3 /*-
4 * Copyright (c) 1999-2002 Robert N. M. Watson
5 * All rights reserved.
6 *
7 * This software was developed by Robert Watson for the TrustedBSD Project.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * $FreeBSD: src/usr.sbin/extattrctl/extattrctl.c,v 1.19 2002/04/19 01:42:55 rwatson Exp $
31 */
32
33 /*
34 * Developed by the TrustedBSD Project.
35 * Support for file system extended attribute.
36 */
37
38 #include <sys/types.h>
39 #include <sys/uio.h>
40 #include <sys/extattr.h>
41 #include <sys/param.h>
42 #include <sys/mount.h>
43
44 #include <ufs/ufs/extattr.h>
45
46 #include <err.h>
47 #include <fcntl.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <unistd.h>
52 #include <util.h>
53
54 #include <machine/bswap.h>
55 #include <machine/endian.h>
56
57 static int needswap;
58
59 static uint32_t
rw32(uint32_t v)60 rw32(uint32_t v)
61 {
62 if (needswap)
63 return (bswap32(v));
64 return (v);
65 }
66
67 __dead static void
usage(void)68 usage(void)
69 {
70
71 fprintf(stderr,
72 "usage:\n"
73 " %s start path\n"
74 " %s stop path\n"
75 " %s initattr [-f] [-p path] attrsize attrfile\n"
76 " %s showattr attrfile\n"
77 " %s enable path attrnamespace attrname attrfile\n"
78 " %s disable path attrnamespace attrname\n",
79 getprogname(), getprogname(), getprogname(),
80 getprogname(), getprogname(), getprogname());
81 exit(1);
82 }
83
84 static uint64_t
num_inodes_by_path(const char * path)85 num_inodes_by_path(const char *path)
86 {
87 struct statvfs buf;
88
89 if (statvfs(path, &buf) == -1) {
90 warn("statvfs(%s)", path);
91 return (-1);
92 }
93
94 return (buf.f_files);
95 }
96
97 static const char zero_buf[8192];
98
99 static int
initattr(int argc,char * argv[])100 initattr(int argc, char *argv[])
101 {
102 struct ufs_extattr_fileheader uef;
103 char *fs_path = NULL;
104 int ch, i, error, flags;
105 ssize_t wlen;
106 size_t easize;
107
108 flags = O_CREAT | O_WRONLY | O_TRUNC | O_EXCL;
109 optind = 0;
110 while ((ch = getopt(argc, argv, "fp:r:w:")) != -1) {
111 switch (ch) {
112 case 'f':
113 flags &= ~O_EXCL;
114 break;
115 case 'p':
116 fs_path = optarg;
117 break;
118 case 'B':
119 #if BYTE_ORDER == LITTLE_ENDIAN
120 if (strcmp(optarg, "le") == 0)
121 needswap = 0;
122 else if (strcmp(optarg, "be") == 0)
123 needswap = 1;
124 else
125 usage();
126 #else
127 if (strcmp(optarg, "be") == 0)
128 needswap = 0;
129 else if (strcmp(optarg, "le") == 0)
130 needswap = 1;
131 else
132 usage();
133 #endif
134 break;
135 case '?':
136 default:
137 usage();
138 }
139 }
140
141 argc -= optind;
142 argv += optind;
143
144 if (argc != 2)
145 usage();
146
147 error = 0;
148 if ((i = open(argv[1], flags, 0600)) == -1) {
149 warn("open(%s)", argv[1]);
150 return (-1);
151 }
152 uef.uef_magic = rw32(UFS_EXTATTR_MAGIC);
153 uef.uef_version = rw32(UFS_EXTATTR_VERSION);
154 uef.uef_size = rw32(atoi(argv[0]));
155 if (write(i, &uef, sizeof(uef)) != sizeof(uef)) {
156 warn("unable to write attribute file header");
157 error = -1;
158 } else if (fs_path != NULL) {
159 easize = (sizeof(uef) + uef.uef_size) *
160 num_inodes_by_path(fs_path);
161 while (easize > 0) {
162 size_t x = (easize > sizeof(zero_buf)) ?
163 sizeof(zero_buf) : easize;
164 wlen = write(i, zero_buf, x);
165 if ((size_t)wlen != x) {
166 warn("unable to write attribute file");
167 error = -1;
168 break;
169 }
170 easize -= wlen;
171 }
172 }
173 close(i);
174 if (error == -1) {
175 unlink(argv[1]);
176 return (-1);
177 }
178
179 return (0);
180 }
181
182 static int
showattr(int argc,char * argv[])183 showattr(int argc, char *argv[])
184 {
185 struct ufs_extattr_fileheader uef;
186 int i, fd;
187 const char *bo;
188
189 if (argc != 1)
190 usage();
191
192 fd = open(argv[0], O_RDONLY);
193 if (fd == -1) {
194 warn("open(%s)", argv[0]);
195 return (-1);
196 }
197
198 i = read(fd, &uef, sizeof(uef));
199 if (i != sizeof(uef)) {
200 warn("unable to read attribute file header");
201 (void)close(fd);
202 return (-1);
203 }
204
205 if (rw32(uef.uef_magic) != UFS_EXTATTR_MAGIC) {
206 needswap = 1;
207 if (rw32(uef.uef_magic) != UFS_EXTATTR_MAGIC) {
208 fprintf(stderr, "%s: bad magic\n", argv[0]);
209 (void)close(fd);
210 return (-1);
211 }
212 }
213
214 #if BYTE_ORDER == LITTLE_ENDIAN
215 bo = needswap ? "big-endian" : "little-endian";
216 #else
217 bo = needswap ? "little-endian" : "big-endian";
218 #endif
219
220 printf("%s: version %u, size %u, byte-order: %s\n",
221 argv[0], rw32(uef.uef_version), rw32(uef.uef_size), bo);
222
223 close(fd);
224 return (0);
225 }
226
227 int
main(int argc,char * argv[])228 main(int argc, char *argv[])
229 {
230 int error = 0, attrnamespace;
231
232 if (argc < 2)
233 usage();
234
235 if (!strcmp(argv[1], "start")) {
236 if (argc != 3)
237 usage();
238 error = extattrctl(argv[2], UFS_EXTATTR_CMD_START, NULL, 0,
239 NULL);
240 if (error)
241 err(1, "start");
242 } else if (!strcmp(argv[1], "stop")) {
243 if (argc != 3)
244 usage();
245 error = extattrctl(argv[2], UFS_EXTATTR_CMD_STOP, NULL, 0,
246 NULL);
247 if (error)
248 err(1, "stop");
249 } else if (!strcmp(argv[1], "enable")) {
250 if (argc != 6)
251 usage();
252 error = extattr_string_to_namespace(argv[3], &attrnamespace);
253 if (error)
254 errx(1, "bad namespace: %s", argv[3]);
255 error = extattrctl(argv[2], UFS_EXTATTR_CMD_ENABLE, argv[5],
256 attrnamespace, argv[4]);
257 if (error)
258 err(1, "enable");
259 } else if (!strcmp(argv[1], "disable")) {
260 if (argc != 5)
261 usage();
262 error = extattr_string_to_namespace(argv[3], &attrnamespace);
263 if (error)
264 errx(1, "bad namespace: %s", argv[3]);
265 error = extattrctl(argv[2], UFS_EXTATTR_CMD_DISABLE, NULL,
266 attrnamespace, argv[4]);
267 if (error)
268 err(1, "disable");
269 } else if (!strcmp(argv[1], "initattr")) {
270 argc -= 2;
271 argv += 2;
272 error = initattr(argc, argv);
273 if (error)
274 return (1);
275 } else if (!strcmp(argv[1], "showattr")) {
276 argc -= 2;
277 argv += 2;
278 error = showattr(argc, argv);
279 if (error)
280 return (1);
281 } else
282 usage();
283
284 return (0);
285 }
286