1*0cbe4818SRobert Mustacchi /*
2*0cbe4818SRobert Mustacchi * This file and its contents are supplied under the terms of the
3*0cbe4818SRobert Mustacchi * Common Development and Distribution License ("CDDL"), version 1.0.
4*0cbe4818SRobert Mustacchi * You may only use this file in accordance with the terms of version
5*0cbe4818SRobert Mustacchi * 1.0 of the CDDL.
6*0cbe4818SRobert Mustacchi *
7*0cbe4818SRobert Mustacchi * A full copy of the text of the CDDL should have accompanied this
8*0cbe4818SRobert Mustacchi * source. A copy of the CDDL is also available via the Internet at
9*0cbe4818SRobert Mustacchi * http://www.illumos.org/license/CDDL.
10*0cbe4818SRobert Mustacchi */
11*0cbe4818SRobert Mustacchi
12*0cbe4818SRobert Mustacchi /*
13*0cbe4818SRobert Mustacchi * Copyright 2025 Oxide Computer Company
14*0cbe4818SRobert Mustacchi */
15*0cbe4818SRobert Mustacchi
16*0cbe4818SRobert Mustacchi /*
17*0cbe4818SRobert Mustacchi * This daemon is the userland component to i2csim(4D). It has a built in notion
18*0cbe4818SRobert Mustacchi * of I2C devices that it emulates to allow for better end-to-end testing.
19*0cbe4818SRobert Mustacchi */
20*0cbe4818SRobert Mustacchi
21*0cbe4818SRobert Mustacchi #include <stdlib.h>
22*0cbe4818SRobert Mustacchi #include <err.h>
23*0cbe4818SRobert Mustacchi #include <unistd.h>
24*0cbe4818SRobert Mustacchi #include <sys/types.h>
25*0cbe4818SRobert Mustacchi #include <sys/stat.h>
26*0cbe4818SRobert Mustacchi #include <fcntl.h>
27*0cbe4818SRobert Mustacchi #include <paths.h>
28*0cbe4818SRobert Mustacchi #include <sys/resource.h>
29*0cbe4818SRobert Mustacchi #include <sys/fork.h>
30*0cbe4818SRobert Mustacchi #include <sys/wait.h>
31*0cbe4818SRobert Mustacchi #include <sys/param.h>
32*0cbe4818SRobert Mustacchi #include <priv.h>
33*0cbe4818SRobert Mustacchi #include <sys/debug.h>
34*0cbe4818SRobert Mustacchi #include <string.h>
35*0cbe4818SRobert Mustacchi #include <sys/sysmacros.h>
36*0cbe4818SRobert Mustacchi
37*0cbe4818SRobert Mustacchi #include "i2csimd.h"
38*0cbe4818SRobert Mustacchi
39*0cbe4818SRobert Mustacchi i2csimd_t i2csimd;
40*0cbe4818SRobert Mustacchi
41*0cbe4818SRobert Mustacchi static const char *at24c_msg0 = "Three rings for Elven-kings, under the sky,";
42*0cbe4818SRobert Mustacchi static const char *at24c_msg1 = "Seven for the Dwarf-lords in their halls of "
43*0cbe4818SRobert Mustacchi "stone,";
44*0cbe4818SRobert Mustacchi static const char *at24c_msg2 = "Nine for Moral Men, doomed to die,";
45*0cbe4818SRobert Mustacchi static const char *at24c_msg3 = "One for the dark Lord on his dark throne";
46*0cbe4818SRobert Mustacchi static const char *at24c_msg4 = "In the Land of Mordor where the Shadows lie.";
47*0cbe4818SRobert Mustacchi static const char *at24c_msg5 = "One ring to rule them all, One ring to find "
48*0cbe4818SRobert Mustacchi "them,";
49*0cbe4818SRobert Mustacchi static const char *at24c_msg6 = "One ring to bring them all and in the "
50*0cbe4818SRobert Mustacchi "darkness bind them.";
51*0cbe4818SRobert Mustacchi static const char *at24c_msg71 = "The Road goes ever on and on,\nDown from the "
52*0cbe4818SRobert Mustacchi "door where it began.\nNow far ahead the Road has gone,\nAnd I must "
53*0cbe4818SRobert Mustacchi "follow, if I can,\nPursuing it with eager feet,\nUntil it joins some "
54*0cbe4818SRobert Mustacchi "larger way\nWhere many paths and errands meet.\nAnd whither then? I "
55*0cbe4818SRobert Mustacchi "cannot say.";
56*0cbe4818SRobert Mustacchi
57*0cbe4818SRobert Mustacchi /*
58*0cbe4818SRobert Mustacchi * Initialize everything we need to answer and serve requests:
59*0cbe4818SRobert Mustacchi *
60*0cbe4818SRobert Mustacchi * - The general fd to the i2csim device
61*0cbe4818SRobert Mustacchi * - All of the actual i2c devices that we have in our tree
62*0cbe4818SRobert Mustacchi *
63*0cbe4818SRobert Mustacchi * Tree for i2csim0
64*0cbe4818SRobert Mustacchi * at24c32: 0x10
65*0cbe4818SRobert Mustacchi * at24c16: 0x20
66*0cbe4818SRobert Mustacchi * pca9548: 0x70
67*0cbe4818SRobert Mustacchi * 0: - pca9548 0x71
68*0cbe4818SRobert Mustacchi * 0: at24c32: 0x72 - at24c_msg0
69*0cbe4818SRobert Mustacchi * 1: at24c32: 0x72 - at24c_msg1
70*0cbe4818SRobert Mustacchi * 2: at24c32: 0x72 - at24c_msg2
71*0cbe4818SRobert Mustacchi * 3: at24c32: 0x72 - at24c_msg3
72*0cbe4818SRobert Mustacchi * 4: at24c32: 0x72 - at24c_msg4
73*0cbe4818SRobert Mustacchi * 5: at24c32: 0x72 - at24c_msg5
74*0cbe4818SRobert Mustacchi * 6: at24c32: 0x72 - at24c_msg6
75*0cbe4818SRobert Mustacchi * 7: at24c32: 0x72 - at24c_msg4
76*0cbe4818SRobert Mustacchi * 1: - at24c32 0x71 - at24c_msg71
77*0cbe4818SRobert Mustacchi * 2: - ts511x 0x71 - 71 C
78*0cbe4818SRobert Mustacchi * 2: - ts511x 0x72 - 72.75 C
79*0cbe4818SRobert Mustacchi * 3: - ts511x 0x71 - 169 C
80*0cbe4818SRobert Mustacchi * 3: - ts511x 0x72 - -23.75 C
81*0cbe4818SRobert Mustacchi */
82*0cbe4818SRobert Mustacchi static void
i2csimd_init(i2csimd_t * simd)83*0cbe4818SRobert Mustacchi i2csimd_init(i2csimd_t *simd)
84*0cbe4818SRobert Mustacchi {
85*0cbe4818SRobert Mustacchi i2csimd_port_t *mux0, *mux1;
86*0cbe4818SRobert Mustacchi
87*0cbe4818SRobert Mustacchi simd->simd_fd = open("/devices/pseudo/i2csim@0:ctrl", O_RDWR);
88*0cbe4818SRobert Mustacchi if (simd->simd_fd < 0) {
89*0cbe4818SRobert Mustacchi err(EXIT_FAILURE, "failed to open i2csim driver");
90*0cbe4818SRobert Mustacchi }
91*0cbe4818SRobert Mustacchi
92*0cbe4818SRobert Mustacchi simd->simd_ports[0].port_ctrl = 0;
93*0cbe4818SRobert Mustacchi simd->simd_ports[0].port_num = 0;
94*0cbe4818SRobert Mustacchi simd->simd_ports[0].port_devs[0x10] = i2csimd_make_at24c32(0x10, NULL,
95*0cbe4818SRobert Mustacchi 0);
96*0cbe4818SRobert Mustacchi simd->simd_ports[0].port_devs[0x20] = i2csimd_make_at24cXX(0x20,
97*0cbe4818SRobert Mustacchi at24c_msg0, strlen(at24c_msg0));
98*0cbe4818SRobert Mustacchi simd->simd_ports[0].port_devs[0x21] = i2csimd_make_at24cXX(0x21,
99*0cbe4818SRobert Mustacchi at24c_msg1, strlen(at24c_msg1));
100*0cbe4818SRobert Mustacchi simd->simd_ports[0].port_devs[0x22] = i2csimd_make_at24cXX(0x22,
101*0cbe4818SRobert Mustacchi at24c_msg2, strlen(at24c_msg2));
102*0cbe4818SRobert Mustacchi simd->simd_ports[0].port_devs[0x23] = i2csimd_make_at24cXX(0x23,
103*0cbe4818SRobert Mustacchi at24c_msg3, strlen(at24c_msg3));
104*0cbe4818SRobert Mustacchi
105*0cbe4818SRobert Mustacchi mux0 = calloc(8, sizeof (i2csimd_port_t));
106*0cbe4818SRobert Mustacchi mux1 = calloc(8, sizeof (i2csimd_port_t));
107*0cbe4818SRobert Mustacchi if (mux0 == NULL || mux1 == NULL) {
108*0cbe4818SRobert Mustacchi err(EXIT_FAILURE, "failed to allocate mux ports");
109*0cbe4818SRobert Mustacchi }
110*0cbe4818SRobert Mustacchi
111*0cbe4818SRobert Mustacchi for (uint32_t i = 0; i < 8; i++) {
112*0cbe4818SRobert Mustacchi mux0[i].port_ctrl = 0;
113*0cbe4818SRobert Mustacchi mux1[i].port_ctrl = 0;
114*0cbe4818SRobert Mustacchi
115*0cbe4818SRobert Mustacchi mux0[i].port_num = i;
116*0cbe4818SRobert Mustacchi mux1[i].port_num = i;
117*0cbe4818SRobert Mustacchi }
118*0cbe4818SRobert Mustacchi
119*0cbe4818SRobert Mustacchi mux1[0].port_devs[0x72] = i2csimd_make_at24c32(0x72, at24c_msg0,
120*0cbe4818SRobert Mustacchi strlen(at24c_msg0));
121*0cbe4818SRobert Mustacchi mux1[1].port_devs[0x72] = i2csimd_make_at24c32(0x72, at24c_msg1,
122*0cbe4818SRobert Mustacchi strlen(at24c_msg1));
123*0cbe4818SRobert Mustacchi mux1[2].port_devs[0x72] = i2csimd_make_at24c32(0x72, at24c_msg2,
124*0cbe4818SRobert Mustacchi strlen(at24c_msg2));
125*0cbe4818SRobert Mustacchi mux1[3].port_devs[0x72] = i2csimd_make_at24c32(0x72, at24c_msg3,
126*0cbe4818SRobert Mustacchi strlen(at24c_msg3));
127*0cbe4818SRobert Mustacchi mux1[4].port_devs[0x72] = i2csimd_make_at24c32(0x72, at24c_msg4,
128*0cbe4818SRobert Mustacchi strlen(at24c_msg4));
129*0cbe4818SRobert Mustacchi mux1[5].port_devs[0x72] = i2csimd_make_at24c32(0x72, at24c_msg5,
130*0cbe4818SRobert Mustacchi strlen(at24c_msg5));
131*0cbe4818SRobert Mustacchi mux1[6].port_devs[0x72] = i2csimd_make_at24c32(0x72, at24c_msg6,
132*0cbe4818SRobert Mustacchi strlen(at24c_msg6));
133*0cbe4818SRobert Mustacchi mux1[7].port_devs[0x72] = i2csimd_make_at24c32(0x72, at24c_msg4,
134*0cbe4818SRobert Mustacchi strlen(at24c_msg4));
135*0cbe4818SRobert Mustacchi
136*0cbe4818SRobert Mustacchi mux0[0].port_devs[0x71] = i2csimd_make_pca9548(0x71,
137*0cbe4818SRobert Mustacchi &simd->simd_ports[0], mux1);
138*0cbe4818SRobert Mustacchi mux0[1].port_devs[0x71] = i2csimd_make_at24c32(0x71, at24c_msg71,
139*0cbe4818SRobert Mustacchi strlen(at24c_msg71));
140*0cbe4818SRobert Mustacchi mux0[2].port_devs[0x71] = i2csimd_make_ts5111(0x71, 0x0470);
141*0cbe4818SRobert Mustacchi mux0[2].port_devs[0x72] = i2csimd_make_ts5111(0x72, 0x048c);
142*0cbe4818SRobert Mustacchi mux0[3].port_devs[0x71] = i2csimd_make_ts5111(0x71, 0x0a90);
143*0cbe4818SRobert Mustacchi mux0[3].port_devs[0x72] = i2csimd_make_ts5111(0x72, 0x1e84);
144*0cbe4818SRobert Mustacchi
145*0cbe4818SRobert Mustacchi simd->simd_ports[0].port_devs[0x70] = i2csimd_make_pca9548(0x70,
146*0cbe4818SRobert Mustacchi &simd->simd_ports[0], mux0);
147*0cbe4818SRobert Mustacchi }
148*0cbe4818SRobert Mustacchi
149*0cbe4818SRobert Mustacchi static void
i2csimd_io_error(i2csimd_t * simd,i2c_errno_t err,i2c_ctrl_error_t ctrl)150*0cbe4818SRobert Mustacchi i2csimd_io_error(i2csimd_t *simd, i2c_errno_t err, i2c_ctrl_error_t ctrl)
151*0cbe4818SRobert Mustacchi {
152*0cbe4818SRobert Mustacchi i2c_error_t *ep;
153*0cbe4818SRobert Mustacchi
154*0cbe4818SRobert Mustacchi if (simd->simd_req.i2csim_type == I2C_CTRL_TYPE_I2C) {
155*0cbe4818SRobert Mustacchi ep = &simd->simd_req.i2csim_i2c.ir_error;
156*0cbe4818SRobert Mustacchi } else {
157*0cbe4818SRobert Mustacchi ep = &simd->simd_req.i2csim_smbus.smbr_error;
158*0cbe4818SRobert Mustacchi }
159*0cbe4818SRobert Mustacchi
160*0cbe4818SRobert Mustacchi ep->i2c_error = err;
161*0cbe4818SRobert Mustacchi ep->i2c_ctrl = ctrl;
162*0cbe4818SRobert Mustacchi }
163*0cbe4818SRobert Mustacchi
164*0cbe4818SRobert Mustacchi static void
i2csimd_i2c(i2csimd_t * simd,i2csimd_dev_t * dev,i2c_req_t * req)165*0cbe4818SRobert Mustacchi i2csimd_i2c(i2csimd_t *simd, i2csimd_dev_t *dev, i2c_req_t *req)
166*0cbe4818SRobert Mustacchi {
167*0cbe4818SRobert Mustacchi if (req->ir_wlen > 0) {
168*0cbe4818SRobert Mustacchi if (!dev->dev_ops->sop_write(dev->dev_arg, req->ir_wlen,
169*0cbe4818SRobert Mustacchi req->ir_wdata)) {
170*0cbe4818SRobert Mustacchi i2csimd_io_error(simd, I2C_CORE_E_CONTROLLER,
171*0cbe4818SRobert Mustacchi I2C_CTRL_E_DATA_NACK);
172*0cbe4818SRobert Mustacchi return;
173*0cbe4818SRobert Mustacchi }
174*0cbe4818SRobert Mustacchi }
175*0cbe4818SRobert Mustacchi
176*0cbe4818SRobert Mustacchi if (req->ir_rlen > 0) {
177*0cbe4818SRobert Mustacchi if (!dev->dev_ops->sop_read(dev->dev_arg, req->ir_rlen,
178*0cbe4818SRobert Mustacchi req->ir_rdata)) {
179*0cbe4818SRobert Mustacchi i2csimd_io_error(simd, I2C_CORE_E_CONTROLLER,
180*0cbe4818SRobert Mustacchi I2C_CTRL_E_DATA_NACK);
181*0cbe4818SRobert Mustacchi return;
182*0cbe4818SRobert Mustacchi }
183*0cbe4818SRobert Mustacchi }
184*0cbe4818SRobert Mustacchi
185*0cbe4818SRobert Mustacchi i2csimd_io_error(simd, I2C_CORE_E_OK, I2C_CTRL_E_OK);
186*0cbe4818SRobert Mustacchi }
187*0cbe4818SRobert Mustacchi
188*0cbe4818SRobert Mustacchi static void
i2csimd_smbus(i2csimd_t * simd,i2csimd_dev_t * dev,smbus_req_t * req)189*0cbe4818SRobert Mustacchi i2csimd_smbus(i2csimd_t *simd, i2csimd_dev_t *dev, smbus_req_t *req)
190*0cbe4818SRobert Mustacchi {
191*0cbe4818SRobert Mustacchi err(EXIT_FAILURE, "implement me");
192*0cbe4818SRobert Mustacchi }
193*0cbe4818SRobert Mustacchi
194*0cbe4818SRobert Mustacchi static void
i2csimd_serve(i2csimd_t * simd)195*0cbe4818SRobert Mustacchi i2csimd_serve(i2csimd_t *simd)
196*0cbe4818SRobert Mustacchi {
197*0cbe4818SRobert Mustacchi for (;;) {
198*0cbe4818SRobert Mustacchi i2csimd_port_t *port = NULL;
199*0cbe4818SRobert Mustacchi i2csim_req_t *req = &simd->simd_req;
200*0cbe4818SRobert Mustacchi const i2c_addr_t *addr;
201*0cbe4818SRobert Mustacchi
202*0cbe4818SRobert Mustacchi if (ioctl(simd->simd_fd, I2CSIM_REQUEST, req) != 0) {
203*0cbe4818SRobert Mustacchi err(EXIT_FAILURE, "failed to get I2C sim request");
204*0cbe4818SRobert Mustacchi }
205*0cbe4818SRobert Mustacchi
206*0cbe4818SRobert Mustacchi switch (req->i2csim_type) {
207*0cbe4818SRobert Mustacchi case I2C_CTRL_TYPE_I2C:
208*0cbe4818SRobert Mustacchi addr = &req->i2csim_i2c.ir_addr;
209*0cbe4818SRobert Mustacchi break;
210*0cbe4818SRobert Mustacchi case I2C_CTRL_TYPE_SMBUS:
211*0cbe4818SRobert Mustacchi addr = &req->i2csim_smbus.smbr_addr;
212*0cbe4818SRobert Mustacchi break;
213*0cbe4818SRobert Mustacchi default:
214*0cbe4818SRobert Mustacchi i2csimd_io_error(simd, I2C_CORE_E_CONTROLLER,
215*0cbe4818SRobert Mustacchi I2C_CTRL_E_INTERNAL);
216*0cbe4818SRobert Mustacchi goto reply;
217*0cbe4818SRobert Mustacchi }
218*0cbe4818SRobert Mustacchi
219*0cbe4818SRobert Mustacchi /*
220*0cbe4818SRobert Mustacchi * Find the controller and port this corresponds to and see if
221*0cbe4818SRobert Mustacchi * there is a logical device there. If we don't know the port,
222*0cbe4818SRobert Mustacchi * fail with an internal controller error. If there's no device
223*0cbe4818SRobert Mustacchi * there NACK.
224*0cbe4818SRobert Mustacchi */
225*0cbe4818SRobert Mustacchi for (size_t i = 0; i < ARRAY_SIZE(simd->simd_ports); i++) {
226*0cbe4818SRobert Mustacchi if (simd->simd_ports[i].port_ctrl == req->i2csim_ctrl &&
227*0cbe4818SRobert Mustacchi simd->simd_ports[i].port_num == req->i2csim_port) {
228*0cbe4818SRobert Mustacchi port = &simd->simd_ports[i];
229*0cbe4818SRobert Mustacchi break;
230*0cbe4818SRobert Mustacchi }
231*0cbe4818SRobert Mustacchi }
232*0cbe4818SRobert Mustacchi
233*0cbe4818SRobert Mustacchi if (port == NULL) {
234*0cbe4818SRobert Mustacchi i2csimd_io_error(simd, I2C_CORE_E_CONTROLLER,
235*0cbe4818SRobert Mustacchi I2C_CTRL_E_INTERNAL);
236*0cbe4818SRobert Mustacchi goto reply;
237*0cbe4818SRobert Mustacchi }
238*0cbe4818SRobert Mustacchi
239*0cbe4818SRobert Mustacchi if (addr->ia_type != I2C_ADDR_7BIT ||
240*0cbe4818SRobert Mustacchi addr->ia_addr >= 1 << 7) {
241*0cbe4818SRobert Mustacchi i2csimd_io_error(simd, I2C_CORE_E_CONTROLLER,
242*0cbe4818SRobert Mustacchi I2C_CTRL_E_INTERNAL);
243*0cbe4818SRobert Mustacchi goto reply;
244*0cbe4818SRobert Mustacchi }
245*0cbe4818SRobert Mustacchi
246*0cbe4818SRobert Mustacchi i2csimd_dev_t *dev = port->port_devs[addr->ia_addr];
247*0cbe4818SRobert Mustacchi if (dev == NULL) {
248*0cbe4818SRobert Mustacchi i2csimd_io_error(simd, I2C_CORE_E_CONTROLLER,
249*0cbe4818SRobert Mustacchi I2C_CTRL_E_ADDR_NACK);
250*0cbe4818SRobert Mustacchi goto reply;
251*0cbe4818SRobert Mustacchi }
252*0cbe4818SRobert Mustacchi
253*0cbe4818SRobert Mustacchi /*
254*0cbe4818SRobert Mustacchi * We have found a device, send it the I/O request.
255*0cbe4818SRobert Mustacchi */
256*0cbe4818SRobert Mustacchi if (req->i2csim_type == I2C_CTRL_TYPE_I2C) {
257*0cbe4818SRobert Mustacchi i2csimd_i2c(simd, dev, &req->i2csim_i2c);
258*0cbe4818SRobert Mustacchi } else {
259*0cbe4818SRobert Mustacchi i2csimd_smbus(simd, dev, &req->i2csim_smbus);
260*0cbe4818SRobert Mustacchi }
261*0cbe4818SRobert Mustacchi
262*0cbe4818SRobert Mustacchi reply:
263*0cbe4818SRobert Mustacchi if (ioctl(simd->simd_fd, I2CSIM_REPLY, req) != 0) {
264*0cbe4818SRobert Mustacchi err(EXIT_FAILURE, "failed to submit I2C sim reply");
265*0cbe4818SRobert Mustacchi }
266*0cbe4818SRobert Mustacchi }
267*0cbe4818SRobert Mustacchi }
268*0cbe4818SRobert Mustacchi
269*0cbe4818SRobert Mustacchi int
main(void)270*0cbe4818SRobert Mustacchi main(void)
271*0cbe4818SRobert Mustacchi {
272*0cbe4818SRobert Mustacchi int dupfd, ret = 0;
273*0cbe4818SRobert Mustacchi struct rlimit rlim;
274*0cbe4818SRobert Mustacchi int pfds[2];
275*0cbe4818SRobert Mustacchi pid_t child;
276*0cbe4818SRobert Mustacchi priv_set_t *pset;
277*0cbe4818SRobert Mustacchi
278*0cbe4818SRobert Mustacchi /*
279*0cbe4818SRobert Mustacchi * Get all of our file descriptors to a reasonable state before we do
280*0cbe4818SRobert Mustacchi * anything.
281*0cbe4818SRobert Mustacchi */
282*0cbe4818SRobert Mustacchi closefrom(STDERR_FILENO + 1);
283*0cbe4818SRobert Mustacchi dupfd = open(_PATH_DEVNULL, O_RDONLY);
284*0cbe4818SRobert Mustacchi if (dupfd < 0) {
285*0cbe4818SRobert Mustacchi err(EXIT_FAILURE, "failed to open %s", _PATH_DEVNULL);
286*0cbe4818SRobert Mustacchi }
287*0cbe4818SRobert Mustacchi if (dup2(dupfd, STDIN_FILENO) == -1) {
288*0cbe4818SRobert Mustacchi err(EXIT_FAILURE, "failed to dup out stdin");
289*0cbe4818SRobert Mustacchi }
290*0cbe4818SRobert Mustacchi VERIFY0(close(dupfd));
291*0cbe4818SRobert Mustacchi
292*0cbe4818SRobert Mustacchi
293*0cbe4818SRobert Mustacchi i2csimd_init(&i2csimd);
294*0cbe4818SRobert Mustacchi
295*0cbe4818SRobert Mustacchi /*
296*0cbe4818SRobert Mustacchi * Now go ahead and do all the prep to daemonize.
297*0cbe4818SRobert Mustacchi */
298*0cbe4818SRobert Mustacchi rlim.rlim_cur = RLIM_INFINITY;
299*0cbe4818SRobert Mustacchi rlim.rlim_max = RLIM_INFINITY;
300*0cbe4818SRobert Mustacchi (void) setrlimit(RLIMIT_CORE, &rlim);
301*0cbe4818SRobert Mustacchi
302*0cbe4818SRobert Mustacchi if (chdir("/var/run") != 0) {
303*0cbe4818SRobert Mustacchi err(EXIT_FAILURE, "failed to chdir to /var/run");
304*0cbe4818SRobert Mustacchi }
305*0cbe4818SRobert Mustacchi
306*0cbe4818SRobert Mustacchi if (pipe(pfds) != 0) {
307*0cbe4818SRobert Mustacchi err(EXIT_FAILURE, "failed to create pipes to daemonize");
308*0cbe4818SRobert Mustacchi }
309*0cbe4818SRobert Mustacchi
310*0cbe4818SRobert Mustacchi child = forkx(FORK_NOSIGCHLD | FORK_WAITPID);
311*0cbe4818SRobert Mustacchi if (child == -1) {
312*0cbe4818SRobert Mustacchi err(EXIT_FAILURE, "failed to fork child");
313*0cbe4818SRobert Mustacchi }
314*0cbe4818SRobert Mustacchi
315*0cbe4818SRobert Mustacchi if (child != 0) {
316*0cbe4818SRobert Mustacchi int estatus;
317*0cbe4818SRobert Mustacchi
318*0cbe4818SRobert Mustacchi (void) close(pfds[1]);
319*0cbe4818SRobert Mustacchi if (read(pfds[0], &estatus, sizeof (estatus)) ==
320*0cbe4818SRobert Mustacchi sizeof (estatus)) {
321*0cbe4818SRobert Mustacchi _exit(estatus);
322*0cbe4818SRobert Mustacchi }
323*0cbe4818SRobert Mustacchi
324*0cbe4818SRobert Mustacchi if (waitpid(child, &estatus, 0) == child &&
325*0cbe4818SRobert Mustacchi WIFEXITED(estatus)) {
326*0cbe4818SRobert Mustacchi _exit(WEXITSTATUS(estatus));
327*0cbe4818SRobert Mustacchi }
328*0cbe4818SRobert Mustacchi
329*0cbe4818SRobert Mustacchi _exit(EXIT_FAILURE);
330*0cbe4818SRobert Mustacchi }
331*0cbe4818SRobert Mustacchi
332*0cbe4818SRobert Mustacchi VERIFY0(setgroups(0, NULL));
333*0cbe4818SRobert Mustacchi VERIFY0(setgid(GID_NOBODY));
334*0cbe4818SRobert Mustacchi VERIFY0(setuid(UID_NOBODY));
335*0cbe4818SRobert Mustacchi
336*0cbe4818SRobert Mustacchi if ((pset = priv_allocset()) == NULL) {
337*0cbe4818SRobert Mustacchi err(EXIT_FAILURE, "failed to allocate privilege set");
338*0cbe4818SRobert Mustacchi }
339*0cbe4818SRobert Mustacchi
340*0cbe4818SRobert Mustacchi priv_basicset(pset);
341*0cbe4818SRobert Mustacchi if (priv_delset(pset, PRIV_PROC_EXEC) == -1 ||
342*0cbe4818SRobert Mustacchi priv_delset(pset, PRIV_PROC_FORK) == -1 ||
343*0cbe4818SRobert Mustacchi priv_delset(pset, PRIV_PROC_INFO) == -1 ||
344*0cbe4818SRobert Mustacchi priv_delset(pset, PRIV_PROC_SESSION) == -1 ||
345*0cbe4818SRobert Mustacchi priv_delset(pset, PRIV_FILE_LINK_ANY) == -1 ||
346*0cbe4818SRobert Mustacchi priv_delset(pset, PRIV_PROC_SECFLAGS) == -1 ||
347*0cbe4818SRobert Mustacchi priv_delset(pset, PRIV_NET_ACCESS) == -1) {
348*0cbe4818SRobert Mustacchi err(EXIT_FAILURE, "failed to construct privilege set");
349*0cbe4818SRobert Mustacchi }
350*0cbe4818SRobert Mustacchi
351*0cbe4818SRobert Mustacchi if (setppriv(PRIV_SET, PRIV_PERMITTED, pset) == -1) {
352*0cbe4818SRobert Mustacchi err(EXIT_FAILURE, "failed to set permitted privileges");
353*0cbe4818SRobert Mustacchi }
354*0cbe4818SRobert Mustacchi
355*0cbe4818SRobert Mustacchi if (setppriv(PRIV_SET, PRIV_PERMITTED, pset) == -1) {
356*0cbe4818SRobert Mustacchi err(EXIT_FAILURE, "failed to set effective privileges");
357*0cbe4818SRobert Mustacchi }
358*0cbe4818SRobert Mustacchi
359*0cbe4818SRobert Mustacchi priv_freeset(pset);
360*0cbe4818SRobert Mustacchi
361*0cbe4818SRobert Mustacchi VERIFY0(close(pfds[0]));
362*0cbe4818SRobert Mustacchi VERIFY3U(setsid(), !=, (pid_t)-1);
363*0cbe4818SRobert Mustacchi
364*0cbe4818SRobert Mustacchi (void) write(pfds[1], &ret, sizeof (ret));
365*0cbe4818SRobert Mustacchi VERIFY0(close(pfds[1]));
366*0cbe4818SRobert Mustacchi
367*0cbe4818SRobert Mustacchi i2csimd_serve(&i2csimd);
368*0cbe4818SRobert Mustacchi return (EXIT_SUCCESS);
369*0cbe4818SRobert Mustacchi }
370