1 /*- 2 * Copyright (c) 2002, 2003 Networks Associates Technology, Inc. 3 * Copyright (c) 2002 Poul-Henning Kamp. 4 * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson 5 * All rights reserved. 6 * 7 * This software was developed for the FreeBSD Project by Poul-Henning 8 * Kamp and Network Associates Laboratories, the Security Research Division 9 * of Network Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 10 * ("CBOSS"), as part of the DARPA CHATS research program 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. The names of the authors may not be used to endorse or promote 21 * products derived from this software without specific prior written 22 * permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * $FreeBSD$ 37 */ 38 39 #include <sys/types.h> 40 #include <sys/uio.h> 41 #include <sys/extattr.h> 42 43 #include <libgen.h> 44 #include <libutil.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <unistd.h> 49 #include <vis.h> 50 #include <err.h> 51 #include <errno.h> 52 53 static enum { EADUNNO, EAGET, EASET, EARM, EALS } what = EADUNNO; 54 55 static void __dead2 56 usage(void) 57 { 58 59 switch (what) { 60 case EAGET: 61 fprintf(stderr, "usage: getextattr [-fhqsx] attrnamespace"); 62 fprintf(stderr, " attrname filename ...\n"); 63 exit(-1); 64 case EASET: 65 fprintf(stderr, "usage: setextattr [-fhnq] attrnamespace"); 66 fprintf(stderr, " attrname attrvalue filename ...\n"); 67 exit(-1); 68 case EARM: 69 fprintf(stderr, "usage: rmextattr [-fhq] attrnamespace"); 70 fprintf(stderr, " attrname filename ...\n"); 71 exit(-1); 72 case EALS: 73 fprintf(stderr, "usage: lsextattr [-fhq] attrnamespace"); 74 fprintf(stderr, " filename ...\n"); 75 exit(-1); 76 case EADUNNO: 77 default: 78 fprintf(stderr, "usage: (getextattr|lsextattr|rmextattr"); 79 fprintf(stderr, "|setextattr)\n"); 80 exit (-1); 81 } 82 } 83 84 static void 85 mkbuf(char **buf, int *oldlen, int newlen) 86 { 87 88 if (*oldlen >= newlen) 89 return; 90 if (*buf != NULL) 91 free(*buf); 92 *buf = malloc(newlen); 93 if (*buf == NULL) 94 err(1, "malloc"); 95 *oldlen = newlen; 96 return; 97 } 98 99 int 100 main(int argc, char *argv[]) 101 { 102 char *buf, *visbuf, *p; 103 104 const char *options, *attrname; 105 size_t len; 106 ssize_t ret; 107 int buflen, visbuflen, ch, error, i, arg_counter, attrnamespace, 108 minargc; 109 110 int flag_force = 0; 111 int flag_nofollow = 0; 112 int flag_null = 0; 113 int flag_quiet = 0; 114 int flag_string = 0; 115 int flag_hex = 0; 116 117 visbuflen = buflen = 0; 118 visbuf = buf = NULL; 119 120 p = basename(argv[0]); 121 if (p == NULL) 122 p = argv[0]; 123 if (!strcmp(p, "getextattr")) { 124 what = EAGET; 125 options = "fhqsx"; 126 minargc = 3; 127 } else if (!strcmp(p, "setextattr")) { 128 what = EASET; 129 options = "fhnq"; 130 minargc = 4; 131 } else if (!strcmp(p, "rmextattr")) { 132 what = EARM; 133 options = "fhq"; 134 minargc = 3; 135 } else if (!strcmp(p, "lsextattr")) { 136 what = EALS; 137 options = "fhq"; 138 minargc = 2; 139 } else { 140 usage(); 141 } 142 143 while ((ch = getopt(argc, argv, options)) != -1) { 144 switch (ch) { 145 case 'f': 146 flag_force = 1; 147 break; 148 case 'h': 149 flag_nofollow = 1; 150 break; 151 case 'n': 152 flag_null = 1; 153 break; 154 case 'q': 155 flag_quiet = 1; 156 break; 157 case 's': 158 flag_string = 1; 159 break; 160 case 'x': 161 flag_hex = 1; 162 break; 163 case '?': 164 default: 165 usage(); 166 } 167 } 168 169 argc -= optind; 170 argv += optind; 171 172 if (argc < minargc) 173 usage(); 174 175 error = extattr_string_to_namespace(argv[0], &attrnamespace); 176 if (error) 177 err(-1, "%s", argv[0]); 178 argc--; argv++; 179 180 if (what != EALS) { 181 attrname = argv[0]; 182 argc--; argv++; 183 } else 184 attrname = NULL; 185 186 if (what == EASET) { 187 mkbuf(&buf, &buflen, strlen(argv[0]) + 1); 188 strcpy(buf, argv[0]); 189 argc--; argv++; 190 } 191 192 for (arg_counter = 0; arg_counter < argc; arg_counter++) { 193 switch (what) { 194 case EARM: 195 if (flag_nofollow) 196 error = extattr_delete_link(argv[arg_counter], 197 attrnamespace, attrname); 198 else 199 error = extattr_delete_file(argv[arg_counter], 200 attrnamespace, attrname); 201 if (error >= 0) 202 continue; 203 break; 204 case EASET: 205 len = strlen(buf) + flag_null; 206 if (flag_nofollow) 207 ret = extattr_set_link(argv[arg_counter], 208 attrnamespace, attrname, buf, len); 209 else 210 ret = extattr_set_file(argv[arg_counter], 211 attrnamespace, attrname, buf, len); 212 if (ret >= 0) { 213 if ((size_t)ret != len && !flag_quiet) { 214 warnx("Set %zd bytes of %zu for %s", 215 ret, len, attrname); 216 } 217 continue; 218 } 219 break; 220 case EALS: 221 if (flag_nofollow) 222 ret = extattr_list_link(argv[arg_counter], 223 attrnamespace, NULL, 0); 224 else 225 ret = extattr_list_file(argv[arg_counter], 226 attrnamespace, NULL, 0); 227 if (ret < 0) 228 break; 229 mkbuf(&buf, &buflen, ret); 230 if (flag_nofollow) 231 ret = extattr_list_link(argv[arg_counter], 232 attrnamespace, buf, buflen); 233 else 234 ret = extattr_list_file(argv[arg_counter], 235 attrnamespace, buf, buflen); 236 if (ret < 0) 237 break; 238 if (!flag_quiet) 239 printf("%s\t", argv[arg_counter]); 240 for (i = 0; i < ret; i += ch + 1) { 241 /* The attribute name length is unsigned. */ 242 ch = (unsigned char)buf[i]; 243 printf("%s%*.*s", i ? "\t" : "", 244 ch, ch, buf + i + 1); 245 } 246 if (!flag_quiet || ret > 0) 247 printf("\n"); 248 continue; 249 case EAGET: 250 if (flag_nofollow) 251 ret = extattr_get_link(argv[arg_counter], 252 attrnamespace, attrname, NULL, 0); 253 else 254 ret = extattr_get_file(argv[arg_counter], 255 attrnamespace, attrname, NULL, 0); 256 if (ret < 0) 257 break; 258 mkbuf(&buf, &buflen, ret); 259 if (flag_nofollow) 260 ret = extattr_get_link(argv[arg_counter], 261 attrnamespace, attrname, buf, buflen); 262 else 263 ret = extattr_get_file(argv[arg_counter], 264 attrnamespace, attrname, buf, buflen); 265 if (ret < 0) 266 break; 267 if (!flag_quiet) 268 printf("%s\t", argv[arg_counter]); 269 if (flag_string) { 270 mkbuf(&visbuf, &visbuflen, ret * 4 + 1); 271 strvisx(visbuf, buf, ret, 272 VIS_SAFE | VIS_WHITE); 273 printf("\"%s\"\n", visbuf); 274 continue; 275 } else if (flag_hex) { 276 for (i = 0; i < ret; i++) 277 printf("%s%02x", i ? " " : "", 278 buf[i]); 279 printf("\n"); 280 continue; 281 } else { 282 fwrite(buf, ret, 1, stdout); 283 printf("\n"); 284 continue; 285 } 286 default: 287 break; 288 } 289 if (!flag_quiet) 290 warn("%s: failed", argv[arg_counter]); 291 if (flag_force) 292 continue; 293 return(1); 294 } 295 return (0); 296 } 297