1204861Sdes/*- 2137015Sdes * Copyright (c) 2014 Spectra Logic Corporation. All rights reserved. 3137015Sdes * Redistribution and use in source and binary forms, with or without 4147001Sdes * modification, are permitted provided that the following conditions 5137015Sdes * are met: 6137015Sdes * 1. Redistributions of source code must retain the above copyright 7137015Sdes * notice, this list of conditions and the following disclaimer. 8218767Sdes * 2. Redistributions in binary form must reproduce the above copyright 9146998Sdes * notice, this list of conditions and the following disclaimer in the 10146998Sdes * documentation and/or other materials provided with the distribution. 11146998Sdes * 12146998Sdes * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 13137015Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 14137015Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 15146998Sdes * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 16137015Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 17137015Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 18137015Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 19137015Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 20146998Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 21146998Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 22137015Sdes * SUCH DAMAGE. 23146998Sdes */ 24146998Sdes 25146998Sdes#include <sys/cdefs.h> 26137015Sdes__FBSDID("$FreeBSD: releng/11.0/sbin/devd/tests/client_test.c 297838 2016-04-11 22:14:29Z asomers $"); 27137015Sdes 28204861Sdes#include <stdbool.h> 29137015Sdes#include <stdio.h> 30137015Sdes 31137015Sdes#include <sys/param.h> 32137015Sdes#include <sys/types.h> 33137015Sdes#include <sys/socket.h> 34137015Sdes#include <sys/un.h> 35137015Sdes 36137015Sdes#include <atf-c.h> 37137015Sdes 38204861Sdesconst char create_pat[] = "!system=DEVFS subsystem=CDEV type=CREATE cdev=md"; 39137015Sdesconst char destroy_pat[] = "!system=DEVFS subsystem=CDEV type=DESTROY cdev=md"; 40137015Sdes 41137015Sdes/* Helper functions*/ 42137015Sdes 43137015Sdes/* 44204861Sdes * Create two devd events. The easiest way I know of, that requires no special 45137015Sdes * hardware, is to create md(4) devices. 46137015Sdes */ 47137015Sdesstatic void 48137015Sdescreate_two_events(void) 49137015Sdes{ 50137015Sdes FILE *create_stdout; 51204861Sdes FILE *destroy_stdout; 52137015Sdes char mdname[80]; 53137015Sdes char destroy_cmd[80]; 54137015Sdes char *error; 55137015Sdes 56137015Sdes create_stdout = popen("mdconfig -a -s 64 -t null", "r"); 57204861Sdes ATF_REQUIRE(create_stdout != NULL); 58137015Sdes error = fgets(mdname, sizeof(mdname), create_stdout); 59137015Sdes ATF_REQUIRE(error != NULL); 60137015Sdes /* We only expect one line of output */ 61137015Sdes ATF_REQUIRE_EQ(0, pclose(create_stdout)); 62137015Sdes 63137015Sdes snprintf(destroy_cmd, nitems(destroy_cmd), "mdconfig -d -u %s", mdname); 64137015Sdes destroy_stdout = popen(destroy_cmd, "r"); 65137015Sdes ATF_REQUIRE(destroy_stdout != NULL); 66204861Sdes /* We expect no output */ 67137015Sdes ATF_REQUIRE_EQ(0, pclose(destroy_stdout)); 68137015Sdes} 69137015Sdes 70137015Sdes/* Setup and return an open client socket */ 71137015Sdesstatic int 72137015Sdescommon_setup(int socktype, const char* sockpath) { 73137015Sdes struct sockaddr_un devd_addr; 74204861Sdes int s, error; 75137015Sdes 76137015Sdes memset(&devd_addr, 0, sizeof(devd_addr)); 77137015Sdes devd_addr.sun_family = PF_LOCAL; 78137015Sdes strlcpy(devd_addr.sun_path, sockpath, sizeof(devd_addr.sun_path)); 79137015Sdes s = socket(PF_LOCAL, socktype, 0); 80137015Sdes ATF_REQUIRE(s >= 0); 81137015Sdes error = connect(s, (struct sockaddr*)&devd_addr, SUN_LEN(&devd_addr)); 82146998Sdes ATF_REQUIRE_EQ(0, error); 83204861Sdes 84146998Sdes create_two_events(); 85146998Sdes return (s); 86204861Sdes} 87146998Sdes 88146998Sdes/* 89146998Sdes * Test Cases 90146998Sdes */ 91147001Sdes 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 */ 96ATF_TC_WITHOUT_HEAD(seqpacket); 97ATF_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 */ 136ATF_TC_WITHOUT_HEAD(stream); 137ATF_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 179ATF_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