client_test.c revision 270242
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: stable/10/sbin/devd/tests/client_test.c 270242 2014-08-20 19:30:58Z asomers $"); 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 */ 43static void 44create_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 swap", "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 */ 73ATF_TC_WITHOUT_HEAD(seqpacket); 74ATF_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 */ 127ATF_TC_WITHOUT_HEAD(stream); 128ATF_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 185ATF_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