1 /*
2  * xattrs.c --- Modify extended attributes via debugfs.
3  *
4  * Copyright (C) 2014 Oracle.  This file may be redistributed
5  * under the terms of the GNU Public License.
6  */
7 
8 #include "config.h"
9 #include <stdio.h>
10 #ifdef HAVE_GETOPT_H
11 #include <getopt.h>
12 #else
13 extern int optind;
14 extern char *optarg;
15 #endif
16 #include <ctype.h>
17 
18 #include "debugfs.h"
19 
20 /* Dump extended attributes */
21 static void dump_xattr_string(FILE *out, const char *str, int len)
22 {
23 	int printable = 0;
24 	int i;
25 
26 	/* check: is string "printable enough?" */
27 	for (i = 0; i < len; i++)
28 		if (isprint(str[i]))
29 			printable++;
30 
31 	if (printable <= len*7/8)
32 		printable = 0;
33 
34 	for (i = 0; i < len; i++)
35 		if (printable)
36 			fprintf(out, isprint(str[i]) ? "%c" : "\\%03o",
37 				(unsigned char)str[i]);
38 		else
39 			fprintf(out, "%02x ", (unsigned char)str[i]);
40 }
41 
42 static int dump_attr(char *name, char *value, size_t value_len, void *data)
43 {
44 	FILE *out = data;
45 
46 	fprintf(out, "  ");
47 	dump_xattr_string(out, name, strlen(name));
48 	if (strcmp(name, "system.data") != 0) {
49 		fprintf(out, " = \"");
50 		dump_xattr_string(out, value, value_len);
51 		fprintf(out, "\"");
52 	}
53 	fprintf(out, " (%zu)\n", value_len);
54 
55 	return 0;
56 }
57 
58 void dump_inode_attributes(FILE *out, ext2_ino_t ino)
59 {
60 	struct ext2_xattr_handle *h;
61 	size_t sz;
62 	errcode_t err;
63 
64 	err = ext2fs_xattrs_open(current_fs, ino, &h);
65 	if (err)
66 		return;
67 
68 	err = ext2fs_xattrs_read(h);
69 	if (err)
70 		goto out;
71 
72 	err = ext2fs_xattrs_count(h, &sz);
73 	if (err || sz == 0)
74 		goto out;
75 
76 	fprintf(out, "Extended attributes:\n");
77 	err = ext2fs_xattrs_iterate(h, dump_attr, out);
78 	if (err)
79 		goto out;
80 
81 out:
82 	err = ext2fs_xattrs_close(&h);
83 }
84 
85 void do_list_xattr(int argc, char **argv)
86 {
87 	ext2_ino_t ino;
88 
89 	if (argc != 2) {
90 		printf("%s: Usage: %s <file>\n", argv[0],
91 		       argv[0]);
92 		return;
93 	}
94 
95 	if (check_fs_open(argv[0]))
96 		return;
97 
98 	ino = string_to_inode(argv[1]);
99 	if (!ino)
100 		return;
101 
102 	dump_inode_attributes(stdout, ino);
103 }
104 
105 void do_get_xattr(int argc, char **argv)
106 {
107 	ext2_ino_t ino;
108 	struct ext2_xattr_handle *h;
109 	FILE *fp = NULL;
110 	char *buf = NULL;
111 	size_t buflen;
112 	int i;
113 	errcode_t err;
114 
115 	reset_getopt();
116 	while ((i = getopt(argc, argv, "f:")) != -1) {
117 		switch (i) {
118 		case 'f':
119 			if (fp)
120 				fclose(fp);
121 			fp = fopen(optarg, "w");
122 			if (fp == NULL) {
123 				perror(optarg);
124 				return;
125 			}
126 			break;
127 		default:
128 			printf("%s: Usage: %s <file> <attr> [-f outfile]\n",
129 			       argv[0], argv[0]);
130 			goto out2;
131 		}
132 	}
133 
134 	if (optind != argc - 2) {
135 		printf("%s: Usage: %s <file> <attr> [-f outfile]\n", argv[0],
136 		       argv[0]);
137 		goto out2;
138 	}
139 
140 	if (check_fs_open(argv[0]))
141 		goto out2;
142 
143 	ino = string_to_inode(argv[optind]);
144 	if (!ino)
145 		goto out2;
146 
147 	err = ext2fs_xattrs_open(current_fs, ino, &h);
148 	if (err)
149 		goto out2;
150 
151 	err = ext2fs_xattrs_read(h);
152 	if (err)
153 		goto out;
154 
155 	err = ext2fs_xattr_get(h, argv[optind + 1], (void **)&buf, &buflen);
156 	if (err)
157 		goto out;
158 
159 	if (fp) {
160 		fwrite(buf, buflen, 1, fp);
161 	} else {
162 		dump_xattr_string(stdout, buf, buflen);
163 		printf("\n");
164 	}
165 
166 	ext2fs_free_mem(&buf);
167 out:
168 	ext2fs_xattrs_close(&h);
169 	if (err)
170 		com_err(argv[0], err, "while getting extended attribute");
171 out2:
172 	if (fp)
173 		fclose(fp);
174 }
175 
176 void do_set_xattr(int argc, char **argv)
177 {
178 	ext2_ino_t ino;
179 	struct ext2_xattr_handle *h;
180 	FILE *fp = NULL;
181 	char *buf = NULL;
182 	size_t buflen;
183 	int i;
184 	errcode_t err;
185 
186 	reset_getopt();
187 	while ((i = getopt(argc, argv, "f:")) != -1) {
188 		switch (i) {
189 		case 'f':
190 			if (fp)
191 				fclose(fp);
192 			fp = fopen(optarg, "r");
193 			if (fp == NULL) {
194 				perror(optarg);
195 				return;
196 			}
197 			break;
198 		default:
199 			goto print_usage;
200 		}
201 	}
202 
203 	if (!(fp && optind == argc - 2) && !(!fp && optind == argc - 3)) {
204 	print_usage:
205 		printf("Usage:\t%s <file> <attr> <value>\n", argv[0]);
206 		printf("\t%s -f <value_file> <file> <attr>\n", argv[0]);
207 		goto out2;
208 	}
209 
210 	if (check_fs_open(argv[0]))
211 		goto out2;
212 	if (check_fs_read_write(argv[0]))
213 		goto out2;
214 	if (check_fs_bitmaps(argv[0]))
215 		goto out2;
216 
217 	ino = string_to_inode(argv[optind]);
218 	if (!ino)
219 		goto out2;
220 
221 	err = ext2fs_xattrs_open(current_fs, ino, &h);
222 	if (err)
223 		goto out2;
224 
225 	err = ext2fs_xattrs_read(h);
226 	if (err)
227 		goto out;
228 
229 	if (fp) {
230 		err = ext2fs_get_mem(current_fs->blocksize, &buf);
231 		if (err)
232 			goto out;
233 		buflen = fread(buf, 1, current_fs->blocksize, fp);
234 	} else {
235 		buf = argv[optind + 2];
236 		buflen = strlen(argv[optind + 2]);
237 	}
238 
239 	err = ext2fs_xattr_set(h, argv[optind + 1], buf, buflen);
240 	if (err)
241 		goto out;
242 
243 	err = ext2fs_xattrs_write(h);
244 	if (err)
245 		goto out;
246 
247 out:
248 	ext2fs_xattrs_close(&h);
249 	if (err)
250 		com_err(argv[0], err, "while setting extended attribute");
251 out2:
252 	if (fp) {
253 		fclose(fp);
254 		ext2fs_free_mem(&buf);
255 	}
256 }
257 
258 void do_rm_xattr(int argc, char **argv)
259 {
260 	ext2_ino_t ino;
261 	struct ext2_xattr_handle *h;
262 	int i;
263 	errcode_t err;
264 
265 	if (argc < 3) {
266 		printf("%s: Usage: %s <file> <attrs>...\n", argv[0], argv[0]);
267 		return;
268 	}
269 
270 	if (check_fs_open(argv[0]))
271 		return;
272 	if (check_fs_read_write(argv[0]))
273 		return;
274 	if (check_fs_bitmaps(argv[0]))
275 		return;
276 
277 	ino = string_to_inode(argv[1]);
278 	if (!ino)
279 		return;
280 
281 	err = ext2fs_xattrs_open(current_fs, ino, &h);
282 	if (err)
283 		return;
284 
285 	err = ext2fs_xattrs_read(h);
286 	if (err)
287 		goto out;
288 
289 	for (i = 2; i < argc; i++) {
290 		err = ext2fs_xattr_remove(h, argv[i]);
291 		if (err)
292 			goto out;
293 	}
294 
295 	err = ext2fs_xattrs_write(h);
296 	if (err)
297 		goto out;
298 out:
299 	ext2fs_xattrs_close(&h);
300 	if (err)
301 		com_err(argv[0], err, "while removing extended attribute");
302 }
303