1a068c194SPoul-Henning Kamp /*- 21de7b4b8SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 31de7b4b8SPedro F. Giffuni * 452271f82SRobert Watson * Copyright (c) 2002, 2003 Networks Associates Technology, Inc. 5a068c194SPoul-Henning Kamp * Copyright (c) 2002 Poul-Henning Kamp. 6a068c194SPoul-Henning Kamp * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson 7a068c194SPoul-Henning Kamp * All rights reserved. 8a068c194SPoul-Henning Kamp * 9a068c194SPoul-Henning Kamp * This software was developed for the FreeBSD Project by Poul-Henning 10a068c194SPoul-Henning Kamp * Kamp and Network Associates Laboratories, the Security Research Division 11a068c194SPoul-Henning Kamp * of Network Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 12a068c194SPoul-Henning Kamp * ("CBOSS"), as part of the DARPA CHATS research program 13a068c194SPoul-Henning Kamp * 14a068c194SPoul-Henning Kamp * Redistribution and use in source and binary forms, with or without 15a068c194SPoul-Henning Kamp * modification, are permitted provided that the following conditions 16a068c194SPoul-Henning Kamp * are met: 17a068c194SPoul-Henning Kamp * 1. Redistributions of source code must retain the above copyright 18a068c194SPoul-Henning Kamp * notice, this list of conditions and the following disclaimer. 19a068c194SPoul-Henning Kamp * 2. Redistributions in binary form must reproduce the above copyright 20a068c194SPoul-Henning Kamp * notice, this list of conditions and the following disclaimer in the 21a068c194SPoul-Henning Kamp * documentation and/or other materials provided with the distribution. 22a068c194SPoul-Henning Kamp * 3. The names of the authors may not be used to endorse or promote 23a068c194SPoul-Henning Kamp * products derived from this software without specific prior written 24a068c194SPoul-Henning Kamp * permission. 25a068c194SPoul-Henning Kamp * 26a068c194SPoul-Henning Kamp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 27a068c194SPoul-Henning Kamp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28a068c194SPoul-Henning Kamp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29a068c194SPoul-Henning Kamp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 30a068c194SPoul-Henning Kamp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31a068c194SPoul-Henning Kamp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32a068c194SPoul-Henning Kamp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33a068c194SPoul-Henning Kamp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34a068c194SPoul-Henning Kamp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35a068c194SPoul-Henning Kamp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36a068c194SPoul-Henning Kamp * SUCH DAMAGE. 37a068c194SPoul-Henning Kamp * 38a068c194SPoul-Henning Kamp * $FreeBSD$ 39a068c194SPoul-Henning Kamp */ 40a068c194SPoul-Henning Kamp 41a068c194SPoul-Henning Kamp #include <sys/types.h> 42c29930cfSAlan Somers #include <sys/sbuf.h> 43a068c194SPoul-Henning Kamp #include <sys/uio.h> 44a068c194SPoul-Henning Kamp #include <sys/extattr.h> 45a068c194SPoul-Henning Kamp 467522ecb3SRobert Watson #include <libgen.h> 47a068c194SPoul-Henning Kamp #include <libutil.h> 48a068c194SPoul-Henning Kamp #include <stdio.h> 49a068c194SPoul-Henning Kamp #include <stdlib.h> 50a068c194SPoul-Henning Kamp #include <string.h> 51a068c194SPoul-Henning Kamp #include <unistd.h> 52a068c194SPoul-Henning Kamp #include <vis.h> 53a068c194SPoul-Henning Kamp #include <err.h> 54a068c194SPoul-Henning Kamp #include <errno.h> 55a068c194SPoul-Henning Kamp 56a068c194SPoul-Henning Kamp static enum { EADUNNO, EAGET, EASET, EARM, EALS } what = EADUNNO; 57a068c194SPoul-Henning Kamp 58a068c194SPoul-Henning Kamp static void __dead2 59a068c194SPoul-Henning Kamp usage(void) 60a068c194SPoul-Henning Kamp { 61a068c194SPoul-Henning Kamp 62a068c194SPoul-Henning Kamp switch (what) { 63a068c194SPoul-Henning Kamp case EAGET: 646c3fb112SRobert Watson fprintf(stderr, "usage: getextattr [-fhqsx] attrnamespace"); 65a068c194SPoul-Henning Kamp fprintf(stderr, " attrname filename ...\n"); 66a068c194SPoul-Henning Kamp exit(-1); 67a068c194SPoul-Henning Kamp case EASET: 68cb0187a0SBrian Feldman fprintf(stderr, "usage: setextattr [-fhnq] attrnamespace"); 69a068c194SPoul-Henning Kamp fprintf(stderr, " attrname attrvalue filename ...\n"); 70c29930cfSAlan Somers fprintf(stderr, " or setextattr -i [-fhnq] attrnamespace"); 71c29930cfSAlan Somers fprintf(stderr, " attrname filename ...\n"); 72a068c194SPoul-Henning Kamp exit(-1); 73a068c194SPoul-Henning Kamp case EARM: 746c3fb112SRobert Watson fprintf(stderr, "usage: rmextattr [-fhq] attrnamespace"); 75a068c194SPoul-Henning Kamp fprintf(stderr, " attrname filename ...\n"); 76a068c194SPoul-Henning Kamp exit(-1); 77a068c194SPoul-Henning Kamp case EALS: 786c3fb112SRobert Watson fprintf(stderr, "usage: lsextattr [-fhq] attrnamespace"); 79a068c194SPoul-Henning Kamp fprintf(stderr, " filename ...\n"); 80a068c194SPoul-Henning Kamp exit(-1); 81a068c194SPoul-Henning Kamp case EADUNNO: 82a068c194SPoul-Henning Kamp default: 83a068c194SPoul-Henning Kamp fprintf(stderr, "usage: (getextattr|lsextattr|rmextattr"); 84a068c194SPoul-Henning Kamp fprintf(stderr, "|setextattr)\n"); 85a068c194SPoul-Henning Kamp exit (-1); 86a068c194SPoul-Henning Kamp } 87a068c194SPoul-Henning Kamp } 88a068c194SPoul-Henning Kamp 89a068c194SPoul-Henning Kamp static void 90a068c194SPoul-Henning Kamp mkbuf(char **buf, int *oldlen, int newlen) 91a068c194SPoul-Henning Kamp { 92a068c194SPoul-Henning Kamp 93a068c194SPoul-Henning Kamp if (*oldlen >= newlen) 94a068c194SPoul-Henning Kamp return; 95a068c194SPoul-Henning Kamp if (*buf != NULL) 96a068c194SPoul-Henning Kamp free(*buf); 97a068c194SPoul-Henning Kamp *buf = malloc(newlen); 98a068c194SPoul-Henning Kamp if (*buf == NULL) 99a068c194SPoul-Henning Kamp err(1, "malloc"); 100a068c194SPoul-Henning Kamp *oldlen = newlen; 101a068c194SPoul-Henning Kamp return; 102a068c194SPoul-Henning Kamp } 103a068c194SPoul-Henning Kamp 104a068c194SPoul-Henning Kamp int 105a068c194SPoul-Henning Kamp main(int argc, char *argv[]) 106a068c194SPoul-Henning Kamp { 107*1137d1a7SAlan Somers #define STDIN_BUF_SZ 4096 108c29930cfSAlan Somers char stdin_data[STDIN_BUF_SZ]; 109c29930cfSAlan Somers char *p; 110a068c194SPoul-Henning Kamp 111a068c194SPoul-Henning Kamp const char *options, *attrname; 112e324bf91SMatthew D Fleming size_t len; 113e324bf91SMatthew D Fleming ssize_t ret; 114c29930cfSAlan Somers int ch, error, i, arg_counter, attrnamespace, minargc; 115a068c194SPoul-Henning Kamp 116c29930cfSAlan Somers char *visbuf = NULL; 117c29930cfSAlan Somers int visbuflen = 0; 118c29930cfSAlan Somers char *buf = NULL; 119c29930cfSAlan Somers int buflen = 0; 120c29930cfSAlan Somers struct sbuf *attrvalue = NULL; 121a068c194SPoul-Henning Kamp int flag_force = 0; 1226c3fb112SRobert Watson int flag_nofollow = 0; 123cb0187a0SBrian Feldman int flag_null = 0; 124c29930cfSAlan Somers int count_quiet = 0; 125c29930cfSAlan Somers int flag_from_stdin = 0; 126a068c194SPoul-Henning Kamp int flag_string = 0; 127a068c194SPoul-Henning Kamp int flag_hex = 0; 128a068c194SPoul-Henning Kamp 1297522ecb3SRobert Watson p = basename(argv[0]); 130a068c194SPoul-Henning Kamp if (p == NULL) 131a068c194SPoul-Henning Kamp p = argv[0]; 132a068c194SPoul-Henning Kamp if (!strcmp(p, "getextattr")) { 133a068c194SPoul-Henning Kamp what = EAGET; 1346c3fb112SRobert Watson options = "fhqsx"; 135878382faSBrian Feldman minargc = 3; 136a068c194SPoul-Henning Kamp } else if (!strcmp(p, "setextattr")) { 137a068c194SPoul-Henning Kamp what = EASET; 138c29930cfSAlan Somers options = "fhinq"; 139c29930cfSAlan Somers minargc = 3; 140a068c194SPoul-Henning Kamp } else if (!strcmp(p, "rmextattr")) { 141a068c194SPoul-Henning Kamp what = EARM; 1426c3fb112SRobert Watson options = "fhq"; 143878382faSBrian Feldman minargc = 3; 144a068c194SPoul-Henning Kamp } else if (!strcmp(p, "lsextattr")) { 145a068c194SPoul-Henning Kamp what = EALS; 1466c3fb112SRobert Watson options = "fhq"; 147878382faSBrian Feldman minargc = 2; 148a068c194SPoul-Henning Kamp } else { 149a068c194SPoul-Henning Kamp usage(); 150a068c194SPoul-Henning Kamp } 151a068c194SPoul-Henning Kamp 152a068c194SPoul-Henning Kamp while ((ch = getopt(argc, argv, options)) != -1) { 153a068c194SPoul-Henning Kamp switch (ch) { 154a068c194SPoul-Henning Kamp case 'f': 155a068c194SPoul-Henning Kamp flag_force = 1; 156a068c194SPoul-Henning Kamp break; 1576c3fb112SRobert Watson case 'h': 1586c3fb112SRobert Watson flag_nofollow = 1; 1596c3fb112SRobert Watson break; 160c29930cfSAlan Somers case 'i': 161c29930cfSAlan Somers flag_from_stdin = 1; 162c29930cfSAlan Somers break; 163cb0187a0SBrian Feldman case 'n': 164cb0187a0SBrian Feldman flag_null = 1; 165cb0187a0SBrian Feldman break; 166a068c194SPoul-Henning Kamp case 'q': 167c29930cfSAlan Somers count_quiet += 1; 168a068c194SPoul-Henning Kamp break; 169a068c194SPoul-Henning Kamp case 's': 170a068c194SPoul-Henning Kamp flag_string = 1; 171a068c194SPoul-Henning Kamp break; 172a068c194SPoul-Henning Kamp case 'x': 173a068c194SPoul-Henning Kamp flag_hex = 1; 174a068c194SPoul-Henning Kamp break; 175a068c194SPoul-Henning Kamp case '?': 176a068c194SPoul-Henning Kamp default: 177a068c194SPoul-Henning Kamp usage(); 178a068c194SPoul-Henning Kamp } 179a068c194SPoul-Henning Kamp } 180a068c194SPoul-Henning Kamp 181a068c194SPoul-Henning Kamp argc -= optind; 182a068c194SPoul-Henning Kamp argv += optind; 183a068c194SPoul-Henning Kamp 184c29930cfSAlan Somers if (what == EASET && flag_from_stdin == 0) 185c29930cfSAlan Somers minargc++; 186c29930cfSAlan Somers 187878382faSBrian Feldman if (argc < minargc) 188a068c194SPoul-Henning Kamp usage(); 189a068c194SPoul-Henning Kamp 190a068c194SPoul-Henning Kamp error = extattr_string_to_namespace(argv[0], &attrnamespace); 191a068c194SPoul-Henning Kamp if (error) 192b689e6a8SRobert Watson err(-1, "%s", argv[0]); 193a068c194SPoul-Henning Kamp argc--; argv++; 194a068c194SPoul-Henning Kamp 19552271f82SRobert Watson if (what != EALS) { 196a068c194SPoul-Henning Kamp attrname = argv[0]; 197a068c194SPoul-Henning Kamp argc--; argv++; 19852271f82SRobert Watson } else 19952271f82SRobert Watson attrname = NULL; 200a068c194SPoul-Henning Kamp 201a068c194SPoul-Henning Kamp if (what == EASET) { 202c29930cfSAlan Somers attrvalue = sbuf_new_auto(); 203c29930cfSAlan Somers if (flag_from_stdin) { 204c29930cfSAlan Somers while ((error = read(0, stdin_data, STDIN_BUF_SZ)) > 0) 205c29930cfSAlan Somers sbuf_bcat(attrvalue, stdin_data, error); 206c29930cfSAlan Somers } else { 207c29930cfSAlan Somers sbuf_cpy(attrvalue, argv[0]); 208a068c194SPoul-Henning Kamp argc--; argv++; 209a068c194SPoul-Henning Kamp } 210c29930cfSAlan Somers sbuf_finish(attrvalue); 211c29930cfSAlan Somers } 212a068c194SPoul-Henning Kamp 213a068c194SPoul-Henning Kamp for (arg_counter = 0; arg_counter < argc; arg_counter++) { 214a068c194SPoul-Henning Kamp switch (what) { 215a068c194SPoul-Henning Kamp case EARM: 2166c3fb112SRobert Watson if (flag_nofollow) 2176c3fb112SRobert Watson error = extattr_delete_link(argv[arg_counter], 2186c3fb112SRobert Watson attrnamespace, attrname); 2196c3fb112SRobert Watson else 220a068c194SPoul-Henning Kamp error = extattr_delete_file(argv[arg_counter], 221a068c194SPoul-Henning Kamp attrnamespace, attrname); 222a068c194SPoul-Henning Kamp if (error >= 0) 223a068c194SPoul-Henning Kamp continue; 224a068c194SPoul-Henning Kamp break; 225a068c194SPoul-Henning Kamp case EASET: 226c29930cfSAlan Somers len = sbuf_len(attrvalue) + flag_null; 2276c3fb112SRobert Watson if (flag_nofollow) 228e324bf91SMatthew D Fleming ret = extattr_set_link(argv[arg_counter], 229c29930cfSAlan Somers attrnamespace, attrname, 230c29930cfSAlan Somers sbuf_data(attrvalue), len); 2316c3fb112SRobert Watson else 232e324bf91SMatthew D Fleming ret = extattr_set_file(argv[arg_counter], 233c29930cfSAlan Somers attrnamespace, attrname, 234c29930cfSAlan Somers sbuf_data(attrvalue), len); 235e324bf91SMatthew D Fleming if (ret >= 0) { 236c29930cfSAlan Somers if ((size_t)ret != len && !count_quiet) { 237e324bf91SMatthew D Fleming warnx("Set %zd bytes of %zu for %s", 238e324bf91SMatthew D Fleming ret, len, attrname); 239e324bf91SMatthew D Fleming } 240a068c194SPoul-Henning Kamp continue; 241e324bf91SMatthew D Fleming } 242a068c194SPoul-Henning Kamp break; 243a068c194SPoul-Henning Kamp case EALS: 24452271f82SRobert Watson if (flag_nofollow) 245e324bf91SMatthew D Fleming ret = extattr_list_link(argv[arg_counter], 24652271f82SRobert Watson attrnamespace, NULL, 0); 24752271f82SRobert Watson else 248e324bf91SMatthew D Fleming ret = extattr_list_file(argv[arg_counter], 24952271f82SRobert Watson attrnamespace, NULL, 0); 250e324bf91SMatthew D Fleming if (ret < 0) 25152271f82SRobert Watson break; 252e324bf91SMatthew D Fleming mkbuf(&buf, &buflen, ret); 25352271f82SRobert Watson if (flag_nofollow) 254e324bf91SMatthew D Fleming ret = extattr_list_link(argv[arg_counter], 25552271f82SRobert Watson attrnamespace, buf, buflen); 25652271f82SRobert Watson else 257e324bf91SMatthew D Fleming ret = extattr_list_file(argv[arg_counter], 25852271f82SRobert Watson attrnamespace, buf, buflen); 259e324bf91SMatthew D Fleming if (ret < 0) 26052271f82SRobert Watson break; 261c29930cfSAlan Somers if (!count_quiet) 26252271f82SRobert Watson printf("%s\t", argv[arg_counter]); 263e324bf91SMatthew D Fleming for (i = 0; i < ret; i += ch + 1) { 26407c19910SZachary Loafman /* The attribute name length is unsigned. */ 26507c19910SZachary Loafman ch = (unsigned char)buf[i]; 26652271f82SRobert Watson printf("%s%*.*s", i ? "\t" : "", 26707c19910SZachary Loafman ch, ch, buf + i + 1); 26807c19910SZachary Loafman } 269c29930cfSAlan Somers if (!count_quiet || ret > 0) 27052271f82SRobert Watson printf("\n"); 27152271f82SRobert Watson continue; 272a068c194SPoul-Henning Kamp case EAGET: 2736c3fb112SRobert Watson if (flag_nofollow) 274e324bf91SMatthew D Fleming ret = extattr_get_link(argv[arg_counter], 2756c3fb112SRobert Watson attrnamespace, attrname, NULL, 0); 2766c3fb112SRobert Watson else 277e324bf91SMatthew D Fleming ret = extattr_get_file(argv[arg_counter], 278a068c194SPoul-Henning Kamp attrnamespace, attrname, NULL, 0); 279e324bf91SMatthew D Fleming if (ret < 0) 280a068c194SPoul-Henning Kamp break; 281e324bf91SMatthew D Fleming mkbuf(&buf, &buflen, ret); 2826c3fb112SRobert Watson if (flag_nofollow) 283e324bf91SMatthew D Fleming ret = extattr_get_link(argv[arg_counter], 2846c3fb112SRobert Watson attrnamespace, attrname, buf, buflen); 2856c3fb112SRobert Watson else 286e324bf91SMatthew D Fleming ret = extattr_get_file(argv[arg_counter], 287a068c194SPoul-Henning Kamp attrnamespace, attrname, buf, buflen); 288e324bf91SMatthew D Fleming if (ret < 0) 289a068c194SPoul-Henning Kamp break; 290c29930cfSAlan Somers if (!count_quiet) 291a068c194SPoul-Henning Kamp printf("%s\t", argv[arg_counter]); 292a068c194SPoul-Henning Kamp if (flag_string) { 293e324bf91SMatthew D Fleming mkbuf(&visbuf, &visbuflen, ret * 4 + 1); 294e324bf91SMatthew D Fleming strvisx(visbuf, buf, ret, 295a068c194SPoul-Henning Kamp VIS_SAFE | VIS_WHITE); 296c29930cfSAlan Somers printf("\"%s\"", visbuf); 297a068c194SPoul-Henning Kamp } else if (flag_hex) { 298e324bf91SMatthew D Fleming for (i = 0; i < ret; i++) 29979e29f95SAlan Somers printf("%s%02x", i ? " " : "", 30079e29f95SAlan Somers (unsigned char)buf[i]); 301a068c194SPoul-Henning Kamp } else { 302e324bf91SMatthew D Fleming fwrite(buf, ret, 1, stdout); 303c29930cfSAlan Somers } 304c29930cfSAlan Somers if (count_quiet < 2) 305a068c194SPoul-Henning Kamp printf("\n"); 306a068c194SPoul-Henning Kamp continue; 307a068c194SPoul-Henning Kamp default: 308a068c194SPoul-Henning Kamp break; 309a068c194SPoul-Henning Kamp } 310c29930cfSAlan Somers if (!count_quiet) 311a068c194SPoul-Henning Kamp warn("%s: failed", argv[arg_counter]); 312a068c194SPoul-Henning Kamp if (flag_force) 313a068c194SPoul-Henning Kamp continue; 314a068c194SPoul-Henning Kamp return(1); 315a068c194SPoul-Henning Kamp } 316a068c194SPoul-Henning Kamp return (0); 317a068c194SPoul-Henning Kamp } 318