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> 40301145Sasomers#include <sys/sbuf.h> 41102607Sphk#include <sys/uio.h> 42102607Sphk#include <sys/extattr.h> 43102607Sphk 44104796Srwatson#include <libgen.h> 45102607Sphk#include <libutil.h> 46102607Sphk#include <stdio.h> 47102607Sphk#include <stdlib.h> 48102607Sphk#include <string.h> 49102607Sphk#include <unistd.h> 50102607Sphk#include <vis.h> 51102607Sphk#include <err.h> 52102607Sphk#include <errno.h> 53102607Sphk 54102607Sphkstatic enum { EADUNNO, EAGET, EASET, EARM, EALS } what = EADUNNO; 55102607Sphk 56102607Sphkstatic void __dead2 57102607Sphkusage(void) 58102607Sphk{ 59102607Sphk 60102607Sphk switch (what) { 61102607Sphk case EAGET: 62104798Srwatson fprintf(stderr, "usage: getextattr [-fhqsx] attrnamespace"); 63102607Sphk fprintf(stderr, " attrname filename ...\n"); 64102607Sphk exit(-1); 65102607Sphk case EASET: 66104803Sgreen fprintf(stderr, "usage: setextattr [-fhnq] attrnamespace"); 67102607Sphk fprintf(stderr, " attrname attrvalue filename ...\n"); 68301145Sasomers fprintf(stderr, " or setextattr -i [-fhnq] attrnamespace"); 69301145Sasomers fprintf(stderr, " attrname filename ...\n"); 70102607Sphk exit(-1); 71102607Sphk case EARM: 72104798Srwatson fprintf(stderr, "usage: rmextattr [-fhq] attrnamespace"); 73102607Sphk fprintf(stderr, " attrname filename ...\n"); 74102607Sphk exit(-1); 75102607Sphk case EALS: 76104798Srwatson fprintf(stderr, "usage: lsextattr [-fhq] attrnamespace"); 77102607Sphk fprintf(stderr, " filename ...\n"); 78102607Sphk exit(-1); 79102607Sphk case EADUNNO: 80102607Sphk default: 81102607Sphk fprintf(stderr, "usage: (getextattr|lsextattr|rmextattr"); 82102607Sphk fprintf(stderr, "|setextattr)\n"); 83102607Sphk exit (-1); 84102607Sphk } 85102607Sphk} 86102607Sphk 87102607Sphkstatic void 88102607Sphkmkbuf(char **buf, int *oldlen, int newlen) 89102607Sphk{ 90102607Sphk 91102607Sphk if (*oldlen >= newlen) 92102607Sphk return; 93102607Sphk if (*buf != NULL) 94102607Sphk free(*buf); 95102607Sphk *buf = malloc(newlen); 96102607Sphk if (*buf == NULL) 97102607Sphk err(1, "malloc"); 98102607Sphk *oldlen = newlen; 99102607Sphk return; 100102607Sphk} 101102607Sphk 102102607Sphkint 103102607Sphkmain(int argc, char *argv[]) 104102607Sphk{ 105301145Sasomers#define STDIN_BUF_SZ 1024 106301145Sasomers char stdin_data[STDIN_BUF_SZ]; 107301145Sasomers char *p; 108102607Sphk 109102607Sphk const char *options, *attrname; 110248995Smdf size_t len; 111248995Smdf ssize_t ret; 112301145Sasomers int ch, error, i, arg_counter, attrnamespace, minargc; 113102607Sphk 114301145Sasomers char *visbuf = NULL; 115301145Sasomers int visbuflen = 0; 116301145Sasomers char *buf = NULL; 117301145Sasomers int buflen = 0; 118301145Sasomers struct sbuf *attrvalue = NULL; 119102607Sphk int flag_force = 0; 120104798Srwatson int flag_nofollow = 0; 121104803Sgreen int flag_null = 0; 122301145Sasomers int count_quiet = 0; 123301145Sasomers int flag_from_stdin = 0; 124102607Sphk int flag_string = 0; 125102607Sphk int flag_hex = 0; 126102607Sphk 127104796Srwatson p = basename(argv[0]); 128102607Sphk if (p == NULL) 129102607Sphk p = argv[0]; 130102607Sphk if (!strcmp(p, "getextattr")) { 131102607Sphk what = EAGET; 132104798Srwatson options = "fhqsx"; 133104801Sgreen minargc = 3; 134102607Sphk } else if (!strcmp(p, "setextattr")) { 135102607Sphk what = EASET; 136301145Sasomers options = "fhinq"; 137301145Sasomers minargc = 3; 138102607Sphk } else if (!strcmp(p, "rmextattr")) { 139102607Sphk what = EARM; 140104798Srwatson options = "fhq"; 141104801Sgreen minargc = 3; 142102607Sphk } else if (!strcmp(p, "lsextattr")) { 143102607Sphk what = EALS; 144104798Srwatson options = "fhq"; 145104801Sgreen minargc = 2; 146102607Sphk } else { 147102607Sphk usage(); 148102607Sphk } 149102607Sphk 150102607Sphk while ((ch = getopt(argc, argv, options)) != -1) { 151102607Sphk switch (ch) { 152102607Sphk case 'f': 153102607Sphk flag_force = 1; 154102607Sphk break; 155104798Srwatson case 'h': 156104798Srwatson flag_nofollow = 1; 157104798Srwatson break; 158301145Sasomers case 'i': 159301145Sasomers flag_from_stdin = 1; 160301145Sasomers break; 161104803Sgreen case 'n': 162104803Sgreen flag_null = 1; 163104803Sgreen break; 164102607Sphk case 'q': 165301145Sasomers count_quiet += 1; 166102607Sphk break; 167102607Sphk case 's': 168102607Sphk flag_string = 1; 169102607Sphk break; 170102607Sphk case 'x': 171102607Sphk flag_hex = 1; 172102607Sphk break; 173102607Sphk case '?': 174102607Sphk default: 175102607Sphk usage(); 176102607Sphk } 177102607Sphk } 178102607Sphk 179102607Sphk argc -= optind; 180102607Sphk argv += optind; 181102607Sphk 182301145Sasomers if (what == EASET && flag_from_stdin == 0) 183301145Sasomers minargc++; 184301145Sasomers 185104801Sgreen if (argc < minargc) 186102607Sphk usage(); 187102607Sphk 188102607Sphk error = extattr_string_to_namespace(argv[0], &attrnamespace); 189102607Sphk if (error) 190180537Srwatson err(-1, "%s", argv[0]); 191102607Sphk argc--; argv++; 192102607Sphk 193115864Srwatson if (what != EALS) { 194102607Sphk attrname = argv[0]; 195102607Sphk argc--; argv++; 196115864Srwatson } else 197115864Srwatson attrname = NULL; 198102607Sphk 199102607Sphk if (what == EASET) { 200301145Sasomers attrvalue = sbuf_new_auto(); 201301145Sasomers if (flag_from_stdin) { 202301145Sasomers while ((error = read(0, stdin_data, STDIN_BUF_SZ)) > 0) 203301145Sasomers sbuf_bcat(attrvalue, stdin_data, error); 204301145Sasomers } else { 205301145Sasomers sbuf_cpy(attrvalue, argv[0]); 206301145Sasomers argc--; argv++; 207301145Sasomers } 208301145Sasomers sbuf_finish(attrvalue); 209102607Sphk } 210102607Sphk 211102607Sphk for (arg_counter = 0; arg_counter < argc; arg_counter++) { 212102607Sphk switch (what) { 213102607Sphk case EARM: 214104798Srwatson if (flag_nofollow) 215104798Srwatson error = extattr_delete_link(argv[arg_counter], 216104798Srwatson attrnamespace, attrname); 217104798Srwatson else 218104798Srwatson error = extattr_delete_file(argv[arg_counter], 219104798Srwatson attrnamespace, attrname); 220102607Sphk if (error >= 0) 221102607Sphk continue; 222102607Sphk break; 223102607Sphk case EASET: 224301145Sasomers len = sbuf_len(attrvalue) + flag_null; 225104798Srwatson if (flag_nofollow) 226248995Smdf ret = extattr_set_link(argv[arg_counter], 227301145Sasomers attrnamespace, attrname, 228301145Sasomers sbuf_data(attrvalue), len); 229104798Srwatson else 230248995Smdf ret = extattr_set_file(argv[arg_counter], 231301145Sasomers attrnamespace, attrname, 232301145Sasomers sbuf_data(attrvalue), len); 233248995Smdf if (ret >= 0) { 234301145Sasomers if ((size_t)ret != len && !count_quiet) { 235248995Smdf warnx("Set %zd bytes of %zu for %s", 236248995Smdf ret, len, attrname); 237248995Smdf } 238102607Sphk continue; 239248995Smdf } 240102607Sphk break; 241102607Sphk case EALS: 242115864Srwatson if (flag_nofollow) 243248995Smdf ret = extattr_list_link(argv[arg_counter], 244115864Srwatson attrnamespace, NULL, 0); 245115864Srwatson else 246248995Smdf ret = extattr_list_file(argv[arg_counter], 247115864Srwatson attrnamespace, NULL, 0); 248248995Smdf if (ret < 0) 249115864Srwatson break; 250248995Smdf mkbuf(&buf, &buflen, ret); 251115864Srwatson if (flag_nofollow) 252248995Smdf ret = extattr_list_link(argv[arg_counter], 253115864Srwatson attrnamespace, buf, buflen); 254115864Srwatson else 255248995Smdf ret = extattr_list_file(argv[arg_counter], 256115864Srwatson attrnamespace, buf, buflen); 257248995Smdf if (ret < 0) 258115864Srwatson break; 259301145Sasomers if (!count_quiet) 260115864Srwatson printf("%s\t", argv[arg_counter]); 261248995Smdf for (i = 0; i < ret; i += ch + 1) { 262208004Szml /* The attribute name length is unsigned. */ 263208004Szml ch = (unsigned char)buf[i]; 264115864Srwatson printf("%s%*.*s", i ? "\t" : "", 265208004Szml ch, ch, buf + i + 1); 266208004Szml } 267301145Sasomers if (!count_quiet || ret > 0) 268247164Spjd printf("\n"); 269115864Srwatson continue; 270102607Sphk case EAGET: 271104798Srwatson if (flag_nofollow) 272248995Smdf ret = extattr_get_link(argv[arg_counter], 273104798Srwatson attrnamespace, attrname, NULL, 0); 274104798Srwatson else 275248995Smdf ret = extattr_get_file(argv[arg_counter], 276104798Srwatson attrnamespace, attrname, NULL, 0); 277248995Smdf if (ret < 0) 278102607Sphk break; 279248995Smdf mkbuf(&buf, &buflen, ret); 280104798Srwatson if (flag_nofollow) 281248995Smdf ret = extattr_get_link(argv[arg_counter], 282104798Srwatson attrnamespace, attrname, buf, buflen); 283104798Srwatson else 284248995Smdf ret = extattr_get_file(argv[arg_counter], 285104798Srwatson attrnamespace, attrname, buf, buflen); 286248995Smdf if (ret < 0) 287102607Sphk break; 288301145Sasomers if (!count_quiet) 289102607Sphk printf("%s\t", argv[arg_counter]); 290102607Sphk if (flag_string) { 291248995Smdf mkbuf(&visbuf, &visbuflen, ret * 4 + 1); 292248995Smdf strvisx(visbuf, buf, ret, 293102607Sphk VIS_SAFE | VIS_WHITE); 294301145Sasomers printf("\"%s\"", visbuf); 295102607Sphk } else if (flag_hex) { 296248995Smdf for (i = 0; i < ret; i++) 297102607Sphk printf("%s%02x", i ? " " : "", 298301145Sasomers (unsigned char)buf[i]); 299102607Sphk } else { 300248995Smdf fwrite(buf, ret, 1, stdout); 301301145Sasomers } 302301145Sasomers if (count_quiet < 2) 303102607Sphk printf("\n"); 304301145Sasomers continue; 305102607Sphk default: 306102607Sphk break; 307102607Sphk } 308301145Sasomers if (!count_quiet) 309102607Sphk warn("%s: failed", argv[arg_counter]); 310102607Sphk if (flag_force) 311102607Sphk continue; 312102607Sphk return(1); 313102607Sphk } 314102607Sphk return (0); 315102607Sphk} 316