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 #include <stdbool.h> 27 #include <stdio.h> 28 29 #include <sys/param.h> 30 #include <sys/types.h> 31 #include <sys/socket.h> 32 #include <sys/un.h> 33 34 #include <atf-c.h> 35 36 const char create_pat[] = "!system=DEVFS subsystem=CDEV type=CREATE cdev=md"; 37 const char destroy_pat[] = "!system=DEVFS subsystem=CDEV type=DESTROY cdev=md"; 38 39 /* Helper functions*/ 40 41 /* 42 * Create two devd events. The easiest way I know of, that requires no special 43 * hardware, is to create md(4) devices. 44 */ 45 static void 46 create_two_events(void) 47 { 48 FILE *create_stdout; 49 FILE *destroy_stdout; 50 char mdname[80]; 51 char destroy_cmd[95]; 52 char *error; 53 54 create_stdout = popen("mdconfig -a -s 64 -t null", "r"); 55 ATF_REQUIRE(create_stdout != NULL); 56 error = fgets(mdname, sizeof(mdname), create_stdout); 57 ATF_REQUIRE(error != NULL); 58 /* We only expect one line of output */ 59 ATF_REQUIRE_EQ(0, pclose(create_stdout)); 60 61 snprintf(destroy_cmd, nitems(destroy_cmd), "mdconfig -d -u %s", mdname); 62 destroy_stdout = popen(destroy_cmd, "r"); 63 ATF_REQUIRE(destroy_stdout != NULL); 64 /* We expect no output */ 65 ATF_REQUIRE_EQ(0, pclose(destroy_stdout)); 66 } 67 68 /* Setup and return an open client socket */ 69 static int 70 common_setup(int socktype, const char* sockpath) { 71 struct sockaddr_un devd_addr; 72 int s, error; 73 74 memset(&devd_addr, 0, sizeof(devd_addr)); 75 devd_addr.sun_family = PF_LOCAL; 76 strlcpy(devd_addr.sun_path, sockpath, sizeof(devd_addr.sun_path)); 77 s = socket(PF_LOCAL, socktype, 0); 78 ATF_REQUIRE(s >= 0); 79 error = connect(s, (struct sockaddr*)&devd_addr, SUN_LEN(&devd_addr)); 80 ATF_REQUIRE_EQ(0, error); 81 82 create_two_events(); 83 return (s); 84 } 85 86 /* 87 * Test Cases 88 */ 89 90 /* 91 * Open a client connection to devd, create some events, and test that they can 92 * be read _whole_ and _one_at_a_time_ from the socket 93 */ 94 ATF_TC_WITHOUT_HEAD(seqpacket); 95 ATF_TC_BODY(seqpacket, tc) 96 { 97 int s; 98 bool got_create_event = false; 99 bool got_destroy_event = false; 100 101 s = common_setup(SOCK_SEQPACKET, "/var/run/devd.seqpacket.pipe"); 102 /* 103 * Loop until both events are detected on _different_ reads 104 * There may be extra events due to unrelated system activity 105 * If we never get both events, then the test will timeout. 106 */ 107 while (!(got_create_event && got_destroy_event)) { 108 int cmp; 109 ssize_t len; 110 char event[1024]; 111 112 /* Read 1 less than sizeof(event) to allow space for NULL */ 113 len = recv(s, event, sizeof(event) - 1, MSG_WAITALL); 114 ATF_REQUIRE(len != -1); 115 /* NULL terminate the result */ 116 event[len] = '\0'; 117 printf("%s", event); 118 cmp = strncmp(event, create_pat, sizeof(create_pat) - 1); 119 if (cmp == 0) 120 got_create_event = true; 121 122 cmp = strncmp(event, destroy_pat, sizeof(destroy_pat) - 1); 123 if (cmp == 0) 124 got_destroy_event = true; 125 } 126 127 close(s); 128 } 129 130 /* 131 * Open a client connection to devd using the stream socket, create some 132 * events, and test that they can be read in any number of reads. 133 */ 134 ATF_TC_WITHOUT_HEAD(stream); 135 ATF_TC_BODY(stream, tc) 136 { 137 int s; 138 bool got_create_event = false; 139 bool got_destroy_event = false; 140 ssize_t len = 0; 141 142 s = common_setup(SOCK_STREAM, "/var/run/devd.pipe"); 143 /* 144 * Loop until both events are detected on the same or different reads. 145 * There may be extra events due to unrelated system activity. 146 * If we never get both events, then the test will timeout. 147 */ 148 while (!(got_create_event && got_destroy_event)) { 149 char event[1024]; 150 ssize_t newlen; 151 char *create_pos, *destroy_pos; 152 153 /* Read 1 less than sizeof(event) to allow space for NULL */ 154 newlen = read(s, &event[len], sizeof(event) - len - 1); 155 ATF_REQUIRE(newlen != -1); 156 len += newlen; 157 /* NULL terminate the result */ 158 event[len] = '\0'; 159 printf("%s", event); 160 161 create_pos = strstr(event, create_pat); 162 if (create_pos != NULL) 163 got_create_event = true; 164 165 destroy_pos = strstr(event, destroy_pat); 166 if (destroy_pos != NULL) 167 got_destroy_event = true; 168 } 169 170 close(s); 171 } 172 173 /* 174 * Main. 175 */ 176 177 ATF_TP_ADD_TCS(tp) 178 { 179 ATF_TP_ADD_TC(tp, seqpacket); 180 ATF_TP_ADD_TC(tp, stream); 181 182 return (atf_no_error()); 183 } 184 185