Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package entr for openSUSE:Factory checked in 
at 2026-03-06 18:18:33
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/entr (Old)
 and      /work/SRC/openSUSE:Factory/.entr.new.561 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "entr"

Fri Mar  6 18:18:33 2026 rev:19 rq:1336809 version:5.8

Changes:
--------
--- /work/SRC/openSUSE:Factory/entr/entr.changes        2025-10-04 
18:53:44.628022747 +0200
+++ /work/SRC/openSUSE:Factory/.entr.new.561/entr.changes       2026-03-06 
18:19:16.013833701 +0100
@@ -1,0 +2,12 @@
+Thu Mar  5 14:44:09 UTC 2026 - Martin Hauke <[email protected]>
+
+- Update to version 5.8
+  * Add usage hint and '-h' flag to display option summary.
+  * Add return value checks for malloc(3) and pipe(2).
+  * Make signal number configurable with ENTR_RESTART_SIGNAL.
+  * Monitor symlinks on Linux.
+  * Avoid expanding filenames using realpath(3).
+  * Linux: return correct status if poll(2) is interrupted.
+  * Always accept directories as input, making '-d' flag optional.
+
+-------------------------------------------------------------------

Old:
----
  entr-5.7.tar.gz
  entr-5.7.tar.gz.sig

New:
----
  entr-5.8.tar.gz
  entr-5.8.tar.gz.sig

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ entr.spec ++++++
--- /var/tmp/diff_new_pack.Al8BtM/_old  2026-03-06 18:19:17.625900131 +0100
+++ /var/tmp/diff_new_pack.Al8BtM/_new  2026-03-06 18:19:17.637900625 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package entr
 #
-# Copyright (c) 2025 SUSE LLC and contributors
+# Copyright (c) 2026 SUSE LLC and contributors
 # Copyright (c) 2016 Daniel Lichtenberger
 #
 # All modifications and additions to the file contributed by third parties
@@ -18,7 +18,7 @@
 
 
 Name:           entr
-Version:        5.7
+Version:        5.8
 Release:        0
 Summary:        A utility for running arbitrary commands when files change
 License:        ISC

++++++ entr-5.7.tar.gz -> entr-5.8.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/entr-5.7/Makefile.bsd new/entr-5.8/Makefile.bsd
--- old/entr-5.7/Makefile.bsd   2025-02-06 20:36:24.000000000 +0100
+++ new/entr-5.8/Makefile.bsd   2026-03-02 22:01:02.000000000 +0100
@@ -19,7 +19,7 @@
        ls entr.1 | EV_TRACE=1 ./entr -zn wc -l entr.1
 
 check: entr
-       ./system_test.sh
+       @./system_test.sh
 
 clean:
        rm -f *.o compat.c entr
@@ -38,6 +38,6 @@
        rm ${DESTDIR}${MANPREFIX}/man1/entr.1
 
 format:
-       ${CLANG_FORMAT} -i *.c *.h
+       ${CLANG_FORMAT} -i *.c *.h missing/*.c missing/*.h
 
 .PHONY: all test check clean format distclean install uninstall
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/entr-5.7/NEWS new/entr-5.8/NEWS
--- old/entr-5.7/NEWS   2025-02-06 20:36:24.000000000 +0100
+++ new/entr-5.8/NEWS   2026-03-02 22:01:02.000000000 +0100
@@ -1,5 +1,16 @@
 = Release History
 
+== 5.8: March 2, 2026
+
+ - MacOS: set open_max limit using MAXFILESPERPROC
+ - Add usage hint and '-h' flag to display option summary
+ - Add return value checks for malloc(3) and pipe(2)
+ - Make signal number configurable with ENTR_RESTART_SIGNAL
+ - Monitor symlinks on Linux and MacOS
+ - Avoid expanding filenames using realpath(3)
+ - Linux: return correct status if poll(2) is interrupted
+ - Always accept directories as input, making '-d' flag optional
+
 == 5.7: February 6, 2025
 
  - Update MANPREFIX for FreeBSD
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/entr-5.7/README.md new/entr-5.8/README.md
--- old/entr-5.7/README.md      2025-02-06 20:36:24.000000000 +0100
+++ new/entr-5.8/README.md      2026-03-02 22:01:02.000000000 +0100
@@ -21,11 +21,11 @@
 may cause `entr` to respond incorrectly. Setting the environment variable
 `ENTR_INOTIFY_WORKAROUND` enables `entr` to operate in these environments.
 
-Linux Features
---------------
+Platform Features
+-----------------
 
-Symlinks can be monitored for changes by setting the environment variable
-`ENTR_INOTIFY_SYMLINK`.
+On Mac OS and Linux, symlinks are not followed unless the environment variable
+`ENTR_FOLLOW_SYMLINK` is set.
 
 Man Page Examples
 -----------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/entr-5.7/data.h new/entr-5.8/data.h
--- old/entr-5.7/data.h 2025-02-06 20:36:24.000000000 +0100
+++ new/entr-5.8/data.h 2026-03-02 22:01:02.000000000 +0100
@@ -24,6 +24,7 @@
        char fn[PATH_MAX];
        int fd;
        int is_dir;
+       int is_symlink;
        int file_count;
        mode_t mode;
        ino_t ino;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/entr-5.7/entr.1 new/entr-5.8/entr.1
--- old/entr-5.7/entr.1 2025-02-06 20:36:24.000000000 +0100
+++ new/entr-5.8/entr.1 2026-03-02 22:01:02.000000000 +0100
@@ -13,7 +13,7 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd February 6, 2025
+.Dd March 2, 2026
 .Dt ENTR 1
 .Os
 .Sh NAME
@@ -52,11 +52,9 @@
 specified on the command line.
 Specify twice to erase the scrollback buffer.
 .It Fl d
-Track the directories of regular files provided as input and exit if a new file
-is added.
-This option also enables directories to be specified explicitly.
-If specified twice, all new entries to a directory are recognized,
-otherwise files with names beginning with
+Track the parent directory of regular files provided as input.
+If specified twice, all new entries to a directory are recognized, otherwise
+files with names beginning with
 .Ql \&.
 are ignored.
 .It Fl n
@@ -74,10 +72,6 @@
 .Ar utility
 which terminates is not executed again until a file system or keyboard event is
 processed.
-.Dv SIGTERM
-is used to terminate the
-.Ar utility
-before it is restarted.
 A process group is created to prevent shell scripts from masking signals.
 .Nm
 waits for the
@@ -144,6 +138,21 @@
 By default
 .Pa $HOME/.entr/status.awk
 is evaluated.
+.It Ev ENTR_RESTART_SIGNAL
+Signal used to terminate the
+.Ar utility .
+Supported signal names are
+.Dv HUP ,
+.Dv INT ,
+.Dv QUIT ,
+.Dv TERM ,
+.Dv USR1
+and
+.Dv USR2 .
+The default is
+.Dv SIGTERM .
+.It Ev EV_TRACE
+Print file system event messages.
 .It Ev PAGER
 Set to
 .Pa /bin/cat
@@ -156,8 +165,6 @@
 flag.
 The default is
 .Pa /bin/sh .
-.It Ev EV_TRACE
-Print file system event messages.
 .El
 .Sh EXIT STATUS
 If the
@@ -178,7 +185,7 @@
 .It 1
 No regular files were provided as input or an error occurred
 .It 2
-A file was added to a directory and the directory watch option was specified
+Files were added or removed from a directory
 .El
 .Sh EXAMPLES
 Rebuild a project if source files change, limiting output to the first 20 
lines:
@@ -195,7 +202,7 @@
 .Pp
 Rebuild project if a source file is modified or added to the src/ directory:
 .Pp
-.Dl $ while sleep 0.1; do ls src/*.rb | entr -d make; done
+.Dl $ while sleep 0.1; do ls -d src src/*.rb | entr make; done
 .Pp
 Auto-reload a web server, or terminate if the server exits
 .Pp
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/entr-5.7/entr.c new/entr-5.8/entr.c
--- old/entr-5.7/entr.c 2025-02-06 20:36:24.000000000 +0100
+++ new/entr-5.8/entr.c 2026-03-02 22:01:02.000000000 +0100
@@ -17,6 +17,7 @@
 #include <sys/param.h>
 #include <sys/resource.h>
 #include <sys/stat.h>
+#include <sys/sysctl.h>
 #include <sys/wait.h>
 
 #include <sys/event.h>
@@ -29,6 +30,7 @@
 #include <limits.h>
 #include <paths.h>
 #include <signal.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -62,6 +64,7 @@
 int child_pid;
 int child_status;
 int terminating;
+int restart_signal;
 
 int aggressive_opt;
 int clear_opt;
@@ -79,10 +82,15 @@
 static char *shell, *shell_base;
 static char *argv0, *argv0_base;
 
+/* function pointers */
+
+int (*xstat)(const char *path, struct stat *sb);
+
 /* forwards */
 
-static void usage();
+static void usage(bool);
 static void terminate_utility();
+static void set_restart_signal();
 static void handle_exit(int sig);
 static void proc_exit(int sig);
 static void print_child_status(int status);
@@ -100,7 +108,6 @@
  */
 int
 main(int argc, char *argv[]) {
-       struct rlimit rl;
        int kq;
        struct sigaction act;
        int ttyfd;
@@ -112,7 +119,7 @@
 
        /* call usage() if no command is supplied */
        if (argc < 2)
-               usage();
+               usage(false);
        argv_index = set_options(argv);
 
        sigemptyset(&act.sa_mask);
@@ -127,25 +134,41 @@
        if (sigaction(SIGHUP, &act, NULL) != 0)
                err(1, "Failed to set SIGHUP handler");
 
+       set_restart_signal();
+
        /* notification used to combine the one-shot and restart options */
        act.sa_flags = 0;
        act.sa_handler = proc_exit;
        if (sigaction(SIGCHLD, &act, NULL) != 0)
                err(1, "Failed to set SIGCHLD handler");
 
+       /* monitor symlinks if possible */
+       xstat = stat;
+#if defined(O_PATH) || defined(O_SYMLINK)
+       if (getenv("ENTR_FOLLOW_SYMLINK") == NULL)
+               xstat = lstat;
+#endif
+
 #if defined(_LINUX_PORT)
        /* attempt to read inotify limits */
        open_max = (unsigned) fs_sysctl(INOTIFY_MAX_USER_WATCHES);
        if (open_max == 0)
                open_max = 65536;
 #elif defined(_MACOS_PORT)
+       struct rlimit rl;
+       int mib[2] = { CTL_KERN, KERN_MAXFILESPERPROC };
+       size_t namelen = sizeof(open_max);
+
        if (getrlimit(RLIMIT_NOFILE, &rl) == -1)
                err(1, "getrlimit");
-       open_max = min(OPEN_MAX, rl.rlim_max);
+       if (sysctl(mib, 2, &open_max, &namelen, NULL, 0) == -1)
+               open_max = OPEN_MAX;
        rl.rlim_cur = open_max;
        if (setrlimit(RLIMIT_NOFILE, &rl) != 0)
                err(1, "setrlimit cannot set rlim_cur to %u", open_max);
 #else /* BSD */
+       struct rlimit rl;
+
        if (getrlimit(RLIMIT_NOFILE, &rl) == -1)
                err(1, "getrlimit");
        open_max = (unsigned) rl.rlim_max;
@@ -161,12 +184,9 @@
        setenv("PAGER", "/bin/cat", 0);
 
        /* ensure a shell is available to use */
-       setenv("SHELL", "/bin/sh", 0);
-
-       shell = getenv("SHELL");
+       if ((shell = getenv("SHELL")) == NULL)
+               shell = "/bin/sh";
        shell_base = strdup(shell);
-       if (shell_base == NULL)
-               err(1, "cannot duplicate string");
        shell_base = basename(shell_base);
 
        /* initialize status filter */
@@ -184,13 +204,15 @@
 
        /* sequential scan may depend on a 0 at the end */
        files = calloc(open_max + 1, sizeof(WatchFile *));
+       if (files == NULL)
+               err(1, "calloc");
 
        if ((kq = kqueue()) == -1)
                err(1, "cannot create kqueue");
 
        /* expect file list from a pipe */
        if (isatty(fileno(stdin)))
-               usage();
+               usage(false);
 
        /* read input and populate watch list, skipping non-regular files */
        n_files = process_input(stdin, files, open_max);
@@ -231,9 +253,28 @@
 /* Utility functions */
 
 void
-usage() {
+usage(bool summary) {
        fprintf(stderr, "release: %s\n", RELEASE);
        fprintf(stderr, "usage: entr [-acdnprsxz] utility [argument [/_] ...] < 
filenames\n");
+       if (!summary) {
+               fprintf(stderr, "hint: use -h to display option summary\n");
+               goto end;
+       }
+
+       printf("summary:\n"
+              "    -a  Do not consolidate events\n"
+              "    -c  Clear screen before execution\n"
+              "    -d  Track files added or removed from directories\n"
+              "    -n  Non-interactive mode\n"
+              "    -p  Wait for first event\n"
+              "    -r  Run as a background process, use signal to restart\n"
+              "    -s  Evaluate using a shell\n"
+              "    -x  Format exit status\n"
+              "    -z  Exit after the utility completes\n");
+       printf("docs:\n"
+              "    man entr\n");
+
+end:
        exit(1);
 }
 
@@ -244,7 +285,7 @@
        terminating = 1;
 
        if (child_pid > 0) {
-               killpg(child_pid, SIGTERM);
+               killpg(child_pid, restart_signal);
                waitpid(child_pid, &status, 0);
                child_pid = 0;
        }
@@ -252,6 +293,30 @@
        terminating = 0;
 }
 
+void
+set_restart_signal() {
+       const char *sig;
+       const int signum[] = { SIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGUSR1, 
SIGUSR2 };
+       const char *signame[] = { "HUP", "INT", "QUIT", "TERM", "USR1", "USR2" 
};
+       int i;
+
+       if ((sig = getenv("ENTR_RESTART_SIGNAL")) == NULL) {
+               restart_signal = SIGTERM;
+               return;
+       }
+
+       if (strncmp(sig, "SIG", 3) == 0)
+               sig += 3;
+
+       for (i = 0; signum[i] < 6; i++) {
+               if (strcmp(sig, signame[i]) == 0)
+                       restart_signal = signum[i];
+       }
+
+       if (restart_signal == 0)
+               errx(1, "unrecognized signal: %s <> (HUP, INT, QUIT, TERM, 
USR1, USR2)", sig);
+}
+
 /* Callbacks */
 
 void
@@ -331,7 +396,7 @@
 int
 process_input(FILE *file, WatchFile *files[], int max_files) {
        char buf[PATH_MAX];
-       char *p, *path;
+       char *p, *path, *parent_path;
        int n_files = 0;
        struct stat sb;
        int i, matches;
@@ -341,39 +406,52 @@
                        *p = '\0';
                if (buf[0] == '\0')
                        continue;
+               path = &buf[0];
 
-               if (stat(buf, &sb) == -1) {
-                       warnx("unable to stat '%s'", buf);
+               if (xstat(path, &sb) == -1) {
+                       warnx("unable to stat '%s'", path);
                        continue;
                }
-               if (S_ISREG(sb.st_mode) != 0) {
+
+               if ((S_ISREG(sb.st_mode) | S_ISLNK(sb.st_mode)) != 0) {
                        files[n_files] = malloc(sizeof(WatchFile));
-                       strlcpy(files[n_files]->fn, buf, MEMBER_SIZE(WatchFile, 
fn));
+                       if (files[n_files] == NULL)
+                               err(1, "malloc");
+                       strlcpy(files[n_files]->fn, path, 
MEMBER_SIZE(WatchFile, fn));
                        files[n_files]->is_dir = 0;
+                       files[n_files]->is_symlink = (S_ISLNK(sb.st_mode) != 0) 
? 1 : 0;
                        files[n_files]->file_count = 0;
                        files[n_files]->mode = sb.st_mode;
                        files[n_files]->ino = sb.st_ino;
                        n_files++;
-               }
-               /* also watch the directory if it's not already in the list */
-               if (dirwatch_opt > 0) {
-                       if (S_ISDIR(sb.st_mode) != 0)
-                               path = &buf[0];
-                       else if ((path = dirname(buf)) == 0)
-                               err(1, "dirname '%s' failed", buf);
-                       for (matches = 0, i = 0; i < n_files; i++)
-                               if (strcmp(files[i]->fn, path) == 0)
-                                       matches++;
-                       if (matches == 0) {
-                               files[n_files] = malloc(sizeof(WatchFile));
-                               strlcpy(files[n_files]->fn, path, 
MEMBER_SIZE(WatchFile, fn));
-                               files[n_files]->is_dir = 1;
-                               files[n_files]->file_count = list_dir(path);
-                               files[n_files]->mode = sb.st_mode;
-                               files[n_files]->ino = sb.st_ino;
-                               n_files++;
+
+                       /* also watch the directory if it's not already in the 
list */
+                       if (dirwatch_opt > 0) {
+                               if ((parent_path = dirname(path)) == 0)
+                                       err(1, "dirname '%s' failed", path);
+                               for (matches = 0, i = 0; i < n_files; i++) {
+                                       if ((files[i]->is_dir == 1) && 
(strcmp(files[i]->fn, parent_path) == 0))
+                                               matches++;
+                               }
+                               if (matches == 0) {
+                                       if (stat(parent_path, &sb) == -1)
+                                               warnx("unable to stat '%s'", 
parent_path);
+                                       path = parent_path;
+                               }
                        }
                }
+               if (S_ISDIR(sb.st_mode) != 0) {
+                       files[n_files] = malloc(sizeof(WatchFile));
+                       if (files[n_files] == NULL)
+                               err(1, "malloc");
+                       strlcpy(files[n_files]->fn, path, 
MEMBER_SIZE(WatchFile, fn));
+                       files[n_files]->is_dir = 1;
+                       files[n_files]->is_symlink = 0;
+                       files[n_files]->file_count = list_dir(path);
+                       files[n_files]->mode = sb.st_mode;
+                       files[n_files]->ino = sb.st_ino;
+                       n_files++;
+               }
                if (n_files + 1 > max_files)
                        return -1;
        }
@@ -404,6 +482,9 @@
        int ch;
        int argc;
 
+       if (argv[1] && strcmp(argv[1], "-h") == 0)
+               usage(true);
+
        /* read arguments until we reach a command */
        for (argc = 1; argv[argc] != 0 && argv[argc][0] == '-'; argc++)
                ;
@@ -437,11 +518,11 @@
                        oneshot_opt = 1;
                        break;
                default:
-                       usage();
+                       usage(false);
                }
        }
        if (argv[optind] == 0)
-               usage();
+               usage(false);
 
        if (status_filter_opt && restart_opt)
                errx(1, "-r and -x may not be combined");
@@ -464,35 +545,41 @@
        char **new_argv;
        char *p, *arg_buf;
        int argc;
+       size_t remaining;
 
        if (restart_opt == 1)
                terminate_utility();
 
+       arg_buf = malloc(ARG_MAX);
+
        if (shell_opt == 1) {
                /* run argv[1] with a shell using the leading edge as $0 */
                argc = 4;
-               arg_buf = malloc(ARG_MAX);
                new_argv = calloc(argc + 1, sizeof(char *));
-               realpath(leading_edge->fn, arg_buf);
+               if (new_argv == NULL)
+                       err(1, "calloc");
                new_argv[0] = shell;
                new_argv[1] = "-c";
                new_argv[2] = argv[0];
-               new_argv[3] = arg_buf;
+               new_argv[3] = leading_edge->fn;
        } else {
                /* clone argv on each invocation to make the implementation of 
more
                 * complex substitution rules possible and easy
                 */
                for (argc = 0; argv[argc]; argc++)
                        ;
-               arg_buf = malloc(ARG_MAX);
                new_argv = calloc(argc + 1, sizeof(char *));
+               if (new_argv == NULL)
+                       err(1, "calloc");
+               new_argv[0] = "/bin/false";
                for (m = 0, i = 0, p = arg_buf; i < argc; i++) {
+                       remaining = ARG_MAX - (p - arg_buf);
                        new_argv[i] = p;
                        if ((m < 1) && (strcmp(argv[i], "/_")) == 0) {
-                               p += strlen(realpath(leading_edge->fn, p));
+                               p += strlcpy(p, leading_edge->fn, remaining);
                                m++;
                        } else
-                               p += strlcpy(p, argv[i], ARG_MAX - (p - 
arg_buf));
+                               p += strlcpy(p, argv[i], remaining);
                        p++;
                }
        }
@@ -553,8 +640,10 @@
 
        /* wait up to 1 second for file to become available */
        for (;;) {
-#ifdef O_EVTONLY
-               file->fd = open(file->fn, O_RDONLY | O_CLOEXEC | O_EVTONLY);
+#if defined(O_EVTONLY)
+               file->fd = open(file->fn, O_RDONLY | O_CLOEXEC | O_EVTONLY | 
O_SYMLINK);
+#elif defined(O_PATH)
+               file->fd = open(file->fn, O_RDONLY | O_CLOEXEC | O_PATH | 
O_NOFOLLOW);
 #else
                file->fd = open(file->fn, O_RDONLY | O_CLOEXEC);
 #endif
@@ -656,10 +745,6 @@
        if ((nev == -1) && (errno != EINTR))
                warn("kevent failed");
 
-       /* escape for test runner */
-       if ((nev == -2) && (collate_only == 0))
-               return;
-
        for (i = 0; i < nev; i++) {
                if (!noninteractive_opt && evList[i].filter == EVFILT_READ) {
                        if (read(STDIN_FILENO, &c, 1) < 1) {
@@ -722,7 +807,7 @@
                }
 
                if (evList[i].fflags & NOTE_ATTRIB && S_ISREG(file->mode) != 0
-                   && stat(file->fn, &sb) == 0) {
+                   && xstat(file->fn, &sb) == 0) {
                        if (file->mode != sb.st_mode) {
                                do_exec = 1;
                                file->mode = sb.st_mode;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/entr-5.7/missing/kqueue_inotify.c 
new/entr-5.8/missing/kqueue_inotify.c
--- old/entr-5.7/missing/kqueue_inotify.c       2025-02-06 20:36:24.000000000 
+0100
+++ new/entr-5.8/missing/kqueue_inotify.c       2026-03-02 22:01:02.000000000 
+0100
@@ -13,8 +13,8 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <sys/inotify.h>
 #include <sys/event.h>
+#include <sys/inotify.h>
 #include <sys/types.h>
 
 #include <err.h>
@@ -38,7 +38,7 @@
 
 /* forwards */
 
-static WatchFile * file_by_descriptor(int fd);
+static WatchFile *file_by_descriptor(int fd);
 
 /* utility functions */
 
@@ -46,7 +46,7 @@
 file_by_descriptor(int wd) {
        int i;
 
-       for (i=0; files[i] != NULL; i++) {
+       for (i = 0; files[i] != NULL; i++) {
                if (files[i]->fd == wd)
                        return files[i];
        }
@@ -59,15 +59,14 @@
        char line[8];
        int value = 0;
 
-       switch(name) {
+       switch (name) {
        case INOTIFY_MAX_USER_WATCHES:
                file = fopen("/proc/sys/fs/inotify/max_user_watches", "r");
 
                if (file == NULL || fgets(line, sizeof(line), file) == NULL) {
                        /* failed to read max_user_watches; sometimes 
inaccessible on Android */
                        value = 0;
-               }
-               else
+               } else
                        value = atoi(line);
 
                if (file)
@@ -79,9 +78,10 @@
 
 /* interface */
 
-#define EVENT_SIZE (sizeof (struct inotify_event))
+#define EVENT_SIZE (sizeof(struct inotify_event))
 #define EVENT_BUF_LEN (32 * (EVENT_SIZE + 16))
-#define IN_ALL 
IN_CLOSE_WRITE|IN_DELETE_SELF|IN_MOVE_SELF|IN_MOVE|IN_ATTRIB|IN_CREATE|IN_DELETE
+#define IN_ALL                                                                 
                    \
+       IN_CLOSE_WRITE | IN_DELETE_SELF | IN_MOVE_SELF | IN_MOVE | IN_ATTRIB | 
IN_CREATE | IN_DELETE
 
 /*
  * inotify and kqueue ids both have the type `int`
@@ -105,8 +105,8 @@
  * eventlist structs filled by this call
  */
 int
-kevent(int kq, const struct kevent *changelist, int nchanges, struct
-       kevent *eventlist, int nevents, const struct timespec *timeout) {
+kevent(int kq, const struct kevent *changelist, int nchanges, struct kevent 
*eventlist, int nevents,
+    const struct timespec *timeout) {
        int n;
        int wd;
        WatchFile *file;
@@ -118,18 +118,21 @@
        const struct kevent *kev;
        int nfds;
 
+       int timeout_ms = -1;
        int ignored = 0;
        struct pollfd pfd[2];
 
        pfd[0].fd = kq;
        pfd[0].events = POLLIN;
+       pfd[0].revents = 0;
        pfd[1].fd = STDIN_FILENO;
        pfd[1].events = POLLIN;
+       pfd[1].revents = 0;
 
        if (nchanges > 0) {
-               for (n=0; n<nchanges; n++) {
-                       kev = changelist + (sizeof(struct kevent)*n);
-                       file = (WatchFile *)kev->udata;
+               for (n = 0; n < nchanges; n++) {
+                       kev = changelist + (sizeof(struct kevent) * n);
+                       file = (WatchFile *) kev->udata;
 
                        if (kev->filter == EVFILT_READ) {
                                if (kev->flags & EV_ADD)
@@ -144,20 +147,18 @@
                        if (kev->flags & EV_DELETE) {
                                inotify_rm_watch(kq /* ifd */, kev->ident);
                                file->fd = -1; /* invalidate */
-                       }
-                       else if (kev->flags & EV_ADD) {
+                       } else if (kev->flags & EV_ADD) {
                                if (getenv("ENTR_INOTIFY_WORKAROUND"))
-                                       wd = inotify_add_watch(kq, file->fn, 
IN_ALL|IN_MODIFY);
-                               else if (getenv("ENTR_INOTIFY_SYMLINK"))
-                                       wd = inotify_add_watch(kq, file->fn, 
IN_ALL|IN_DONT_FOLLOW);
+                                       wd = inotify_add_watch(kq, file->fn, 
IN_ALL | IN_MODIFY);
+                               else if (file->is_symlink)
+                                       wd = inotify_add_watch(kq, file->fn, 
IN_ALL | IN_DONT_FOLLOW);
                                else
                                        wd = inotify_add_watch(kq, file->fn, 
IN_ALL);
                                if (wd < 0)
                                        return -1;
                                close(file->fd);
                                file->fd = wd; /* replace with watch descriptor 
*/
-                       }
-                       else
+                       } else
                                ignored++;
                }
                return nchanges - ignored;
@@ -167,14 +168,15 @@
                nfds = 2; /* inotify and stdin */
        else
                nfds = 1; /* inotify */
-       if (timeout == NULL)
-               poll(pfd, nfds, -1);
-       else
-               poll(pfd, nfds, timeout->tv_nsec/1000000);
+
+       if (timeout)
+               timeout_ms = timeout->tv_nsec / 1000000;
+       if (poll(pfd, nfds, timeout_ms) == -1)
+               return -1;
 
        n = 0;
        do {
-               if (pfd[0].revents & (POLLERR|POLLNVAL))
+               if (pfd[0].revents & (POLLERR | POLLNVAL))
                        errx(1, "bad fd %d", pfd[0].fd);
                if (pfd[0].revents & POLLIN) {
                        pos = 0;
@@ -192,20 +194,30 @@
 
                                /* convert iev->mask; to comparable kqueue 
flags */
                                fflags = 0;
-                               if (iev->mask & IN_DELETE_SELF) fflags |= 
NOTE_DELETE;
-                               if (iev->mask & IN_CLOSE_WRITE) fflags |= 
NOTE_WRITE;
-                               if (iev->mask & IN_CREATE)      fflags |= 
NOTE_WRITE;
-                               if (iev->mask & IN_DELETE)      fflags |= 
NOTE_WRITE;
-                               if (iev->mask & IN_MOVE_SELF)   fflags |= 
NOTE_RENAME;
-                               if (iev->mask & IN_MOVED_TO)    fflags |= 
NOTE_RENAME;
-                               if (iev->mask & IN_MOVED_FROM)  fflags |= 
NOTE_RENAME;
-                               if (iev->mask & IN_ATTRIB)      fflags |= 
NOTE_ATTRIB;
+                               if (iev->mask & IN_DELETE_SELF)
+                                       fflags |= NOTE_DELETE;
+                               if (iev->mask & IN_CLOSE_WRITE)
+                                       fflags |= NOTE_WRITE;
+                               if (iev->mask & IN_CREATE)
+                                       fflags |= NOTE_WRITE;
+                               if (iev->mask & IN_DELETE)
+                                       fflags |= NOTE_WRITE;
+                               if (iev->mask & IN_MOVE_SELF)
+                                       fflags |= NOTE_RENAME;
+                               if (iev->mask & IN_MOVED_TO)
+                                       fflags |= NOTE_RENAME;
+                               if (iev->mask & IN_MOVED_FROM)
+                                       fflags |= NOTE_RENAME;
+                               if (iev->mask & IN_ATTRIB)
+                                       fflags |= NOTE_ATTRIB;
                                if (getenv("ENTR_INOTIFY_WORKAROUND"))
-                                       if (iev->mask & IN_MODIFY)  fflags |= 
NOTE_WRITE;
-                               if (fflags == 0) continue;
+                                       if (iev->mask & IN_MODIFY)
+                                               fflags |= NOTE_WRITE;
+                               if (fflags == 0)
+                                       continue;
 
                                /* merge events if we're not acting on a new 
file descriptor */
-                               if ((n > 0) && (eventlist[n-1].ident == 
iev->wd))
+                               if ((n > 0) && (eventlist[n - 1].ident == 
iev->wd))
                                        fflags |= eventlist[--n].fflags;
 
                                eventlist[n].ident = iev->wd;
@@ -219,9 +231,9 @@
                        }
                }
                if (read_stdin == 1) {
-                       if (pfd[1].revents & (POLLERR|POLLNVAL))
+                       if (pfd[1].revents & (POLLERR | POLLNVAL))
                                errx(1, "bad fd %d", pfd[1].fd);
-                       else if (pfd[1].revents & (POLLHUP|POLLIN)) {
+                       else if (pfd[1].revents & (POLLHUP | POLLIN)) {
                                fflags = 0;
                                eventlist[n].ident = pfd[1].fd;
                                eventlist[n].filter = EVFILT_READ;
@@ -233,8 +245,7 @@
                                break;
                        }
                }
-       }
-       while ((poll(pfd, nfds, 50) > 0));
+       } while ((poll(pfd, nfds, 50) > 0));
 
        return n;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/entr-5.7/missing/strlcpy.c 
new/entr-5.8/missing/strlcpy.c
--- old/entr-5.7/missing/strlcpy.c      2025-02-06 20:36:24.000000000 +0100
+++ new/entr-5.8/missing/strlcpy.c      2026-03-02 22:01:02.000000000 +0100
@@ -16,8 +16,8 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <sys/types.h>
 #include <string.h>
+#include <sys/types.h>
 
 /*
  * Copy string src to buffer dst of size dsize.  At most dsize-1
@@ -25,8 +25,7 @@
  * Returns strlen(src); if retval >= dsize, truncation occurred.
  */
 size_t
-strlcpy(char *dst, const char *src, size_t dsize)
-{
+strlcpy(char *dst, const char *src, size_t dsize) {
        const char *osrc = src;
        size_t nleft = dsize;
 
@@ -41,10 +40,10 @@
        /* Not enough room in dst, add NUL and traverse rest of src. */
        if (nleft == 0) {
                if (dsize != 0)
-                       *dst = '\0';            /* NUL-terminate dst */
+                       *dst = '\0'; /* NUL-terminate dst */
                while (*src++)
                        ;
        }
 
-       return(src - osrc - 1); /* count does not include NUL */
+       return (src - osrc - 1); /* count does not include NUL */
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/entr-5.7/missing/sys/sysctl.h 
new/entr-5.8/missing/sys/sysctl.h
--- old/entr-5.7/missing/sys/sysctl.h   1970-01-01 01:00:00.000000000 +0100
+++ new/entr-5.8/missing/sys/sysctl.h   2026-03-02 22:01:02.000000000 +0100
@@ -0,0 +1 @@
+/* empty unit: sysctl(2) not called on Linux */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/entr-5.7/status.c new/entr-5.8/status.c
--- old/entr-5.7/status.c       2025-02-06 20:36:24.000000000 +0100
+++ new/entr-5.8/status.c       2026-03-02 22:01:02.000000000 +0100
@@ -43,6 +43,8 @@
        awk_script = getenv("ENTR_STATUS_SCRIPT");
        if ((!awk_script) || (strlen(awk_script) == 0)) {
                pw = getpwuid(getuid());
+               if (pw == NULL)
+                       errx(1, "getpwuid");
                asprintf(&awk_script, "%s/.entr/status.awk", pw->pw_dir);
        }
 
@@ -66,7 +68,10 @@
        if (safe == 2)
                argv[5] = NULL;
 
-       pipe(status_stdin_pipe);
+       int rc = pipe(status_stdin_pipe);
+       if (rc == -1)
+               err(1, "pipe");
+
        status_pid = fork();
        if (status_pid == -1)
                err(1, "fork");
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/entr-5.7/system_test.sh new/entr-5.8/system_test.sh
--- old/entr-5.7/system_test.sh 2025-02-06 20:36:24.000000000 +0100
+++ new/entr-5.8/system_test.sh 2026-03-02 22:01:02.000000000 +0100
@@ -38,7 +38,7 @@
 
 utils="file pgrep git vim tmux"
 for util in $utils; do
-       p=$(command -pv $util) || {
+       p=$(command -v $util) || {
                echo "ERROR: could not locate the '$util' utility" >&2
                echo "System tests depend on the following: $utils" >&2
                exit 1
@@ -62,11 +62,21 @@
 # fast tests
 
 try "no arguments"
-       entr 2> /dev/null || code=$?
-       assert $code 1
+       entr >$tmp/exec.out 2>$tmp/exec.err
+       assert $? 1
+       grep -q "usage:" $tmp/exec.err
+       assert $? 0
+
+try "display option summary"
+       entr_tty -h >$tmp/exec.out 2>$tmp/exec.err
+       assert $? 1
+       grep -q "usage:" $tmp/exec.err
+       assert $? 0
+       grep -q "summary:" $tmp/exec.out
+       assert $? 0
 
 try "no input"
-       entr echo "vroom" 2> /dev/null || code=$?
+       echo | entr echo "vroom" 2> /dev/null || code=$?
        assert $code 1
 
 try "reload and clear options with no utility to run"
@@ -83,6 +93,14 @@
        rmdir $tmp/dir1
        assert $code 1
 
+try "invalid signal number set"
+       ls $tmp | ENTR_RESTART_SIGNAL="" entr echo 2> /dev/null || code=$?
+       assert $code 1
+       ls $tmp | ENTR_RESTART_SIGNAL="0" entr echo 2> /dev/null || code=$?
+       assert $code 1
+       ls $tmp | ENTR_RESTART_SIGNAL="KILL" entr echo 2> /dev/null || code=$?
+       assert $code 1
+
 # status message tests
 
 try "install default status script"
@@ -286,7 +304,7 @@
 
 try "exec single shell utility and exit when a file is added to a specific 
path"
        setup
-       ls -d $tmp | entr -dp sh -c 'echo ping' >$tmp/exec.out 2>$tmp/exec.err \
+       ls -d $tmp | entr -p sh -c 'echo ping' >$tmp/exec.out 2>$tmp/exec.err \
            || true &
        bgpid=$! ; zz
        touch $tmp/newfile
@@ -294,6 +312,34 @@
        assert "$(cat $tmp/exec.out)" "ping"
        assert "$(cat $tmp/exec.err)" "entr: directory altered"
 
+try "exec utility when a symlink is changed"
+       setup
+       ln -sf $tmp/file1 $tmp/link
+       echo $tmp/link | entr -p echo "changed" > $tmp/exec.out &
+       bgpid=$! ; zz
+       ln -sf $tmp/file2 $tmp/link ; zz
+       kill -INT $bgpid
+       wait $bgpid; assert "$?" "0"
+       if [ $(uname | grep -E 'Darwin|Linux') ]; then
+               assert "$(cat $tmp/exec.out)" "changed"
+       else
+               skip "O_SYMLINK not supported"
+       fi
+
+try "exec utility when a broken symlink is changed"
+       if [ $(uname | grep -E 'Darwin|Linux') ]; then
+               setup
+               ln -sf $tmp/file9 $tmp/link
+               echo $tmp/link | entr -p echo "changed" > $tmp/exec.out &
+               bgpid=$! ; zz
+               ln -sf $tmp/file1 $tmp/link ; zz
+               kill -INT $bgpid
+               wait $bgpid; assert "$?" "0"
+               assert "$(cat $tmp/exec.out)" "changed"
+       else
+               skip "O_SYMLINK not supported"
+       fi
+
 try "do nothing when a file not monitored is changed in directory watch mode"
        setup
        ls $tmp/file2 | entr -dp echo "changed" >$tmp/exec.out 2>$tmp/exec.err &
@@ -403,15 +449,15 @@
        wait $bgpid; assert "$?" "0"
        assert "$(cat $tmp/exec.out)" "$(printf 'started.\nstarted.')"
 
-try "ensure that all shell subprocesses are terminated in restart mode"
+try "ensure that all shell subprocesses are terminated with custom signal in 
restart mode"
        setup
        cat <<-SCRIPT > $tmp/go.sh
        #!/bin/sh
-       trap 'echo "caught signal"; exit' TERM
+       trap 'echo "caught signal"; exit' INT
        echo "running"; sleep 10
        SCRIPT
        chmod +x $tmp/go.sh
-       ls $tmp/file2 | entr -r sh -c "$tmp/go.sh" 2> /dev/null > $tmp/exec.out 
&
+       ls $tmp/file2 | ENTR_RESTART_SIGNAL=INT entr -r sh -c "$tmp/go.sh" 2> 
/dev/null > $tmp/exec.out &
        bgpid=$! ; zz
        kill -INT $bgpid ; zz
        assert "$(cat $tmp/exec.out)" "$(printf 'running\ncaught signal')"
@@ -521,7 +567,7 @@
                echo 456 >> $tmp/file2 ; zz
                kill -INT $bgpid
                wait $bgpid; assert "$?" "0"
-               assert "$(cat $tmp/exec.out | tr '/pts' '/tty')" "/dev/tty"
+               assert "$(awk '/dev.(tty|pts)/ { print "/dev/tty" }' 
$tmp/exec.out)" "/dev/tty"
        fi
 
 try "exec a command using shell option"

Reply via email to