1102607Sphk/*- 2115864Srwatson * Copyright (c) 2002, 2003 Networks Associates Technology, Inc. 3102607Sphk * Copyright (c) 2002 Poul-Henning Kamp. 4102607Sphk * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson 5102607Sphk * All rights reserved. 6102607Sphk * 7102607Sphk * This software was developed for the FreeBSD Project by Poul-Henning 8102607Sphk * Kamp and Network Associates Laboratories, the Security Research Division 9102607Sphk * of Network Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 10102607Sphk * ("CBOSS"), as part of the DARPA CHATS research program 11102607Sphk * 12102607Sphk * Redistribution and use in source and binary forms, with or without 13102607Sphk * modification, are permitted provided that the following conditions 14102607Sphk * are met: 15102607Sphk * 1. Redistributions of source code must retain the above copyright 16102607Sphk * notice, this list of conditions and the following disclaimer. 17102607Sphk * 2. Redistributions in binary form must reproduce the above copyright 18102607Sphk * notice, this list of conditions and the following disclaimer in the 19102607Sphk * documentation and/or other materials provided with the distribution. 20102607Sphk * 3. The names of the authors may not be used to endorse or promote 21102607Sphk * products derived from this software without specific prior written 22102607Sphk * permission. 23102607Sphk * 24102607Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 25102607Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26102607Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27102607Sphk * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 28102607Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29102607Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30102607Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31102607Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32102607Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33102607Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34102607Sphk * SUCH DAMAGE. 35102607Sphk * 36102607Sphk * $FreeBSD$ 37102607Sphk */ 38102607Sphk 39102607Sphk#include <sys/types.h> 40102607Sphk#include <sys/uio.h> 41102607Sphk#include <sys/extattr.h> 42102607Sphk 43104796Srwatson#include <libgen.h> 44102607Sphk#include <libutil.h> 45102607Sphk#include <stdio.h> 46102607Sphk#include <stdlib.h> 47102607Sphk#include <string.h> 48102607Sphk#include <unistd.h> 49102607Sphk#include <vis.h> 50102607Sphk#include <err.h> 51102607Sphk#include <errno.h> 52102607Sphk 53102607Sphkstatic enum { EADUNNO, EAGET, EASET, EARM, EALS } what = EADUNNO; 54102607Sphk 55102607Sphkstatic void __dead2 56102607Sphkusage(void) 57102607Sphk{ 58102607Sphk 59102607Sphk switch (what) { 60102607Sphk case EAGET: 61104798Srwatson fprintf(stderr, "usage: getextattr [-fhqsx] attrnamespace"); 62102607Sphk fprintf(stderr, " attrname filename ...\n"); 63102607Sphk exit(-1); 64102607Sphk case EASET: 65104803Sgreen fprintf(stderr, "usage: setextattr [-fhnq] attrnamespace"); 66102607Sphk fprintf(stderr, " attrname attrvalue filename ...\n"); 67102607Sphk exit(-1); 68102607Sphk case EARM: 69104798Srwatson fprintf(stderr, "usage: rmextattr [-fhq] attrnamespace"); 70102607Sphk fprintf(stderr, " attrname filename ...\n"); 71102607Sphk exit(-1); 72102607Sphk case EALS: 73104798Srwatson fprintf(stderr, "usage: lsextattr [-fhq] attrnamespace"); 74102607Sphk fprintf(stderr, " filename ...\n"); 75102607Sphk exit(-1); 76102607Sphk case EADUNNO: 77102607Sphk default: 78102607Sphk fprintf(stderr, "usage: (getextattr|lsextattr|rmextattr"); 79102607Sphk fprintf(stderr, "|setextattr)\n"); 80102607Sphk exit (-1); 81102607Sphk } 82102607Sphk} 83102607Sphk 84102607Sphkstatic void 85102607Sphkmkbuf(char **buf, int *oldlen, int newlen) 86102607Sphk{ 87102607Sphk 88102607Sphk if (*oldlen >= newlen) 89102607Sphk return; 90102607Sphk if (*buf != NULL) 91102607Sphk free(*buf); 92102607Sphk *buf = malloc(newlen); 93102607Sphk if (*buf == NULL) 94102607Sphk err(1, "malloc"); 95102607Sphk *oldlen = newlen; 96102607Sphk return; 97102607Sphk} 98102607Sphk 99102607Sphkint 100102607Sphkmain(int argc, char *argv[]) 101102607Sphk{ 102102607Sphk char *buf, *visbuf, *p; 103102607Sphk 104102607Sphk const char *options, *attrname; 105248995Smdf size_t len; 106248995Smdf ssize_t ret; 107104801Sgreen int buflen, visbuflen, ch, error, i, arg_counter, attrnamespace, 108104801Sgreen minargc; 109102607Sphk 110102607Sphk int flag_force = 0; 111104798Srwatson int flag_nofollow = 0; 112104803Sgreen int flag_null = 0; 113102607Sphk int flag_quiet = 0; 114102607Sphk int flag_string = 0; 115102607Sphk int flag_hex = 0; 116102607Sphk 117102607Sphk visbuflen = buflen = 0; 118102607Sphk visbuf = buf = NULL; 119102607Sphk 120104796Srwatson p = basename(argv[0]); 121102607Sphk if (p == NULL) 122102607Sphk p = argv[0]; 123102607Sphk if (!strcmp(p, "getextattr")) { 124102607Sphk what = EAGET; 125104798Srwatson options = "fhqsx"; 126104801Sgreen minargc = 3; 127102607Sphk } else if (!strcmp(p, "setextattr")) { 128102607Sphk what = EASET; 129104803Sgreen options = "fhnq"; 130104801Sgreen minargc = 4; 131102607Sphk } else if (!strcmp(p, "rmextattr")) { 132102607Sphk what = EARM; 133104798Srwatson options = "fhq"; 134104801Sgreen minargc = 3; 135102607Sphk } else if (!strcmp(p, "lsextattr")) { 136102607Sphk what = EALS; 137104798Srwatson options = "fhq"; 138104801Sgreen minargc = 2; 139102607Sphk } else { 140102607Sphk usage(); 141102607Sphk } 142102607Sphk 143102607Sphk while ((ch = getopt(argc, argv, options)) != -1) { 144102607Sphk switch (ch) { 145102607Sphk case 'f': 146102607Sphk flag_force = 1; 147102607Sphk break; 148104798Srwatson case 'h': 149104798Srwatson flag_nofollow = 1; 150104798Srwatson break; 151104803Sgreen case 'n': 152104803Sgreen flag_null = 1; 153104803Sgreen break; 154102607Sphk case 'q': 155102607Sphk flag_quiet = 1; 156102607Sphk break; 157102607Sphk case 's': 158102607Sphk flag_string = 1; 159102607Sphk break; 160102607Sphk case 'x': 161102607Sphk flag_hex = 1; 162102607Sphk break; 163102607Sphk case '?': 164102607Sphk default: 165102607Sphk usage(); 166102607Sphk } 167102607Sphk } 168102607Sphk 169102607Sphk argc -= optind; 170102607Sphk argv += optind; 171102607Sphk 172104801Sgreen if (argc < minargc) 173102607Sphk usage(); 174102607Sphk 175102607Sphk error = extattr_string_to_namespace(argv[0], &attrnamespace); 176102607Sphk if (error) 177180537Srwatson err(-1, "%s", argv[0]); 178102607Sphk argc--; argv++; 179102607Sphk 180115864Srwatson if (what != EALS) { 181102607Sphk attrname = argv[0]; 182102607Sphk argc--; argv++; 183115864Srwatson } else 184115864Srwatson attrname = NULL; 185102607Sphk 186102607Sphk if (what == EASET) { 187102607Sphk mkbuf(&buf, &buflen, strlen(argv[0]) + 1); 188102607Sphk strcpy(buf, argv[0]); 189102607Sphk argc--; argv++; 190102607Sphk } 191102607Sphk 192102607Sphk for (arg_counter = 0; arg_counter < argc; arg_counter++) { 193102607Sphk switch (what) { 194102607Sphk case EARM: 195104798Srwatson if (flag_nofollow) 196104798Srwatson error = extattr_delete_link(argv[arg_counter], 197104798Srwatson attrnamespace, attrname); 198104798Srwatson else 199104798Srwatson error = extattr_delete_file(argv[arg_counter], 200104798Srwatson attrnamespace, attrname); 201102607Sphk if (error >= 0) 202102607Sphk continue; 203102607Sphk break; 204102607Sphk case EASET: 205248995Smdf len = strlen(buf) + flag_null; 206104798Srwatson if (flag_nofollow) 207248995Smdf ret = extattr_set_link(argv[arg_counter], 208248995Smdf attrnamespace, attrname, buf, len); 209104798Srwatson else 210248995Smdf ret = extattr_set_file(argv[arg_counter], 211248995Smdf attrnamespace, attrname, buf, len); 212248995Smdf if (ret >= 0) { 213248995Smdf if ((size_t)ret != len && !flag_quiet) { 214248995Smdf warnx("Set %zd bytes of %zu for %s", 215248995Smdf ret, len, attrname); 216248995Smdf } 217102607Sphk continue; 218248995Smdf } 219102607Sphk break; 220102607Sphk case EALS: 221115864Srwatson if (flag_nofollow) 222248995Smdf ret = extattr_list_link(argv[arg_counter], 223115864Srwatson attrnamespace, NULL, 0); 224115864Srwatson else 225248995Smdf ret = extattr_list_file(argv[arg_counter], 226115864Srwatson attrnamespace, NULL, 0); 227248995Smdf if (ret < 0) 228115864Srwatson break; 229248995Smdf mkbuf(&buf, &buflen, ret); 230115864Srwatson if (flag_nofollow) 231248995Smdf ret = extattr_list_link(argv[arg_counter], 232115864Srwatson attrnamespace, buf, buflen); 233115864Srwatson else 234248995Smdf ret = extattr_list_file(argv[arg_counter], 235115864Srwatson attrnamespace, buf, buflen); 236248995Smdf if (ret < 0) 237115864Srwatson break; 238115864Srwatson if (!flag_quiet) 239115864Srwatson printf("%s\t", argv[arg_counter]); 240248995Smdf for (i = 0; i < ret; i += ch + 1) { 241208004Szml /* The attribute name length is unsigned. */ 242208004Szml ch = (unsigned char)buf[i]; 243115864Srwatson printf("%s%*.*s", i ? "\t" : "", 244208004Szml ch, ch, buf + i + 1); 245208004Szml } 246248995Smdf if (!flag_quiet || ret > 0) 247247164Spjd printf("\n"); 248115864Srwatson continue; 249102607Sphk case EAGET: 250104798Srwatson if (flag_nofollow) 251248995Smdf ret = extattr_get_link(argv[arg_counter], 252104798Srwatson attrnamespace, attrname, NULL, 0); 253104798Srwatson else 254248995Smdf ret = extattr_get_file(argv[arg_counter], 255104798Srwatson attrnamespace, attrname, NULL, 0); 256248995Smdf if (ret < 0) 257102607Sphk break; 258248995Smdf mkbuf(&buf, &buflen, ret); 259104798Srwatson if (flag_nofollow) 260248995Smdf ret = extattr_get_link(argv[arg_counter], 261104798Srwatson attrnamespace, attrname, buf, buflen); 262104798Srwatson else 263248995Smdf ret = extattr_get_file(argv[arg_counter], 264104798Srwatson attrnamespace, attrname, buf, buflen); 265248995Smdf if (ret < 0) 266102607Sphk break; 267102607Sphk if (!flag_quiet) 268102607Sphk printf("%s\t", argv[arg_counter]); 269102607Sphk if (flag_string) { 270248995Smdf mkbuf(&visbuf, &visbuflen, ret * 4 + 1); 271248995Smdf strvisx(visbuf, buf, ret, 272102607Sphk VIS_SAFE | VIS_WHITE); 273102607Sphk printf("\"%s\"\n", visbuf); 274102607Sphk continue; 275102607Sphk } else if (flag_hex) { 276248995Smdf for (i = 0; i < ret; i++) 277102607Sphk printf("%s%02x", i ? " " : "", 278102607Sphk buf[i]); 279102607Sphk printf("\n"); 280102607Sphk continue; 281102607Sphk } else { 282248995Smdf fwrite(buf, ret, 1, stdout); 283102607Sphk printf("\n"); 284102607Sphk continue; 285102607Sphk } 286102607Sphk default: 287102607Sphk break; 288102607Sphk } 289102607Sphk if (!flag_quiet) 290102607Sphk warn("%s: failed", argv[arg_counter]); 291102607Sphk if (flag_force) 292102607Sphk continue; 293102607Sphk return(1); 294102607Sphk } 295102607Sphk return (0); 296102607Sphk} 297