xref: /freebsd/usr.sbin/extattrctl/extattrctl.c (revision e8d8bef961a50d4dc22501cde4fb9fb0be1b2532)
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 
53 int initattr(int argc, char *argv[]);
54 int showattr(int argc, char *argv[]);
55 long num_inodes_by_path(char *path);
56 void usage(void);
57 
58 void
59 usage(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 
73 long
74 num_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 
88 static const char zero_buf[8192];
89 
90 int
91 initattr(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 
157 int
158 showattr(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 
197 int
198 main(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