1 /*- 2 * Copyright (c) 2014 Spectra Logic Corporation. All rights reserved. 3 * Redistribution and use in source and binary forms, with or without 4 * modification, are permitted provided that the following conditions 5 * are met: 6 * 1. Redistributions of source code must retain the above copyright 7 * notice, this list of conditions and the following disclaimer. 8 * 2. Redistributions in binary form must reproduce the above copyright 9 * notice, this list of conditions and the following disclaimer in the 10 * documentation and/or other materials provided with the distribution. 11 * 12 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 13 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 14 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 15 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 16 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 17 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 18 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 19 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 20 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 21 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 22 * SUCH DAMAGE. 23 */ 24 25 #include <sys/cdefs.h> 26 __FBSDID("$FreeBSD$"); 27 28 #include <stdbool.h> 29 #include <stdio.h> 30 31 #include <sys/param.h> 32 #include <sys/types.h> 33 #include <sys/socket.h> 34 #include <sys/un.h> 35 36 #include <atf-c.h> 37 /* Helper functions*/ 38 39 /* 40 * Create two devd events. The easiest way I know of, that requires no special 41 * hardware, is to create md(4) devices. 42 */ 43 static void 44 create_two_events(void) 45 { 46 FILE *create_stdout; 47 FILE *destroy_stdout; 48 char mdname[80]; 49 char destroy_cmd[80]; 50 char *error; 51 52 create_stdout = popen("mdconfig -a -s 64 -t null", "r"); 53 ATF_REQUIRE(create_stdout != NULL); 54 error = fgets(mdname, sizeof(mdname), create_stdout); 55 ATF_REQUIRE(error != NULL); 56 /* We only expect one line of output */ 57 ATF_REQUIRE_EQ(0, pclose(create_stdout)); 58 59 snprintf(destroy_cmd, nitems(destroy_cmd), "mdconfig -d -u %s", mdname); 60 destroy_stdout = popen(destroy_cmd, "r"); 61 /* We expect no output */ 62 ATF_REQUIRE_EQ(0, pclose(destroy_stdout)); 63 } 64 65 /* 66 * Test Cases 67 */ 68 69 /* 70 * Open a client connection to devd, create some events, and test that they can 71 * be read _whole_ and _one_at_a_time_ from the socket 72 */ 73 ATF_TC_WITHOUT_HEAD(seqpacket); 74 ATF_TC_BODY(seqpacket, tc) 75 { 76 int s; 77 int error; 78 struct sockaddr_un devd_addr; 79 bool got_create_event = false; 80 bool got_destroy_event = false; 81 const char create_pat[] = 82 "!system=DEVFS subsystem=CDEV type=CREATE cdev=md"; 83 const char destroy_pat[] = 84 "!system=DEVFS subsystem=CDEV type=DESTROY cdev=md"; 85 86 memset(&devd_addr, 0, sizeof(devd_addr)); 87 devd_addr.sun_family = PF_LOCAL; 88 strlcpy(devd_addr.sun_path, "/var/run/devd.seqpacket.pipe", 89 sizeof(devd_addr.sun_path)); 90 91 s = socket(PF_LOCAL, SOCK_SEQPACKET, 0); 92 ATF_REQUIRE(s >= 0); 93 error = connect(s, (struct sockaddr*)&devd_addr, SUN_LEN(&devd_addr)); 94 ATF_REQUIRE_EQ(0, error); 95 96 create_two_events(); 97 98 /* 99 * Loop until both events are detected on _different_ reads 100 * There may be extra events due to unrelated system activity 101 * If we never get both events, then the test will timeout. 102 */ 103 while (!(got_create_event && got_destroy_event)) { 104 int cmp; 105 ssize_t len; 106 char event[1024]; 107 108 len = recv(s, event, sizeof(event), MSG_WAITALL); 109 ATF_REQUIRE(len != -1); 110 /* NULL terminate the result */ 111 event[len] = '\0'; 112 printf("%s", event); 113 cmp = strncmp(event, create_pat, sizeof(create_pat) - 1); 114 if (cmp == 0) 115 got_create_event = true; 116 117 cmp = strncmp(event, destroy_pat, sizeof(destroy_pat) - 1); 118 if (cmp == 0) 119 got_destroy_event = true; 120 } 121 } 122 123 /* 124 * Open a client connection to devd using the stream socket, create some 125 * events, and test that they can be read in any number of reads. 126 */ 127 ATF_TC_WITHOUT_HEAD(stream); 128 ATF_TC_BODY(stream, tc) 129 { 130 int s; 131 int error; 132 struct sockaddr_un devd_addr; 133 bool got_create_event = false; 134 bool got_destroy_event = false; 135 const char create_pat[] = 136 "!system=DEVFS subsystem=CDEV type=CREATE cdev=md"; 137 const char destroy_pat[] = 138 "!system=DEVFS subsystem=CDEV type=DESTROY cdev=md"; 139 ssize_t len = 0; 140 141 memset(&devd_addr, 0, sizeof(devd_addr)); 142 devd_addr.sun_family = PF_LOCAL; 143 strlcpy(devd_addr.sun_path, "/var/run/devd.pipe", 144 sizeof(devd_addr.sun_path)); 145 146 s = socket(PF_LOCAL, SOCK_STREAM, 0); 147 ATF_REQUIRE(s >= 0); 148 error = connect(s, (struct sockaddr*)&devd_addr, SUN_LEN(&devd_addr)); 149 ATF_REQUIRE_EQ(0, error); 150 151 create_two_events(); 152 153 /* 154 * Loop until both events are detected on _different_ reads 155 * There may be extra events due to unrelated system activity 156 * If we never get both events, then the test will timeout. 157 */ 158 while (!(got_create_event && got_destroy_event)) { 159 char event[1024]; 160 ssize_t newlen; 161 char *create_pos, *destroy_pos; 162 163 newlen = read(s, &event[len], sizeof(event) - len); 164 ATF_REQUIRE(newlen != -1); 165 len += newlen; 166 /* NULL terminate the result */ 167 event[newlen] = '\0'; 168 printf("%s", event); 169 170 create_pos = strstr(event, create_pat); 171 if (create_pos != NULL) 172 got_create_event = true; 173 174 destroy_pos = strstr(event, destroy_pat); 175 if (destroy_pos != NULL) 176 got_destroy_event = true; 177 178 } 179 } 180 181 /* 182 * Main. 183 */ 184 185 ATF_TP_ADD_TCS(tp) 186 { 187 ATF_TP_ADD_TC(tp, seqpacket); 188 ATF_TP_ADD_TC(tp, stream); 189 190 return (atf_no_error()); 191 } 192 193