Hi, I have just merged the support to control dillo from a UNIX control socket. There is now a new program called "dilloc" to send commands from the CLI. If there is only one dillo process it will choose it, otherwise it needs to be specified in the DILLO_PID env var. Use "dilloc help" to see all the commands available. It needs to be enabled at configure time with --enable-control-socket. The origin of this feature is to improve the test suite by controlling dillo automatically, but I think it will also be useful for users. In particular, the load and dump commands allow the manipulation of any loaded page as a UNIX pipeline: % dilloc dump | <manipulate-cmd> | dilloc load Or go to an alternative page from the current URL: % dilloc open $(dilloc url | sed 's/www\.reddit/old.reddit/') Let me know if you find something that doesn't work well, it is experimental for now. Best, Rodrigo.
Hello, On Fri, 19 Dec 2025 18:29:03 +0100 Rodrigo Arias <rodarima@gmail.com> wrote:
I have just merged the support to control dillo from a UNIX control socket. There is now a new program called "dilloc" to send commands from the CLI. ... I think it will also be useful for users.
I have been looking forward to this since I saw the demo on Mastodon. I am sure that I'll find a use.
Let me know if you find something that doesn't work well, it is experimental for now.
Not a big deal, but I did need to manual make the ~/.dillo/ctl directory. It is possible that I missed that part in the instructions. Best, Bobby Hiltz
Hi,
Not a big deal, but I did need to manual make the ~/.dillo/ctl directory. It is possible that I missed that part in the instructions.
When running dillo it should create the directory on its own (let me know otherwise). But if you run dilloc first without the ctl directory, it will complain and exit: % dilloc ping error: cannot open /home/ram/.dillo/ctl directory: No such file or directory Even if the ctl directory is present but no dillo is found, it should fail with: % dilloc ping error: cannot find ctl socket, is dillo running? Maybe I can make the error message a bit more user friendly for the case when there is no directory. In any case, users should not need to create any directory. Best, Rodrigo.
That is exactly what happened. I didn't run dillo, I tried running `dilloc help` first. Like many errors, this one was between the keyboard and the chair.
Hi Rodrigo, Rodrigo Arias <rodarima@gmail.com> wrote:
I have just merged the support to control dillo from a UNIX control socket. There is now a new program called "dilloc" to send commands from the CLI. If there is only one dillo process it will choose it, otherwise it needs to be specified in the DILLO_PID env var.
I just went to test this and ran into a possible issue. This is with a fully stock dillo build/install, running on OpenBSD 7.8 amd64: $ dillo -v Dillo Libraries: fltk/1.3.9 jpeg/3.1.2 png/1.6.50 webp/1.6.0 zlib/1.3.1.1-motley brotli/1.0.9 LibreSSL/4.2.0 Features: +GIF +JPEG +PNG +SVG +WEBP +BROTLI +XEMBED +TLS +IPV6 +CTL $ dillo paths: Creating directory '/home/user/.dillo/' paths: Cannot open file '/home/user/.dillo/dillorc': No such file or directory paths: Using /usr/local/etc/dillo/dillorc paths: Cannot open file '/home/user/.dillo/keysrc': No such file or directory paths: Using /usr/local/etc/dillo/keysrc paths: Cannot open file '/home/user/.dillo/domainrc': No such file or directory paths: Using /usr/local/etc/dillo/domainrc Domain: Default accept. dillo_dns_init: Here we go! (threaded) TLS library: LibreSSL 4.2.0 Cookies: Created file: /home/user/.dillo/cookiesrc Disabling cookies. paths: Cannot open file '/home/user/.dillo/hsts_preload': No such file or directory paths: Using /usr/local/etc/dillo/hsts_preload Nav_open_url: new url='about:splash' Dillo starts normally, then I do this: $ dilloc help Right away dillo exits and the console message shows this: ** ERROR **: Control_read_cb Resource temporarily unavailable This is with just one dillo process running, but I also tested with setting the DILLO_PID variable. That actually gives a working result for only one try, and then gives the error if you try again: $ dillo & [1] 12345 ... $ export DILLO_PID=12345 $ dilloc ping pong $ dilloc ping ** ERROR **: Control_read_cb Resource temporarily unavailable (dillo exits) I verified that the process ID remains unchanged and the variable is still set between dilloc runs, so I'm not sure what's going on. Happy to troubleshoot further if you have any suggestions. Regards, Alex
Hi,
Right away dillo exits and the console message shows this:
** ERROR **: Control_read_cb Resource temporarily unavailable
Hmm, I don't think I'm catching all possible errors from that socket. Maybe this patch can help: ---8<--- diff --git a/src/IO/control.c b/src/IO/control.c index 6f677e52..c6cd15bf 100644 --- a/src/IO/control.c +++ b/src/IO/control.c @@ -110,7 +110,7 @@ static void Control_read_cb(int fd, void *data) r = read(new_fd, buf, 1); _MSG("read = %zd\n", r); if (r < 0) { - if (errno == EINTR) { + if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) { continue; } else { MSG_ERR("Control_read_cb %s\n", dStrerror(errno)); ---8<--- Let me know if that makes it work. Best, Rodrigo.
Rodrigo Arias <rodarima@gmail.com> wrote:
Hi,
Right away dillo exits and the console message shows this:
** ERROR **: Control_read_cb Resource temporarily unavailable
Hmm, I don't think I'm catching all possible errors from that socket. Maybe this patch can help:
---8<--- diff --git a/src/IO/control.c b/src/IO/control.c index 6f677e52..c6cd15bf 100644 --- a/src/IO/control.c +++ b/src/IO/control.c @@ -110,7 +110,7 @@ static void Control_read_cb(int fd, void *data) r = read(new_fd, buf, 1); _MSG("read = %zd\n", r); if (r < 0) { - if (errno == EINTR) { + if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) { continue; } else { MSG_ERR("Control_read_cb %s\n", dStrerror(errno)); ---8<---
Let me know if that makes it work.
Looks to be working now! Thanks for this very cool new feature, BTW! Regards, Alex PS. Any chance of adding an option to reload dillorc prefs too? :)
Hi,
Looks to be working now! Thanks for this very cool new feature, BTW!
Nice! Let me know if you find some other problems.
PS. Any chance of adding an option to reload dillorc prefs too? :)
That would be doable, but I'm not sure if we can just re-parse all settings as-is without propagating the new values to other parts of Dillo which might have made a copy. Which use case do you have in mind? For the user agent rotation? Best, Rodrigo.
Hi, Rodrigo Arias <rodarima@gmail.com> wrote:
PS. Any chance of adding an option to reload dillorc prefs too? :)
That would be doable, but I'm not sure if we can just re-parse all settings as-is without propagating the new values to other parts of Dillo which might have made a copy.
Which use case do you have in mind? For the user agent rotation?
That was my initial use-case, but I also think that being able to change things like fonts and colors without having to restart dillo could be more useful for average users. For example switching between a light and dark color mode, or switching between regular fonts and CJK, etc. Thanks! Alex
Hi, On Sat, Dec 20, 2025 at 01:24:55PM +0000, a1ex@dismail.de wrote:
Hmm, I don't think I'm catching all possible errors from that socket. Maybe this patch can help:
---8<--- diff --git a/src/IO/control.c b/src/IO/control.c index 6f677e52..c6cd15bf 100644 --- a/src/IO/control.c +++ b/src/IO/control.c @@ -110,7 +110,7 @@ static void Control_read_cb(int fd, void *data) r = read(new_fd, buf, 1); _MSG("read = %zd\n", r); if (r < 0) { - if (errno == EINTR) { + if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) { continue; } else { MSG_ERR("Control_read_cb %s\n", dStrerror(errno)); ---8<---
Let me know if that makes it work.
Looks to be working now! Thanks for this very cool new feature, BTW!
I took a closer look and it seems that this patch doesn't address the actual problem. The problem is that BSD inherits the non-blocking behavior while Linux doesn't (POSIX doesn't seem to indicate what should be done). We want the new_fd to work in blocking mode, so this patch should fix it for BSD and Linux (otherwise let me know): ---8<--- diff --git a/src/IO/control.c b/src/IO/control.c index 6f677e52..0d11187e 100644 --- a/src/IO/control.c +++ b/src/IO/control.c @@ -95,12 +95,30 @@ static void Control_read_cb(int fd, void *data) int new_fd = accept(control_fd, NULL, NULL); if (new_fd < 0) { - if (errno != EWOULDBLOCK) { - MSG("accept failed: %s\n", strerror(errno)); + if (errno == EAGAIN || errno == EWOULDBLOCK) { + /* Nothing? */ + return; + } else { + MSG_ERR("accept failed: %s\n", strerror(errno)); exit(1); } - /* Nothing? */ - return; + } + + /* From accept(2) man page: + * + * On Linux, the new socket returned by accept() does not inherit + * file status flags such as O_NONBLOCK and O_ASYNC from the + * listening socket. This behavior differs from the canonical BSD + * sockets implementation. Portable programs should not rely on + * inheritance or noninheritance of file status flags and always + * explicitly set all required flags on the socket returned from + * accept(). + * + * So, disable O_NONBLOCK flag explicitly. + */ + if (fcntl(new_fd, F_SETFL, 0) == -1) { + MSG_ERR("control socket fcntl failed: %s\n", strerror(errno)); + exit(1); } ssize_t r; ---8<--- Best, Rodrigo.
Rodrigo Arias <rodarima@gmail.com> wrote:
I took a closer look and it seems that this patch doesn't address the actual problem. The problem is that BSD inherits the non-blocking behavior while Linux doesn't (POSIX doesn't seem to indicate what should be done). We want the new_fd to work in blocking mode, so this patch should fix it for BSD and Linux (otherwise let me know):
---8<--- diff --git a/src/IO/control.c b/src/IO/control.c index 6f677e52..0d11187e 100644 --- a/src/IO/control.c +++ b/src/IO/control.c @@ -95,12 +95,30 @@ static void Control_read_cb(int fd, void *data)
int new_fd = accept(control_fd, NULL, NULL); if (new_fd < 0) { - if (errno != EWOULDBLOCK) { - MSG("accept failed: %s\n", strerror(errno)); + if (errno == EAGAIN || errno == EWOULDBLOCK) { + /* Nothing? */ + return; + } else { + MSG_ERR("accept failed: %s\n", strerror(errno)); exit(1); } - /* Nothing? */ - return; + } + + /* From accept(2) man page: + * + * On Linux, the new socket returned by accept() does not inherit + * file status flags such as O_NONBLOCK and O_ASYNC from the + * listening socket. This behavior differs from the canonical BSD + * sockets implementation. Portable programs should not rely on + * inheritance or noninheritance of file status flags and always + * explicitly set all required flags on the socket returned from + * accept(). + * + * So, disable O_NONBLOCK flag explicitly. + */ + if (fcntl(new_fd, F_SETFL, 0) == -1) { + MSG_ERR("control socket fcntl failed: %s\n", strerror(errno)); + exit(1); }
ssize_t r; ---8<---
Tested & works fine here :)
participants (3)
-
a1ex@dismail.de -
Bobby Hiltz -
Rodrigo Arias