1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2018 Joyent, Inc. 14 * Copyright 2022 OmniOS Community Edition (OmniOSce) Association. 15 */ 16 17 #include <errno.h> 18 #include <fcntl.h> 19 #include <pthread.h> 20 #include <signal.h> 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <strings.h> 24 #include <unistd.h> 25 26 #include <sys/types.h> 27 #include <sys/stat.h> 28 29 #include "testlib.h" 30 #include "mevent.h" 31 32 static char *cookie = "Chocolate chip with fudge stripes"; 33 34 static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; 35 static pthread_cond_t cv = PTHREAD_COND_INITIALIZER; 36 37 static void 38 callback(int fd, enum ev_type ev, void *arg) 39 { 40 static off_t size = 0; 41 struct stat st; 42 43 ASSERT_INT_EQ(("bad event"), ev, EVF_VNODE); 44 ASSERT_PTR_EQ(("bad cookie"), arg, cookie); 45 46 if (fstat(fd, &st) != 0) 47 FAIL_ERRNO("fstat failed"); 48 49 ASSERT_INT64_NEQ(("File size has not changed"), size, st.st_size); 50 size = st.st_size; 51 52 pthread_mutex_lock(&mtx); 53 pthread_cond_signal(&cv); 54 VERBOSE(("wakeup")); 55 pthread_mutex_unlock(&mtx); 56 } 57 58 static void 59 test_fd(int fd, char *tag) 60 { 61 struct mevent *evp; 62 int err; 63 64 evp = mevent_add_flags(fd, EVF_VNODE, EVFF_ATTRIB, callback, cookie); 65 ASSERT_PTR_NEQ(("%s: mevent_add", tag), evp, NULL); 66 67 for (uint_t i = 0; cookie[i] != '\0'; i++) { 68 ssize_t written; 69 70 pthread_mutex_lock(&mtx); 71 72 if (i > 0) { 73 /* 74 * Check that no events are emitted for writes which do 75 * not alter the size. 76 */ 77 if (lseek(fd, -1, SEEK_CUR) == -1) 78 FAIL_ERRNO("lseek"); 79 if (write(fd, "X", 1) == -1) 80 FAIL_ERRNO("write"); 81 } 82 83 written = write(fd, cookie + i, 1); 84 if (written < 0) 85 FAIL_ERRNO("bad write"); 86 ASSERT_INT64_EQ(("write byte %d of cookie", i), written, 1); 87 88 /* Wait for the size change to be processed */ 89 pthread_cond_wait(&cv, &mtx); 90 pthread_mutex_unlock(&mtx); 91 /* 92 * This is a bit unsatisfactory but we need to allow time 93 * for mevent to re-associate the port or the next write could 94 * be missed. 95 */ 96 usleep(500); 97 } 98 99 err = mevent_disable(evp); 100 ASSERT_INT_EQ(("%s: mevent_disable: %s", tag, strerror(err)), err, 0); 101 102 (void) printf("PASS %s - %s\n", testlib_prog, tag); 103 } 104 105 int 106 main(int argc, const char **argv) 107 { 108 start_test(argv[0], 5); 109 start_event_thread(); 110 int fd; 111 112 /* Test with a temporary file in /tmp */ 113 char *template = strdup("/tmp/mevent.vnode.XXXXXX"); 114 ASSERT_PTR_NEQ(("strdup"), template, NULL); 115 fd = mkstemp(template); 116 if (fd == -1) 117 FAIL_ERRNO("Couldn't create temporary file with mkstemp"); 118 119 VERBOSE(("Opened temporary file at '%s'", template)); 120 121 test_fd(fd, "temporary file"); 122 123 /* Test with a file which is unlinked from the filesystem */ 124 FILE *fp = tmpfile(); 125 ASSERT_PTR_NEQ(("tmpfile"), fp, NULL); 126 127 fd = fileno(fp); 128 if (fd == -1) 129 FAIL_ERRNO("Couldn't get file descriptor for temporary file"); 130 131 test_fd(fd, "anon file"); 132 133 /* 134 * Defer to here to avoid generating a new event before the disable has 135 * been processed and the port deassociated. 136 */ 137 unlink(template); 138 free(template); 139 140 PASS(); 141 } 142