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