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 51 int initattr(int argc, char *argv[]); 52 int showattr(int argc, char *argv[]); 53 long num_inodes_by_path(char *path); 54 void usage(void); 55 56 void 57 usage(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 71 long 72 num_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 86 static const char zero_buf[8192]; 87 88 int 89 initattr(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 155 int 156 showattr(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 195 int 196 main(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