1 /* utftpd_rcs: rcs support functions */
2 
3 /*
4  * Copyright (C) 1999 Uwe Ohse
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20 
21 #include "config.h"
22 #include <sys/types.h>
fz(const densvars<num> & d)23 #include <sys/ioctl.h>
24 #include <sys/stat.h>
25 #include <signal.h>
26 #include <fcntl.h>
27 
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include "no_tftp.h"
31 #include <netdb.h>
32 #include <pwd.h>
33 #include <grp.h>
34 
35 #include <setjmp.h>
36 #include <syslog.h>
37 #include <errno.h>
38 #include <ctype.h>
39 #include <sys/wait.h>
40 #include <string.h>
41 #include <stdlib.h>
42 #include <unistd.h>
43 #include "uogetopt.h"
44 #include "timselsysdep.h"
45 #include "nonblock.h"
46 #include "str2num.h"
47 #include "uostr.h"
48 #include "uoio.h"
49 #include "sys/wait.h"
50 #include "wildmat.h"
51 #include "utftpd.h"
52 #include "str_ulong.h"
53 
54 static int
55 utftpd_rcs_test(const char *filename, struct utftpd_ctrl *flags)
56 {
57 	const char *slash;
58 	static uostr_t s=UOSTR_INIT;
59 	size_t pos;
60 	struct stat st;
61 	if (!opt_rcs_co || !opt_rcs_ci) return -1;
62 	slash=strrchr(filename,'/');
63 	if (!uostr_dup_mem(&s,filename,slash-filename+1)) goto oom;
64 	pos=s.len;
65 	/* try to get an RCS file */
66 	if (!uostr_add_cstr(&s,"RCS/")) goto oom;
67 	if (!uostr_add_cstr(&s,slash+1)) goto oom;
68 	if (!uostr_add_mem(&s,",v",3)) goto oom; /* \0 */
69 	if (0==stat(s.data,&st)) {
70 		return 0;
71 	}
72 	return 1; /* this file is not under RCS */
73   oom:
74   	syslog(LOG_ERR,"out of memory");
75 	do_nak(flags->remotefd,EUNDEF,"out of memory");
76 	_exit(1); return 0; /* supress useless warning */
77 }
78 
79 /*
80  * this is very easy compared to SCCS, since RCS by default does not
81  * create a new revision when checking in unchanged files.
82  */
83 static int
84 utftpd_rcs_ci(const char *comment, struct utftpd_ctrl *flags)
85 {
86 	const char *slash;
87 	static uostr_t s=UOSTR_INIT;
88 	size_t pos;
89 	const char *er;
90 	pid_t pid;
91 
92 	slash=strrchr(flags->filename,'/');
93 	if (!uostr_dup_mem(&s,flags->filename,slash-flags->filename+1)) goto oom;
94 	pos=s.len;
95 	/* try to get an RCS file */
96 	if (!uostr_add_cstr(&s,"RCS/")) goto oom;
97 	if (!uostr_add_cstr(&s,slash+1)) goto oom;
98 	if (!uostr_add_mem(&s,",v",3)) goto oom; /* \0 */
99 
100 	/* the top level closed the file */
101 	pid=fork();
102 	if (pid==0) {
103 		static uostr_t co=UOSTR_INIT;
104 		union {const char **a1; char *const *a2;} d;
105 		const char *argv[5];
106 		int oc=0;
107 		uostr_xdup_cstr(&co,"-mby utftpd for ");
108 		uostr_xadd_cstr(&co,remoteip);
109 		uostr_xadd_cstr(&co," ");
110 		if (comment) {
111 			uostr_xadd_cstr(&co," ");
112 			uostr_xadd_cstr(&co,comment);
113 		}
114 		uostr_xadd_mem(&co,"",1);
115 		uostr_cut(&s,pos); uostr_add_mem(&s,"",1);
116 		if (-1==chdir(s.data)) _exit(1);
117 		if (-1==dup2(nullfd,2)) _exit(1);
118 		argv[oc++]="ci";
119 		if (flags->revision) {
120 			static uostr_t rev=UOSTR_INIT;
121 			if (!uostr_add_cstr(&rev,"-r")) _exit(1);
122 			if (!uostr_add_cstr(&rev,flags->revision)) _exit(1);
123 			if (!uostr_add_mem(&rev,"",1)) _exit(1);
124 			argv[oc++]=rev.data;
125 		}
126 		argv[oc++]=co.data;
127 		argv[oc]=strdup(slash+1);
128 		if (!argv[oc++]) _exit(1);
129 		argv[oc++]=0;
130 		d.a1=argv;
131 		execv(opt_rcs_ci,d.a2);
132 		_exit(1);
133 	} else if (pid==-1) {
134 		er=strerror(errno);
135 		syslog(LOG_ERR,"can't fork: %s",er);
136 		do_nak(flags->remotefd,EUNDEF,er);
137 		_exit(1);
138 	} else {
139 		int fail=wait_check_and_log(pid);
140 		if (fail) {
141 			syslog(LOG_ERR,"version control system failed");
142 			do_nak(flags->remotefd,EUNDEF,"version control system failed");
143 			_exit(1);
144 		}
145 	}
146 	return 0;
147   oom:
148   	syslog(LOG_ERR,"out of memory");
149 	do_nak(flags->remotefd,EUNDEF,"out of memory");
150 	_exit(1); return 0; /* supress useless warning */
151 }
152 
153 /* this is almost the same than try_sccs_get,
154  * but with slight differences in file name
155  * mangling and options.
156  */
157 static int
158 utftpd_rcs_co(int mode, struct utftpd_ctrl *flags)
159 {
160 	const char *slash;
161 	static uostr_t s=UOSTR_INIT;
162 	size_t pos;
163 
164 	const char *er;
165 	int fds[2];
166 	pid_t pid;
167 
168 	if (!opt_rcs_co || !opt_rcs_ci) return 0;
169 	slash=strrchr(flags->filename,'/');
170 	if (!uostr_dup_mem(&s,flags->filename,slash-flags->filename+1)) goto oom;
171 	pos=s.len;
172 	/* try to get an RCS file */
173 	if (!uostr_add_cstr(&s,"RCS/")) goto oom;
174 	if (!uostr_add_cstr(&s,slash+1)) goto oom;
175 	if (!uostr_add_mem(&s,",v",3)) goto oom; /* \0 */
176 
177 	if (mode==TSG_READ && -1==pipe(fds)) {
178 		er=strerror(errno);
179 		syslog(LOG_ERR,"pipe: %s",er);
180 		do_nak(flags->remotefd,EUNDEF,er);
181 		_exit(1);
182 	}
183 
184 	pid=fork();
185 	if (pid==0) {
186 		union {const char **a1; char *const *a2;} d;
187 		const char *argv[10]; /* 6 */
188 		int oc=0;
189 		uostr_cut(&s,pos); uostr_add_mem(&s,"",1);
190 		if (-1==chdir(s.data)) _exit(1);
191 		if (-1==dup2(nullfd,2)) _exit(1);
192 		if (mode == TSG_READ && -1==dup2(fds[1],1)) _exit(1);
193 		argv[oc++]="co";
194 		/* check out a specific revision only if it not for a "write" request */
195 		if (mode==TSG_WRITE) argv[oc++]="-l";
196 		else if (flags->revision) {
197 			static uostr_t rev=UOSTR_INIT;
198 			if (!uostr_add_cstr(&rev,"-r")) _exit(1);
199 			if (!uostr_add_cstr(&rev,flags->revision)) _exit(1);
200 			if (!uostr_add_mem(&rev,"",1)) _exit(1);
201 			argv[oc++]=rev.data;
202 		}
203 		if (mode==TSG_READ) {
204 			argv[oc++]="-p";
205 			close(fds[0]);
206 		}
207 		argv[oc++]=strdup(slash+1);
208 		if (!argv[oc-1]) _exit(1);
209 		argv[oc]=0;
210 		d.a1=argv;
211 		execv(opt_rcs_co,d.a2);
212 		_exit(1);
213 	} else if (pid==-1) {
214 		er=strerror(errno);
215 		syslog(LOG_ERR,"can't fork: %s",er);
216 		do_nak(flags->remotefd,EUNDEF,er);
217 		_exit(1);
218 	} else  {
219 		if (mode==TSG_READ) {
220 			flags->pid=pid;
221 			flags->filefd=fds[0];
222 			close(fds[1]);
223 		} else {
224 			pid=waitpid(pid,0,0);
225 #define ADD_ON 0
226 #ifndef HAVE_FSYNC
227 # ifdef (O_SYNC)
228 #  undef ADD_ON
229 #  define ADD_ON O_SYNC
230 # endif
231 #endif
232 			flags->filefd=open(flags->filename,O_WRONLY|O_TRUNC|ADD_ON,0644);
233 			if (flags->filefd!=-1) return 0;
234 			syslog(LOG_ERR,"version control system failed, cannot open %s: %s",flags->filename,strerror(errno));
235 			do_nak(flags->remotefd,EUNDEF,"version control system failed");
236 			_exit(1);
237 		}
238 	}
239 
240 	return 0;
241   oom:
242   	syslog(LOG_ERR,"out of memory");
243 	do_nak(flags->remotefd,EUNDEF,"out of memory");
244 	_exit(1); return 0; /* suppress useless warning */
245 }
246 
247 struct utftpd_vc utftpd_rcs={
248 	utftpd_rcs_test,
249 	utftpd_rcs_ci,
250 	utftpd_rcs_co,
251 	NULL
252 };
253 
254