Re: Save link as... silent failure on gopher protocol
by Diego
Very thanks.
I await.
Chers
Diego.
El dom, 12 jul 2026 a las 21:46, Rodrigo Arias (<rodarima(a)gmail.com>)
escribió:
> Hi,
>
> On Thu, Jul 09, 2026 at 01:37:14AM +0200, Diego wrote:
> >¿Can i have some feedback? ¿Do the patchs work for you? ¿do it seem a
> >practical idea? ¿etc?
>
> Thanks, I received the patches but I haven't had time to look at this
> yet, I have have it in my queue.
>
> Best,
> Rodrigo.
>
> >
> >cheers!
> >Diego.
> >
> >
> >El vie, 3 jul 2026 a las 14:17, Diego (<darkspirit5000(a)gmail.com>)
> escribió:
> >
> >> Hello, I'm sending two patches with an idea to solve this problem.
> >> It's a proof of concept that I'm offering to develop and complete,
> >> although I have very little free time.
> >>
> >> The first patch works with the latest dillo release (3.3.0) but also
> works
> >> with the current repository.
> >> It implements changes in dillo, download.dpi, and the file and data DPIs
> >> as examples.
> >> The second patch works with the latest gopher.dpi repository.
> >>
> >> The main idea is that the DPIs that handle protocols save the URL and
> >> write the file themselves, coordinating with download.dpi and dillo.
> >>
> >> To do this, they implement a new DPI command: `save_url`
> >> d_cmd = a_Dpip_build_cmd("cmd=%s url=%s destination=%s", "save_url",
> url,
> >> dl_dest);
> >>
> >> Dillo initiates a download, sending it to download.dpi as before. If
> it's
> >> HTTP* or FTP*, it downloads directly as it does now. Otherwise, it will
> >> send a `save_url` command to Dillo to coordinate. This allows Dillo to
> >> notify the user, verify the security of the change, etc.Currently, Dillo
> >> only checks if there's a DPI that handles the requested protocol.
> >>
> >> (A new function (`a_Dpiapi_is_service_handled(server_str)`) queries
> `dpid`
> >> without executing the DPI. No code is modified in `dpid`. Modifying
> `dpid`
> >> or executing the DPI would allow querying the capabilities of the DPIs,
> but
> >> it doesn't seem necessary.)
> >>
> >> - If a DPI is present, it sends the `save_url` command to the DPI that
> >> coordinates with `download.dpi` via a secondary channel so that
> downloads
> >> can continue even if all Dillo windows are closed.
> >>
> >> - If the protocol isn't handled, it notifies download.dpi through the
> >> secondary channel (this reduces the amount of code).
> >>
> >> The next step would be to implement `save_url` in other protocol DPIs.
> >>
> >> A possible change to download.dpi once all is done is to leave
> >> download.dpi it as just a GUI for DPIs and extract the code to download
> >> HTTP to a DPI. (There's already ftp.dpi)
> >>
> >> One last thing: can you recommend a simple Git manual?
> >>
> >>
> >> Saludos
> >> Diego.
> >>
> >> El lun, 25 may 2026 a las 21:23, Rodrigo Arias (<rodarima(a)gmail.com>)
> >> escribió:
> >>
> >>> Hi,
> >>>
> >>> On Mon, May 25, 2026 at 09:25:58AM -0700, Ben Collver wrote:
> >>> >Good day,
> >>> >
> >>> >I am using dillo 3.3.0 on Slackware64 15.0.
> >>> >
> >>> >If I open a gopher directory, right-click on an item, and click
> >>> >Save link as..., this opens a file save dialog. If i click OK, it
> >>> >dismisses the dialog. I expected it to save something, but it
> >>> >creates no new files.
> >>> >
> >>> >Gopher URI: gopher://gopher.pglaf.org/1/4/0/2/8/40282/
> >>> >Top item: 40282-0
> >>> >
> >>> >I found the following workaround:
> >>> >
> >>> >* Left click 40282-0
> >>> >* Click Save button in browser toolbar
> >>> >
> >>> >This creates a new file as expected.
> >>>
> >>> Yes, this is a known limitation of the downloads in Dillo. Using the
> >>> "Save link as" to fetch a new resource will use wget under the hood,
> >>> which only allows http(s). You can see the message in the console:
> >>>
> >>> > UIcmd_save: /tmp/40282-0.txt
> >>> > ** WARNING **: Ignoring download request for
> >>> > 'gopher://gopher.pglaf.org/0/4/0/2/8/40282/40282-0.txt': not in
> cache
> >>> > and not downloadable.
> >>>
> >>> Browsing to the target file makes the gopher plugin fetch the file and
> >>> place it in the Dillo cache (you can see it in about:cache). Then
> saving
> >>> the current page (or going back and clicking the "Save link as" entry)
> >>> works because it fetches it from the cache.
> >>>
> >>> It is planned to solve this some time in the future, but involves
> >>> complex changes. In the meanwhile, you can use this workaround.
> >>>
> >>> Best,
> >>> Rodrigo.
> >>> _______________________________________________
> >>> Dillo-dev mailing list -- dillo-dev(a)mailman3.com
> >>> To unsubscribe send an email to dillo-dev-leave(a)mailman3.com
> >>>
> >>
>
> >_______________________________________________
> >Dillo-dev mailing list -- dillo-dev(a)mailman3.com
> >To unsubscribe send an email to dillo-dev-leave(a)mailman3.com
>
> _______________________________________________
> Dillo-dev mailing list -- dillo-dev(a)mailman3.com
> To unsubscribe send an email to dillo-dev-leave(a)mailman3.com
>
July 12, 2026
Updated unveil patch
by a1ex@dismail.de
Hi,
Here is a new patch. I have done quite a bit more work on this and
think it may be close to completion.
The '~/Downloads' directory has been unveiled to match the behavior of
Firefox and Chromium on OpenBSD, but Dillo's default of '/tmp'
continues to work as well.
I have also made sure everything works fine when there is no ~/.dillo
directory, Dillo can create it, and also can access the system defaults
in '/usr/local/etc/dillo'.
dpid is also now unveiled, as well as all of the stock plugins except
hello.dpi, I didn't see any point to that.
Here are some other tests which I have run:
- Regular browsing works fine
- Connect to an FTP site and download a file, also view a text file and
view an image
- Open a text and image file from /tmp and ~/Downloads
- Add/remove bookmarks
- Download a file to /tmp and ~/Downloads
- Save a page to /tmp and ~/Downloads
- View source still works
- Fonts and cursor icons are working correctly
- data: uri works correctly with text and images
So far everything seems to be fine. I will keep testing, but would
really appreciate some help with reviewing this, there could be some
edge-cases which I missed.
Regards,
Alex
diff -upr a/dpi/bookmarks.c b/dpi/bookmarks.c
--- a/dpi/bookmarks.c Sat Jun 29 16:33:08 2024
+++ b/dpi/bookmarks.c Sun Jul 28 16:21:05 2024
@@ -25,6 +25,7 @@
#include <stddef.h>
#include <string.h>
#include <unistd.h>
+#include <err.h>
#include <errno.h>
#include <ctype.h>
#include <sys/socket.h>
@@ -1616,6 +1617,16 @@ int main(void) {
socklen_t address_size;
char *tok;
Dsh *sh;
+
+ /* Use unveil on OpenBSD */
+ #ifdef __OpenBSD__
+ char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL);
+ if (unveil(dil_loc, "rwc") == -1) {
+ err(1, "unveil failed");
+ }
+ dFree(dil_loc);
+ unveil(NULL, NULL);
+ #endif
/* Arrange the cleanup function for terminations via exit() */
atexit(cleanup);
diff -upr a/dpi/cookies.c b/dpi/cookies.c
--- a/dpi/cookies.c Sat Jun 29 16:33:08 2024
+++ b/dpi/cookies.c Sun Jul 28 16:21:05 2024
@@ -39,6 +39,7 @@ int main(void)
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
+#include <err.h>
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
@@ -1643,6 +1644,16 @@ int main(void) {
int sock_fd, code;
char *buf;
Dsh *sh;
+
+ /* Use unveil on OpenBSD */
+ #ifdef __OpenBSD__
+ char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL);
+ if (unveil(dil_loc, "rwc") == -1) {
+ err(1, "unveil failed");
+ }
+ dFree(dil_loc);
+ unveil(NULL, NULL);
+ #endif
/* Arrange the cleanup function for terminations via exit() */
atexit(cleanup);
diff -upr a/dpi/datauri.c b/dpi/datauri.c
--- a/dpi/datauri.c Sat Jun 29 16:33:08 2024
+++ b/dpi/datauri.c Sun Jul 28 16:21:05 2024
@@ -12,6 +12,7 @@
*/
#include <unistd.h>
+#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -289,6 +290,19 @@ int main(void)
unsigned char *data;
int rc;
size_t data_size = 0;
+
+ /* Use unveil on OpenBSD */
+ #ifdef __OpenBSD__
+ if (unveil("/tmp", "rwc") == -1) {
+ err(1, "unveil failed");
+ }
+ char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL);
+ if (unveil(dil_loc, "rwc") == -1) {
+ err(1, "unveil failed");
+ }
+ dFree(dil_loc);
+ unveil(NULL, NULL);
+ #endif
/* Initialize the SockHandler */
sh = a_Dpip_dsh_new(STDIN_FILENO, STDOUT_FILENO, 8*1024);
diff -upr a/dpi/downloads.cc b/dpi/downloads.cc
--- a/dpi/downloads.cc Sat Jun 29 16:33:08 2024
+++ b/dpi/downloads.cc Sun Jul 28 16:21:05 2024
@@ -18,6 +18,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <ctype.h>
@@ -1104,6 +1105,38 @@ static void custLabelMeasure(const Fl_Label* o,
int& W int main()
{
int ww = 420, wh = 85;
+
+ /* Use unveil on OpenBSD */
+ #ifdef __OpenBSD__
+ if (unveil("/tmp", "rwc") == -1) {
+ err(1, "unveil failed");
+ }
+ if (unveil("/etc/fonts", "r") == -1) {
+ err(1, "unveil failed");
+ }
+ if (unveil("/usr/local/bin/wget", "x") == -1) {
+ err(1, "unveil failed");
+ }
+ char *xauth_loc = dStrconcat(dGethomedir(), "/.Xauthority", NULL);
+ if (unveil(xauth_loc, "r") == -1) {
+ err(1, "unveil failed");
+ }
+ dFree(xauth_loc);
+ if (unveil("/usr/local/share/fonts", "r") == -1) {
+ err(1, "unveil failed");
+ }
+ char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL);
+ if (unveil(dil_loc, "rwc") == -1) {
+ err(1, "unveil failed");
+ }
+ dFree(dil_loc);
+ char *dl_loc = dStrconcat(dGethomedir(), "/Downloads", NULL);
+ if (unveil(dl_loc, "rwc") == -1) {
+ err(1, "unveil failed");
+ }
+ dFree(dl_loc);
+ unveil(NULL, NULL);
+ #endif
Fl::lock();
diff -upr a/dpi/file.c b/dpi/file.c
--- a/dpi/file.c Sat Jun 29 16:33:08 2024
+++ b/dpi/file.c Sun Jul 28 16:21:05 2024
@@ -22,6 +22,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <err.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/stat.h>
@@ -1070,6 +1071,23 @@ int main(void)
socklen_t sin_sz;
int sock_fd, c_st, st = 1;
+ /* Use unveil on OpenBSD */
+ #ifdef __OpenBSD__
+ if (unveil("/tmp", "rw") == -1) {
+ err(1, "unveil failed");
+ }
+ char *dl_loc = dStrconcat(dGethomedir(), "/Downloads", NULL);
+ if (unveil(dl_loc, "rw") == -1) {
+ err(1, "unveil failed");
+ }
+ dFree(dl_loc);
+ char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL);
+ if (unveil(dil_loc, "rwc") == -1) {
+ err(1, "unveil failed");
+ }
+ unveil(NULL, NULL);
+ #endif
+
/* Arrange the cleanup function for abnormal terminations */
if (signal (SIGINT, termination_handler) == SIG_IGN)
diff -upr a/dpi/ftp.c b/dpi/ftp.c
--- a/dpi/ftp.c Sat Jun 29 16:33:08 2024
+++ b/dpi/ftp.c Sun Jul 28 16:21:05 2024
@@ -29,6 +29,7 @@
*/
#include <unistd.h>
+#include <err.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
@@ -281,6 +282,28 @@ int main(int argc, char **argv)
char *dpip_tag = NULL, *cmd = NULL, *url = NULL, *url2 = NULL;
int st, rc;
char *p, *d_cmd;
+
+ /* Use unveil on OpenBSD */
+ #ifdef __OpenBSD__
+ if (unveil("/tmp", "rwc") == -1) {
+ err(1, "unveil failed");
+ }
+ if (unveil("/usr/local/bin/wget", "x") == -1) {
+ err(1, "unveil failed");
+ }
+ char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL);
+ if (unveil(dil_loc, "rwc") == -1) {
+ err(1, "unveil failed");
+ }
+ dFree(dil_loc);
+ char *dl_loc = dStrconcat(dGethomedir(), "/Downloads", NULL);
+ if (unveil(dl_loc, "rwc") == -1) {
+ err(1, "unveil failed");
+ }
+ dFree(dl_loc);
+ unveil(NULL, NULL);
+ #endif
+
/* wget may need to write a temporary file... */
rc = chdir("/tmp");
diff -upr a/dpi/vsource.c b/dpi/vsource.c
--- a/dpi/vsource.c Sat Jun 29 16:33:08 2024
+++ b/dpi/vsource.c Sun Jul 28 16:21:05 2024
@@ -13,6 +13,7 @@
*/
#include <unistd.h>
+#include <err.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
@@ -172,6 +173,16 @@ int main(void)
int data_size;
char *dpip_tag, *cmd = NULL, *cmd2 = NULL, *url = NULL, *size_str =
NULL; char *d_cmd;
+
+ /* Use unveil on OpenBSD */
+ #ifdef __OpenBSD__
+ char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL);
+ if (unveil(dil_loc, "r") == -1) {
+ err(1, "unveil failed");
+ }
+ dFree(dil_loc);
+ unveil(NULL, NULL);
+ #endif
_MSG("starting...\n");
//sleep(20);
diff -upr a/dpid/main.c b/dpid/main.c
--- a/dpid/main.c Sat Jun 29 16:33:08 2024
+++ b/dpid/main.c Sun Jul 28 16:21:30 2024
@@ -19,6 +19,7 @@
#include <errno.h> /* for ckd_write */
#include <unistd.h> /* for ckd_write */
+#include <err.h>
#include <stdlib.h> /* for exit */
#include <assert.h> /* for assert */
#include <sys/stat.h> /* for umask */
@@ -236,6 +237,21 @@ int main(void)
services_list = NULL;
//daemon(0,0); /* Use 0,1 for feedback */
/* TODO: call setsid() ?? */
+
+ /* Use unveil on OpenBSD */
+ #ifdef __OpenBSD__
+ if (unveil("/usr/local/lib/dillo", "rx") == -1) {
+ err(1, "unveil failed");
+ }
+ if (unveil("/usr/local/etc/dillo", "r") == -1) {
+ err(1, "unveil failed");
+ }
+ char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL);
+ if (unveil(dil_loc, "rwc") == -1) {
+ err(1, "unveil failed");
+ }
+ unveil(NULL, NULL);
+ #endif
/* Allow read and write access, but only for the user.
* TODO: can this cause trouble with umount? */
diff -upr a/src/dillo.cc b/src/dillo.cc
--- a/src/dillo.cc Sat Jun 29 16:33:08 2024
+++ b/src/dillo.cc Sun Jul 28 16:33:29 2024
@@ -23,6 +23,7 @@
#include <stdio.h>
#include <unistd.h>
+#include <err.h>
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
@@ -396,6 +397,47 @@ int main(int argc, char **argv)
srand((uint_t)(time(0) ^ getpid()));
+ // unveil()
+ #ifdef __OpenBSD__
+ if (unveil("/usr/local/share/fonts", "r") == -1) {
+ err(1, "unveil failed");
+ }
+ if (unveil("/usr/local/etc/dillo", "r") == -1) {
+ err(1, "unveil failed");
+ }
+ if (unveil("/tmp", "rwc") == -1) {
+ err(1, "unveil failed");
+ }
+ if (unveil("/usr/local/bin/dpid", "x") == -1) {
+ err(1, "unveil failed");
+ }
+ if (unveil("/etc/fonts", "r") == -1) {
+ err(1, "unveil failed");
+ }
+ if (unveil("/etc/resolv.conf", "r") == -1) {
+ err(1, "unveil failed");
+ }
+ if (unveil("/etc/ssl/cert.pem", "r") == -1) {
+ err(1, "unveil failed");
+ }
+ char *dl_loc = dStrconcat(dGethomedir(), "/Downloads", NULL);
+ if (unveil(dl_loc, "rwc") == -1) {
+ err(1, "unveil failed");
+ }
+ dFree(dl_loc);
+ char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL);
+ if (unveil(dil_loc, "rwc") == -1) {
+ err(1, "unveil failed");
+ }
+ dFree(dil_loc);
+ char *xauth_loc = dStrconcat(dGethomedir(), "/.Xauthority", NULL);
+ if (unveil(xauth_loc, "r") == -1) {
+ err(1, "unveil failed");
+ }
+ dFree(xauth_loc);
+ unveil(NULL, NULL);
+ #endif
+
// Some OSes exit dillo without this (not GNU/Linux).
signal(SIGPIPE, SIG_IGN);
// Establish our custom SIGCHLD handler
July 28, 2024
Re: Updated unveil patch
by Rodrigo Arias
Hi Alex,
On Sun, Jul 28, 2024 at 07:14:04PM +0200, a1ex(a)dismail.de wrote:
>Hi,
>
>Here is a new patch. I have done quite a bit more work on this and
>think it may be close to completion.
Thank you for the effort! I think this is getting in good shape.
Some preliminary comments:
Even if you compile for OpenBSD, unveil() was not introduced until
OpenBSD 6.4, so there is the possibility that is not available for an
user building Dillo for an old OpenBSD.
I recommend you add a configure switch (in configure.ac) to enable or
disable unveil(). By default you can keep it disabled and let the user
enable it manually, until we have more feedback to make it enabled by
default. Maybe by defining ENABLE_UNVEIL? You can take the --enable-svg
and ENABLE_SVG as an example.
Dillo from OpenBSD ports may enable it by default adding
--enable-unveil, so users test it without having to do any extra
configuration.
You should also make a dillorc configure option to enable/disable the
unveil feature in runtime, so it can help debug problems. You can make
the dillorc option enabled by default, which will only take action when
unveil support has been compiled in.
>The '~/Downloads' directory has been unveiled to match the behavior of
>Firefox and Chromium on OpenBSD, but Dillo's default of '/tmp'
>continues to work as well.
The download directory is set in the dillorc configuration file, and can
be any other place. Is it viable to read the configuration first and
then unveil the appropriate directory?
>I have also made sure everything works fine when there is no ~/.dillo
>directory, Dillo can create it, and also can access the system defaults
>in '/usr/local/etc/dillo'.
This is also controlled by the prefix variable, which can be set to any
other directory than /usr/local. This should be passed to the code to
form the complete path, an example is the DILLO_DOCDIR which is defined
as:
-DDILLO_DOCDIR='"$(docdir)/"'
In src/Makefile.am.
You'll want to use the $(sysconfdir) autoconf variable:
https://www.gnu.org/prep/standards/html_node/Directory-Variables.html#Direc…
>dpid is also now unveiled, as well as all of the stock plugins except
>hello.dpi, I didn't see any point to that.
>
>Here are some other tests which I have run:
>
>- Regular browsing works fine
>- Connect to an FTP site and download a file, also view a text file and
> view an image
>- Open a text and image file from /tmp and ~/Downloads
>- Add/remove bookmarks
>- Download a file to /tmp and ~/Downloads
>- Save a page to /tmp and ~/Downloads
>- View source still works
>- Fonts and cursor icons are working correctly
>- data: uri works correctly with text and images
>
>So far everything seems to be fine. I will keep testing, but would
>really appreciate some help with reviewing this, there could be some
>edge-cases which I missed.
As this won't be a simple patch, I suggest you open a PR in GitHub, so
the CI can compile your patch revisions for multiple platforms and pass
the tests. Otherwise I would have to spend the time to do it myself.
I'm thinking if we can automate those tests in the CI. Probably we would
need to add OpenBSD as a target first, as we only have FreeBSD.
>Regards,
>Alex
>
>
>
>diff -upr a/dpi/bookmarks.c b/dpi/bookmarks.c
>--- a/dpi/bookmarks.c Sat Jun 29 16:33:08 2024
>+++ b/dpi/bookmarks.c Sun Jul 28 16:21:05 2024
>@@ -25,6 +25,7 @@
> #include <stddef.h>
> #include <string.h>
> #include <unistd.h>
>+#include <err.h>
> #include <errno.h>
> #include <ctype.h>
> #include <sys/socket.h>
>@@ -1616,6 +1617,16 @@ int main(void) {
> socklen_t address_size;
> char *tok;
> Dsh *sh;
>+
>+ /* Use unveil on OpenBSD */
>+ #ifdef __OpenBSD__
>+ char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL);
>+ if (unveil(dil_loc, "rwc") == -1) {
>+ err(1, "unveil failed");
The err() function is non-portable, please use Dillo MSG* macros or
perror() + exit(). This should be caught by the CI.
Also, ensure the indentation is kept at 3 characters (not my decision).
Would it make sense to add an unveil() wrapper? This would make it
easier to integrate with other platforms than OpenBSD (and you also get
the error checking in one place). Something like this:
void dUnveil(const char *path, const char *perm)
{
#ifdef USE_UNVEIL
#ifdef __OpenBSD__
if (unveil(path, perm) == -1) {
MSG("unveil(%s, %s) failed: %s\n", path, perm, strerror(errno));
exit(1);
}
#endif
/* Other platforms... */
#endif
}
Not sure if we can make all those repeated calls into something that we
can reuse for all dpis and dillo main too.
>+ }
>+ dFree(dil_loc);
>+ unveil(NULL, NULL);
>+ #endif
>
> /* Arrange the cleanup function for terminations via exit() */
> atexit(cleanup);
>diff -upr a/dpi/cookies.c b/dpi/cookies.c
>--- a/dpi/cookies.c Sat Jun 29 16:33:08 2024
>+++ b/dpi/cookies.c Sun Jul 28 16:21:05 2024
>@@ -39,6 +39,7 @@ int main(void)
> #include <fcntl.h>
> #include <unistd.h>
> #include <errno.h>
>+#include <err.h>
> #include <stddef.h>
> #include <string.h>
> #include <stdlib.h>
>@@ -1643,6 +1644,16 @@ int main(void) {
> int sock_fd, code;
> char *buf;
> Dsh *sh;
>+
>+ /* Use unveil on OpenBSD */
>+ #ifdef __OpenBSD__
>+ char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL);
>+ if (unveil(dil_loc, "rwc") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ dFree(dil_loc);
>+ unveil(NULL, NULL);
>+ #endif
>
> /* Arrange the cleanup function for terminations via exit() */
> atexit(cleanup);
>diff -upr a/dpi/datauri.c b/dpi/datauri.c
>--- a/dpi/datauri.c Sat Jun 29 16:33:08 2024
>+++ b/dpi/datauri.c Sun Jul 28 16:21:05 2024
>@@ -12,6 +12,7 @@
> */
>
> #include <unistd.h>
>+#include <err.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
>@@ -289,6 +290,19 @@ int main(void)
> unsigned char *data;
> int rc;
> size_t data_size = 0;
>+
>+ /* Use unveil on OpenBSD */
>+ #ifdef __OpenBSD__
>+ if (unveil("/tmp", "rwc") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL);
>+ if (unveil(dil_loc, "rwc") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ dFree(dil_loc);
>+ unveil(NULL, NULL);
>+ #endif
>
> /* Initialize the SockHandler */
> sh = a_Dpip_dsh_new(STDIN_FILENO, STDOUT_FILENO, 8*1024);
>diff -upr a/dpi/downloads.cc b/dpi/downloads.cc
>--- a/dpi/downloads.cc Sat Jun 29 16:33:08 2024
>+++ b/dpi/downloads.cc Sun Jul 28 16:21:05 2024
>@@ -18,6 +18,7 @@
> #include <stdlib.h>
> #include <string.h>
> #include <unistd.h>
>+#include <err.h>
> #include <errno.h>
> #include <fcntl.h>
> #include <ctype.h>
>@@ -1104,6 +1105,38 @@ static void custLabelMeasure(const Fl_Label* o,
>int& W int main()
> {
> int ww = 420, wh = 85;
>+
>+ /* Use unveil on OpenBSD */
>+ #ifdef __OpenBSD__
>+ if (unveil("/tmp", "rwc") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ if (unveil("/etc/fonts", "r") == -1) {
>+ err(1, "unveil failed");
>+ }
Not sure if you may need other user-defined places for fonts.
>+ if (unveil("/usr/local/bin/wget", "x") == -1) {
>+ err(1, "unveil failed");
>+ }
You should find wget by locating it in the $PATH, not assuming it would
be here. Users may place their own wget binary somewhere else and this
would break the downloads.
>+ char *xauth_loc = dStrconcat(dGethomedir(), "/.Xauthority", NULL);
>+ if (unveil(xauth_loc, "r") == -1) {
>+ err(1, "unveil failed");
>+ }
The .Xauthority file should be read from $AUTHORITY and then from there
if not set.
>+ dFree(xauth_loc);
>+ if (unveil("/usr/local/share/fonts", "r") == -1) {
>+ err(1, "unveil failed");
>+ }
Trailing whitespaces here^
>+ char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL);
>+ if (unveil(dil_loc, "rwc") == -1) {
>+ err(1, "unveil failed");
>+ }
I'll suggest adding another rule to protect ~/.dillo/dillorc from
modification.
>+ dFree(dil_loc);
>+ char *dl_loc = dStrconcat(dGethomedir(), "/Downloads", NULL);
Same here, the downloads directory is given by the dillorc, you cannot
assume it will be set there.
>+ if (unveil(dl_loc, "rwc") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ dFree(dl_loc);
>+ unveil(NULL, NULL);
>+ #endif
>
> Fl::lock();
>
>diff -upr a/dpi/file.c b/dpi/file.c
>--- a/dpi/file.c Sat Jun 29 16:33:08 2024
>+++ b/dpi/file.c Sun Jul 28 16:21:05 2024
>@@ -22,6 +22,7 @@
> #include <stdlib.h>
> #include <string.h>
> #include <unistd.h>
>+#include <err.h>
> #include <sys/select.h>
> #include <sys/socket.h>
> #include <sys/stat.h>
>@@ -1070,6 +1071,23 @@ int main(void)
> socklen_t sin_sz;
> int sock_fd, c_st, st = 1;
>
>+ /* Use unveil on OpenBSD */
>+ #ifdef __OpenBSD__
>+ if (unveil("/tmp", "rw") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ char *dl_loc = dStrconcat(dGethomedir(), "/Downloads", NULL);
>+ if (unveil(dl_loc, "rw") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ dFree(dl_loc);
>+ char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL);
>+ if (unveil(dil_loc, "rwc") == -1) {
>+ err(1, "unveil failed");
>+ }
Not sure if we want to constraint file:// like this. What if we are
using Dillo to read local HTML files in ~/?
>+ unveil(NULL, NULL);
>+ #endif
>+
> /* Arrange the cleanup function for abnormal terminations */
> if (signal (SIGINT, termination_handler) == SIG_IGN)
>
>diff -upr a/dpi/ftp.c b/dpi/ftp.c
>--- a/dpi/ftp.c Sat Jun 29 16:33:08 2024
>+++ b/dpi/ftp.c Sun Jul 28 16:21:05 2024
>@@ -29,6 +29,7 @@
> */
>
> #include <unistd.h>
>+#include <err.h>
> #include <sys/types.h>
> #include <sys/socket.h>
> #include <sys/un.h>
>@@ -281,6 +282,28 @@ int main(int argc, char **argv)
> char *dpip_tag = NULL, *cmd = NULL, *url = NULL, *url2 = NULL;
> int st, rc;
> char *p, *d_cmd;
>+
>+ /* Use unveil on OpenBSD */
>+ #ifdef __OpenBSD__
>+ if (unveil("/tmp", "rwc") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ if (unveil("/usr/local/bin/wget", "x") == -1) {
>+ err(1, "unveil failed");
>+ }
Notice wget may need ~/.netrc to access FTP files. But maybe it is good
to leave it out.
>+ char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL);
>+ if (unveil(dil_loc, "rwc") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ dFree(dil_loc);
>+ char *dl_loc = dStrconcat(dGethomedir(), "/Downloads", NULL);
>+ if (unveil(dl_loc, "rwc") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ dFree(dl_loc);
>+ unveil(NULL, NULL);
>+ #endif
>+
>
> /* wget may need to write a temporary file... */
> rc = chdir("/tmp");
>diff -upr a/dpi/vsource.c b/dpi/vsource.c
>--- a/dpi/vsource.c Sat Jun 29 16:33:08 2024
>+++ b/dpi/vsource.c Sun Jul 28 16:21:05 2024
>@@ -13,6 +13,7 @@
> */
>
> #include <unistd.h>
>+#include <err.h>
> #include <sys/types.h>
> #include <stdio.h>
> #include <stdlib.h>
>@@ -172,6 +173,16 @@ int main(void)
> int data_size;
> char *dpip_tag, *cmd = NULL, *cmd2 = NULL, *url = NULL, *size_str =
>NULL; char *d_cmd;
>+
>+ /* Use unveil on OpenBSD */
>+ #ifdef __OpenBSD__
>+ char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL);
>+ if (unveil(dil_loc, "r") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ dFree(dil_loc);
>+ unveil(NULL, NULL);
>+ #endif
>
> _MSG("starting...\n");
> //sleep(20);
>diff -upr a/dpid/main.c b/dpid/main.c
>--- a/dpid/main.c Sat Jun 29 16:33:08 2024
>+++ b/dpid/main.c Sun Jul 28 16:21:30 2024
>@@ -19,6 +19,7 @@
>
> #include <errno.h> /* for ckd_write */
> #include <unistd.h> /* for ckd_write */
>+#include <err.h>
> #include <stdlib.h> /* for exit */
> #include <assert.h> /* for assert */
> #include <sys/stat.h> /* for umask */
>@@ -236,6 +237,21 @@ int main(void)
> services_list = NULL;
> //daemon(0,0); /* Use 0,1 for feedback */
> /* TODO: call setsid() ?? */
>+
>+ /* Use unveil on OpenBSD */
>+ #ifdef __OpenBSD__
>+ if (unveil("/usr/local/lib/dillo", "rx") == -1) {
>+ err(1, "unveil failed");
>+ }
Plugins can also be found on the dpi_dir directory defined by the user
in the .dillo/dpidrc, so we would need to parse it first.
>+ if (unveil("/usr/local/etc/dillo", "r") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL);
>+ if (unveil(dil_loc, "rwc") == -1) {
I would also protect dpidrc from writing as well as dillorc.
>+ err(1, "unveil failed");
>+ }
>+ unveil(NULL, NULL);
I assume exec dpis don't inherit the unveil() configuration (?)
>+ #endif
>
> /* Allow read and write access, but only for the user.
> * TODO: can this cause trouble with umount? */
>diff -upr a/src/dillo.cc b/src/dillo.cc
>--- a/src/dillo.cc Sat Jun 29 16:33:08 2024
>+++ b/src/dillo.cc Sun Jul 28 16:33:29 2024
>@@ -23,6 +23,7 @@
>
> #include <stdio.h>
> #include <unistd.h>
>+#include <err.h>
> #include <stdlib.h>
> #include <time.h>
> #include <sys/types.h>
>@@ -396,6 +397,47 @@ int main(int argc, char **argv)
>
> srand((uint_t)(time(0) ^ getpid()));
>
>+ // unveil()
>+ #ifdef __OpenBSD__
>+ if (unveil("/usr/local/share/fonts", "r") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ if (unveil("/usr/local/etc/dillo", "r") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ if (unveil("/tmp", "rwc") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ if (unveil("/usr/local/bin/dpid", "x") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ if (unveil("/etc/fonts", "r") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ if (unveil("/etc/resolv.conf", "r") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ if (unveil("/etc/ssl/cert.pem", "r") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ char *dl_loc = dStrconcat(dGethomedir(), "/Downloads", NULL);
>+ if (unveil(dl_loc, "rwc") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ dFree(dl_loc);
>+ char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL);
>+ if (unveil(dil_loc, "rwc") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ dFree(dil_loc);
>+ char *xauth_loc = dStrconcat(dGethomedir(), "/.Xauthority", NULL);
>
>+ if (unveil(xauth_loc, "r") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ dFree(xauth_loc);
>+ unveil(NULL, NULL);
>+ #endif
>+
> // Some OSes exit dillo without this (not GNU/Linux).
> signal(SIGPIPE, SIG_IGN);
> // Establish our custom SIGCHLD handler
>
>diff -upr a/dpi/bookmarks.c b/dpi/bookmarks.c
>--- a/dpi/bookmarks.c Sat Jun 29 16:33:08 2024
>+++ b/dpi/bookmarks.c Sun Jul 28 16:21:05 2024
>@@ -25,6 +25,7 @@
> #include <stddef.h>
> #include <string.h>
> #include <unistd.h>
>+#include <err.h>
> #include <errno.h>
> #include <ctype.h>
> #include <sys/socket.h>
>@@ -1616,6 +1617,16 @@ int main(void) {
> socklen_t address_size;
> char *tok;
> Dsh *sh;
>+
>+ /* Use unveil on OpenBSD */
>+ #ifdef __OpenBSD__
>+ char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL);
>+ if (unveil(dil_loc, "rwc") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ dFree(dil_loc);
>+ unveil(NULL, NULL);
>+ #endif
>
> /* Arrange the cleanup function for terminations via exit() */
> atexit(cleanup);
>diff -upr a/dpi/cookies.c b/dpi/cookies.c
>--- a/dpi/cookies.c Sat Jun 29 16:33:08 2024
>+++ b/dpi/cookies.c Sun Jul 28 16:21:05 2024
>@@ -39,6 +39,7 @@ int main(void)
> #include <fcntl.h>
> #include <unistd.h>
> #include <errno.h>
>+#include <err.h>
> #include <stddef.h>
> #include <string.h>
> #include <stdlib.h>
>@@ -1643,6 +1644,16 @@ int main(void) {
> int sock_fd, code;
> char *buf;
> Dsh *sh;
>+
>+ /* Use unveil on OpenBSD */
>+ #ifdef __OpenBSD__
>+ char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL);
>+ if (unveil(dil_loc, "rwc") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ dFree(dil_loc);
>+ unveil(NULL, NULL);
>+ #endif
>
> /* Arrange the cleanup function for terminations via exit() */
> atexit(cleanup);
>diff -upr a/dpi/datauri.c b/dpi/datauri.c
>--- a/dpi/datauri.c Sat Jun 29 16:33:08 2024
>+++ b/dpi/datauri.c Sun Jul 28 16:21:05 2024
>@@ -12,6 +12,7 @@
> */
>
> #include <unistd.h>
>+#include <err.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
>@@ -289,6 +290,19 @@ int main(void)
> unsigned char *data;
> int rc;
> size_t data_size = 0;
>+
>+ /* Use unveil on OpenBSD */
>+ #ifdef __OpenBSD__
>+ if (unveil("/tmp", "rwc") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL);
>+ if (unveil(dil_loc, "rwc") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ dFree(dil_loc);
>+ unveil(NULL, NULL);
>+ #endif
>
> /* Initialize the SockHandler */
> sh = a_Dpip_dsh_new(STDIN_FILENO, STDOUT_FILENO, 8*1024);
>diff -upr a/dpi/downloads.cc b/dpi/downloads.cc
>--- a/dpi/downloads.cc Sat Jun 29 16:33:08 2024
>+++ b/dpi/downloads.cc Sun Jul 28 16:21:05 2024
>@@ -18,6 +18,7 @@
> #include <stdlib.h>
> #include <string.h>
> #include <unistd.h>
>+#include <err.h>
> #include <errno.h>
> #include <fcntl.h>
> #include <ctype.h>
>@@ -1104,6 +1105,38 @@ static void custLabelMeasure(const Fl_Label* o, int& W
> int main()
> {
> int ww = 420, wh = 85;
>+
>+ /* Use unveil on OpenBSD */
>+ #ifdef __OpenBSD__
>+ if (unveil("/tmp", "rwc") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ if (unveil("/etc/fonts", "r") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ if (unveil("/usr/local/bin/wget", "x") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ char *xauth_loc = dStrconcat(dGethomedir(), "/.Xauthority", NULL);
>+ if (unveil(xauth_loc, "r") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ dFree(xauth_loc);
>+ if (unveil("/usr/local/share/fonts", "r") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL);
>+ if (unveil(dil_loc, "rwc") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ dFree(dil_loc);
>+ char *dl_loc = dStrconcat(dGethomedir(), "/Downloads", NULL);
>+ if (unveil(dl_loc, "rwc") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ dFree(dl_loc);
>+ unveil(NULL, NULL);
>+ #endif
>
> Fl::lock();
>
>diff -upr a/dpi/file.c b/dpi/file.c
>--- a/dpi/file.c Sat Jun 29 16:33:08 2024
>+++ b/dpi/file.c Sun Jul 28 16:21:05 2024
>@@ -22,6 +22,7 @@
> #include <stdlib.h>
> #include <string.h>
> #include <unistd.h>
>+#include <err.h>
> #include <sys/select.h>
> #include <sys/socket.h>
> #include <sys/stat.h>
>@@ -1070,6 +1071,23 @@ int main(void)
> socklen_t sin_sz;
> int sock_fd, c_st, st = 1;
>
>+ /* Use unveil on OpenBSD */
>+ #ifdef __OpenBSD__
>+ if (unveil("/tmp", "rw") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ char *dl_loc = dStrconcat(dGethomedir(), "/Downloads", NULL);
>+ if (unveil(dl_loc, "rw") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ dFree(dl_loc);
>+ char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL);
>+ if (unveil(dil_loc, "rwc") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ unveil(NULL, NULL);
>+ #endif
>+
> /* Arrange the cleanup function for abnormal terminations */
> if (signal (SIGINT, termination_handler) == SIG_IGN)
>
>diff -upr a/dpi/ftp.c b/dpi/ftp.c
>--- a/dpi/ftp.c Sat Jun 29 16:33:08 2024
>+++ b/dpi/ftp.c Sun Jul 28 16:21:05 2024
>@@ -29,6 +29,7 @@
> */
>
> #include <unistd.h>
>+#include <err.h>
> #include <sys/types.h>
> #include <sys/socket.h>
> #include <sys/un.h>
>@@ -281,6 +282,28 @@ int main(int argc, char **argv)
> char *dpip_tag = NULL, *cmd = NULL, *url = NULL, *url2 = NULL;
> int st, rc;
> char *p, *d_cmd;
>+
>+ /* Use unveil on OpenBSD */
>+ #ifdef __OpenBSD__
>+ if (unveil("/tmp", "rwc") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ if (unveil("/usr/local/bin/wget", "x") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL);
>+ if (unveil(dil_loc, "rwc") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ dFree(dil_loc);
>+ char *dl_loc = dStrconcat(dGethomedir(), "/Downloads", NULL);
>+ if (unveil(dl_loc, "rwc") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ dFree(dl_loc);
>+ unveil(NULL, NULL);
>+ #endif
>+
>
> /* wget may need to write a temporary file... */
> rc = chdir("/tmp");
>diff -upr a/dpi/vsource.c b/dpi/vsource.c
>--- a/dpi/vsource.c Sat Jun 29 16:33:08 2024
>+++ b/dpi/vsource.c Sun Jul 28 16:21:05 2024
>@@ -13,6 +13,7 @@
> */
>
> #include <unistd.h>
>+#include <err.h>
> #include <sys/types.h>
> #include <stdio.h>
> #include <stdlib.h>
>@@ -172,6 +173,16 @@ int main(void)
> int data_size;
> char *dpip_tag, *cmd = NULL, *cmd2 = NULL, *url = NULL, *size_str = NULL;
> char *d_cmd;
>+
>+ /* Use unveil on OpenBSD */
>+ #ifdef __OpenBSD__
>+ char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL);
>+ if (unveil(dil_loc, "r") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ dFree(dil_loc);
>+ unveil(NULL, NULL);
>+ #endif
>
> _MSG("starting...\n");
> //sleep(20);
>diff -upr a/dpid/main.c b/dpid/main.c
>--- a/dpid/main.c Sat Jun 29 16:33:08 2024
>+++ b/dpid/main.c Sun Jul 28 16:21:30 2024
>@@ -19,6 +19,7 @@
>
> #include <errno.h> /* for ckd_write */
> #include <unistd.h> /* for ckd_write */
>+#include <err.h>
> #include <stdlib.h> /* for exit */
> #include <assert.h> /* for assert */
> #include <sys/stat.h> /* for umask */
>@@ -236,6 +237,21 @@ int main(void)
> services_list = NULL;
> //daemon(0,0); /* Use 0,1 for feedback */
> /* TODO: call setsid() ?? */
>+
>+ /* Use unveil on OpenBSD */
>+ #ifdef __OpenBSD__
>+ if (unveil("/usr/local/lib/dillo", "rx") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ if (unveil("/usr/local/etc/dillo", "r") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL);
>+ if (unveil(dil_loc, "rwc") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ unveil(NULL, NULL);
>+ #endif
>
> /* Allow read and write access, but only for the user.
> * TODO: can this cause trouble with umount? */
>diff -upr a/src/dillo.cc b/src/dillo.cc
>--- a/src/dillo.cc Sat Jun 29 16:33:08 2024
>+++ b/src/dillo.cc Sun Jul 28 16:33:29 2024
>@@ -23,6 +23,7 @@
>
> #include <stdio.h>
> #include <unistd.h>
>+#include <err.h>
> #include <stdlib.h>
> #include <time.h>
> #include <sys/types.h>
>@@ -396,6 +397,47 @@ int main(int argc, char **argv)
>
> srand((uint_t)(time(0) ^ getpid()));
>
>+ // unveil()
>+ #ifdef __OpenBSD__
>+ if (unveil("/usr/local/share/fonts", "r") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ if (unveil("/usr/local/etc/dillo", "r") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ if (unveil("/tmp", "rwc") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ if (unveil("/usr/local/bin/dpid", "x") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ if (unveil("/etc/fonts", "r") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ if (unveil("/etc/resolv.conf", "r") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ if (unveil("/etc/ssl/cert.pem", "r") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ char *dl_loc = dStrconcat(dGethomedir(), "/Downloads", NULL);
>+ if (unveil(dl_loc, "rwc") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ dFree(dl_loc);
>+ char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL);
>+ if (unveil(dil_loc, "rwc") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ dFree(dil_loc);
>+ char *xauth_loc = dStrconcat(dGethomedir(), "/.Xauthority", NULL);
>+ if (unveil(xauth_loc, "r") == -1) {
>+ err(1, "unveil failed");
>+ }
>+ dFree(xauth_loc);
>+ unveil(NULL, NULL);
>+ #endif
>+
> // Some OSes exit dillo without this (not GNU/Linux).
> signal(SIGPIPE, SIG_IGN);
> // Establish our custom SIGCHLD handler
>_______________________________________________
>Dillo-dev mailing list -- dillo-dev(a)mailman3.com
>To unsubscribe send an email to dillo-dev-leave(a)mailman3.com
July 28, 2024