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