jcs's openbsd hax
openbsd
at jcs 515 lines 12 kB view raw
1.\" $OpenBSD: imsg_init.3,v 1.46 2025/06/13 18:34:00 schwarze Exp $ 2.\" 3.\" Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org> 4.\" Copyright (c) 2010 Nicholas Marriott <nicm@openbsd.org> 5.\" 6.\" Permission to use, copy, modify, and distribute this software for any 7.\" purpose with or without fee is hereby granted, provided that the above 8.\" copyright notice and this permission notice appear in all copies. 9.\" 10.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14.\" WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17.\" 18.Dd $Mdocdate: June 13 2025 $ 19.Dt IMSG_ADD 3 20.Os 21.Sh NAME 22.Nm imsg_add , 23.Nm imsg_close , 24.Nm imsg_compose , 25.Nm imsg_compose_ibuf , 26.Nm imsg_composev , 27.Nm imsg_create , 28.Nm imsg_forward , 29.Nm imsg_free , 30.Nm imsg_get_buf , 31.Nm imsg_get_data , 32.Nm imsg_get_fd , 33.Nm imsg_get_ibuf , 34.Nm imsg_get_id , 35.Nm imsg_get_len , 36.Nm imsg_get_pid , 37.Nm imsg_get_strbuf , 38.Nm imsg_get_type , 39.Nm imsg_ibufq_pop , 40.Nm imsg_ibufq_push , 41.Nm imsg_set_maxsize , 42.Nm imsgbuf_allow_fdpass , 43.Nm imsgbuf_clear , 44.Nm imsgbuf_flush , 45.Nm imsgbuf_get , 46.Nm imsgbuf_init , 47.Nm imsgbuf_queuelen , 48.Nm imsgbuf_read , 49.Nm imsgbuf_set_maxsize , 50.Nm imsgbuf_write 51.Nd IPC messaging functions 52.Sh SYNOPSIS 53.Lb libutil 54.In imsg.h 55.Fd #define IMSG_HEADER_SIZE sizeof(struct imsg_hdr) 56.Fd #define MAX_IMSGSIZE 16384 57.Ft int 58.Fn imsg_add "struct ibuf *msg" "const void *data" "size_t datalen" 59.Ft void 60.Fn imsg_close "struct imsgbuf *imsgbuf" "struct ibuf *msg" 61.Ft int 62.Fn imsg_compose "struct imsgbuf *imsgbuf" "uint32_t type" "uint32_t id" \ 63 "pid_t pid" "int fd" "const void *data" "size_t datalen" 64.Ft int 65.Fn imsg_compose_ibuf "struct imsgbuf *imsgbuf" "uint32_t type" \ 66 "uint32_t id" "pid_t pid" "struct ibuf *buf" 67.Ft struct ibuf * 68.Fn imsg_create "struct imsgbuf *imsgbuf" "uint32_t type" "uint32_t id" \ 69 "pid_t pid" "size_t datalen" 70.Ft int 71.Fn imsg_forward "struct imsgbuf *imsgbuf" "struct imsg *msg" 72.Ft void 73.Fn imsg_free "struct imsg *imsg" 74.Ft int 75.Fn imsg_get_buf "struct imsg *imsg" "void *data" "size_t len" 76.Ft int 77.Fn imsg_get_data "struct imsg *imsg" "void *data" "size_t len" 78.Ft int 79.Fn imsg_get_fd "struct imsg *imsg" 80.Ft int 81.Fn imsg_get_ibuf "struct imsg *imsg" "struct ibuf *ibuf" 82.Ft uint32_t 83.Fn imsg_get_id "struct imsg *imsg" 84.Ft size_t 85.Fn imsg_get_len "struct imsg *imsg" 86.Ft pid_t 87.Fn imsg_get_pid "struct imsg *imsg" 88.Ft int 89.Fn imsg_get_strbuf "struct imsg *imsg" "char *str" "size_t len" 90.Ft uint32_t 91.Fn imsg_get_type "struct imsg *imsg" 92.Ft int 93.Fn imsg_ibufq_pop "struct ibufqueue *bufq" "struct imsg *imsg" 94.Ft void 95.Fn imsg_ibufq_push "struct ibufqueue *bufq" "struct imsg *imsg" 96.Ft int 97.Fn imsg_set_maxsize "struct ibuf *msg" "size_t max" 98.Ft void 99.Fn imsgbuf_allow_fdpass "struct imsgbuf *imsgbuf" 100.Ft void 101.Fn imsgbuf_clear "struct imsgbuf *imsgbuf" 102.Ft int 103.Fn imsgbuf_flush "struct imsgbuf *imsgbuf" 104.Ft int 105.Fn imsgbuf_get "struct imsgbuf *imsgbuf" "struct imsg *imsg" 106.Ft int 107.Fn imsgbuf_init "struct imsgbuf *imsgbuf" "int fd" 108.Ft uint32_t 109.Fn imsgbuf_queuelen "struct imsgbuf *imsgbuf" 110.Ft int 111.Fn imsgbuf_read "struct imsgbuf *imsgbuf" 112.Ft int 113.Fn imsgbuf_set_maxsize "struct imsgbuf *imsgbuf" "uint32_t max" 114.Ft int 115.Fn imsgbuf_write "struct imsgbuf *imsgbuf" 116.In sys/uio.h 117.Ft int 118.Fn imsg_composev "struct imsgbuf *imsgbuf" "uint32_t type" "uint32_t id" \ 119 "pid_t pid" "int fd" "const struct iovec *iov" "int iovcnt" 120.Sh DESCRIPTION 121The 122.Nm imsg 123functions provide a simple mechanism for communication between local processes 124using sockets. 125Each transmitted message is guaranteed to be presented to the receiving program 126whole. 127They are commonly used in privilege separated processes, where processes with 128different rights are required to cooperate. 129.Pp 130.Fn imsgbuf_init 131initializes 132.Fa imsgbuf 133as one side of a channel associated with 134.Fa fd . 135The file descriptor is used to send and receive messages, 136but is not closed by any of the imsg functions. 137It returns 0 if successful and -1 on failure. 138.Pp 139.Fn imsgbuf_allow_fdpass 140enables file descriptor passing in both directions for this 141.Fa imsgbuf . 142.Pp 143.Fn imsgbuf_set_maxsize 144changes the default maximum payload size 145to 146.Fa max . 147It returns 0 if successful and -1 on failure. 148.Pp 149The 150.Fn imsgbuf_clear 151function frees any data allocated as part of an imsgbuf. 152This function does not close the file descriptor used for communication. 153.Pp 154The 155.Fn imsgbuf_read 156routine reads pending data with 157.Xr recvmsg 2 158and queues it as individual messages on 159.Fa imsgbuf . 160It returns 1 on success, 0 if the connection is closed, or \-1 on error 161and the global variable 162.Va errno 163is set to indicate the error. 164The errors 165.Er EINTR 166and 167.Er EAGAIN 168are treated as follows. 169.Er EINTR 170will automatically retry the read operation while the other errors are 171ignored with a 1 return. 172.Pp 173.Fn imsgbuf_write 174writes out queued messages. 175It returns 0 if it succeeds, -1 on error and the global variable 176.Va errno 177is set to indicate the error. 178The errors 179.Er EINTR , 180.Er EAGAIN , 181and 182.Er ENOBUFS 183are treated as follows. 184.Er EINTR 185will automatically retry the write operation while the other errors are 186ignored with a 0 return. 187.Pp 188.Fn imsgbuf_flush 189calls 190.Fn imsgbuf_write 191in a loop until all imsgs in the output buffer are sent. 192It returns 0 if it succeeds, \-1 otherwise and the global variable 193.Va errno 194is set to indicate the error. 195.Fn imsgbuf_flush 196should not be called on non-blocking sockets since it will busy loop if the 197socket is not available. 198.Pp 199.Fn imsgbuf_get 200fills in an individual imsg pending on 201.Fa imsgbuf 202into the structure pointed to by 203.Fa imsg . 204It returns 1 on success, 0 if no messages are ready, or \-1 for an error. 205Received messages are returned as a 206.Em struct imsg , 207which must be freed by 208.Fn imsg_free 209when no longer required. 210.Pp 211.Fn imsgbuf_queuelen 212returns the number of messages ready to be sent. 213This function returns 0 if no messages are pending for transmission. 214.Pp 215.Fn imsg_create , 216.Fn imsg_add 217and 218.Fn imsg_close 219are generic construction routines for messages that are to be sent using an 220imsgbuf. 221.Pp 222.Fn imsg_create 223creates a new message with header specified by 224.Fa type , 225.Fa id 226and 227.Fa pid . 228A 229.Fa pid 230of zero uses the process ID returned by 231.Xr getpid 2 232when 233.Fa imsgbuf 234was initialized. 235In addition to this common imsg header, 236.Fa datalen 237bytes of space may be reserved for attaching to this imsg. 238This space is populated using 239.Fn imsg_add . 240.Fn imsg_create 241returns a pointer to a new message if it succeeds, NULL otherwise. 242.Pp 243.Fn imsg_add 244appends to 245.Fa msg 246.Fa datalen 247bytes of ancillary data pointed to by 248.Fa data . 249It returns 250.Fa datalen 251if it succeeds, otherwise 252.Fa msg 253is freed and \-1 is returned. 254.Pp 255.Fn imsg_set_maxsize 256reduces the maximum payload of 257.Fa msg 258to 259.Fa max . 260The routine returns 0 if it succeeds, \-1 otherwise. 261.Pp 262.Fn imsg_close 263completes creation of 264.Fa msg 265by adding it to 266.Fa imsgbuf 267output buffer. 268.Pp 269.Fn imsg_compose 270is used to quickly create and queue an imsg. 271It takes the same parameters as the 272.Fn imsg_create , 273.Fn imsg_add 274and 275.Fn imsg_close 276routines, 277except that only one ancillary data buffer can be provided. 278Additionally, the file descriptor 279.Fa fd 280may be passed over the socket to the other process. 281If 282.Fa fd 283is given, it is closed in the sending program after the message is sent. 284A value of \-1 indicates no file descriptor should be passed. 285This routine returns 1 if it succeeds, \-1 otherwise. 286.Pp 287.Fn imsg_composev 288is similar to 289.Fn imsg_compose . 290It takes the same parameters, except that the ancillary data buffer is specified 291by 292.Fa iovec . 293.Pp 294.Fn imsg_compose_ibuf 295is similar to 296.Fn imsg_compose . 297It takes the same parameters, except that the ancillary data buffer is specified 298by an ibuf 299.Fa buf . 300This routine returns 1 if it succeeds, \-1 otherwise. 301In either case the buffer 302.Fa buf 303is consumed by the function. 304.Pp 305.Fn imsg_forward 306forwards a just received 307.Fa msg 308unaltered on 309.Fa imsgbuf . 310File descriptors are not forwarded by this function. 311It is possible to call 312.Fn imsg_forward 313more than once per message. 314.Pp 315The accessors 316.Fn imsg_get_type , 317.Fn imsg_get_pid , 318.Fn imsg_get_id , 319and 320.Fn imsg_get_len , 321return the 322.Fa type , 323.Fa pid , 324.Fa id , 325and payload length used in 326.Fn imsg_create 327to build the 328.Fa imsg . 329If there is no payload 330.Fn imsg_get_len 331returns 0. 332.Pp 333.Fn imsg_get_fd 334returns the file descriptor and passes the responsibility to track the 335descriptor back to the program. 336Unclaimed file descriptors are closed by 337.Fn imsg_free . 338.Pp 339.Fn imsg_get_data 340and 341.Fn imsg_get_ibuf 342are used to extract the payload of an 343.Fa imsg . 344.Fn imsg_get_data 345can be used if the structure of the payload is known and can be extracted 346in one go. 3470 is returned on success and \-1 on failure. 348.Fn imsg_get_ibuf 349initializes the passed 350.Fa ibuf 351to hold the payload which can be read using 352.Xr ibuf_get 3 . 353The 354.Fa ibuf 355remains valid until 356.Fn imsg_free 357is called and there is no need to call 358.Fn ibuf_free 359on this stack based buffer. 360The function returns 0 on success, \-1 otherwise. 361.Pp 362.Fn imsg_get_buf 363and 364.Fn imsg_get_strbuf 365read 366.Fa len 367bytes from the 368.Fa imsg 369and copy them into 370.Fa buf 371or 372.Fa str , 373respectively. 374.Fn imsg_get_strbuf 375ensures that 376.Fa str 377is NUL-terminated. 378The functions return 0 on success, \-1 otherwise. 379.Pp 380.Fn imsg_set_maxsize 381reduces the maximum payload of 382.Fa msg 383to 384.Fa max . 385The routine returns 0 if it succeeds, \-1 otherwise. 386.Pp 387.Fn imsg_ibufq_pop 388and 389.Fn imsg_ibufq_push 390allow to requeue an imsg onto the ibufqueue 391.Fa bufq . 392.Fn imsg_ibufq_pop 393returns 1 on success, 0 if no messages are ready, or \-1 for an error. 394See 395.Xr ibufq_new 3 for more info. 396.Pp 397MAX_IMSGSIZE is defined as the maximum size of a single imsg, currently 39816384 bytes. 399.Sh EXAMPLES 400In a typical program, a channel between two processes is created with 401.Xr socketpair 2 , 402and an 403.Em imsgbuf 404created around one file descriptor in each process: 405.Bd -literal -offset indent 406struct imsgbuf parent_ibuf, child_ibuf; 407int imsg_fds[2]; 408 409if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1) 410 err(1, "socketpair"); 411 412switch (fork()) { 413case -1: 414 err(1, "fork"); 415case 0: 416 /* child */ 417 close(imsg_fds[0]); 418 if (imsgbuf_init(&child_ibuf, imsg_fds[1]) == -1) 419 err(1, NULL); 420 exit(child_main(&child_ibuf)); 421} 422 423/* parent */ 424close(imsg_fds[1]); 425if (imsgbuf_init(&parent_ibuf, imsg_fds[0]) == -1) 426 err(1, NULL); 427exit(parent_main(&parent_ibuf)); 428.Ed 429.Pp 430Messages may then be composed and queued on the 431.Em imsgbuf , 432for example using the 433.Fn imsg_compose 434function: 435.Bd -literal -offset indent 436enum imsg_type { 437 IMSG_A_MESSAGE, 438 IMSG_MESSAGE2 439}; 440 441int 442child_main(struct imsgbuf *imsgbuf) 443{ 444 int idata; 445 ... 446 idata = 42; 447 imsg_compose(imsgbuf, IMSG_A_MESSAGE, 448 0, 0, -1, &idata, sizeof idata); 449 ... 450} 451.Ed 452.Pp 453A mechanism such as 454.Xr poll 2 455or the 456.Xr event 3 457library is used to monitor the socket file descriptor. 458When the socket is ready for writing, queued messages are transmitted with 459.Fn imsgbuf_write : 460.Bd -literal -offset indent 461 if (imsgbuf_write(imsgbuf) == -1) { 462 if (errno == EPIPE) 463 /* handle closed connection */ 464 else 465 /* handle write failure */ 466 } 467.Ed 468.Pp 469And when ready for reading, messages are first received using 470.Fn imsgbuf_read 471and then extracted with 472.Fn imsgbuf_get : 473.Bd -literal -offset indent 474void 475dispatch_imsg(struct imsgbuf *imsgbuf) 476{ 477 struct imsg imsg; 478 int n, idata; 479 480 switch (imsgbuf_read(imsgbuf)) { 481 case -1: 482 /* handle read error */ 483 break; 484 case 0: 485 /* handle closed connection */ 486 break; 487 } 488 489 for (;;) { 490 if ((n = imsgbuf_get(imsgbuf, &imsg)) == -1) { 491 /* handle read error */ 492 break; 493 } 494 if (n == 0) /* no more messages */ 495 return; 496 497 switch (imsg_get_type(&imsg)) { 498 case IMSG_A_MESSAGE: 499 if (imsg_get_data(&imsg, &idata, 500 sizeof(idata)) == -1) { 501 /* handle corrupt message */ 502 } 503 /* handle message received */ 504 break; 505 ... 506 } 507 508 imsg_free(&imsg); 509 } 510} 511.Ed 512.Sh SEE ALSO 513.Xr socketpair 2 , 514.Xr ibuf_add 3 , 515.Xr unix 4