xref: /titanic_41/usr/src/cmd/zevadm/zevadm.c (revision 4b0d01e9d944e10498c80bc88d80a2f5cdd9be22)
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <stdlib.h>
4 #include <fcntl.h>
5 #include <stropts.h>
6 #include <poll.h>
7 #include <string.h>
8 #include <sys/fs/zev.h>
9 #include <errno.h>
10 #include <sys/sysmacros.h>
11 #include <stdarg.h>
12 
13 #define ZEV_DEVICE "/devices/pseudo/zev@0:ctrl"
14 
15 static char *zev_device = ZEV_DEVICE;
16 
17 static char *zev_op_name[] = {
18 	"ERROR",
19 	"MARK",
20 	"ZFS_MOUNT",
21 	"ZFS_UMOUNT",
22 	"ZVOL_WRITE",
23 	"ZVOL_TRUNCATE",
24 	"ZNODE_CLOSE_AFTER_UPDATE",
25 	"ZNODE_CREATE",
26 	"ZNODE_MKDIR",
27 	"ZNODE_MAKE_XATTR_DIR",
28 	"ZNODE_REMOVE",
29 	"ZNODE_RMDIR",
30 	"ZNODE_LINK",
31 	"ZNODE_SYMLINK",
32 	"ZNODE_RENAME",
33 	"ZNODE_WRITE",
34 	"ZNODE_TRUNCATE",
35 	"ZNODE_SETATTR",
36 	"ZNODE_ACL",
37 	NULL
38 };
39 
40 static int verbose = 0;
41 static int grep_friendly = 0;
42 
43 static void
44 zpf(char *fmt, ...)
45 {
46 	va_list	ap;
47 
48 	va_start(ap, fmt);
49 	vprintf(fmt, ap);
50 	va_end(ap);
51 	if (grep_friendly) {
52 		printf(" ");
53 	} else {
54 		printf("\n");
55 	}
56 }
57 
58 static void
59 znl(void)
60 {
61 	if (grep_friendly)
62 		printf("\n");
63 }
64 
65 static int
66 zev_statistics(int fd)
67 {
68 	zev_statistics_t zs;
69 	if (ioctl(fd, ZEV_IOC_GET_GLOBAL_STATISTICS, &zs)) {
70 		perror("getting statistics data failed");
71 		return (EXIT_FAILURE);
72 	}
73 	printf("ZEV module state:\n");
74 
75 	printf("    queue length in bytes   : %lu\n", zs.zev_queue_len);
76 	printf("    queue length limit      : %lu\n", zs.zev_max_queue_len);
77 	printf("    bytes read from device  : %lu\n", zs.zev_bytes_read);
78 	printf("    module internal errors  : %lu\n\n", zs.zev_cnt_errors);
79 
80 	printf("    discarded events        : %lu\n",
81 	    zs.zev_cnt_discarded_events);
82 	printf("    discarded bytes         : %lu\n\n", zs.zev_bytes_discarded);
83 
84 	printf("ZFS event statistics:\n");
85 
86 	printf("    total ZFS events        : %lu\n", zs.zev_cnt_total_events);
87 	printf("    ZFS mount               : %lu\n", zs.zev_cnt_zfs_mount);
88 	printf("    ZFS umount              : %lu\n", zs.zev_cnt_zfs_umount);
89 	printf("    ZVOL write              : %lu\n", zs.zev_cnt_zvol_write);
90 	printf("    ZVOL truncate           : %lu\n", zs.zev_cnt_zvol_truncate);
91 	printf("    ZNODE close after update: %lu\n",
92 	    zs.zev_cnt_znode_close_after_update);
93 	printf("    ZNODE create            : %lu\n", zs.zev_cnt_znode_create);
94 	printf("    ZNODE remove            : %lu\n", zs.zev_cnt_znode_remove);
95 	printf("    ZNODE link              : %lu\n", zs.zev_cnt_znode_link);
96 	printf("    ZNODE symlink           : %lu\n", zs.zev_cnt_znode_symlink);
97 	printf("    ZNODE rename            : %lu\n", zs.zev_cnt_znode_rename);
98 	printf("    ZNODE write             : %lu\n", zs.zev_cnt_znode_write);
99 	printf("    ZNODE truncate          : %lu\n",
100 	    zs.zev_cnt_znode_truncate);
101 	printf("    ZNODE setattr           : %lu\n", zs.zev_cnt_znode_setattr);
102 	printf("    ZNODE acl               : %lu\n", zs.zev_cnt_znode_acl);
103 	return EXIT_SUCCESS;
104 }
105 
106 static void
107 zev_print_inode_info(char *name, zev_inode_info_t *info)
108 {
109 	zpf("  %s.inode: %llu", name, info->ino);
110 	zpf("  %s.gen: %llu", name, info->gen);
111 	zpf("  %s.mtime: %llu", name, info->mtime);
112 	zpf("  %s.ctime: %llu", name, info->ctime);
113 	zpf("  %s.size: %llu", name, info->size);
114 	zpf("  %s.mode: %llo", name, info->mode);
115 	zpf("  %s.links: %llu", name, info->links);
116 	zpf("  %s.type: %lu", name, info->type);
117 	zpf("  %s.flags: %lu", name, info->flags);
118 }
119 
120 static void
121 zev_print_mark_payload(zev_mark_t *rec)
122 {
123 	int i;
124 	int j;
125 	uint8_t *p;
126 	char c;
127 
128 	zpf("  payload:");
129 	p = (uint8_t *)ZEV_PAYLOAD(rec);
130 	for (i=0; i<rec->payload_len; i+=16) {
131 		printf("  ");
132 		for (j=i; j<rec->payload_len && j<i+16; j++) {
133 			printf("%02x ", p[j]);
134 			if (j == i + 7)
135 				printf(" ");
136 		}
137 		if (grep_friendly)
138 			continue;
139 		for (; j<i+16; j++) {
140 			printf("   ");
141 			if (j == i + 7)
142 				printf(" ");
143 		}
144 		printf("    ");
145 		for (j=i; j<rec->payload_len && j<i+16; j++) {
146 			c = '.';
147 			if (p[j] >= ' ' && p[j] <= '~')
148 				c = p[j];
149 			printf("%c", c);
150 			if (j == i + 7)
151 				printf(" ");
152 		}
153 		printf("\n");
154 	}
155 }
156 
157 static void
158 zev_print_error(char *buf)
159 {
160 	zev_error_t *rec = (zev_error_t *)buf;
161 	time_t op_time = rec->op_time;
162 	char *ct = ctime(&op_time); ct[24] = '\0';
163 
164 	if (verbose) {
165 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
166 		zpf("  guid: %llu", rec->guid);
167 		zpf("  failed.op: %s",
168 		    zev_op_name[rec->failed_op - ZEV_OP_MIN]);
169 		zpf("  message: %s", ZEV_ERRSTR(rec));
170 		znl();
171 	} else {
172 		printf("%s %s: failed_op=%s msg=%s\n",
173 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
174 		       zev_op_name[rec->failed_op - ZEV_OP_MIN],
175 		       ZEV_ERRSTR(rec));
176 	}
177 }
178 
179 static void
180 zev_print_mark(char *buf)
181 {
182 	zev_mark_t *rec = (zev_mark_t *)buf;
183 	time_t op_time = rec->op_time;
184 	char *ct = ctime(&op_time); ct[24] = '\0';
185 
186 	if (verbose) {
187 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
188 		zpf("  guid: %llu", rec->guid);
189 		zpf("  mark.id: %llu", rec->mark_id);
190 		zpf("  payload.len: %llu", rec->payload_len);
191 		if (rec->payload_len)
192 			zev_print_mark_payload(rec);
193 		znl();
194 	} else {
195 		printf("%s %s: guid=%llu mark_id=%lld payload_len=%ld\n",
196 		       ct, zev_op_name[rec->op - ZEV_OP_MIN], rec->guid,
197 		       rec->mark_id, rec->payload_len);
198 	}
199 }
200 
201 static void
202 zev_print_zfs_mount(char *buf)
203 {
204 	zev_zfs_mount_t *rec = (zev_zfs_mount_t *)buf;
205 	time_t op_time = rec->op_time;
206 	char *ct = ctime(&op_time); ct[24] = '\0';
207 
208 	if (verbose) {
209 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
210 		zpf("  guid: %llu", rec->guid);
211 		zpf("  dataset: %s", ZEV_DATASET(rec));
212 		zpf("  mountpoint: %s", ZEV_MOUNTPOINT(rec));
213 		zpf("  remount: %s", rec->remount ? "true" : "false");
214 		zev_print_inode_info("root", &rec->root);
215 		znl();
216 	} else {
217 		printf("%s %s: guid=%llu remount=%s dataset='%s' "
218 		       "mountpoint='%s'\n",
219 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
220 		       rec->guid,
221 		       rec->remount ? "true" : "false",
222 		       ZEV_DATASET(rec),
223 		       ZEV_MOUNTPOINT(rec));
224 	}
225 }
226 
227 static void
228 zev_print_zfs_umount(char *buf)
229 {
230 	zev_zfs_umount_t *rec = (zev_zfs_umount_t *)buf;
231 	time_t op_time = rec->op_time;
232 	char *ct = ctime(&op_time); ct[24] = '\0';
233 
234 	if (verbose) {
235 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
236 		zpf("  guid: %llu", rec->guid);
237 		znl();
238 	} else {
239 		printf("%s %s: guid=%llu\n",
240 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
241 		       rec->guid);
242 	}
243 }
244 
245 static void
246 zev_print_zvol_truncate(char *buf)
247 {
248 	zev_zvol_truncate_t *rec = (zev_zvol_truncate_t *)buf;
249 	time_t op_time = rec->op_time;
250 	char *ct = ctime(&op_time); ct[24] = '\0';
251 
252 	if (verbose) {
253 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
254 		zpf("  guid: %llu", rec->guid);
255 		zpf("  txg: %llu", rec->txg);
256 		zpf("  offset: %llu", rec->offset);
257 		zpf("  length: %llu", rec->length);
258 		znl();
259 	} else {
260 		printf("%s %s: guid=%llu offset=%llu length=%llu\n",
261 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
262 		       rec->guid,
263 		       rec->offset,
264 		       rec->length);
265 	}
266 }
267 
268 static void
269 zev_print_zvol_write(char *buf)
270 {
271 	zev_print_zvol_truncate(buf);
272 }
273 
274 static void
275 zev_print_znode_close_after_update(char *buf)
276 {
277 	zev_znode_close_after_update_t *rec =
278 	    (zev_znode_close_after_update_t *)buf;
279 	time_t op_time = rec->op_time;
280 	char *ct = ctime(&op_time); ct[24] = '\0';
281 
282 	if (verbose) {
283 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
284 		zpf("  guid: %llu", rec->guid);
285 		zev_print_inode_info("file", &rec->file);
286 		znl();
287 	} else {
288 		printf("%s %s: guid=%llu file=%llu.%llu\n",
289 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
290 		       rec->guid,
291 		       rec->file.ino, rec->file.gen);
292 	}
293 }
294 
295 static void
296 zev_print_znode_create(char *buf)
297 {
298 	zev_znode_create_t *rec = (zev_znode_create_t *)buf;
299 	time_t op_time = rec->op_time;
300 	char *ct = ctime(&op_time); ct[24] = '\0';
301 
302 	if (verbose) {
303 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
304 		zpf("  guid: %llu", rec->guid);
305 		zpf("  txg: %llu", rec->txg);
306 		zpf("  name: '%s'", ZEV_NAME(rec));
307 		zev_print_inode_info("file", &rec->file);
308 		zev_print_inode_info("parent", &rec->parent);
309 		znl();
310 	} else {
311 		printf("%s %s: guid=%llu parent=%llu.%llu file=%llu.%llu "
312 		       "file.mtime=%llu, parent.mtime=%llu, name='%s'\n",
313 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
314 		       rec->guid,
315 		       rec->parent.ino, rec->parent.gen,
316 		       rec->file.ino, rec->file.gen,
317 		       rec->file.mtime, rec->parent.mtime,
318 		       ZEV_NAME(rec));
319 	}
320 }
321 
322 static void
323 zev_print_znode_mkdir(char *buf)
324 {
325 	zev_print_znode_create(buf);
326 }
327 
328 static void
329 zev_print_znode_make_xattr_dir(char *buf)
330 {
331 	zev_print_znode_create(buf);
332 }
333 
334 static void
335 zev_print_znode_remove(char *buf)
336 {
337 	zev_znode_remove_t *rec = (zev_znode_remove_t *)buf;
338 	time_t op_time = rec->op_time;
339 	char *ct = ctime(&op_time); ct[24] = '\0';
340 
341 	if (verbose) {
342 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
343 		zpf("  guid: %llu", rec->guid);
344 		zpf("  txg: %llu", rec->txg);
345 		zpf("  file.name: '%s'", ZEV_NAME(rec));
346 		zev_print_inode_info("file", &rec->file);
347 		zev_print_inode_info("parent", &rec->parent);
348 		znl();
349 	} else {
350 		printf("%s %s: guid=%llu parent=%llu.%llu "
351 		       "file.mtime=%llu name='%s'\n",
352 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
353 		       rec->guid,
354 		       rec->parent.ino, rec->parent.gen,
355 		       rec->file.mtime,
356 		       ZEV_NAME(rec));
357 	}
358 }
359 
360 static void
361 zev_print_znode_rmdir(char *buf)
362 {
363 	zev_print_znode_remove(buf);
364 }
365 
366 static void
367 zev_print_znode_link(char *buf)
368 {
369 	zev_znode_link_t *rec = (zev_znode_link_t *)buf;
370 	time_t op_time = rec->op_time;
371 	char *ct = ctime(&op_time); ct[24] = '\0';
372 
373 	if (verbose) {
374 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
375 		zpf("  guid: %llu", rec->guid);
376 		zpf("  txg: %llu", rec->txg);
377 		zpf("  link.name: '%s'", ZEV_NAME(rec));
378 		zev_print_inode_info("file", &rec->file);
379 		zev_print_inode_info("parent", &rec->parent);
380 		znl();
381 	} else {
382 		printf("%s %s: parent=%llu.%llu file=%llu.%llu "
383 		       "file.ctime=%llu parent.ctime=%llu name='%s'\n",
384 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
385 		       rec->parent.ino, rec->parent.gen,
386 		       rec->file.ino, rec->file.gen,
387 		       rec->file.ctime, rec->parent.ctime,
388 		       ZEV_NAME(rec));
389 	}
390 }
391 
392 static void
393 zev_print_znode_symlink(char *buf)
394 {
395 	zev_znode_symlink_t *rec = (zev_znode_symlink_t *)buf;
396 	time_t op_time = rec->op_time;
397 	char *ct = ctime(&op_time); ct[24] = '\0';
398 
399 	if (verbose) {
400 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
401 		zpf("  guid: %llu", rec->guid);
402 		zpf("  txg: %llu", rec->txg);
403 		zpf("  symlink.name: '%s'", ZEV_NAME(rec));
404 		zpf("  symlink.link: '%s'", ZEV_LINK(rec));
405 		zev_print_inode_info("file", &rec->file);
406 		zev_print_inode_info("parent", &rec->parent);
407 		znl();
408 	} else {
409 		printf("%s %s: parent=%llu.%llu file=%llu.%llu "
410 		       "name='%s' link='%s'\n",
411 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
412 		       rec->parent.ino, rec->parent.gen,
413 		       rec->file.ino, rec->file.gen,
414 		       ZEV_NAME(rec),
415 		       ZEV_LINK(rec));
416 	}
417 }
418 
419 static void
420 zev_print_znode_rename(char *buf)
421 {
422 	zev_znode_rename_t *rec = (zev_znode_rename_t *)buf;
423 	time_t op_time = rec->op_time;
424 	char *ct = ctime(&op_time); ct[24] = '\0';
425 
426 	if (verbose) {
427 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
428 		zpf("  guid: %llu", rec->guid);
429 		zpf("  txg: %llu", rec->txg);
430 		zpf("  file.srcname: '%s'", ZEV_SRCNAME(rec));
431 		zpf("  file.dstname: '%s'", ZEV_DSTNAME(rec));
432 		zev_print_inode_info("file", &rec->file);
433 		zev_print_inode_info("srcdir", &rec->srcdir);
434 		zev_print_inode_info("dstdir", &rec->dstdir);
435 		znl();
436 	} else {
437 		printf("%s %s: srcdir=%llu.%llu dstdir=%llu.%llu "
438 		       "file=%llu.%llu file.mtime=%llu, file.ctime=%llu, "
439 		       "srcdir.mtime=%llu, srcdir.ctime=%llu, "
440 		       "dstdir.mtime=%llu, dstdir.ctime=%llu, "
441 		       "srcname='%s' dstname='%s'\n",
442 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
443 		       rec->srcdir.ino, rec->srcdir.gen,
444 		       rec->dstdir.ino, rec->dstdir.gen,
445 		       rec->file.ino, rec->file.gen,
446 		       rec->file.mtime, rec->file.ctime,
447 		       rec->srcdir.mtime, rec->srcdir.ctime,
448 		       rec->dstdir.mtime, rec->dstdir.ctime,
449 		       ZEV_SRCNAME(rec),
450 		       ZEV_DSTNAME(rec));
451 	}
452 }
453 
454 static void
455 sig2hex_direct(const uint8_t *sig, char *hex)
456 {
457 	int     i;
458 
459 	for (i = 0; i < SHA1_DIGEST_LENGTH; ++i) {
460 		sprintf(hex + 2 * i, "%02x", sig[i]);
461 	}
462 	hex[SHA1_DIGEST_LENGTH * 2] = '\0';
463 }
464 
465 static void
466 zev_print_znode_write(char *buf)
467 {
468 	zev_znode_write_t *rec = (zev_znode_write_t *)buf;
469 	time_t op_time = rec->op_time;
470 	char *ct = ctime(&op_time); ct[24] = '\0';
471 	zev_sig_t *sig;
472 	char sigval[(SHA1_DIGEST_LENGTH * 2) + 1];
473 	int i;
474 
475 	if (verbose) {
476 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
477 		zpf("  guid: %llu", rec->guid);
478 		zpf("  txg: %llu", rec->txg);
479 		zpf("  offset: %llu", rec->offset);
480 		zpf("  length: %llu", rec->length);
481 		zev_print_inode_info("file", &rec->file);
482 		znl();
483 		for (i=0; i<rec->signature_cnt; i++) {
484 			sig = (zev_sig_t *)ZEV_SIGNATURES(rec);
485 			sig += i;
486 			sig2hex_direct(sig->value, sigval);
487 			printf("  sig: level %d, offset %llu, value %s\n",
488 			       sig->level, sig->block_offset, sigval);
489 		}
490 	} else {
491 		printf("%s %s: file=%llu.%llu offset=%llu length=%llu\n",
492 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
493 		       rec->file.ino, rec->file.gen,
494 		       rec->offset, rec->length);
495 	}
496 }
497 
498 static void
499 zev_print_znode_truncate(char *buf)
500 {
501 	zev_print_znode_write(buf);
502 }
503 
504 static void
505 zev_print_znode_setattr(char *buf)
506 {
507 	zev_znode_setattr_t *rec = (zev_znode_setattr_t *)buf;
508 	time_t op_time = rec->op_time;
509 	char *ct = ctime(&op_time); ct[24] = '\0';
510 
511 	if (verbose) {
512 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
513 		zpf("  guid: %llu", rec->guid);
514 		zpf("  txg: %llu", rec->txg);
515 		zev_print_inode_info("file", &rec->file);
516 		znl();
517 	} else {
518 		printf("%s %s: file=%llu.%llu mtime=%llu\n",
519 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
520 		       rec->file.ino, rec->file.gen, rec->file.mtime);
521 	}
522 }
523 
524 static void
525 zev_print_znode_acl(char *buf)
526 {
527 	zev_print_znode_setattr(buf);
528 }
529 
530 static void
531 zev_print_event(char *buf, int len)
532 {
533 	int record_len;
534 	int op;
535 
536 	record_len = *(uint32_t *)buf;
537 	if (record_len != len) {
538 		fprintf(stderr, "record length mismatch: got %d, expected %d\n",
539 		        record_len, len);
540 		exit(1);
541 	}
542 	op = *((uint32_t *)buf + 1);
543 	if (op < ZEV_OP_MIN || op > ZEV_OP_MAX) {
544 		fprintf(stderr, "unknown op code: %d\n", op);
545 		exit(1);
546 	}
547 	switch (op) {
548 	case ZEV_OP_ERROR:
549 		zev_print_error(buf);
550 		break;
551 	case ZEV_OP_MARK:
552 		zev_print_mark(buf);
553 		break;
554 	case ZEV_OP_ZFS_MOUNT:
555 		zev_print_zfs_mount(buf);
556 		break;
557 	case ZEV_OP_ZFS_UMOUNT:
558 		zev_print_zfs_umount(buf);
559 		break;
560 	case ZEV_OP_ZVOL_TRUNCATE:
561 		zev_print_zvol_truncate(buf);
562 		break;
563 	case ZEV_OP_ZVOL_WRITE:
564 		zev_print_zvol_write(buf);
565 		break;
566 	case ZEV_OP_ZNODE_CLOSE_AFTER_UPDATE:
567 		zev_print_znode_close_after_update(buf);
568 		break;
569 	case ZEV_OP_ZNODE_CREATE:
570 		zev_print_znode_create(buf);
571 		break;
572 	case ZEV_OP_ZNODE_MKDIR:
573 		zev_print_znode_mkdir(buf);
574 		break;
575 	case ZEV_OP_ZNODE_MAKE_XATTR_DIR:
576 		zev_print_znode_make_xattr_dir(buf);
577 		break;
578 	case ZEV_OP_ZNODE_REMOVE:
579 		zev_print_znode_remove(buf);
580 		break;
581 	case ZEV_OP_ZNODE_RMDIR:
582 		zev_print_znode_rmdir(buf);
583 		break;
584 	case ZEV_OP_ZNODE_LINK:
585 		zev_print_znode_link(buf);
586 		break;
587 	case ZEV_OP_ZNODE_SYMLINK:
588 		zev_print_znode_symlink(buf);
589 		break;
590 	case ZEV_OP_ZNODE_RENAME:
591 		zev_print_znode_rename(buf);
592 		break;
593 	case ZEV_OP_ZNODE_WRITE:
594 		zev_print_znode_write(buf);
595 		break;
596 	case ZEV_OP_ZNODE_TRUNCATE:
597 		zev_print_znode_truncate(buf);
598 		break;
599 	case ZEV_OP_ZNODE_SETATTR:
600 		zev_print_znode_setattr(buf);
601 		break;
602 	case ZEV_OP_ZNODE_ACL:
603 		zev_print_znode_acl(buf);
604 		break;
605 	default:
606 		fprintf(stderr, "unhandled op code: %d\n", op);
607 		exit(1);
608 	}
609 }
610 
611 static int
612 zev_poll_events(int fd, int create_tmp_queue)
613 {
614 	struct pollfd pfd[1];
615 	int ret;
616 	char buf[4096];
617 	zev_event_t *ev;
618 	int off = 0;
619 	zev_ioctl_add_queue_t aq;
620 	int q_fd;
621 
622 	if (create_tmp_queue) {
623 		aq.zev_max_queue_len = 0;
624 		aq.zev_flags = ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
625 		snprintf(aq.zev_name, ZEV_MAX_QUEUE_NAME_LEN,
626 			 "zevadm.%ld.%ld", time(NULL), getpid());
627 		aq.zev_namelen = strlen(aq.zev_name);
628 
629 		if (ioctl(fd, ZEV_IOC_ADD_QUEUE, &aq)) {
630 			perror("adding temporary queue failed");
631 			return (EXIT_FAILURE);
632 		}
633 
634 		snprintf(buf, sizeof(buf),
635 		         "/devices/pseudo/zev@0:%s", aq.zev_name);
636 		q_fd = open(buf, O_RDONLY);
637 		if (q_fd < 0) {
638 			perror("opening queue device failed");
639 			return (EXIT_FAILURE);
640 		}
641 	} else {
642 		q_fd = fd;
643 	}
644 
645 	while (1) {
646 		pfd[0].fd = q_fd;
647 		pfd[0].events = POLLIN;
648 		ret = poll(pfd, 1, 1000);
649 		if (ret < 0) {
650 			perror("poll failed");
651 			close(q_fd);
652 			return(EXIT_FAILURE);
653 		}
654 		if (!(pfd[0].revents & POLLIN))
655 			continue;
656 		/* data available */
657 		ret = read(q_fd, buf, sizeof(buf));
658 		if (ret < 0) {
659 			perror("read failed");
660 			close(q_fd);
661 			return(EXIT_FAILURE);
662 		}
663 		if (ret == 0)
664 			continue;
665 		while (ret > off) {
666 			ev = (zev_event_t *)(buf + off);
667 			zev_print_event(buf + off, ev->header.record_len);
668 			off += ev->header.record_len;
669 		}
670 		off = 0;
671 	}
672 	if (create_tmp_queue)
673 		close(q_fd);
674 	return EXIT_SUCCESS;
675 }
676 
677 static void
678 usage(char *progname)
679 {
680 	fprintf(stderr, "usage: %s [-d <dev>] [options]\n", progname);
681 	fprintf(stderr, "\n");
682 	fprintf(stderr, " Status information:\n");
683 	fprintf(stderr, "   -s                   show zev statistics\n");
684 	fprintf(stderr, "   -p                   poll for ZFS events\n");
685 	fprintf(stderr, "   -D                   print zev module debug "
686 	        "information\n");
687 	fprintf(stderr, "\n");
688 	fprintf(stderr, " Tune zev module settings:\n");
689 	fprintf(stderr, "   -Q <bytes>           set maximum event queue "
690 	        "length\n");
691 	fprintf(stderr, "   -m <pool>            mute pool, no events for "
692 	        "this pool\n");
693 	fprintf(stderr, "   -M <pool>            unmute pool\n");
694 	fprintf(stderr, "\n");
695 	fprintf(stderr, " Queue management:\n");
696 	fprintf(stderr, "   -l                   list queues\n");
697 	fprintf(stderr, "   -a <name>            add non-blocking queue\n");
698 	fprintf(stderr, "   -A <name>            add blocking queue\n");
699 	fprintf(stderr, "   -r <name>            remove queue\n");
700 	fprintf(stderr, "   -b <name>            make queue non-blocking "
701 	        "(default)\n");
702 	fprintf(stderr, "   -B <name>            make queue block when full\n");
703 	fprintf(stderr, "   -P <name>            display queue properties\n");
704 	fprintf(stderr, "   -L <name> <bytes>    set maximum event queue "
705 	        "length\n");
706 	fprintf(stderr, "   -t <name> <bytes>    set queue length poll "
707 	        "throttle\n");
708 	fprintf(stderr, "\n");
709 	fprintf(stderr, " Other options:\n");
710 	fprintf(stderr, "   -d <dev>             non-default device file. "
711 	        "('%s')\n", ZEV_DEVICE);
712 	fprintf(stderr, "   -q <name>            use device file for this "
713 		"queue name\n");
714 	fprintf(stderr, "   -k <guid>:<payload>  queue mark event\n");
715 	fprintf(stderr, "   -c <filename>        list file's content "
716 		"checksums\n");
717 	fprintf(stderr, "   -v                   verbose: additional output "
718 	        "for some operations\n");
719 	fprintf(stderr, "   -g                   grep-friendly event output, "
720 	        "one event per line\n");
721 	exit (EXIT_FAILURE);
722 }
723 
724 static int
725 zev_add_queue(int fd, char *arg, int blocking)
726 {
727 	zev_ioctl_add_queue_t aq;
728 	int namelen;
729 
730 	namelen = strlen(arg);
731 	if (namelen > ZEV_MAX_QUEUE_NAME_LEN) {
732 		fprintf(stderr, "queue name too long: %s\n", arg);
733 		return (EXIT_FAILURE);
734 	}
735 
736 	aq.zev_namelen = namelen;
737 	strcpy(aq.zev_name, arg);
738 	aq.zev_flags = ZEV_FL_PERSISTENT;
739 	if (blocking) {
740 		aq.zev_flags |= ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
741 		aq.zev_max_queue_len = ZEV_MAX_QUEUE_LEN;
742 	} else {
743 		aq.zev_max_queue_len = (1024 * 1024);
744 	}
745 
746 	if (ioctl(fd, ZEV_IOC_ADD_QUEUE, &aq)) {
747 		perror("adding queue failed");
748 		return (EXIT_FAILURE);
749 	}
750 	return (0);
751 }
752 
753 static int
754 zev_remove_queue(int fd, char *arg)
755 {
756 	zev_ioctl_remove_queue_t aq;
757 	int namelen;
758 
759 	namelen = strlen(arg);
760 	if (namelen > ZEV_MAX_QUEUE_NAME_LEN) {
761 		fprintf(stderr, "queue name too long: %s\n", arg);
762 		return (EXIT_FAILURE);
763 	}
764 
765 	aq.zev_queue_name.zev_namelen = namelen;
766 	strcpy(aq.zev_queue_name.zev_name, arg);
767 
768 	if (ioctl(fd, ZEV_IOC_REMOVE_QUEUE, &aq)) {
769 		perror("removing queue failed");
770 		return (EXIT_FAILURE);
771 	}
772 	return (0);
773 }
774 
775 static int
776 zev_set_global_max_queue_len(int fd, char *arg)
777 {
778 	uint64_t maxqueuelen;
779 
780 	errno = 0;
781 	maxqueuelen = strtol(arg, (char **)NULL, 10);
782 	if (errno) {
783 		fprintf(stderr, "invalid queue length parameter: %s\n", arg);
784 		return (EXIT_FAILURE);
785 	}
786 	if (ioctl(fd, ZEV_IOC_SET_MAX_QUEUE_LEN, &maxqueuelen)) {
787 		perror("setting max queue length failed");
788 		return (EXIT_FAILURE);
789 	}
790 	return (0);
791 }
792 
793 static int
794 zev_mute_unmute_impl(int fd, char *poolname, int mute)
795 {
796 	zev_ioctl_poolarg_t pa;
797 	int len;
798 	int op = mute ? ZEV_IOC_MUTE_POOL : ZEV_IOC_UNMUTE_POOL;
799 	len = strlen(poolname);
800 	if (len <= 0 || len >= sizeof(pa.zev_poolname)) {
801 		fprintf(stderr, "invalid poolname: %s\n", poolname);
802 		return (EXIT_FAILURE);
803 	}
804 	strcpy(pa.zev_poolname, poolname);
805 	pa.zev_poolname_len = len;
806 	if (ioctl(fd, op, &pa)) {
807 		perror("muting pool data failed");
808 		return (EXIT_FAILURE);
809 	}
810 	return (0);
811 }
812 
813 int
814 zev_mute_pool(int fd, char *poolname)
815 {
816 	return zev_mute_unmute_impl(fd, poolname, 1);
817 }
818 
819 int
820 zev_unmute_pool(int fd, char *poolname)
821 {
822 	return zev_mute_unmute_impl(fd, poolname, 0);
823 }
824 
825 static int
826 zev_debug_info(int fd)
827 {
828 	zev_ioctl_debug_info_t di;
829 
830 	if (ioctl(fd, ZEV_IOC_GET_DEBUG_INFO, &di)) {
831 		perror("getting zev debug info failed");
832 		return (EXIT_FAILURE);
833 	}
834 
835 	printf("memory allocated: %llu bytes\n", di.zev_memory_allocated);
836 	printf("checksum cache size: %llu\n", di.zev_chksum_cache_size);
837 	printf("checksum cache hits: %llu\n", di.zev_chksum_cache_hits);
838 	printf("checksum cache misses: %llu\n", di.zev_chksum_cache_misses);
839 	return 0;
840 }
841 
842 static int
843 zev_mark(int fd, char *arg)
844 {
845 	zev_ioctl_mark_t *mark;
846 	uint64_t guid;
847 	int len;
848 	char *p;
849 
850 	p = strchr(arg, ':');
851 	if (!p) {
852 		fprintf(stderr, "expected value is <guid>:<payload>, "
853 		        "e.g. '123:hello'\n");
854 		exit (EXIT_FAILURE);
855 	}
856 	*p = '\n';
857 	p++;
858 
859 	errno = 0;
860 	guid = strtoll(arg, (char **)NULL, 10);
861 	if (errno) {
862 		fprintf(stderr, "guid must be a number.\n");
863 		exit (EXIT_FAILURE);
864 	}
865 
866 	len = strlen(p);
867 
868 	mark = malloc(sizeof(*mark) + len + 1);
869 	if (!mark) {
870 		fprintf(stderr, "can't allocate mark structure: %s\n",
871 		        strerror(errno));
872 		exit (EXIT_FAILURE);
873 	}
874 	mark->zev_guid = guid;
875 	mark->zev_mark_id = 0;
876 	mark->zev_payload_len = len;
877 	strcpy(ZEV_PAYLOAD(mark), p);
878 
879 	if (ioctl(fd, ZEV_IOC_MARK, mark)) {
880 		perror("queueing mark failed");
881 		return (EXIT_FAILURE);
882 	}
883 
884 	printf("mark id: %lu\n", mark->zev_mark_id);
885 	return (0);
886 }
887 
888 static int
889 zev_queue_blocking(int fd, char *arg, int block)
890 {
891 	zev_ioctl_get_queue_properties_t gqp;
892 
893 	gqp.zev_queue_name.zev_namelen = strlen(arg);
894 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
895 		fprintf(stderr, "queue name too long.\n");
896 		return EXIT_FAILURE;
897 	}
898 	strcpy(gqp.zev_queue_name.zev_name, arg);
899 
900 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
901 		perror("getting queue properties failed");
902 		return (EXIT_FAILURE);
903 	}
904 	if (block) {
905 		gqp.zev_flags |= ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
906 	} else {
907 		gqp.zev_flags &= ~ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
908 	}
909 	if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) {
910 		perror("setting queue properties failed");
911 		return (EXIT_FAILURE);
912 	}
913 	return (0);
914 }
915 
916 static int
917 zev_set_max_queue_len(int fd, char *arg, char *len)
918 {
919 	zev_ioctl_get_queue_properties_t gqp;
920 
921 	if (!len) {
922 		fprintf(stderr, "queue size parameter missing.\n");
923 		return EXIT_FAILURE;
924 	}
925 
926 	gqp.zev_queue_name.zev_namelen = strlen(arg);
927 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
928 		fprintf(stderr, "queue name too long.\n");
929 		return EXIT_FAILURE;
930 	}
931 	strcpy(gqp.zev_queue_name.zev_name, arg);
932 
933 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
934 		perror("getting queue properties failed");
935 		return (EXIT_FAILURE);
936 	}
937 	gqp.zev_max_queue_len = atol(len);
938 	if (gqp.zev_max_queue_len == 0 && strcmp("0", len)) {
939 		fprintf(stderr, "queue size parameter garbled.\n");
940 		return (EXIT_FAILURE);
941 	}
942 	if (gqp.zev_max_queue_len > ZEV_MAX_QUEUE_LEN) {
943 		fprintf(stderr, "queue size parameter out of bounds.\n");
944 		return (EXIT_FAILURE);
945 	}
946 
947 	if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) {
948 		perror("setting queue properties failed");
949 		return (EXIT_FAILURE);
950 	}
951 	return (0);
952 }
953 
954 static int
955 zev_set_poll_wakeup_queue_len(int fd, char *arg, char *len)
956 {
957 	zev_ioctl_get_queue_properties_t gqp;
958 
959 	if (!len) {
960 		fprintf(stderr, "poll throttle parameter missing.\n");
961 		return EXIT_FAILURE;
962 	}
963 
964 	gqp.zev_queue_name.zev_namelen = strlen(arg);
965 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
966 		fprintf(stderr, "queue name too long.\n");
967 		return EXIT_FAILURE;
968 	}
969 	strcpy(gqp.zev_queue_name.zev_name, arg);
970 
971 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
972 		perror("getting queue properties failed");
973 		return (EXIT_FAILURE);
974 	}
975 	gqp.zev_poll_wakeup_threshold = atol(len);
976 	if (gqp.zev_poll_wakeup_threshold == 0 && strcmp("0", len)) {
977 		fprintf(stderr, "poll throttle parameter garbled.\n");
978 		return (EXIT_FAILURE);
979 	}
980 	if (gqp.zev_poll_wakeup_threshold > ZEV_MAX_POLL_WAKEUP_QUEUE_LEN) {
981 		fprintf(stderr, "poll throttle parameter out of bounds.\n");
982 		return (EXIT_FAILURE);
983 	}
984 
985 	if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) {
986 		perror("setting queue properties failed");
987 		return (EXIT_FAILURE);
988 	}
989 	return (0);
990 }
991 
992 static int
993 zev_queue_properties(int fd, char *arg)
994 {
995 	zev_ioctl_get_queue_properties_t gqp;
996 
997 	gqp.zev_queue_name.zev_namelen = strlen(arg);
998 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
999 		fprintf(stderr, "queue name too long.\n");
1000 		return EXIT_FAILURE;
1001 	}
1002 	strcpy(gqp.zev_queue_name.zev_name, arg);
1003 
1004 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
1005 		perror("getting queue properties failed");
1006 		return (EXIT_FAILURE);
1007 	}
1008 
1009 	printf("queue        : %s\n", arg);
1010 	printf("max size     : %" PRIu64 "\n", gqp.zev_max_queue_len);
1011 	printf("poll throttle: %" PRIu64 "\n", gqp.zev_poll_wakeup_threshold);
1012 	printf("persistent   : %s\n",
1013 		gqp.zev_flags & ZEV_FL_PERSISTENT ? "yes" : "no");
1014 	printf("blocking     : %s\n",
1015 		gqp.zev_flags & ZEV_FL_BLOCK_WHILE_QUEUE_FULL ? "yes" : "no");
1016 
1017 	return (0);
1018 }
1019 
1020 static int
1021 zev_list_queues(int fd)
1022 {
1023 	zev_ioctl_get_queue_properties_t gqp;
1024 	zev_ioctl_get_queue_list_t gql;
1025 	zev_ioctl_get_queue_statistics_t gs;
1026 	uint64_t	i;
1027 	char		name[ZEV_MAX_QUEUE_NAME_LEN+1];
1028 
1029 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_LIST, &gql)) {
1030 		perror("getting queue list failed");
1031 		return (EXIT_FAILURE);
1032 	}
1033 
1034 	printf("Name                                     Size       "
1035 	       "Max Size   Wakeup Per Block\n");
1036 
1037 	for (i=0; i<gql.zev_n_queues; i++) {
1038 		strncpy(name, gql.zev_queue_name[i].zev_name,
1039 		        ZEV_MAX_QUEUE_NAME_LEN);
1040 		name[gql.zev_queue_name[i].zev_namelen] = '\0';
1041 
1042 		memcpy(gqp.zev_queue_name.zev_name,
1043 		    gql.zev_queue_name[i].zev_name, ZEV_MAX_QUEUE_NAME_LEN);
1044 		gqp.zev_queue_name.zev_namelen =
1045 		    gql.zev_queue_name[i].zev_namelen;
1046 
1047 		if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
1048 			if (errno == ENOENT)
1049 				continue;
1050 			perror("getting queue properties failed");
1051 			return (EXIT_FAILURE);
1052 		}
1053 
1054 		memcpy(gs.zev_queue_name.zev_name,
1055 		    gql.zev_queue_name[i].zev_name, ZEV_MAX_QUEUE_NAME_LEN);
1056 		gs.zev_queue_name.zev_namelen =
1057 		    gql.zev_queue_name[i].zev_namelen;
1058 
1059 		if (ioctl(fd, ZEV_IOC_GET_QUEUE_STATISTICS, &gs)) {
1060 			if (errno == ENOENT)
1061 				continue;
1062 			perror("getting statistics data failed");
1063 			return (EXIT_FAILURE);
1064 		}
1065 
1066 		printf("%-40s %-10" PRIu64 " %-10" PRIu64 " %-6" PRIu64
1067 		       " %-3s %-3s\n",
1068 			name,
1069 			gs.zev_statistics.zev_queue_len,
1070 			gqp.zev_max_queue_len,
1071 			gqp.zev_poll_wakeup_threshold,
1072 			gqp.zev_flags & ZEV_FL_PERSISTENT ? "yes" : "no",
1073 			gqp.zev_flags & ZEV_FL_BLOCK_WHILE_QUEUE_FULL ?
1074 				 "yes" : "no");
1075 	}
1076 
1077 	return (0);
1078 }
1079 
1080 static int
1081 zev_checksum(int dev_fd, char *filename)
1082 {
1083 	int fd;
1084 	offset_t off;
1085 	offset_t data;
1086 	zev_sig_t *sig;
1087 	char *buf;
1088 	zev_ioctl_get_signatures_t *gs;
1089 	int i;
1090 	char sigval[(SHA1_DIGEST_LENGTH * 2) + 1];
1091 	int buf_size;
1092 
1093 	/* control struct, one lv1 signature and up to 256 lv0 signatures */
1094 	buf_size = (1 + 256) * sizeof(zev_sig_t);
1095 	buf = malloc(sizeof(zev_ioctl_get_signatures_t) + buf_size);
1096 	if (!buf) {
1097 		perror("can't allocate checksum buffer");
1098 		return (EXIT_FAILURE);
1099 	}
1100 
1101 	fd = open(filename, O_RDONLY);
1102 	if (fd < 0) {
1103 		perror("can't open file");
1104 		return (EXIT_FAILURE);
1105 	}
1106 
1107 	gs = (zev_ioctl_get_signatures_t *)buf;
1108 	gs->zev_fd = fd;
1109 	gs->zev_bufsize = buf_size;
1110 
1111 	off = 0;
1112 	data = 0;
1113 	while (1) {
1114 		errno = 0;
1115 		data = llseek(fd, off, SEEK_DATA);
1116 		if (data < 0) {
1117 			if (errno == ENXIO)	/* no more data */
1118 				break;
1119 			perror("llseek failed");
1120 			goto err;
1121 		}
1122 		data = P2ALIGN(data, ZEV_L1_SIZE);
1123 		off = data + ZEV_L1_SIZE;
1124 
1125 		gs->zev_offset = data;
1126 		gs->zev_len = ZEV_L1_SIZE;
1127 
1128 		if (ioctl(dev_fd, ZEV_IOC_GET_FILE_SIGNATURES, gs)) {
1129 			perror("ioctl to get signatures failed");
1130 			goto err;
1131 		}
1132 
1133 		for (i=0; i<gs->zev_signature_cnt; i++) {
1134 			sig = (zev_sig_t *)ZEV_SIGNATURES(gs);
1135 			sig += i;
1136 			sig2hex_direct(sig->value, sigval);
1137 			printf("level %d, offset %llu, value %s\n",
1138 			       sig->level, sig->block_offset, sigval);
1139 		}
1140 	}
1141 
1142 	free(buf);
1143 	close(fd);
1144 	return 0;
1145 err:
1146 	free(buf);
1147 	close(fd);
1148 	return (EXIT_FAILURE);
1149 }
1150 
1151 int
1152 main(int argc, char **argv)
1153 {
1154 	int fd;
1155 	int c;
1156 	extern char *optarg;
1157 	int create_tmp_queue = 1;
1158 	char buf[MAXPATHLEN];
1159 
1160 	/* open device */
1161 	fd = open(zev_device, O_RDONLY);
1162 	if (fd < 0) {
1163 		perror("opening zev device failed");
1164 		return EXIT_FAILURE;
1165 	}
1166 	while ((c = getopt(argc, argv,
1167 	                   "gvspc:d:Dlk:L:q:Qt:m:M:a:A:r:P:b:B:h?")) != -1){
1168 		switch(c) {
1169 		case 'g':
1170 			grep_friendly++;
1171 			verbose++;
1172 			break;
1173 		case 'v':
1174 			verbose++;
1175 			break;
1176 		case 's':
1177 			return zev_statistics(fd);
1178 		case 'p':
1179 			return zev_poll_events(fd, create_tmp_queue);
1180 		case 'c':
1181 			return zev_checksum(fd, optarg);
1182 		case 'D':
1183 			return zev_debug_info(fd);
1184 		case 'd':
1185 			close(fd);
1186 			zev_device = optarg;
1187 			fd = open(zev_device, O_RDONLY);
1188 			if (fd < 0) {
1189 				perror("opening zev device failed");
1190 				return EXIT_FAILURE;
1191 			}
1192 			create_tmp_queue = 0;
1193 			break;
1194 		case 'q':
1195 			snprintf(buf, sizeof(buf),
1196 				 "/devices/pseudo/zev@0:%s", optarg);
1197 			close(fd);
1198 			zev_device = buf;
1199 			fd = open(zev_device, O_RDONLY);
1200 			if (fd < 0) {
1201 				perror("opening zev device failed");
1202 				return EXIT_FAILURE;
1203 			}
1204 			create_tmp_queue = 0;
1205 			break;
1206 		case 'l':
1207 			return zev_list_queues(fd);
1208 		case 'Q':
1209 			return zev_set_global_max_queue_len(fd, optarg);
1210 		case 'L':
1211 			return zev_set_max_queue_len(fd, optarg, argv[optind]);
1212 		case 't':
1213 			return zev_set_poll_wakeup_queue_len(fd, optarg,
1214 			                                     argv[optind]);
1215 		case 'm':
1216 			return zev_mute_pool(fd, optarg);
1217 		case 'M':
1218 			return zev_unmute_pool(fd, optarg);
1219 		case 'k':
1220 			return zev_mark(fd, optarg);
1221 		case 'a':
1222 			return zev_add_queue(fd, optarg, 0);
1223 		case 'A':
1224 			return zev_add_queue(fd, optarg, 1);
1225 		case 'r':
1226 			return zev_remove_queue(fd, optarg);
1227 		case 'b':
1228 			return zev_queue_blocking(fd, optarg, 0);
1229 		case 'B':
1230 			return zev_queue_blocking(fd, optarg, 1);
1231 		case 'P':
1232 			return zev_queue_properties(fd, optarg);
1233 		case 'h':
1234 		case '?':
1235 		default:
1236 			usage(argv[0]);
1237 		}
1238 	}
1239 	usage(argv[0]);
1240 	close(fd);
1241 	return EXIT_FAILURE;
1242 }
1243 
1244