rmextattr.c revision 301145
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: stable/10/usr.sbin/extattr/rmextattr.c 301145 2016-06-01 17:22:15Z asomers $
37 */
38
39#include <sys/types.h>
40#include <sys/sbuf.h>
41#include <sys/uio.h>
42#include <sys/extattr.h>
43
44#include <libgen.h>
45#include <libutil.h>
46#include <stdio.h>
47#include <stdlib.h>
48#include <string.h>
49#include <unistd.h>
50#include <vis.h>
51#include <err.h>
52#include <errno.h>
53
54static enum { EADUNNO, EAGET, EASET, EARM, EALS } what = EADUNNO;
55
56static void __dead2
57usage(void)
58{
59
60	switch (what) {
61	case EAGET:
62		fprintf(stderr, "usage: getextattr [-fhqsx] attrnamespace");
63		fprintf(stderr, " attrname filename ...\n");
64		exit(-1);
65	case EASET:
66		fprintf(stderr, "usage: setextattr [-fhnq] attrnamespace");
67		fprintf(stderr, " attrname attrvalue filename ...\n");
68		fprintf(stderr, "   or  setextattr -i [-fhnq] attrnamespace");
69		fprintf(stderr, " attrname filename ...\n");
70		exit(-1);
71	case EARM:
72		fprintf(stderr, "usage: rmextattr [-fhq] attrnamespace");
73		fprintf(stderr, " attrname filename ...\n");
74		exit(-1);
75	case EALS:
76		fprintf(stderr, "usage: lsextattr [-fhq] attrnamespace");
77		fprintf(stderr, " filename ...\n");
78		exit(-1);
79	case EADUNNO:
80	default:
81		fprintf(stderr, "usage: (getextattr|lsextattr|rmextattr");
82		fprintf(stderr, "|setextattr)\n");
83		exit (-1);
84	}
85}
86
87static void
88mkbuf(char **buf, int *oldlen, int newlen)
89{
90
91	if (*oldlen >= newlen)
92		return;
93	if (*buf != NULL)
94		free(*buf);
95	*buf = malloc(newlen);
96	if (*buf == NULL)
97		err(1, "malloc");
98	*oldlen = newlen;
99	return;
100}
101
102int
103main(int argc, char *argv[])
104{
105#define STDIN_BUF_SZ 1024
106	char	 stdin_data[STDIN_BUF_SZ];
107	char	*p;
108
109	const char *options, *attrname;
110	size_t	len;
111	ssize_t	ret;
112	int	 ch, error, i, arg_counter, attrnamespace, minargc;
113
114	char   *visbuf = NULL;
115	int	visbuflen = 0;
116	char   *buf = NULL;
117	int	buflen = 0;
118	struct	sbuf *attrvalue = NULL;
119	int	flag_force = 0;
120	int	flag_nofollow = 0;
121	int	flag_null = 0;
122	int	count_quiet = 0;
123	int	flag_from_stdin = 0;
124	int	flag_string = 0;
125	int	flag_hex = 0;
126
127	p = basename(argv[0]);
128	if (p == NULL)
129		p = argv[0];
130	if (!strcmp(p, "getextattr")) {
131		what = EAGET;
132		options = "fhqsx";
133		minargc = 3;
134	} else if (!strcmp(p, "setextattr")) {
135		what = EASET;
136		options = "fhinq";
137		minargc = 3;
138	} else if (!strcmp(p, "rmextattr")) {
139		what = EARM;
140		options = "fhq";
141		minargc = 3;
142	} else if (!strcmp(p, "lsextattr")) {
143		what = EALS;
144		options = "fhq";
145		minargc = 2;
146	} else {
147		usage();
148	}
149
150	while ((ch = getopt(argc, argv, options)) != -1) {
151		switch (ch) {
152		case 'f':
153			flag_force = 1;
154			break;
155		case 'h':
156			flag_nofollow = 1;
157			break;
158		case 'i':
159			flag_from_stdin = 1;
160			break;
161		case 'n':
162			flag_null = 1;
163			break;
164		case 'q':
165			count_quiet += 1;
166			break;
167		case 's':
168			flag_string = 1;
169			break;
170		case 'x':
171			flag_hex = 1;
172			break;
173		case '?':
174		default:
175			usage();
176		}
177	}
178
179	argc -= optind;
180	argv += optind;
181
182	if (what == EASET && flag_from_stdin == 0)
183		minargc++;
184
185	if (argc < minargc)
186		usage();
187
188	error = extattr_string_to_namespace(argv[0], &attrnamespace);
189	if (error)
190		err(-1, "%s", argv[0]);
191	argc--; argv++;
192
193	if (what != EALS) {
194		attrname = argv[0];
195		argc--; argv++;
196	} else
197		attrname = NULL;
198
199	if (what == EASET) {
200		attrvalue = sbuf_new_auto();
201		if (flag_from_stdin) {
202			while ((error = read(0, stdin_data, STDIN_BUF_SZ)) > 0)
203				sbuf_bcat(attrvalue, stdin_data, error);
204		} else {
205			sbuf_cpy(attrvalue, argv[0]);
206			argc--; argv++;
207		}
208		sbuf_finish(attrvalue);
209	}
210
211	for (arg_counter = 0; arg_counter < argc; arg_counter++) {
212		switch (what) {
213		case EARM:
214			if (flag_nofollow)
215				error = extattr_delete_link(argv[arg_counter],
216				    attrnamespace, attrname);
217			else
218				error = extattr_delete_file(argv[arg_counter],
219				    attrnamespace, attrname);
220			if (error >= 0)
221				continue;
222			break;
223		case EASET:
224			len = sbuf_len(attrvalue) + flag_null;
225			if (flag_nofollow)
226				ret = extattr_set_link(argv[arg_counter],
227				    attrnamespace, attrname,
228				    sbuf_data(attrvalue), len);
229			else
230				ret = extattr_set_file(argv[arg_counter],
231				    attrnamespace, attrname,
232				    sbuf_data(attrvalue), len);
233			if (ret >= 0) {
234				if ((size_t)ret != len && !count_quiet) {
235					warnx("Set %zd bytes of %zu for %s",
236					    ret, len, attrname);
237				}
238				continue;
239			}
240			break;
241		case EALS:
242			if (flag_nofollow)
243				ret = extattr_list_link(argv[arg_counter],
244				    attrnamespace, NULL, 0);
245			else
246				ret = extattr_list_file(argv[arg_counter],
247				    attrnamespace, NULL, 0);
248			if (ret < 0)
249				break;
250			mkbuf(&buf, &buflen, ret);
251			if (flag_nofollow)
252				ret = extattr_list_link(argv[arg_counter],
253				    attrnamespace, buf, buflen);
254			else
255				ret = extattr_list_file(argv[arg_counter],
256				    attrnamespace, buf, buflen);
257			if (ret < 0)
258				break;
259			if (!count_quiet)
260				printf("%s\t", argv[arg_counter]);
261			for (i = 0; i < ret; i += ch + 1) {
262			    /* The attribute name length is unsigned. */
263			    ch = (unsigned char)buf[i];
264			    printf("%s%*.*s", i ? "\t" : "",
265				ch, ch, buf + i + 1);
266			}
267			if (!count_quiet || ret > 0)
268				printf("\n");
269			continue;
270		case EAGET:
271			if (flag_nofollow)
272				ret = extattr_get_link(argv[arg_counter],
273				    attrnamespace, attrname, NULL, 0);
274			else
275				ret = extattr_get_file(argv[arg_counter],
276				    attrnamespace, attrname, NULL, 0);
277			if (ret < 0)
278				break;
279			mkbuf(&buf, &buflen, ret);
280			if (flag_nofollow)
281				ret = extattr_get_link(argv[arg_counter],
282				    attrnamespace, attrname, buf, buflen);
283			else
284				ret = extattr_get_file(argv[arg_counter],
285				    attrnamespace, attrname, buf, buflen);
286			if (ret < 0)
287				break;
288			if (!count_quiet)
289				printf("%s\t", argv[arg_counter]);
290			if (flag_string) {
291				mkbuf(&visbuf, &visbuflen, ret * 4 + 1);
292				strvisx(visbuf, buf, ret,
293				    VIS_SAFE | VIS_WHITE);
294				printf("\"%s\"", visbuf);
295			} else if (flag_hex) {
296				for (i = 0; i < ret; i++)
297					printf("%s%02x", i ? " " : "",
298							(unsigned char)buf[i]);
299			} else {
300				fwrite(buf, ret, 1, stdout);
301			}
302			if (count_quiet < 2)
303				printf("\n");
304			continue;
305		default:
306			break;
307		}
308		if (!count_quiet)
309			warn("%s: failed", argv[arg_counter]);
310		if (flag_force)
311			continue;
312		return(1);
313	}
314	return (0);
315}
316