1 /*- 2 * Copyright (c) 2002 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 <libutil.h> 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <unistd.h> 48 #include <vis.h> 49 #include <err.h> 50 #include <errno.h> 51 52 static enum { EADUNNO, EAGET, EASET, EARM, EALS } what = EADUNNO; 53 54 static void __dead2 55 usage(void) 56 { 57 58 switch (what) { 59 case EAGET: 60 fprintf(stderr, "usage: getextattr [-fqsx] attrnamespace"); 61 fprintf(stderr, " attrname filename ...\n"); 62 exit(-1); 63 case EASET: 64 fprintf(stderr, "usage: setextattr [-fq] attrnamespace"); 65 fprintf(stderr, " attrname attrvalue filename ...\n"); 66 exit(-1); 67 case EARM: 68 fprintf(stderr, "usage: rmextattr [-fq] attrnamespace"); 69 fprintf(stderr, " attrname filename ...\n"); 70 exit(-1); 71 case EALS: 72 fprintf(stderr, "usage: lsextattr [-fq] attrnamespace"); 73 fprintf(stderr, " filename ...\n"); 74 exit(-1); 75 case EADUNNO: 76 default: 77 fprintf(stderr, "usage: (getextattr|lsextattr|rmextattr"); 78 fprintf(stderr, "|setextattr)\n"); 79 exit (-1); 80 } 81 } 82 83 static void 84 mkbuf(char **buf, int *oldlen, int newlen) 85 { 86 87 if (*oldlen >= newlen) 88 return; 89 if (*buf != NULL) 90 free(*buf); 91 *buf = malloc(newlen); 92 if (*buf == NULL) 93 err(1, "malloc"); 94 *oldlen = newlen; 95 return; 96 } 97 98 int 99 main(int argc, char *argv[]) 100 { 101 char *buf, *visbuf, *p; 102 103 const char *options, *attrname; 104 int buflen, visbuflen, ch, error, i, arg_counter, attrnamespace; 105 106 int flag_force = 0; 107 int flag_quiet = 0; 108 int flag_string = 0; 109 int flag_hex = 0; 110 111 visbuflen = buflen = 0; 112 visbuf = buf = NULL; 113 114 p = strrchr(argv[0], '/'); 115 if (p == NULL) 116 p = argv[0]; 117 if (!strcmp(p, "getextattr")) { 118 what = EAGET; 119 options = "fqsx"; 120 } else if (!strcmp(p, "setextattr")) { 121 what = EASET; 122 options = "fq"; 123 } else if (!strcmp(p, "rmextattr")) { 124 what = EARM; 125 options = "fq"; 126 } else if (!strcmp(p, "lsextattr")) { 127 what = EALS; 128 options = "fq"; 129 } else { 130 usage(); 131 } 132 133 while ((ch = getopt(argc, argv, options)) != -1) { 134 switch (ch) { 135 case 'f': 136 flag_force = 1; 137 break; 138 case 'q': 139 flag_quiet = 1; 140 break; 141 case 's': 142 flag_string = 1; 143 break; 144 case 'x': 145 flag_hex = 1; 146 break; 147 case '?': 148 default: 149 usage(); 150 } 151 } 152 153 argc -= optind; 154 argv += optind; 155 156 if (argc < 2) 157 usage(); 158 159 error = extattr_string_to_namespace(argv[0], &attrnamespace); 160 if (error) 161 err(-1, argv[0]); 162 argc--; argv++; 163 164 if (what == EALS) { 165 attrname = ""; 166 } else { 167 attrname = argv[0]; 168 argc--; argv++; 169 } 170 171 if (what == EASET) { 172 mkbuf(&buf, &buflen, strlen(argv[0]) + 1); 173 strcpy(buf, argv[0]); 174 argc--; argv++; 175 } 176 177 for (arg_counter = 0; arg_counter < argc; arg_counter++) { 178 switch (what) { 179 case EARM: 180 error = extattr_delete_file(argv[arg_counter], 181 attrnamespace, attrname); 182 if (error >= 0) 183 continue; 184 break; 185 case EASET: 186 error = extattr_set_file(argv[arg_counter], 187 attrnamespace, attrname, buf, strlen(buf)); 188 if (error >= 0) 189 continue; 190 break; 191 case EALS: 192 case EAGET: 193 error = extattr_get_file(argv[arg_counter], 194 attrnamespace, attrname, NULL, 0); 195 if (error < 0) 196 break; 197 mkbuf(&buf, &buflen, error); 198 error = extattr_get_file(argv[arg_counter], 199 attrnamespace, attrname, buf, buflen); 200 if (error < 0) 201 break; 202 if (!flag_quiet) 203 printf("%s\t", argv[arg_counter]); 204 if (what == EALS) { 205 for (i = 0; i < error; i += buf[i] + 1) 206 printf("%s%*.*s", i ? "\t" : "", 207 buf[i], buf[i], buf + i + 1); 208 printf("\n"); 209 continue; 210 } 211 if (flag_string) { 212 mkbuf(&visbuf, &visbuflen, error * 4 + 1); 213 strvisx(visbuf, buf, error, 214 VIS_SAFE | VIS_WHITE); 215 printf("\"%s\"\n", visbuf); 216 continue; 217 } else if (flag_hex) { 218 for (i = 0; i < error; i++) 219 printf("%s%02x", i ? " " : "", 220 buf[i]); 221 printf("\n"); 222 continue; 223 } else { 224 fwrite(buf, buflen, 1, stdout); 225 printf("\n"); 226 continue; 227 } 228 default: 229 break; 230 } 231 if (!flag_quiet) 232 warn("%s: failed", argv[arg_counter]); 233 if (flag_force) 234 continue; 235 return(1); 236 } 237 return (0); 238 } 239