1 /*
2  * CDDL HEADER START
3  *
4  * This file and its contents are supplied under the terms of the
5  * Common Development and Distribution License ("CDDL"), version 1.0.
6  * You may use this file only in accordance with the terms of version
7  * 1.0 of the CDDL.
8  *
9  * A full copy of the text of the CDDL should have accompanied this
10  * source.  A copy of the CDDL is also available via the Internet at
11  * http://www.opensource.org/licenses/cddl1.txt
12  * See the License for the specific language governing permissions
13  * and limitations under the License.
14  *
15  * When distributing Covered Code, include this CDDL HEADER in each
16  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17  * If applicable, add the following below this CDDL HEADER, with the
18  * fields enclosed by brackets "[]" replaced with your own identifying
19  * information: Portions Copyright [yyyy] [name of copyright owner]
20  *
21  * CDDL HEADER END
22  */
23 /*
24  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
25  * Use is subject to license terms.
26  */
27 /*
28  * @(#)report.cc 1.17 06/12/12
29  */
30 
31 #pragma	ident	"@(#)report.cc	1.17	06/12/12"
32 
33 /*
34  * Copyright 2017-2021 J. Schilling
35  *
36  * @(#)report.cc	1.13 21/08/15 2017-2021 J. Schilling
37  */
38 #include <schily/mconfig.h>
39 #ifndef lint
40 static	UConst char sccsid[] =
41 	"@(#)report.cc	1.13 21/08/15 2017-2021 J. Schilling";
42 #endif
43 
44 #if defined(SCHILY_BUILD) || defined(SCHILY_INCLUDES)
45 #include <schily/stdio.h>
46 #include <schily/stdlib.h>
47 #include <schily/string.h>
48 #include <schily/param.h>
49 #include <schily/wait.h>
50 #include <schily/unistd.h>
51 #else
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <sys/param.h>
56 #include <sys/wait.h>
57 #include <unistd.h>
58 #define	WAIT_T	int
59 #endif
60 
61 #include <vroot/report.h>
62 #include <vroot/vroot.h>
63 #include <avo/intl.h>	/* for NOCATGETS */
64 #include <mk/defs.h>	/* for tmpdir */
65 
66 static	FILE	*report_file;
67 static	FILE	*command_output_fp;
68 static	char	*target_being_reported_for;
69 static	char	*search_dir;
70 static  char	command_output_tmpfile[30];
71 static	int	is_path = 0;
72 static	char	sfile[MAXPATHLEN];
73 extern "C" {
74 static	void	(*warning_ptr) (char *, ...) = (void (*) (char *, ...)) NULL;
75 }
76 
77 FILE *
get_report_file(void)78 get_report_file(void)
79 {
80 	return(report_file);
81 }
82 
83 char *
get_target_being_reported_for(void)84 get_target_being_reported_for(void)
85 {
86 	return(target_being_reported_for);
87 }
88 
89 #ifdef	HAVE_ATEXIT
90 extern "C" {
91 static void
close_report_file(void)92 close_report_file(void)
93 {
94 	(void)fputs("\n", report_file);
95 	(void)fclose(report_file);
96 }
97 } // extern "C"
98 #else
99 static void
close_report_file(int,...)100 close_report_file(int, ...)
101 {
102 	(void)fputs("\n", report_file);
103 	(void)fclose(report_file);
104 }
105 #endif
106 
107 static void
clean_up(FILE * nse_depinfo_fp,FILE * merge_fp,char * nse_depinfo_file,char * merge_file,int unlinkf)108 clean_up(FILE *nse_depinfo_fp, FILE *merge_fp, char *nse_depinfo_file, char *merge_file, int unlinkf)
109 {
110 	fclose(nse_depinfo_fp);
111 	fclose(merge_fp);
112 	fclose(command_output_fp);
113 	unlink(command_output_tmpfile);
114 	if (unlinkf)
115 		unlink(merge_file);
116 	else
117 		rename(merge_file, nse_depinfo_file);
118 }
119 
120 
121 /*
122  *  Update the file, if necessary.  We don't want to rewrite
123  *  the file if we don't have to because we don't want the time of the file
124  *  to change in that case.
125  */
126 extern "C" {
127 #ifdef	HAVE_ATEXIT
128 static void
close_file(void)129 close_file(void)
130 #else
131 static void
132 close_file(int, ...)
133 #endif
134 {
135 	char		line[MAXPATHLEN+2];
136 	char		buf[MAXPATHLEN+2];
137 	FILE		*nse_depinfo_fp;
138 	FILE		*merge_fp;
139 	char		nse_depinfo_file[MAXPATHLEN];
140 	char		merge_file[MAXPATHLEN];
141 	char		lock_file[MAXPATHLEN];
142 	int		err;
143 	int		len;
144 	int		changed = 0;
145 	int		file_locked;
146 
147 	fprintf(command_output_fp, "\n");
148 	fclose(command_output_fp);
149 	if ((command_output_fp = fopen(command_output_tmpfile, "r")) == NULL) {
150 		return;
151 	}
152 	sprintf(nse_depinfo_file, "%s/%s", search_dir, NSE_DEPINFO);
153 	sprintf(merge_file, NOCATGETS("%s/.tmp%s.%d"), search_dir, NSE_DEPINFO, getpid());
154 	sprintf(lock_file, "%s/%s", search_dir, NSE_DEPINFO_LOCK);
155 	err = file_lock(nse_depinfo_file, lock_file, &file_locked, 0);
156 	if (err) {
157 		if (warning_ptr != (void (*) (char *, ...)) NULL) {
158 			(*warning_ptr)(gettext("Couldn't write to %s"), nse_depinfo_file);
159                       }
160 		unlink(command_output_tmpfile);
161 		return;
162 	}
163 	/* If .nse_depinfo file doesn't exist */
164 	if ((nse_depinfo_fp = fopen(nse_depinfo_file, "r+")) == NULL) {
165 		if (is_path) {
166 			if ((nse_depinfo_fp =
167 			     fopen(nse_depinfo_file, "w")) == NULL) {
168 				fprintf(stderr, gettext("Cannot open `%s' for writing\n"),
169 				    nse_depinfo_file);
170 				unlink(command_output_tmpfile);
171 
172 				unlink(lock_file);
173 				return;
174 			}
175 			while (fgets(line, MAXPATHLEN+2, command_output_fp)
176 			       != NULL) {
177 				fprintf(nse_depinfo_fp, "%s", line);
178 			}
179 			fclose(command_output_fp);
180 		}
181 		fclose(nse_depinfo_fp);
182 		if (file_locked) {
183 			unlink(lock_file);
184 		}
185 		unlink(command_output_tmpfile);
186 		return;
187 	}
188 	if ((merge_fp = fopen(merge_file, "w")) == NULL) {
189 		fprintf(stderr, gettext("Cannot open %s for writing\n"), merge_file);
190 		if (file_locked) {
191 			unlink(lock_file);
192 		}
193 		unlink(command_output_tmpfile);
194 		return;
195 	}
196 	len = strlen(sfile);
197 	while (fgets(line, MAXPATHLEN+2, nse_depinfo_fp) != NULL) {
198 		if (strncmp(line, sfile, len) == 0 && line[len] == ':') {
199 			while (fgets(buf, MAXPATHLEN+2, command_output_fp)
200 			       != NULL) {
201 				if (is_path) {
202 					fprintf(merge_fp, "%s", buf);
203 					if (strcmp(line, buf)) {
204 						/* changed */
205 						changed = 1;
206 					}
207 				}
208 				if (buf[strlen(buf)-1] == '\n') {
209 					break;
210 				}
211 			}
212 			if (changed || !is_path) {
213 				while (fgets(line, MAXPATHLEN, nse_depinfo_fp)
214 				       != NULL) {
215 					fputs(line, merge_fp);
216 				}
217 				clean_up(nse_depinfo_fp, merge_fp,
218 					 nse_depinfo_file, merge_file, 0);
219 			} else {
220 				clean_up(nse_depinfo_fp, merge_fp,
221 					 nse_depinfo_file, merge_file, 1);
222 			}
223 			if (file_locked) {
224 				unlink(lock_file);
225 			}
226 			unlink(command_output_tmpfile);
227 			return;
228 		} /* entry found */
229 		fputs(line, merge_fp);
230 	}
231 	/* Entry never found.  Add it if there is a search path */
232 	if (is_path) {
233 		while (fgets(line, MAXPATHLEN+2, command_output_fp) != NULL) {
234 			fprintf(nse_depinfo_fp, "%s", line);
235 		}
236 	}
237 	clean_up(nse_depinfo_fp, merge_fp, nse_depinfo_file, merge_file, 1);
238 	if (file_locked) {
239 		unlink(lock_file);
240 	}
241 }
242 
243 } // extern "C"
244 
245 static void
report_dep(char * iflag,char * filename)246 report_dep(char *iflag, char *filename)
247 {
248 
249 	if (command_output_fp == NULL) {
250 		sprintf(command_output_tmpfile,
251 			NOCATGETS("%s/%s.%d.XXXXXX"), tmpdir, NSE_DEPINFO, getpid());
252 		int fd = mkstemp(command_output_tmpfile);
253 		if ((fd < 0) || (command_output_fp = fdopen(fd, "w")) == NULL) {
254 			return;
255 		}
256 		if ((search_dir = getenv(NOCATGETS("NSE_DEP"))) == NULL) {
257 			return;
258 		}
259 #ifdef	HAVE_ATEXIT
260 		atexit(close_file);
261 #else
262 		on_exit(close_file, 0);
263 #endif
264 		strcpy(sfile, filename);
265 		if (iflag == NULL || *iflag == '\0') {
266 			return;
267 		}
268 		fprintf(command_output_fp, "%s:", sfile);
269 	}
270 	fprintf(command_output_fp, " ");
271 	fprintf(command_output_fp, "%s", iflag);
272 	if (iflag != NULL) {
273 		is_path = 1;
274 	}
275 }
276 
277 void
report_libdep(char * lib,char * flag)278 report_libdep(char *lib, char *flag)
279 {
280 	char		*ptr;
281 	char		filename[MAXPATHLEN];
282 	char		*p;
283 
284 	if ((p= getenv(SUNPRO_DEPENDENCIES)) == NULL) {
285 		return;
286 	}
287 	ptr = strchr(p, ' ');
288 	if(ptr) {
289 		sprintf(filename, "%s-%s", ptr+1, flag);
290 		is_path = 1;
291 		report_dep(lib, filename);
292 	}
293 }
294 
295 void
report_search_path(char * iflag)296 report_search_path(char *iflag)
297 {
298 	char		curdir[MAXPATHLEN];
299 	char		*sdir;
300 	char		*newiflag;
301 	char		filename[MAXPATHLEN];
302 	char		*p, *ptr;
303 
304 	if ((sdir = getenv(NOCATGETS("NSE_DEP"))) == NULL) {
305 		return;
306 	}
307 	if ((p= getenv(SUNPRO_DEPENDENCIES)) == NULL) {
308 		return;
309 	}
310 	ptr = strchr(p, ' ');
311 	if( ! ptr ) {
312 		return;
313 	}
314 	sprintf(filename, NOCATGETS("%s-CPP"), ptr+1);
315 	if (getcwd(curdir, sizeof(curdir)) == NULL)
316 		curdir[0] = nul_char;
317 	if (strcmp(curdir, sdir) != 0 && strlen(iflag) > 2 &&
318 	    iflag[2] != '/') {
319 		/* Makefile must have had an "cd xx; cc ..." */
320 		/* Modify the -I path to be relative to the cd */
321 		newiflag = (char *)malloc(strlen(iflag) + strlen(curdir) + 2);
322 		sprintf(newiflag, "-%c%s/%s", iflag[1], curdir, &iflag[2]);
323 		report_dep(newiflag, filename);
324 		free(newiflag);
325 	} else {
326 		report_dep(iflag, filename);
327 	}
328 }
329 
330 void
report_dependency(register const char * name)331 report_dependency(register const char *name)
332 {
333 	register char	*filename;
334 	char		buffer[MAXPATHLEN+1];
335 	register char	*p;
336 	register char	*p2;
337 	char		nse_depinfo_file[MAXPATHLEN];
338 
339 	if (report_file == NULL) {
340 		if ((filename= getenv(SUNPRO_DEPENDENCIES)) == NULL) {
341 			report_file = (FILE *)-1;
342 			return;
343 		}
344 		if (strlen(filename) == 0) {
345 			report_file = (FILE *)-1;
346 			return;
347 		}
348 		(void)strcpy(buffer, name);
349 		name = buffer;
350 		p = strchr(filename, ' ');
351 		if(p) {
352 			*p= 0;
353 		} else {
354 			report_file = (FILE *)-1;
355 			return;
356 		}
357 		if ((report_file= fopen(filename, "a")) == NULL) {
358 			if ((report_file= fopen(filename, "w")) == NULL) {
359 				report_file= (FILE *)-1;
360 				return;
361 			}
362 		}
363 #ifdef	HAVE_ATEXIT
364 		atexit(close_report_file);
365 #else
366 		(void)on_exit(close_report_file, (char *)report_file);
367 #endif
368 		if ((p2= strchr(p+1, ' ')) != NULL)
369 			*p2= 0;
370 		target_being_reported_for= (char *)malloc((unsigned)(strlen(p+1)+1));
371 		(void)strcpy(target_being_reported_for, p+1);
372 		(void)fputs(p+1, report_file);
373 		(void)fputs(":", report_file);
374 		*p= ' ';
375 		if (p2 != NULL)
376 			*p2= ' ';
377 	}
378 	if (report_file == (FILE *)-1)
379 		return;
380 	(void)fputs(name, report_file);
381 	(void)fputs(" ", report_file);
382 }
383 
384 #ifdef MAKE_IT
385 void
386 make_it(filename)
387 	register char	*filename;
388 {
389 	register char	*command;
390 	register char	*argv[6];
391 	register int	pid;
392 	WAIT_T		foo;
393 
394 	if (getenv(SUNPRO_DEPENDENCIES) == NULL) return;
395 	command= alloca(strlen(filename)+32);
396 	(void)sprintf(command, NOCATGETS("make %s\n"), filename);
397 	switch (pid= fork()) {
398 		case 0: /* child */
399 			argv[0]= NOCATGETS("csh");
400 			argv[1]= NOCATGETS("-c");
401 			argv[2]= command;
402 			argv[3]= 0;
403 			(void)dup2(2, 1);
404 			execve(NOCATGETS("/bin/sh"), argv, environ);
405 			perror(NOCATGETS("execve error"));
406 			exit(1);
407 		case -1: /* error */
408 			perror(NOCATGETS("fork error"));
409 		default: /* parent */
410 			while (wait(&foo) != pid);};
411 }
412 #endif
413 
414