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?