I have thought of a way pledge(2) can be made a little more library-friendly.
This is not a patch, but just a thought. There are 2 setups I have thought of: =============== 1. Variable arguments =============== int pledge(const char *promises, const char *paths[]) { return vpledge(1, promises, paths); } int vpledge(const size_t npledge, ...); ----- In a program, this may be something like this: #include <stdio.h> #include <unistd.h> #include <ultralib.h> #include <extralib.h> #include <superlib.h> #include <mechalib.h> int main(void) { if(vpledge(5, "stdio rpath wpath cpath", NULL, ultra_promises, ultra_pledgepaths, extra_promises, NULL, super_promises, NULL, mecha_promises, mecha_pledgepaths) == -1) errx("pledge"); ... [other code] ... }; ------- In vpledge(), "npledge" refers to the number of pledge-pairs, which consist of: const char *promises, const char *paths[] These have the same semantics as the original pledge(). A library can export *_promises and *_pledgepaths symbols, pointing to static text. This allows the library to change without the program being affected because the new library changes call something outside the original pledge() of a program. ============= 2. Using a struct ================== ----- struct pledge { char *promises; char *paths[]; }; ----- int pledge(const char *promises, const char *paths[]) { struct pledge pl = { .promises, paths }; return pledges(1, &pl); } int pledges(const size_t npledge, const struct pledge pledge_array[]); ----- In a program, this may be something like this: #include <stdio.h> #include <unistd.h> #include <ultralib.h> #include <extralib.h> #include <superlib.h> #include <mechalib.h> int main(void) { struct pledge pl[4]; pl[0].promises = "stdio rpath wpath cpath"; ultra_getpledge(&pl[1]); extra_getpledge(&pl[2]); super_getpledge(&pl[3]); mecha_getpledge(&pl[4]); if(pledges(5, pl) == -1) errx("pledge"); ... [other code] ... }; ------- A library can tell the application what pledges are in use as follows: static const char *pledge_promises = "stdio fattr sendfd recvfd" void ultra_getpledge(struct pledge *const pl) { pl->promises = pledge_promises; pl->paths = NULL; } ============== I think that #1 has the advantage of it being easier to code so a program can ratchet down its abilities. #2 allows one to group the pledge arguments into a single struct. Thoughts?