PLUMB(3)

πŸ“¦ version 0_git20260208, in alpine 3.24, arch rolling, nixos 26.05, nixpkgs unstable

🌸 NAME 🌸

okay so this is PLUMB(3), from the Library Functions Manual, and it's the whole plumb-message situation, bestie. The stars of the show are: eplumb, plumbfree, plumbopen, plumbunmount, plumbopenfid, plumbsend, plumbsendtofid, plumbsendtext, plumblookup, plumbpack, plumbpackattr, plumbaddattr, plumbdelattr, plumbrecv, plumbrecvfid, plumbunpack, plumbunpackpartial, plumbunpackattr, Plumbmsg β€” plumb messages. periodt πŸ’…

✨ SYNOPSIS ✨

#include <u.h>
#include <libc.h>
#include <plumb.h>

int        plumbopen(char *port, int omode)

int        plumbunmount(void)

int        plumbsend(int fd, Plumbmsg *m)

int        plumbsendtext(int fd, char *src, char *dst, char *wdir, char *data)

void       plumbfree(Plumbmsg *m)

Plumbmsg*  plumbrecv(int fd)

char*      plumbpack(Plumbmsg *m, int *np)

Plumbmsg*  plumbunpack(char *buf, int n)

Plumbmsg*  plumbunpackpartial(char *buf, int n, int *morep)

char*      plumbpackattr(Plumbattr *a)

Plumbattr* plumbunpackattr(char *a)

char*      plumblookup(Plumbattr *a, char *name)

Plumbattr* plumbaddattr(Plumbattr *a, Plumbattr *new)

Plumbattr* plumbdelattr(Plumbattra *a, char *name)

int        eplumb(int key, char *port)

#include <9pclient.h>

CFid       *plumbopenfid(char *port, int omode)

Plumbmsg*  plumbrecvfid(CFid *fid)

int        plumbsendtofid(CFid *fid, Plumbmsg *m)
yes bestie, Plumbattra is literally what the page says in that plumbdelattr signature β€” keeping it exactly, no cap 🫢

πŸ’… DESCRIPTION πŸ’…

These routines are your group chat for plumb(7) messages: sending them, receiving them, and translating them between text and these data structures. iconic little setup:

typedef
struct Plumbmsg
{
      char      *src;
      char      *dst;
      char      *wdir;
      char      *type;
      Plumbattr *attr;
      int       ndata;
      char      *data;
} Plumbmsg;

typedef
struct Plumbattr
{
      char      *name;
      char      *value;
      Plumbattr *next;
} Plumbattr;
  • plumbopen β€” opens the named plumb port using open(3) mode omode. If port starts with a slash, it's treated as a literal file name. Otherwise, it goes looking for where the plumber(4) service lives and opens the port there. slay.
  • eplumb β€” for programs using the event(3) interface, this registers receipt of messages from the named port using the given key.
  • plumbunmount β€” the library mounts the plumber(4) service on demand (via the 9pclient(3) library) and reuses that mount for later plumbopen calls. plumbunmount makes the library throw away its cached mount. That's useful if the plumber service itself got restarted and a client wants to reconnect. fresh start energy ✨
  • plumbsend β€” formats message m and writes it to file descriptor fd, which will usually be the result of plumbopen("send", OWRITE). Main character behavior.
  • plumbsendtext β€” the simplified text-only version. It assumes type is text, sets attr to nil, and sets ndata to strlen(data).
  • plumbfree β€” frees all the data associated with message m. Every component of m must therefore have been allocated with malloc(3). no random stack vibes, bestie.
  • plumbrecv β€” returns the next message available on file descriptor fd, or nil for error.
  • plumbpack β€” encodes message m as a character string in the format of plumb(7), and sets *np to the length in bytes of that string.
  • plumbunpack β€” the inverse of plumbpack: it translates the n bytes of buf into a Plumbmsg.
  • plumbunpackpartial β€” for messages that show up in pieces. The first call for a given message must be enough to unpack the header; subsequent calls allow unpacking messages with long data sections. For each call, buf points to the beginning of the complete message received so far, and n reports the total number of bytes received for that message. If the message is complete, the return value is as in plumbunpack. If it's not complete, and morep is not null, the return value is nil and *morep gets set to the number of bytes remaining to be read for this message to be complete (recall that the byte count is in the header). Those bytes should be read by the caller, placed at location buf+n, and the message unpacked again. If an error happens, the return value is nil and *morep is zero.
  • plumbpackattr β€” converts the list a of Plumbattr structures into a null-terminated string. If an attribute value contains white space, quote characters, or equal signs, the value gets quoted appropriately. A newline character terminates processing. bougie formatting, but make it correct πŸ’–
  • plumbunpackattr β€” converts the null-terminated string a back into a list of Plumbattr structures.
  • plumblookup β€” searches the Plumbattr list a for an attribute with the given name and returns the associated value. The returned string is the original value, not a copy. If the attribute has no value, you get the empty string. If the attribute doesn't occur in the list at all, you get nil.
  • plumbaddattr β€” appends the new Plumbattr (which may itself be a list) to the attribute list a and returns the new list.
  • the next sentence on the page says Plumbattr searches list a β€” literally, the page says Plumbattr here, not Plumbdelattr, so I'm keeping that exact. It searches for the first attribute with name name, deletes it from the list, and returns the resulting list. Plumbdelattr is a no-op if no such attribute exists.
  • error-detail tea β€” the file descriptor returned by plumbopen is created with fsopenfd (see 9pclient(3)), which masks information about read and write errors. That's acceptable for use in plumbrecv, but not for plumbsend, which depends on seeing details of write errors. plumbopenfid, plumbrecvfid, and plumbsendtofid give you an explicit interface to lib9pclient that preserves the exact error details. yup, that's the whole point πŸ”₯

πŸŽ€ SOURCE πŸŽ€

/src/libplumb

πŸ¦‹ SEE ALSO πŸ¦‹

plumb(1), event(3), plumber(4), plumb(7)

πŸ’€ DIAGNOSTICS πŸ’€

When appropriate β€” including when a plumbsend fails β€” these routines set errstr.

πŸ™ˆ BUGS πŸ™ˆ

To avoid rewriting clients that use plumbsend, the call plumbopen("send", OWRITE) returns a useless file descriptor (it is opened to /dev/null). Plumbsend looks for this particular file descriptor and uses a static copy of the CFid instead. yes, that's the little hack, bestie πŸ’…


πŸ’– okay that's the tea: this is the PLUMB(3) page from the Library Functions Manual, source /src/libplumb, and the footer/version-date situation is just PLUMB(3) β€” no extra date shown. bye bestie 🫢πŸ’