Re: [dev] [st] externalpipe on OpenBSD

2024-03-07 Thread Страхиња Радић
Hi, can anyone take a look at this and approve or comment if there is anything 
to add to or change about the patch?

https://lists.suckless.org/wiki/2402/4748.html



Re: [dev] [st] externalpipe on OpenBSD

2024-02-21 Thread Страхиња Радић
On 24/02/21 10:12AM, Страхиња Радић wrote:
> [...] (the program specified in openurlcmd doesn't get 
> executed).

I narrowed this down to adding "exec" to the second pledge:

+@@ -803,7 +809,7 @@ ttynew(const char *line, char *cmd, const char *out, char 
**args)
+   break;
+   default:
+ #ifdef __OpenBSD__
+-  if (pledge("stdio rpath tty proc", NULL) == -1)
++  if (pledge("stdio rpath tty proc exec", NULL) == -1)
+   die("pledge\n");
+ #endif

with the added "exec", the program in openurlcmd gets executed. What I don't 
know, however, is why is st not aborted if it is in violation of pledge, 
instead of silently failing. The changed pledge is in the parent, which 
continues execution.


> I also noticed that when I simply comment out the pledge, the program is 
> executed, but nothing is passed to openurlcmd.

Disregard this, it was due to having the debug version of script in openurlcmd 
still installed in the system.

* * *

Anyway, I have attached the proposed "0.8.5" diff with this message. Is it ok 
if I try to commit it to the wiki?
diff --git a/st.c b/st.c
index 034954d..98f2589 100644
--- a/st.c
+++ b/st.c
@@ -718,8 +718,14 @@ sigchld(int a)
 	if ((p = waitpid(pid, &stat, WNOHANG)) < 0)
 		die("waiting for pid %hd failed: %s\n", pid, strerror(errno));
 
-	if (pid != p)
+	if (pid != p) {
+		if (p == 0 && wait(&stat) < 0)
+			die("wait: %s\n", strerror(errno));
+
+		/* reinstall sigchld handler */
+		signal(SIGCHLD, sigchld);
 		return;
+	}
 
 	if (WIFEXITED(stat) && WEXITSTATUS(stat))
 		die("child exited with status %d\n", WEXITSTATUS(stat));
@@ -803,7 +809,7 @@ ttynew(const char *line, char *cmd, const char *out, char **args)
 		break;
 	default:
 #ifdef __OpenBSD__
-		if (pledge("stdio rpath tty proc", NULL) == -1)
+		if (pledge("stdio rpath tty proc exec", NULL) == -1)
 			die("pledge\n");
 #endif
 		close(s);
@@ -1991,6 +1997,59 @@ strparse(void)
 	}
 }
 
+void
+externalpipe(const Arg *arg)
+{
+	int to[2];
+	char buf[UTF_SIZ];
+	void (*oldsigpipe)(int);
+	Glyph *bp, *end;
+	int lastpos, n, newline;
+
+	if (pipe(to) == -1)
+		return;
+
+	switch (fork()) {
+	case -1:
+		close(to[0]);
+		close(to[1]);
+		return;
+	case 0:
+		dup2(to[0], STDIN_FILENO);
+		close(to[0]);
+		close(to[1]);
+		execvp(((char **)arg->v)[0], (char **)arg->v);
+		fprintf(stderr, "st: execvp %s\n", ((char **)arg->v)[0]);
+		perror("failed");
+		exit(0);
+	}
+
+	close(to[0]);
+	/* ignore sigpipe for now, in case child exists early */
+	oldsigpipe = signal(SIGPIPE, SIG_IGN);
+	newline = 0;
+	for (n = 0; n < term.row; n++) {
+		bp = term.line[n];
+		lastpos = MIN(tlinelen(n) + 1, term.col) - 1;
+		if (lastpos < 0)
+			break;
+		end = &bp[lastpos + 1];
+		for (; bp < end; ++bp)
+			if (xwrite(to[1], buf, utf8encode(bp->u, buf)) < 0)
+break;
+		if ((newline = term.line[n][lastpos].mode & ATTR_WRAP))
+			continue;
+		if (xwrite(to[1], "\n", 1) < 0)
+			break;
+		newline = 0;
+	}
+	if (newline)
+		(void)xwrite(to[1], "\n", 1);
+	close(to[1]);
+	/* restore */
+	signal(SIGPIPE, oldsigpipe);
+}
+
 void
 strdump(void)
 {
diff --git a/st.h b/st.h
index fd3b0d8..754cd08 100644
--- a/st.h
+++ b/st.h
@@ -81,6 +81,7 @@ void die(const char *, ...);
 void redraw(void);
 void draw(void);
 
+void externalpipe(const Arg *);
 void printscreen(const Arg *);
 void printsel(const Arg *);
 void sendbreak(const Arg *);
-- 
2.42.0