12bb8e5e2SAndreas Jaekel #include <stdio.h> 22bb8e5e2SAndreas Jaekel #include <unistd.h> 32bb8e5e2SAndreas Jaekel #include <stdlib.h> 42bb8e5e2SAndreas Jaekel #include <fcntl.h> 52bb8e5e2SAndreas Jaekel #include <stropts.h> 62bb8e5e2SAndreas Jaekel #include <poll.h> 72bb8e5e2SAndreas Jaekel #include <string.h> 82bb8e5e2SAndreas Jaekel #include <sys/fs/zev.h> 92bb8e5e2SAndreas Jaekel #include <errno.h> 10*9193e9c2SAndreas Jaekel #include <libnvpair.h> 112bb8e5e2SAndreas Jaekel 122bb8e5e2SAndreas Jaekel #define OP_STATISTICS (1 << 0) 132bb8e5e2SAndreas Jaekel #define OP_POLL_EVENTS (1 << 1) 142bb8e5e2SAndreas Jaekel #define OP_MUTE_POOL (1 << 2) 152bb8e5e2SAndreas Jaekel #define OP_UNMUTE_POOL (1 << 3) 162bb8e5e2SAndreas Jaekel #define OP_SET_MAX_QUEUE_LEN (1 << 4) 172bb8e5e2SAndreas Jaekel 182bb8e5e2SAndreas Jaekel #define ZEV_DEVICE "/devices/pseudo/zev@0:zev" 192bb8e5e2SAndreas Jaekel 202bb8e5e2SAndreas Jaekel static char *zev_device = ZEV_DEVICE; 212bb8e5e2SAndreas Jaekel 22*9193e9c2SAndreas Jaekel static char *zev_op_name[] = { 23*9193e9c2SAndreas Jaekel "ZEV_OP_ERROR", 24*9193e9c2SAndreas Jaekel "ZEV_OP_ZFS_MOUNT", 25*9193e9c2SAndreas Jaekel "ZEV_OP_ZFS_UMOUNT", 26*9193e9c2SAndreas Jaekel "ZEV_OP_ZVOL_WRITE", 27*9193e9c2SAndreas Jaekel "ZEV_OP_ZVOL_TRUNCATE", 28*9193e9c2SAndreas Jaekel "ZEV_OP_ZNODE_CLOSE_AFTER_UPDATE", 29*9193e9c2SAndreas Jaekel "ZEV_OP_ZNODE_CREATE", 30*9193e9c2SAndreas Jaekel "ZEV_OP_ZNODE_MKDIR", 31*9193e9c2SAndreas Jaekel "ZEV_OP_ZNODE_MAKE_XATTR_DIR", 32*9193e9c2SAndreas Jaekel "ZEV_OP_ZNODE_REMOVE", 33*9193e9c2SAndreas Jaekel "ZEV_OP_ZNODE_RMDIR", 34*9193e9c2SAndreas Jaekel "ZEV_OP_ZNODE_LINK", 35*9193e9c2SAndreas Jaekel "ZEV_OP_ZNODE_SYMLINK", 36*9193e9c2SAndreas Jaekel "ZEV_OP_ZNODE_RENAME", 37*9193e9c2SAndreas Jaekel "ZEV_OP_ZNODE_WRITE", 38*9193e9c2SAndreas Jaekel "ZEV_OP_ZNODE_TRUNCATE", 39*9193e9c2SAndreas Jaekel "ZEV_OP_ZNODE_SETATTR", 40*9193e9c2SAndreas Jaekel "ZEV_OP_ZNODE_ACL", 41*9193e9c2SAndreas Jaekel NULL 42*9193e9c2SAndreas Jaekel }; 43*9193e9c2SAndreas Jaekel 442bb8e5e2SAndreas Jaekel static void 452bb8e5e2SAndreas Jaekel zev_statistics(int fd) 462bb8e5e2SAndreas Jaekel { 472bb8e5e2SAndreas Jaekel zev_statistics_t zs; 482bb8e5e2SAndreas Jaekel if (ioctl(fd, ZEV_IOC_GET_STATISTICS, &zs)) { 492bb8e5e2SAndreas Jaekel perror("getting statistics data failed"); 502bb8e5e2SAndreas Jaekel exit (EXIT_FAILURE); 512bb8e5e2SAndreas Jaekel } 522bb8e5e2SAndreas Jaekel printf("ZEV module state:\n"); 532bb8e5e2SAndreas Jaekel 542bb8e5e2SAndreas Jaekel printf(" queue length in bytes : %lu\n", zs.zev_queue_len); 552bb8e5e2SAndreas Jaekel printf(" queue length limit : %lu\n", zs.zev_max_queue_len); 56205a9bc9SAndreas Jaekel printf(" poll wakeup throttle : %lu\n\n", 57205a9bc9SAndreas Jaekel zs.zev_poll_wakeup_queue_len); 582bb8e5e2SAndreas Jaekel printf(" bytes read from device : %lu\n", zs.zev_bytes_read); 592bb8e5e2SAndreas Jaekel printf(" module internal errors : %lu\n\n", zs.zev_cnt_errors); 602bb8e5e2SAndreas Jaekel 612bb8e5e2SAndreas Jaekel printf("ZFS event statistics:\n"); 622bb8e5e2SAndreas Jaekel 632bb8e5e2SAndreas Jaekel printf(" total ZFS events : %lu\n", zs.zev_cnt_total_events); 642bb8e5e2SAndreas Jaekel printf(" ZFS mount : %lu\n", zs.zev_cnt_zfs_mount); 652bb8e5e2SAndreas Jaekel printf(" ZFS umount : %lu\n", zs.zev_cnt_zfs_umount); 662bb8e5e2SAndreas Jaekel printf(" ZVOL write : %lu\n", zs.zev_cnt_zvol_write); 672bb8e5e2SAndreas Jaekel printf(" ZVOL truncate : %lu\n", zs.zev_cnt_zvol_truncate); 682bb8e5e2SAndreas Jaekel printf(" ZNODE close after update: %lu\n", 692bb8e5e2SAndreas Jaekel zs.zev_cnt_znode_close_after_update); 702bb8e5e2SAndreas Jaekel printf(" ZNODE create : %lu\n", zs.zev_cnt_znode_create); 712bb8e5e2SAndreas Jaekel printf(" ZNODE remove : %lu\n", zs.zev_cnt_znode_remove); 722bb8e5e2SAndreas Jaekel printf(" ZNODE link : %lu\n", zs.zev_cnt_znode_link); 732bb8e5e2SAndreas Jaekel printf(" ZNODE symlink : %lu\n", zs.zev_cnt_znode_symlink); 742bb8e5e2SAndreas Jaekel printf(" ZNODE rename : %lu\n", zs.zev_cnt_znode_rename); 752bb8e5e2SAndreas Jaekel printf(" ZNODE write : %lu\n", zs.zev_cnt_znode_write); 762bb8e5e2SAndreas Jaekel printf(" ZNODE truncate : %lu\n", 772bb8e5e2SAndreas Jaekel zs.zev_cnt_znode_truncate); 782bb8e5e2SAndreas Jaekel printf(" ZNODE setattr : %lu\n", zs.zev_cnt_znode_setattr); 792bb8e5e2SAndreas Jaekel printf(" ZNODE acl : %lu\n", zs.zev_cnt_znode_acl); 802bb8e5e2SAndreas Jaekel } 812bb8e5e2SAndreas Jaekel 822bb8e5e2SAndreas Jaekel static void 83*9193e9c2SAndreas Jaekel zev_print_event(char *buf, int len) 84*9193e9c2SAndreas Jaekel { 85*9193e9c2SAndreas Jaekel nvlist_t *nvl; 86*9193e9c2SAndreas Jaekel nvpair_t *curr, *next; 87*9193e9c2SAndreas Jaekel int err; 88*9193e9c2SAndreas Jaekel char *key; 89*9193e9c2SAndreas Jaekel data_type_t type; 90*9193e9c2SAndreas Jaekel uchar_t op; 91*9193e9c2SAndreas Jaekel uint64_t op_time; 92*9193e9c2SAndreas Jaekel char *when; 93*9193e9c2SAndreas Jaekel time_t ot; 94*9193e9c2SAndreas Jaekel boolean_t val_bool; 95*9193e9c2SAndreas Jaekel uint64_t val_uint64; 96*9193e9c2SAndreas Jaekel char *val_string; 97*9193e9c2SAndreas Jaekel uchar_t val_byte; 98*9193e9c2SAndreas Jaekel int32_t val_int32; 99*9193e9c2SAndreas Jaekel 100*9193e9c2SAndreas Jaekel if (0 != nvlist_unpack(buf, len, &nvl, NV_ENCODE_NATIVE)) { 101*9193e9c2SAndreas Jaekel fprintf(stderr, "zev event garbled: can't unpack nvlist\n"); 102*9193e9c2SAndreas Jaekel exit(1); 103*9193e9c2SAndreas Jaekel } 104*9193e9c2SAndreas Jaekel 105*9193e9c2SAndreas Jaekel if (0 != nvlist_lookup_byte(nvl, "op", &op)) { 106*9193e9c2SAndreas Jaekel fprintf(stderr, "zev event garbled: no op specified\n"); 107*9193e9c2SAndreas Jaekel exit(1); 108*9193e9c2SAndreas Jaekel } 109*9193e9c2SAndreas Jaekel if (op < ZEV_OP_MIN || op > ZEV_OP_MAX) { 110*9193e9c2SAndreas Jaekel fprintf(stderr, "zev event garbled: op %d is outside range\n", 111*9193e9c2SAndreas Jaekel op); 112*9193e9c2SAndreas Jaekel exit(1); 113*9193e9c2SAndreas Jaekel } 114*9193e9c2SAndreas Jaekel if (0 != nvlist_lookup_uint64(nvl, "op_time", &op_time)) { 115*9193e9c2SAndreas Jaekel fprintf(stderr, "zev event garbled: no op_time specified\n"); 116*9193e9c2SAndreas Jaekel exit(1); 117*9193e9c2SAndreas Jaekel } 118*9193e9c2SAndreas Jaekel ot = op_time; 119*9193e9c2SAndreas Jaekel when = ctime(&ot); 120*9193e9c2SAndreas Jaekel when[24] = '\0'; 121*9193e9c2SAndreas Jaekel printf("%s %s", when, zev_op_name[op - ZEV_OP_MIN]); 122*9193e9c2SAndreas Jaekel 123*9193e9c2SAndreas Jaekel curr = nvlist_next_nvpair(nvl, NULL); 124*9193e9c2SAndreas Jaekel while (curr != NULL) { 125*9193e9c2SAndreas Jaekel nvpair_t *next = nvlist_next_nvpair(nvl, curr); 126*9193e9c2SAndreas Jaekel key = nvpair_name(curr); 127*9193e9c2SAndreas Jaekel if (!strcmp(key, "op")) 128*9193e9c2SAndreas Jaekel goto skip; 129*9193e9c2SAndreas Jaekel if (!strcmp(key, "op_time")) 130*9193e9c2SAndreas Jaekel goto skip; 131*9193e9c2SAndreas Jaekel type = nvpair_type(curr); 132*9193e9c2SAndreas Jaekel switch (type) { 133*9193e9c2SAndreas Jaekel case DATA_TYPE_BOOLEAN_VALUE: 134*9193e9c2SAndreas Jaekel nvlist_lookup_boolean_value(nvl, key, &val_bool); 135*9193e9c2SAndreas Jaekel printf(" %s=%s", key, (val_bool ? "true" : "false")); 136*9193e9c2SAndreas Jaekel break; 137*9193e9c2SAndreas Jaekel case DATA_TYPE_BYTE: 138*9193e9c2SAndreas Jaekel nvlist_lookup_byte(nvl, key, &val_byte); 139*9193e9c2SAndreas Jaekel printf(" %s=%d", key, val_byte); 140*9193e9c2SAndreas Jaekel break; 141*9193e9c2SAndreas Jaekel case DATA_TYPE_UINT64: 142*9193e9c2SAndreas Jaekel nvlist_lookup_uint64(nvl, key, &val_uint64); 143*9193e9c2SAndreas Jaekel printf(" %s=%llu", key, val_uint64); 144*9193e9c2SAndreas Jaekel break; 145*9193e9c2SAndreas Jaekel case DATA_TYPE_INT32: 146*9193e9c2SAndreas Jaekel nvlist_lookup_int32(nvl, key, &val_int32); 147*9193e9c2SAndreas Jaekel printf(" %s=%d", key, val_int32); 148*9193e9c2SAndreas Jaekel break; 149*9193e9c2SAndreas Jaekel case DATA_TYPE_STRING: 150*9193e9c2SAndreas Jaekel nvlist_lookup_string(nvl, key, &val_string); 151*9193e9c2SAndreas Jaekel printf(" %s=%s", key, val_string); 152*9193e9c2SAndreas Jaekel break; 153*9193e9c2SAndreas Jaekel default: 154*9193e9c2SAndreas Jaekel fprintf(stderr, "unexpected nvlist data type: %d\n", 155*9193e9c2SAndreas Jaekel type); 156*9193e9c2SAndreas Jaekel exit(1); 157*9193e9c2SAndreas Jaekel } 158*9193e9c2SAndreas Jaekel skip: 159*9193e9c2SAndreas Jaekel curr = next; 160*9193e9c2SAndreas Jaekel } 161*9193e9c2SAndreas Jaekel printf("\n"); 162*9193e9c2SAndreas Jaekel } 163*9193e9c2SAndreas Jaekel 164*9193e9c2SAndreas Jaekel static void 1652bb8e5e2SAndreas Jaekel zev_poll_events(int fd) 1662bb8e5e2SAndreas Jaekel { 1672bb8e5e2SAndreas Jaekel struct pollfd pfd[1]; 1682bb8e5e2SAndreas Jaekel int ret; 169*9193e9c2SAndreas Jaekel char buf[4096]; 1702bb8e5e2SAndreas Jaekel while (1) { 1712bb8e5e2SAndreas Jaekel pfd[0].fd = fd; 1722bb8e5e2SAndreas Jaekel pfd[0].events = POLLIN; 1732bb8e5e2SAndreas Jaekel ret = poll(pfd, 1, 1000); 1742bb8e5e2SAndreas Jaekel if (ret < 0) { 1752bb8e5e2SAndreas Jaekel perror("poll failed"); 1762bb8e5e2SAndreas Jaekel exit(EXIT_FAILURE); 1772bb8e5e2SAndreas Jaekel } 1782bb8e5e2SAndreas Jaekel if (!(pfd[0].revents & POLLIN)) 1792bb8e5e2SAndreas Jaekel continue; 1802bb8e5e2SAndreas Jaekel /* data available */ 1812bb8e5e2SAndreas Jaekel ret = read(fd, buf, sizeof(buf)); 1822bb8e5e2SAndreas Jaekel if (ret < 0) { 1832bb8e5e2SAndreas Jaekel perror("read failed"); 1842bb8e5e2SAndreas Jaekel exit(EXIT_FAILURE); 1852bb8e5e2SAndreas Jaekel } 1862bb8e5e2SAndreas Jaekel if (ret == 0) 1872bb8e5e2SAndreas Jaekel continue; 188*9193e9c2SAndreas Jaekel zev_print_event(buf, ret); 1892bb8e5e2SAndreas Jaekel } 1902bb8e5e2SAndreas Jaekel return; 1912bb8e5e2SAndreas Jaekel } 1922bb8e5e2SAndreas Jaekel 1932bb8e5e2SAndreas Jaekel static void 1942bb8e5e2SAndreas Jaekel usage(char *progname) 1952bb8e5e2SAndreas Jaekel { 1962bb8e5e2SAndreas Jaekel fprintf(stderr, "usage: %s [-s] [-d <dev>]\n", progname); 1972bb8e5e2SAndreas Jaekel fprintf(stderr, " -s show zev statistics\n"); 1982bb8e5e2SAndreas Jaekel fprintf(stderr, " -p poll for ZFS events\n"); 1992bb8e5e2SAndreas Jaekel fprintf(stderr, " -q <bytes> set maximum event queue length\n"); 200205a9bc9SAndreas Jaekel fprintf(stderr, " -t <bytes> set queue length poll throttle\n"); 2012bb8e5e2SAndreas Jaekel fprintf(stderr, " -m <pool> mute pool, no events for this pool\n"); 2022bb8e5e2SAndreas Jaekel fprintf(stderr, " -M <pool> unmute pool\n"); 2032bb8e5e2SAndreas Jaekel fprintf(stderr, " -d <dev> device file to use. default is '%s'\n", 2042bb8e5e2SAndreas Jaekel ZEV_DEVICE); 2052bb8e5e2SAndreas Jaekel exit (EXIT_FAILURE); 2062bb8e5e2SAndreas Jaekel } 2072bb8e5e2SAndreas Jaekel 2082bb8e5e2SAndreas Jaekel static int 2092bb8e5e2SAndreas Jaekel zev_set_max_queue_len(int fd, char *optarg) 2102bb8e5e2SAndreas Jaekel { 2112bb8e5e2SAndreas Jaekel uint64_t maxqueuelen; 2122bb8e5e2SAndreas Jaekel 2132bb8e5e2SAndreas Jaekel errno = 0; 2142bb8e5e2SAndreas Jaekel maxqueuelen = strtol(optarg, (char **)NULL, 10); 2152bb8e5e2SAndreas Jaekel if (errno) { 2162bb8e5e2SAndreas Jaekel fprintf(stderr, "invalid queue length parameter: %s\n", optarg); 2172bb8e5e2SAndreas Jaekel return (EXIT_FAILURE); 2182bb8e5e2SAndreas Jaekel } 2192bb8e5e2SAndreas Jaekel if (ioctl(fd, ZEV_IOC_SET_MAX_QUEUE_LEN, &maxqueuelen)) { 2202bb8e5e2SAndreas Jaekel perror("setting max queue length failed"); 2212bb8e5e2SAndreas Jaekel return (EXIT_FAILURE); 2222bb8e5e2SAndreas Jaekel } 2232bb8e5e2SAndreas Jaekel return (0); 2242bb8e5e2SAndreas Jaekel } 2252bb8e5e2SAndreas Jaekel 2262bb8e5e2SAndreas Jaekel static int 227205a9bc9SAndreas Jaekel zev_set_poll_wakeup_queue_len(int fd, char *optarg) 228205a9bc9SAndreas Jaekel { 229205a9bc9SAndreas Jaekel uint64_t queuelen; 230205a9bc9SAndreas Jaekel 231205a9bc9SAndreas Jaekel errno = 0; 232205a9bc9SAndreas Jaekel queuelen = strtol(optarg, (char **)NULL, 10); 233205a9bc9SAndreas Jaekel if (errno) { 234205a9bc9SAndreas Jaekel fprintf(stderr, "invalid queue length parameter: %s\n", optarg); 235205a9bc9SAndreas Jaekel return (EXIT_FAILURE); 236205a9bc9SAndreas Jaekel } 237205a9bc9SAndreas Jaekel if (ioctl(fd, ZEV_IOC_SET_POLL_WAKEUP_QUEUE_LEN, &queuelen)) { 238205a9bc9SAndreas Jaekel perror("setting poll wakeup queue length failed"); 239205a9bc9SAndreas Jaekel return (EXIT_FAILURE); 240205a9bc9SAndreas Jaekel } 241205a9bc9SAndreas Jaekel return (0); 242205a9bc9SAndreas Jaekel } 243205a9bc9SAndreas Jaekel 244205a9bc9SAndreas Jaekel static int 2452bb8e5e2SAndreas Jaekel zev_mute_unmute_impl(int fd, char *poolname, int mute) 2462bb8e5e2SAndreas Jaekel { 2472bb8e5e2SAndreas Jaekel zev_ioctl_poolarg_t pa; 2482bb8e5e2SAndreas Jaekel int len; 2492bb8e5e2SAndreas Jaekel int op = mute ? ZEV_IOC_MUTE_POOL : ZEV_IOC_UNMUTE_POOL; 2502bb8e5e2SAndreas Jaekel len = strlen(poolname); 2512bb8e5e2SAndreas Jaekel if (len <= 0 || len >= sizeof(pa.zev_poolname)) { 2522bb8e5e2SAndreas Jaekel fprintf(stderr, "invalid poolname: %s\n", poolname); 2532bb8e5e2SAndreas Jaekel return (EXIT_FAILURE); 2542bb8e5e2SAndreas Jaekel } 2552bb8e5e2SAndreas Jaekel strcpy(pa.zev_poolname, poolname); 2562bb8e5e2SAndreas Jaekel pa.zev_poolname_len = len; 2572bb8e5e2SAndreas Jaekel if (ioctl(fd, op, &pa)) { 2582bb8e5e2SAndreas Jaekel perror("muting pool data failed"); 2592bb8e5e2SAndreas Jaekel return (EXIT_FAILURE); 2602bb8e5e2SAndreas Jaekel } 2612bb8e5e2SAndreas Jaekel return (0); 2622bb8e5e2SAndreas Jaekel } 2632bb8e5e2SAndreas Jaekel 2642bb8e5e2SAndreas Jaekel int 2652bb8e5e2SAndreas Jaekel zev_mute_pool(int fd, char *poolname) 2662bb8e5e2SAndreas Jaekel { 2672bb8e5e2SAndreas Jaekel return zev_mute_unmute_impl(fd, poolname, 1); 2682bb8e5e2SAndreas Jaekel } 2692bb8e5e2SAndreas Jaekel 2702bb8e5e2SAndreas Jaekel int 2712bb8e5e2SAndreas Jaekel zev_unmute_pool(int fd, char *poolname) 2722bb8e5e2SAndreas Jaekel { 2732bb8e5e2SAndreas Jaekel return zev_mute_unmute_impl(fd, poolname, 0); 2742bb8e5e2SAndreas Jaekel } 2752bb8e5e2SAndreas Jaekel 2762bb8e5e2SAndreas Jaekel int 2772bb8e5e2SAndreas Jaekel main(int argc, char **argv) 2782bb8e5e2SAndreas Jaekel { 2792bb8e5e2SAndreas Jaekel int fd; 2802bb8e5e2SAndreas Jaekel int c; 2812bb8e5e2SAndreas Jaekel int ops = 0; 2822bb8e5e2SAndreas Jaekel extern char *optarg; 2832bb8e5e2SAndreas Jaekel 2842bb8e5e2SAndreas Jaekel /* open device */ 2852bb8e5e2SAndreas Jaekel fd = open(zev_device, O_RDONLY); 2862bb8e5e2SAndreas Jaekel if (fd < 0) { 2872bb8e5e2SAndreas Jaekel perror("opening zev device failed"); 2882bb8e5e2SAndreas Jaekel return EXIT_FAILURE; 2892bb8e5e2SAndreas Jaekel } 290205a9bc9SAndreas Jaekel while ((c = getopt(argc, argv, "spdq:t:m:M:h?")) != -1) { 2912bb8e5e2SAndreas Jaekel switch(c) { 2922bb8e5e2SAndreas Jaekel case 's': 2932bb8e5e2SAndreas Jaekel ops |= OP_STATISTICS; 2942bb8e5e2SAndreas Jaekel break; 2952bb8e5e2SAndreas Jaekel case 'p': 2962bb8e5e2SAndreas Jaekel ops |= OP_POLL_EVENTS; 2972bb8e5e2SAndreas Jaekel break; 2982bb8e5e2SAndreas Jaekel case 'd': 2992bb8e5e2SAndreas Jaekel zev_device = optarg; 3002bb8e5e2SAndreas Jaekel break; 3012bb8e5e2SAndreas Jaekel case 'q': 3022bb8e5e2SAndreas Jaekel return zev_set_max_queue_len(fd, optarg); 303205a9bc9SAndreas Jaekel case 't': 304205a9bc9SAndreas Jaekel return zev_set_poll_wakeup_queue_len(fd, optarg); 3052bb8e5e2SAndreas Jaekel case 'm': 3062bb8e5e2SAndreas Jaekel return zev_mute_pool(fd, optarg); 3072bb8e5e2SAndreas Jaekel case 'M': 3082bb8e5e2SAndreas Jaekel return zev_unmute_pool(fd, optarg); 3092bb8e5e2SAndreas Jaekel case 'h': 3102bb8e5e2SAndreas Jaekel case '?': 3112bb8e5e2SAndreas Jaekel default: 3122bb8e5e2SAndreas Jaekel usage(argv[0]); 3132bb8e5e2SAndreas Jaekel } 3142bb8e5e2SAndreas Jaekel } 3152bb8e5e2SAndreas Jaekel if (!ops) 3162bb8e5e2SAndreas Jaekel usage(argv[0]); 3172bb8e5e2SAndreas Jaekel if (ops & OP_STATISTICS) 3182bb8e5e2SAndreas Jaekel zev_statistics(fd); 3192bb8e5e2SAndreas Jaekel if (ops & OP_POLL_EVENTS) 3202bb8e5e2SAndreas Jaekel zev_poll_events(fd); 3212bb8e5e2SAndreas Jaekel close(fd); 3222bb8e5e2SAndreas Jaekel return EXIT_SUCCESS; 3232bb8e5e2SAndreas Jaekel } 3242bb8e5e2SAndreas Jaekel 325