1cdfa64aaSAlan Somers /*- 2cdfa64aaSAlan Somers * Copyright (c) 2014 Spectra Logic Corporation. All rights reserved. 3cdfa64aaSAlan Somers * Redistribution and use in source and binary forms, with or without 4cdfa64aaSAlan Somers * modification, are permitted provided that the following conditions 5cdfa64aaSAlan Somers * are met: 6cdfa64aaSAlan Somers * 1. Redistributions of source code must retain the above copyright 7cdfa64aaSAlan Somers * notice, this list of conditions and the following disclaimer. 8cdfa64aaSAlan Somers * 2. Redistributions in binary form must reproduce the above copyright 9cdfa64aaSAlan Somers * notice, this list of conditions and the following disclaimer in the 10cdfa64aaSAlan Somers * documentation and/or other materials provided with the distribution. 11cdfa64aaSAlan Somers * 12cdfa64aaSAlan Somers * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 13cdfa64aaSAlan Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 14cdfa64aaSAlan Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 15cdfa64aaSAlan Somers * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 16cdfa64aaSAlan Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 17cdfa64aaSAlan Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 18cdfa64aaSAlan Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 19cdfa64aaSAlan Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 20cdfa64aaSAlan Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 21cdfa64aaSAlan Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 22cdfa64aaSAlan Somers * SUCH DAMAGE. 23cdfa64aaSAlan Somers */ 24cdfa64aaSAlan Somers 25cdfa64aaSAlan Somers #include <sys/param.h> 26cdfa64aaSAlan Somers #include <sys/socket.h> 27cdfa64aaSAlan Somers #include <sys/un.h> 28cdfa64aaSAlan Somers 29*30cafaa9SMark Johnston #include <stdbool.h> 30*30cafaa9SMark Johnston #include <stdio.h> 31*30cafaa9SMark Johnston #include <stdlib.h> 32*30cafaa9SMark Johnston 33cdfa64aaSAlan Somers #include <atf-c.h> 342c6254c2SAlan Somers 352c6254c2SAlan Somers const char create_pat[] = "!system=DEVFS subsystem=CDEV type=CREATE cdev=md"; 362c6254c2SAlan Somers const char destroy_pat[] = "!system=DEVFS subsystem=CDEV type=DESTROY cdev=md"; 372c6254c2SAlan Somers 38cdfa64aaSAlan Somers /* Helper functions*/ 39cdfa64aaSAlan Somers 40cdfa64aaSAlan Somers /* 41cdfa64aaSAlan Somers * Create two devd events. The easiest way I know of, that requires no special 42cdfa64aaSAlan Somers * hardware, is to create md(4) devices. 43cdfa64aaSAlan Somers */ 44cdfa64aaSAlan Somers static void 45cdfa64aaSAlan Somers create_two_events(void) 46cdfa64aaSAlan Somers { 47cdfa64aaSAlan Somers FILE *create_stdout; 48cdfa64aaSAlan Somers FILE *destroy_stdout; 49cdfa64aaSAlan Somers char mdname[80]; 50958160f3SEitan Adler char destroy_cmd[95]; 51cdfa64aaSAlan Somers char *error; 52cdfa64aaSAlan Somers 53cdfa64aaSAlan Somers create_stdout = popen("mdconfig -a -s 64 -t null", "r"); 54cdfa64aaSAlan Somers ATF_REQUIRE(create_stdout != NULL); 55cdfa64aaSAlan Somers error = fgets(mdname, sizeof(mdname), create_stdout); 56cdfa64aaSAlan Somers ATF_REQUIRE(error != NULL); 57cdfa64aaSAlan Somers /* We only expect one line of output */ 58cdfa64aaSAlan Somers ATF_REQUIRE_EQ(0, pclose(create_stdout)); 59cdfa64aaSAlan Somers 60cdfa64aaSAlan Somers snprintf(destroy_cmd, nitems(destroy_cmd), "mdconfig -d -u %s", mdname); 61cdfa64aaSAlan Somers destroy_stdout = popen(destroy_cmd, "r"); 6281ade99cSAlan Somers ATF_REQUIRE(destroy_stdout != NULL); 63cdfa64aaSAlan Somers /* We expect no output */ 64cdfa64aaSAlan Somers ATF_REQUIRE_EQ(0, pclose(destroy_stdout)); 65cdfa64aaSAlan Somers } 66cdfa64aaSAlan Somers 672c6254c2SAlan Somers /* Setup and return an open client socket */ 682c6254c2SAlan Somers static int 692c6254c2SAlan Somers common_setup(int socktype, const char* sockpath) { 702c6254c2SAlan Somers struct sockaddr_un devd_addr; 712c6254c2SAlan Somers int s, error; 722c6254c2SAlan Somers 732c6254c2SAlan Somers memset(&devd_addr, 0, sizeof(devd_addr)); 742c6254c2SAlan Somers devd_addr.sun_family = PF_LOCAL; 752c6254c2SAlan Somers strlcpy(devd_addr.sun_path, sockpath, sizeof(devd_addr.sun_path)); 762c6254c2SAlan Somers s = socket(PF_LOCAL, socktype, 0); 772c6254c2SAlan Somers ATF_REQUIRE(s >= 0); 782c6254c2SAlan Somers error = connect(s, (struct sockaddr*)&devd_addr, SUN_LEN(&devd_addr)); 792c6254c2SAlan Somers ATF_REQUIRE_EQ(0, error); 802c6254c2SAlan Somers 812c6254c2SAlan Somers create_two_events(); 822c6254c2SAlan Somers return (s); 832c6254c2SAlan Somers } 842c6254c2SAlan Somers 85cdfa64aaSAlan Somers /* 86cdfa64aaSAlan Somers * Test Cases 87cdfa64aaSAlan Somers */ 88cdfa64aaSAlan Somers 89cdfa64aaSAlan Somers /* 90cdfa64aaSAlan Somers * Open a client connection to devd, create some events, and test that they can 91cdfa64aaSAlan Somers * be read _whole_ and _one_at_a_time_ from the socket 92cdfa64aaSAlan Somers */ 93cdfa64aaSAlan Somers ATF_TC_WITHOUT_HEAD(seqpacket); 94cdfa64aaSAlan Somers ATF_TC_BODY(seqpacket, tc) 95cdfa64aaSAlan Somers { 96cdfa64aaSAlan Somers int s; 97cdfa64aaSAlan Somers bool got_create_event = false; 98cdfa64aaSAlan Somers bool got_destroy_event = false; 99cdfa64aaSAlan Somers 1002c6254c2SAlan Somers s = common_setup(SOCK_SEQPACKET, "/var/run/devd.seqpacket.pipe"); 101cdfa64aaSAlan Somers /* 102cdfa64aaSAlan Somers * Loop until both events are detected on _different_ reads 103cdfa64aaSAlan Somers * There may be extra events due to unrelated system activity 104cdfa64aaSAlan Somers * If we never get both events, then the test will timeout. 105cdfa64aaSAlan Somers */ 106cdfa64aaSAlan Somers while (!(got_create_event && got_destroy_event)) { 107cdfa64aaSAlan Somers int cmp; 108cdfa64aaSAlan Somers ssize_t len; 109cdfa64aaSAlan Somers char event[1024]; 110cdfa64aaSAlan Somers 11181ade99cSAlan Somers /* Read 1 less than sizeof(event) to allow space for NULL */ 11281ade99cSAlan Somers len = recv(s, event, sizeof(event) - 1, MSG_WAITALL); 113cdfa64aaSAlan Somers ATF_REQUIRE(len != -1); 114cdfa64aaSAlan Somers /* NULL terminate the result */ 115cdfa64aaSAlan Somers event[len] = '\0'; 116cdfa64aaSAlan Somers printf("%s", event); 117cdfa64aaSAlan Somers cmp = strncmp(event, create_pat, sizeof(create_pat) - 1); 118cdfa64aaSAlan Somers if (cmp == 0) 119cdfa64aaSAlan Somers got_create_event = true; 120cdfa64aaSAlan Somers 121cdfa64aaSAlan Somers cmp = strncmp(event, destroy_pat, sizeof(destroy_pat) - 1); 122cdfa64aaSAlan Somers if (cmp == 0) 123cdfa64aaSAlan Somers got_destroy_event = true; 124cdfa64aaSAlan Somers } 12581ade99cSAlan Somers 12681ade99cSAlan Somers close(s); 127cdfa64aaSAlan Somers } 128cdfa64aaSAlan Somers 129cdfa64aaSAlan Somers /* 130cdfa64aaSAlan Somers * Open a client connection to devd using the stream socket, create some 131cdfa64aaSAlan Somers * events, and test that they can be read in any number of reads. 132cdfa64aaSAlan Somers */ 133cdfa64aaSAlan Somers ATF_TC_WITHOUT_HEAD(stream); 134cdfa64aaSAlan Somers ATF_TC_BODY(stream, tc) 135cdfa64aaSAlan Somers { 136*30cafaa9SMark Johnston char *event; 137cdfa64aaSAlan Somers int s; 138cdfa64aaSAlan Somers bool got_create_event = false; 139cdfa64aaSAlan Somers bool got_destroy_event = false; 140*30cafaa9SMark Johnston size_t len = 0, sz; 141cdfa64aaSAlan Somers 1422c6254c2SAlan Somers s = common_setup(SOCK_STREAM, "/var/run/devd.pipe"); 143*30cafaa9SMark Johnston 144*30cafaa9SMark Johnston /* 145*30cafaa9SMark Johnston * Use a large buffer: we're reading from a stream socket so can't rely 146*30cafaa9SMark Johnston * on record boundaries. Instead, we just keep appending to the buffer. 147*30cafaa9SMark Johnston */ 148*30cafaa9SMark Johnston sz = 1024 * 1024; 149*30cafaa9SMark Johnston event = malloc(sz); 150*30cafaa9SMark Johnston ATF_REQUIRE(event != NULL); 151*30cafaa9SMark Johnston 152cdfa64aaSAlan Somers /* 1532c6254c2SAlan Somers * Loop until both events are detected on the same or different reads. 1542c6254c2SAlan Somers * There may be extra events due to unrelated system activity. 155cdfa64aaSAlan Somers * If we never get both events, then the test will timeout. 156cdfa64aaSAlan Somers */ 157*30cafaa9SMark Johnston while (!(got_create_event && got_destroy_event) && len < sz - 1) { 158cdfa64aaSAlan Somers ssize_t newlen; 159cdfa64aaSAlan Somers char *create_pos, *destroy_pos; 160cdfa64aaSAlan Somers 16181ade99cSAlan Somers /* Read 1 less than sizeof(event) to allow space for NULL */ 162*30cafaa9SMark Johnston newlen = read(s, &event[len], sz - len - 1); 163*30cafaa9SMark Johnston ATF_REQUIRE(newlen > 0); 164cdfa64aaSAlan Somers len += newlen; 165cdfa64aaSAlan Somers /* NULL terminate the result */ 1662c6254c2SAlan Somers event[len] = '\0'; 167cdfa64aaSAlan Somers 168cdfa64aaSAlan Somers create_pos = strstr(event, create_pat); 169d8e198e6SBjoern A. Zeeb if (create_pos != NULL) 170cdfa64aaSAlan Somers got_create_event = true; 171cdfa64aaSAlan Somers 172cdfa64aaSAlan Somers destroy_pos = strstr(event, destroy_pat); 173d8e198e6SBjoern A. Zeeb if (destroy_pos != NULL) 174cdfa64aaSAlan Somers got_destroy_event = true; 175cdfa64aaSAlan Somers } 176*30cafaa9SMark Johnston printf("%s", event); 177*30cafaa9SMark Johnston if (len >= sz - 1) 178*30cafaa9SMark Johnston atf_tc_fail("Event buffer overflowed"); 17981ade99cSAlan Somers 180*30cafaa9SMark Johnston free(event); 18181ade99cSAlan Somers close(s); 182cdfa64aaSAlan Somers } 183cdfa64aaSAlan Somers 184cdfa64aaSAlan Somers /* 185cdfa64aaSAlan Somers * Main. 186cdfa64aaSAlan Somers */ 187cdfa64aaSAlan Somers 188cdfa64aaSAlan Somers ATF_TP_ADD_TCS(tp) 189cdfa64aaSAlan Somers { 190cdfa64aaSAlan Somers ATF_TP_ADD_TC(tp, seqpacket); 191cdfa64aaSAlan Somers ATF_TP_ADD_TC(tp, stream); 192cdfa64aaSAlan Somers 193cdfa64aaSAlan Somers return (atf_no_error()); 194cdfa64aaSAlan Somers } 195cdfa64aaSAlan Somers 196