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