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