xref: /freebsd/usr.bin/diff/pr.c (revision 6fa5bf0832efe8a894f612968c5afe1ad91f3a03)
1*6fa5bf08SBaptiste Daroussin /*-
2*6fa5bf08SBaptiste Daroussin  * Copyright (c) 2017 Baptiste Daroussin <bapt@FreeBSD.org>
3*6fa5bf08SBaptiste Daroussin  * All rights reserved.
4*6fa5bf08SBaptiste Daroussin  *
5*6fa5bf08SBaptiste Daroussin  * Redistribution and use in source and binary forms, with or without
6*6fa5bf08SBaptiste Daroussin  * modification, are permitted provided that the following conditions
7*6fa5bf08SBaptiste Daroussin  * are met:
8*6fa5bf08SBaptiste Daroussin  * 1. Redistributions of source code must retain the above copyright
9*6fa5bf08SBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer
10*6fa5bf08SBaptiste Daroussin  *    in this position and unchanged.
11*6fa5bf08SBaptiste Daroussin  * 2. Redistributions in binary form must reproduce the above copyright
12*6fa5bf08SBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer in the
13*6fa5bf08SBaptiste Daroussin  *    documentation and/or other materials provided with the distribution.
14*6fa5bf08SBaptiste Daroussin  *
15*6fa5bf08SBaptiste Daroussin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16*6fa5bf08SBaptiste Daroussin  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17*6fa5bf08SBaptiste Daroussin  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18*6fa5bf08SBaptiste Daroussin  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19*6fa5bf08SBaptiste Daroussin  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20*6fa5bf08SBaptiste Daroussin  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21*6fa5bf08SBaptiste Daroussin  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22*6fa5bf08SBaptiste Daroussin  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23*6fa5bf08SBaptiste Daroussin  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24*6fa5bf08SBaptiste Daroussin  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25*6fa5bf08SBaptiste Daroussin  */
26*6fa5bf08SBaptiste Daroussin 
27*6fa5bf08SBaptiste Daroussin #include <sys/cdefs.h>
28*6fa5bf08SBaptiste Daroussin __FBSDID("$FreeBSD$");
29*6fa5bf08SBaptiste Daroussin 
30*6fa5bf08SBaptiste Daroussin #include <sys/procdesc.h>
31*6fa5bf08SBaptiste Daroussin #include <sys/wait.h>
32*6fa5bf08SBaptiste Daroussin 
33*6fa5bf08SBaptiste Daroussin #include <err.h>
34*6fa5bf08SBaptiste Daroussin #include <paths.h>
35*6fa5bf08SBaptiste Daroussin #include <signal.h>
36*6fa5bf08SBaptiste Daroussin #include <stdio.h>
37*6fa5bf08SBaptiste Daroussin #include <stdlib.h>
38*6fa5bf08SBaptiste Daroussin #include <unistd.h>
39*6fa5bf08SBaptiste Daroussin 
40*6fa5bf08SBaptiste Daroussin #include "pr.h"
41*6fa5bf08SBaptiste Daroussin #include "diff.h"
42*6fa5bf08SBaptiste Daroussin #include "xmalloc.h"
43*6fa5bf08SBaptiste Daroussin 
44*6fa5bf08SBaptiste Daroussin #define _PATH_PR "/usr/bin/pr"
45*6fa5bf08SBaptiste Daroussin 
46*6fa5bf08SBaptiste Daroussin struct pr *
47*6fa5bf08SBaptiste Daroussin start_pr(char *file1, char *file2)
48*6fa5bf08SBaptiste Daroussin {
49*6fa5bf08SBaptiste Daroussin 	int pfd[2];
50*6fa5bf08SBaptiste Daroussin 	int pr_pd;
51*6fa5bf08SBaptiste Daroussin 	pid_t pid;
52*6fa5bf08SBaptiste Daroussin 	char *header;
53*6fa5bf08SBaptiste Daroussin 	struct pr *pr;
54*6fa5bf08SBaptiste Daroussin 
55*6fa5bf08SBaptiste Daroussin 	pr = xcalloc(1, sizeof(*pr));
56*6fa5bf08SBaptiste Daroussin 
57*6fa5bf08SBaptiste Daroussin 	xasprintf(&header, "%s %s %s", diffargs, file1, file2);
58*6fa5bf08SBaptiste Daroussin 	signal(SIGPIPE, SIG_IGN);
59*6fa5bf08SBaptiste Daroussin 	fflush(stdout);
60*6fa5bf08SBaptiste Daroussin 	rewind(stdout);
61*6fa5bf08SBaptiste Daroussin 	pipe(pfd);
62*6fa5bf08SBaptiste Daroussin 	switch ((pid = pdfork(&pr_pd, PD_CLOEXEC))) {
63*6fa5bf08SBaptiste Daroussin 	case -1:
64*6fa5bf08SBaptiste Daroussin 		status |= 2;
65*6fa5bf08SBaptiste Daroussin 		free(header);
66*6fa5bf08SBaptiste Daroussin 		err(2, "No more processes");
67*6fa5bf08SBaptiste Daroussin 	case 0:
68*6fa5bf08SBaptiste Daroussin 		/* child */
69*6fa5bf08SBaptiste Daroussin 		if (pfd[0] != STDIN_FILENO) {
70*6fa5bf08SBaptiste Daroussin 			dup2(pfd[0], STDIN_FILENO);
71*6fa5bf08SBaptiste Daroussin 			close(pfd[0]);
72*6fa5bf08SBaptiste Daroussin 		}
73*6fa5bf08SBaptiste Daroussin 		close(pfd[1]);
74*6fa5bf08SBaptiste Daroussin 		execl(_PATH_PR, _PATH_PR, "-h", header, (char *)0);
75*6fa5bf08SBaptiste Daroussin 		_exit(127);
76*6fa5bf08SBaptiste Daroussin 	default:
77*6fa5bf08SBaptiste Daroussin 
78*6fa5bf08SBaptiste Daroussin 		/* parent */
79*6fa5bf08SBaptiste Daroussin 		if (pfd[1] != STDOUT_FILENO) {
80*6fa5bf08SBaptiste Daroussin 			pr->ostdout = dup(STDOUT_FILENO);
81*6fa5bf08SBaptiste Daroussin 			dup2(pfd[1], STDOUT_FILENO);
82*6fa5bf08SBaptiste Daroussin 			close(pfd[1]);
83*6fa5bf08SBaptiste Daroussin 			close(pfd[1]);
84*6fa5bf08SBaptiste Daroussin 			}
85*6fa5bf08SBaptiste Daroussin 			close(pfd[0]);
86*6fa5bf08SBaptiste Daroussin 			rewind(stdout);
87*6fa5bf08SBaptiste Daroussin 			free(header);
88*6fa5bf08SBaptiste Daroussin 			pr->kq = kqueue();
89*6fa5bf08SBaptiste Daroussin 			if (pr->kq == -1)
90*6fa5bf08SBaptiste Daroussin 				err(2, "kqueue");
91*6fa5bf08SBaptiste Daroussin 			pr->e = xmalloc(sizeof(struct kevent));
92*6fa5bf08SBaptiste Daroussin 			EV_SET(pr->e, pr_pd, EVFILT_PROCDESC, EV_ADD, NOTE_EXIT, 0,
93*6fa5bf08SBaptiste Daroussin 			    NULL);
94*6fa5bf08SBaptiste Daroussin 			if (kevent(pr->kq, pr->e, 1, NULL, 0, NULL) == -1)
95*6fa5bf08SBaptiste Daroussin 				err(2, "kevent");
96*6fa5bf08SBaptiste Daroussin 	}
97*6fa5bf08SBaptiste Daroussin 	return (pr);
98*6fa5bf08SBaptiste Daroussin }
99*6fa5bf08SBaptiste Daroussin 
100*6fa5bf08SBaptiste Daroussin /* close the pipe to pr and restore stdout */
101*6fa5bf08SBaptiste Daroussin void
102*6fa5bf08SBaptiste Daroussin stop_pr(struct pr *pr)
103*6fa5bf08SBaptiste Daroussin {
104*6fa5bf08SBaptiste Daroussin 	int wstatus;
105*6fa5bf08SBaptiste Daroussin 
106*6fa5bf08SBaptiste Daroussin 	if (pr == NULL)
107*6fa5bf08SBaptiste Daroussin 		return;
108*6fa5bf08SBaptiste Daroussin 
109*6fa5bf08SBaptiste Daroussin 	fflush(stdout);
110*6fa5bf08SBaptiste Daroussin 	if (pr->ostdout != STDOUT_FILENO) {
111*6fa5bf08SBaptiste Daroussin 		close(STDOUT_FILENO);
112*6fa5bf08SBaptiste Daroussin 		dup2(pr->ostdout, STDOUT_FILENO);
113*6fa5bf08SBaptiste Daroussin 		close(pr->ostdout);
114*6fa5bf08SBaptiste Daroussin 	}
115*6fa5bf08SBaptiste Daroussin 	if (kevent(pr->kq, NULL, 0, pr->e, 1, NULL) == -1)
116*6fa5bf08SBaptiste Daroussin 		err(2, "kevent");
117*6fa5bf08SBaptiste Daroussin 	wstatus = pr->e[0].data;
118*6fa5bf08SBaptiste Daroussin 	close(pr->kq);
119*6fa5bf08SBaptiste Daroussin 	if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) != 0)
120*6fa5bf08SBaptiste Daroussin 		errx(2, "pr exited abnormally");
121*6fa5bf08SBaptiste Daroussin 	else if (WIFSIGNALED(wstatus))
122*6fa5bf08SBaptiste Daroussin 		errx(2, "pr killed by signal %d",
123*6fa5bf08SBaptiste Daroussin 		    WTERMSIG(wstatus));
124*6fa5bf08SBaptiste Daroussin }
125