Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 23 Dec 2002 07:30:54 -0500 (EST)
From:      Alan Eldridge <alane@freebsd.org>
To:        FreeBSD-gnats-submit@freebsd.org
Cc:        demon@freebsd.org, ports@freebsd.org
Message-ID:  <200212231230.gBNCUsSL064381@wwweasel.geeksrus.net>

next in thread | raw e-mail | index | archive | help

>Submitter-Id:	current-users
>Originator:	Alan Eldridge
>Organization:	Geeksrus.NET
>Confidential:	no 
>Synopsis:	
>Responsible:	demon
>Severity:	serious
>Priority:	medium
>Category:	ports
>Class:		change-request
>Release:	FreeBSD 4.7-STABLE i386
>Environment:
System: FreeBSD wwweasel.geeksrus.net 4.7-STABLE FreeBSD 4.7-STABLE #0: Fri Dec 20 06:38:48 EST 2002 root@wwweasel.geeksrus.net:/usr/obj/usr/src/sys/THRAK i386


>Description:

Links, as great as it is, has no way to print. This patch hijacks the
generic file open function, so anyplace you can enter a filename to save
you can type "| command" and the data will go to the command instead.
Printing is as easy as doing the "save formatted" command and giving a
filename of "| lpr".

This patch is non-invasive for the most part. It creates one new
function (create_process(commandline)) in session.c, and adds an if
statement to see if the save file begins with a "|": if it does
we hijack it to create_process instead.

I plan on submitting this to the author as well. However, it's a nice
value-add for FreeBSD, and people are welcome to try it out on their
own. The patch, which follows, is also available at:

http://people.freebsd.org/~alane/patches/patch-links-save_to_pipe.txt

>How-To-Repeat:
>Fix:

==8<====8<====8<====8<====8<====8<====8<====8<====8<====8<==
Index: files/patch-session.c
===================================================================
RCS file: files/patch-session.c
diff -N files/patch-session.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ files/patch-session.c	23 Dec 2002 12:07:48 -0000
@@ -0,0 +1,119 @@
+--- session.c.orig	Sun Jun  9 15:49:24 2002
++++ session.c	Mon Dec 23 07:07:36 2002
+@@ -1,4 +1,4 @@
+-/* session.c
++/* session.c -*-mode: c; c-basic-offset: 8-*-
+  * (c) 2002 Mikulas Patocka
+  * This file is a part of the Links program, released under GPL.
+  */
+@@ -503,6 +503,95 @@
+ 	}
+ }
+ 
++int create_process(unsigned char *szfn)
++{
++	int pid, rgfd[ 2 ];
++	unsigned char *command = szfn;
++
++	pipe(rgfd);
++	if ((pid = fork()) < 0) {
++		close(rgfd[ 0 ]);
++		close(rgfd[ 1 ]);
++		return -1;
++	} else if (pid > 0) {
++		/* parent:
++		   1. The write "handle" returned to the caller is
++		   the canonical write end of the pipe pair.
++		   2. We close the "read" end since we are not using
++		   it and we don't want fd leakage.
++		   3. The first thing the child is going to do is
++		   fork and exit, so the process we want to run will
++		   belong to init, not us. It's gross, but more
++		   portable than becoming a session leader. So we wait.
++		*/
++		int status;
++
++		wait(&status);
++		close(rgfd[ 0 ]);
++		return rgfd[ 1 ];
++	} else {
++		/* child:
++		   at this point, if something goes wrong,
++		   there's really nothing we can do about it;
++		   the parent will get a SIGPIPE when it
++		   tries to write.
++		*/
++		int fdnull = open("/dev/null", O_WRONLY);
++
++		/* 
++		   fork again, so we are re-parented to init
++		   and avoid the whole SIGCHLD issue. if we
++		   aren't the chile, we die. We use _exit so 
++		   we don't flush any output buffers.
++		*/
++		if ((pid = fork()) != 0) {
++			_exit(0);
++		}
++
++		/* grandchild:
++		   If we got here, we are in the grandchild process,
++		   whose parent has died and been reaped. Our parent
++		   should be init (the primordial process).
++
++		   Before we exec the command, we need to set up
++		   stdin, stdout, and stderr.
++		   1. stdin gets a dup2 of the "read" end of the 
++		   pipe.
++		   2. stdout and stderr get copies of an fd opened
++		   to "/dev/null".
++		*/
++		dup2(rgfd[ 0 ], 0);
++		dup2(fdnull, 1);
++		dup2(fdnull, 2);
++		
++		/* 
++		   Now we can close everything that is still
++		   open, because we've dup'd what we needed.
++		*/
++		close(fdnull);
++		close(rgfd[ 0 ]);
++		close(rgfd[ 1 ]);
++
++		/* 
++		   Let the shell handle the command. We use
++		   a hard-coded /bin/sh to avoid someone setting
++		   SHELL to an odd value and causing damage.
++
++		   Any damage that is done to the user should be
++		   self-inflicted, not the result of a maliciously
++		   set environment var.
++		*/
++		execlp("/bin/sh", "/bin/sh", "-c", command, 0);
++
++		/* failure:
++		   If we get here, there's not much to do but die.
++		   We use _exit so we don't flush any output buffers.
++		*/
++		_exit(1);
++	}
++	/* Trust me, you can't get here. */
++}
++
+ int create_download_file(struct terminal *term, unsigned char *fi, int safe)
+ {
+ 	unsigned char *file = fi;
+@@ -514,6 +603,14 @@
+ #else
+ 	int sf = safe;
+ #endif
++	if (*fi == '|') {
++		/*
++		  This will hook any command that saves
++		  a file to disk and hijack it to write
++		  to the input of a process. Cool, huh?
++		*/
++		return create_process(fi + 1);
++	}
+ 	wd = get_cwd();
+ 	set_cwd(term->cwd);
+ 	if (file[0] == '~' && dir_sep(file[1])) {
==8<====8<====8<====8<====8<====8<====8<====8<====8<====8<==



To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-ports" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200212231230.gBNCUsSL064381>