1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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$
31 */
32/*
33 * Developed by the TrustedBSD Project.
34 * Support for file system extended attribute.
35 */
36
37#include <sys/types.h>
38#include <sys/uio.h>
39#include <sys/extattr.h>
40#include <sys/param.h>
41#include <sys/mount.h>
42
43#include <ufs/ufs/extattr.h>
44
45#include <errno.h>
46#include <fcntl.h>
47#include <libutil.h>
48#include <stdio.h>
49#include <stdlib.h>
50#include <string.h>
51#include <unistd.h>
52
53int initattr(int argc, char *argv[]);
54int showattr(int argc, char *argv[]);
55long num_inodes_by_path(char *path);
56void usage(void);
57
58void
59usage(void)
60{
61
62	fprintf(stderr,
63	    "usage:\n"
64	    "  extattrctl start path\n"
65	    "  extattrctl stop path\n"
66	    "  extattrctl initattr [-f] [-p path] attrsize attrfile\n"
67	    "  extattrctl showattr attrfile\n"
68	    "  extattrctl enable path attrnamespace attrname attrfile\n"
69	    "  extattrctl disable path attrnamespace attrname\n");
70	exit(-1);
71}
72
73long
74num_inodes_by_path(char *path)
75{
76	struct statfs	buf;
77	int	error;
78
79	error = statfs(path, &buf);
80	if (error) {
81		perror("statfs");
82		return (-1);
83	}
84
85	return (buf.f_files);
86}
87
88static const char zero_buf[8192];
89
90int
91initattr(int argc, char *argv[])
92{
93	struct ufs_extattr_fileheader	uef;
94	char	*fs_path = NULL;
95	int	ch, i, error, flags;
96	ssize_t	wlen;
97	size_t	easize;
98
99	flags = O_CREAT | O_WRONLY | O_TRUNC | O_EXCL;
100	optind = 0;
101	while ((ch = getopt(argc, argv, "fp:r:w:")) != -1)
102		switch (ch) {
103		case 'f':
104			flags &= ~O_EXCL;
105			break;
106		case 'p':
107			fs_path = optarg;
108			break;
109		case '?':
110		default:
111			usage();
112		}
113
114	argc -= optind;
115	argv += optind;
116
117	if (argc != 2)
118		usage();
119
120	error = 0;
121	if ((i = open(argv[1], flags, 0600)) == -1) {
122		/* unable to open file */
123		perror(argv[1]);
124		return (-1);
125	}
126	uef.uef_magic = UFS_EXTATTR_MAGIC;
127	uef.uef_version = UFS_EXTATTR_VERSION;
128	uef.uef_size = atoi(argv[0]);
129	if (write(i, &uef, sizeof(uef)) == -1)
130		error = -1;
131	else if (fs_path != NULL) {
132		easize = (sizeof uef + uef.uef_size) *
133		    num_inodes_by_path(fs_path);
134		while (easize > 0) {
135			if (easize > sizeof zero_buf)
136				wlen = write(i, zero_buf, sizeof zero_buf);
137			else
138				wlen = write(i, zero_buf, easize);
139			if (wlen == -1) {
140				error = -1;
141				break;
142			}
143			easize -= wlen;
144		}
145	}
146	if (error == -1) {
147		perror(argv[1]);
148		unlink(argv[1]);
149		close(i);
150		return (-1);
151	}
152
153	close(i);
154	return (0);
155}
156
157int
158showattr(int argc, char *argv[])
159{
160	struct ufs_extattr_fileheader	uef;
161	int i, fd;
162
163	if (argc != 1)
164		usage();
165
166	fd = open(argv[0], O_RDONLY);
167	if (fd == -1) {
168		perror(argv[0]);
169		return (-1);
170	}
171
172	i = read(fd, &uef, sizeof(uef));
173	if (i == -1) {
174		perror(argv[0]);
175		close(fd);
176		return (-1);
177	}
178	if (i != sizeof(uef)) {
179		fprintf(stderr, "%s: invalid file header\n", argv[0]);
180		close(fd);
181		return (-1);
182	}
183
184	if (uef.uef_magic != UFS_EXTATTR_MAGIC) {
185		fprintf(stderr, "%s: bad magic\n", argv[0]);
186		close(fd);
187		return (-1);
188	}
189
190	printf("%s: version %d, size %d\n", argv[0], uef.uef_version,
191	    uef.uef_size);
192
193	close(fd);
194	return (0);
195}
196
197int
198main(int argc, char *argv[])
199{
200	int	error = 0, attrnamespace;
201
202	if (argc < 2)
203		usage();
204
205	if (!strcmp(argv[1], "start")) {
206		if (argc != 3)
207			usage();
208		error = extattrctl(argv[2], UFS_EXTATTR_CMD_START, NULL, 0,
209		    NULL);
210		if (error) {
211			perror("extattrctl start");
212			return (-1);
213		}
214	} else if (!strcmp(argv[1], "stop")) {
215		if (argc != 3)
216			usage();
217		error = extattrctl(argv[2], UFS_EXTATTR_CMD_STOP, NULL, 0,
218		   NULL);
219		if (error) {
220			perror("extattrctl stop");
221			return (-1);
222		}
223	} else if (!strcmp(argv[1], "enable")) {
224		if (argc != 6)
225			usage();
226		error = extattr_string_to_namespace(argv[3], &attrnamespace);
227		if (error) {
228			perror("extattrctl enable");
229			return (-1);
230		}
231		error = extattrctl(argv[2], UFS_EXTATTR_CMD_ENABLE, argv[5],
232		    attrnamespace, argv[4]);
233		if (error) {
234			perror("extattrctl enable");
235			return (-1);
236		}
237	} else if (!strcmp(argv[1], "disable")) {
238		if (argc != 5)
239			usage();
240		error = extattr_string_to_namespace(argv[3], &attrnamespace);
241		if (error) {
242			perror("extattrctl disable");
243			return (-1);
244		}
245		error = extattrctl(argv[2], UFS_EXTATTR_CMD_DISABLE, NULL,
246		    attrnamespace, argv[4]);
247		if (error) {
248			perror("extattrctl disable");
249			return (-1);
250		}
251	} else if (!strcmp(argv[1], "initattr")) {
252		argc -= 2;
253		argv += 2;
254		error = initattr(argc, argv);
255		if (error)
256			return (-1);
257	} else if (!strcmp(argv[1], "showattr")) {
258		argc -= 2;
259		argv += 2;
260		error = showattr(argc, argv);
261		if (error)
262			return (-1);
263	} else
264		usage();
265
266	return (0);
267}
268