1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/types.h>
32 #include <sys/wait.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <pkgstrct.h>
36 #include <unistd.h>
37 #include <pkglib.h>
38 #include <libintl.h>
39 #include "libadm.h"
40 #include "libinst.h"
41 #include "dryrun.h"
42 
43 #define	HDR_FSUSAGE	"#name remote_name writeable bfree bused ifree iused"
44 
45 #define	ERR_NOCREAT	"cannot create %s."
46 #define	ERR_NOOPEN	"cannot open %s."
47 #define	ERR_NOWRITE	"cannot write to %s."
48 #define	ERR_NOREAD	"cannot read from %s."
49 #define	ERR_FSFAIL	"cannot construct filesystem table entry."
50 #define	ERR_BADTYPE	"cannot record %s dryrun from %s continuation file."
51 #define	ERR_NOCONT	"cannot install from continue file due to error " \
52 			    "stacking."
53 
54 #define	ISUMASC_SUFFIX	".isum.asc"
55 #define	FSASC_SUFFIX	".fs.asc"
56 #define	IPOASC_SUFFIX	".ipo.asc"
57 #define	IBIN_SUFFIX	".inst.bin"
58 
59 #define	MALCOUNT	5	/* package entries to allocate in a block */
60 #define	PKGNAMESIZE	32	/* package entries to allocate in a block */
61 
62 extern struct cfextra **extlist;
63 extern char *pkginst;
64 
65 static struct cfextra **extptr;
66 static int	dryrun_mode = 0;
67 static int	continue_mode = 0;
68 static int	this_exitcode = 0;
69 
70 /* The dryrun and continuation filenames */
71 static char *dryrun_sumasc;
72 static char *dryrun_fsasc;
73 static char *dryrun_poasc;
74 static char *dryrun_bin;
75 static char *continue_bin;
76 
77 /* These tell us if the actual files are initialized yet. */
78 static int dryrun_initialized = 0;
79 static int continue_initialized = 0;
80 
81 static int this_type;		/* type of transaction from main.c */
82 
83 static int pkg_handle = -1;
84 static int tot_pkgs;
85 
86 /* Their associated file pointers */
87 static FILE *fp_dra;
88 static int fd_drb;
89 static int fd_cnb;
90 
91 struct dr_pkg_entry {
92 	char pkginst[PKGNAMESIZE + 2];
93 	struct dr_pkg_entry *next;
94 };
95 
96 static struct drinfo {
97 	unsigned partial_set:1;	/* 1 if a partial installation was detected. */
98 	unsigned partial:1;	/* 1 if a partial installation was detected. */
99 	unsigned runlevel_set:1;
100 	unsigned runlevel:1;	/* 1 if runlevel test returned an error. */
101 	unsigned pkgfiles_set:1;
102 	unsigned pkgfiles:1;
103 	unsigned depend_set:1;
104 	unsigned depend:1;
105 	unsigned space_set:1;
106 	unsigned space:1;
107 	unsigned conflict_set:1;
108 	unsigned conflict:1;
109 	unsigned setuid_set:1;
110 	unsigned setuid:1;
111 	unsigned priv_set:1;
112 	unsigned priv:1;
113 	unsigned pkgdirs_set:1;
114 	unsigned pkgdirs:1;
115 	unsigned reqexit_set:1;
116 	unsigned checkexit_set:1;
117 
118 	int	type;		/* type of operation */
119 	int	reqexit;	/* request script exit code */
120 	int	checkexit;	/* checkinstall script exit code */
121 	int	exitcode;	/* overall program exit code. */
122 
123 	struct dr_pkg_entry *packages;	/* pointer to the list of packages */
124 
125 	int total_ext_recs;	/* total extlist entries */
126 	int total_fs_recs;	/* total fs_tab entries */
127 	int total_pkgs;		/* total number of dryrun packages */
128 	int do_not_continue;	/* error stacking is likely */
129 } dr_info;
130 
131 static char	*exitmsg;	/* the last meaningful message printed */
132 
133 /*
134  * In the event that live continue (continue from a dryrun source only)
135  * becomes a feature, it will be necessary to keep track of those events such
136  * as multiply edited files and files dependent upon multiple class action
137  * scripts that will lead to "tolerance stacking". Calling this function
138  * states that we've lost the level of precision necessary for a live
139  * continue.
140  */
141 void
set_continue_not_ok(void)142 set_continue_not_ok(void)
143 {
144 	dr_info.do_not_continue = 1;
145 }
146 
147 int
continue_is_ok(void)148 continue_is_ok(void)
149 {
150 	return (!dr_info.do_not_continue);
151 }
152 
153 static void
wr_OK(FILE * fp,char * parameter,int set,int value)154 wr_OK(FILE *fp, char *parameter, int set, int value)
155 {
156 	(void) fprintf(fp, "%s=%s\n", parameter,
157 		(set ? (value ? "OK" : "NOT_OK") : "NOT_TESTED"));
158 }
159 
160 static void
add_pkg_to_list(char * pkgname)161 add_pkg_to_list(char *pkgname)
162 {
163 	struct dr_pkg_entry **pkg_entry;
164 
165 	if (pkg_handle == -1) {
166 		if ((pkg_handle = bl_create(MALCOUNT,
167 		    sizeof (struct dr_pkg_entry), "package dryrun")) == -1)
168 			return;
169 	}
170 
171 	pkg_entry = &(dr_info.packages);
172 
173 	while (*pkg_entry != NULL)
174 		pkg_entry = &((*pkg_entry)->next);
175 
176 	/* LINTED pointer cast may result in improper alignment */
177 	*pkg_entry = (struct dr_pkg_entry *)bl_next_avail(pkg_handle);
178 	dr_info.total_pkgs++;
179 
180 	(void) snprintf((*pkg_entry)->pkginst, PKGNAMESIZE, "%s%s",
181 		(pkgname ? pkgname : ""), ((this_exitcode == 0) ? "" : "-"));
182 }
183 
184 static void
write_pkglist_ascii(void)185 write_pkglist_ascii(void)
186 {
187 	struct dr_pkg_entry *pkg_entry;
188 
189 	(void) fprintf(fp_dra, "PKG_LIST=\"");
190 
191 	pkg_entry = dr_info.packages;
192 	while (pkg_entry) {
193 		(void) fprintf(fp_dra, " %s", pkg_entry->pkginst);
194 		pkg_entry = pkg_entry->next;
195 	}
196 
197 	(void) fprintf(fp_dra, "\"\n");
198 }
199 
200 static int
write_string(int fd,char * string)201 write_string(int fd, char *string)
202 {
203 	int string_size;
204 
205 	if (string)
206 		string_size = strlen(string) + 1;
207 	else
208 		string_size = 0;
209 
210 	if (write(fd, &string_size, sizeof (string_size)) == -1) {
211 		progerr(gettext(ERR_NOWRITE), dryrun_bin);
212 		return (0);
213 	}
214 
215 	if (string_size > 0) {
216 		if (write(fd, string, string_size) == -1) {
217 			progerr(gettext(ERR_NOWRITE), dryrun_bin);
218 			return (0);
219 		}
220 	}
221 
222 	return (1);
223 }
224 
225 static char *
read_string(int fd,char * buffer)226 read_string(int fd, char *buffer)
227 {
228 	size_t string_size;
229 
230 	if (read(fd, &(string_size), sizeof (string_size)) == -1) {
231 		progerr(gettext(ERR_NOREAD), continue_bin);
232 		return (NULL);
233 	}
234 
235 	if (string_size != 0) {
236 		if (read(fd, buffer, string_size) == -1) {
237 			progerr(gettext(ERR_NOREAD), continue_bin);
238 			return (NULL);
239 		}
240 	} else {
241 		return (NULL);
242 	}
243 
244 	return (buffer);
245 }
246 
247 static void
write_dryrun_ascii()248 write_dryrun_ascii()
249 {
250 	int n;
251 	char *fs_mntpt, *src_name;
252 
253 	if ((fp_dra = fopen(dryrun_sumasc, "wb")) == NULL) {
254 		progerr(gettext(ERR_NOOPEN), dryrun_sumasc);
255 		return;
256 	}
257 
258 	(void) fprintf(fp_dra, "DR_TYPE=%s\n", (dr_info.type == REMOVE_TYPE ?
259 	    "REMOVE" : "INSTALL"));
260 
261 	(void) fprintf(fp_dra, "PKG_INSTALL_ROOT=%s\n", (((get_inst_root()) &&
262 	    (strcmp(get_inst_root(), "/") != 0)) ?
263 	    get_inst_root() : ""));
264 
265 	write_pkglist_ascii();
266 
267 	wr_OK(fp_dra, "CONTINUE", 1, !(dr_info.do_not_continue));
268 
269 	wr_OK(fp_dra, "PARTIAL", dr_info.partial_set, dr_info.partial);
270 
271 	wr_OK(fp_dra, "RUNLEVEL", dr_info.runlevel_set, dr_info.runlevel);
272 
273 	(void) fprintf(fp_dra, "REQUESTEXITCODE=%d\n", dr_info.reqexit);
274 
275 	(void) fprintf(fp_dra, "CHECKINSTALLEXITCODE=%d\n", dr_info.checkexit);
276 
277 	wr_OK(fp_dra, "PKGFILES", dr_info.pkgfiles_set, dr_info.pkgfiles);
278 
279 	wr_OK(fp_dra, "DEPEND", dr_info.depend_set, dr_info.depend);
280 
281 	wr_OK(fp_dra, "SPACE", dr_info.space_set, dr_info.space);
282 
283 	wr_OK(fp_dra, "CONFLICT", dr_info.conflict_set, dr_info.conflict);
284 
285 	wr_OK(fp_dra, "SETUID", dr_info.setuid_set, dr_info.setuid);
286 
287 	wr_OK(fp_dra, "PRIV", dr_info.priv_set, dr_info.priv);
288 
289 	wr_OK(fp_dra, "PKGDIRS", dr_info.pkgdirs_set, dr_info.pkgdirs);
290 
291 	(void) fprintf(fp_dra, "EXITCODE=%d\n", dr_info.exitcode);
292 
293 	(void) fprintf(fp_dra, "ERRORMSG=%s\n", (exitmsg ? exitmsg : "NONE"));
294 
295 	(void) fclose(fp_dra);
296 
297 	if ((fp_dra = fopen(dryrun_fsasc, "wb")) == NULL) {
298 		progerr(gettext(ERR_NOOPEN), dryrun_fsasc);
299 		return;
300 	}
301 
302 	(void) fprintf(fp_dra, "%s\nFSUSAGE=\\\n\"\\\n", HDR_FSUSAGE);
303 
304 	for (n = 0; fs_mntpt = get_fs_name_n(n); n++) {
305 		int bfree, bused;
306 		bfree = get_blk_free_n(n);
307 		bused = get_blk_used_n(n);
308 
309 		if (bfree || bused) {
310 			(void) fprintf(fp_dra, "%s %s %s %d %d %lu %lu \\\n",
311 			    fs_mntpt,
312 			    ((src_name = get_source_name_n(n)) ?
313 			    src_name : "none?"),
314 			    (is_fs_writeable_n(n) ? "TRUE" : "FALSE"),
315 			    bfree,
316 			    bused,
317 			    get_inode_free_n(n),
318 			    get_inode_used_n(n));
319 		}
320 	}
321 
322 	dr_info.total_fs_recs = n;
323 
324 	(void) fprintf(fp_dra, "\"\n");
325 
326 	(void) fclose(fp_dra);
327 
328 	if ((fp_dra = fopen(dryrun_poasc, "wb")) == NULL) {
329 		progerr(gettext(ERR_NOOPEN), dryrun_poasc);
330 		return;
331 	}
332 
333 	dr_info.total_ext_recs = 0;
334 
335 	(void) fprintf(fp_dra, "WOULD_INSTALL=\\\n\"\\\n");
336 
337 	for (n = 0; extptr && extptr[n]; n++) {
338 		/*
339 		 * Write it out if it's a successful change or it is from the
340 		 * prior dryrun file (meaning it was a change back then).
341 		 */
342 		if ((this_exitcode == 0 &&
343 		    (extptr[n]->mstat.contchg || extptr[n]->mstat.attrchg)) ||
344 		    extptr[n]->mstat.preloaded) {
345 			(void) fprintf(fp_dra, "%c %s \\\n",
346 				extptr[n]->cf_ent.ftype,
347 				extptr[n]->client_path);
348 
349 			/* Count it, if it's going into the dryrun file. */
350 			if (extptr[n]->cf_ent.ftype != 'i')
351 				dr_info.total_ext_recs++;
352 		}
353 	}
354 
355 	(void) fprintf(fp_dra, "\"\n");
356 
357 	(void) fclose(fp_dra);
358 }
359 
360 /*
361  * This writes out a dryrun file.
362  */
363 static void
write_dryrun_bin()364 write_dryrun_bin()
365 {
366 	struct fstable *fs_entry;
367 	struct pinfo *pkginfo;
368 	struct dr_pkg_entry *pkg_entry;
369 	int n;
370 	int fsentry_size = sizeof (struct fstable);
371 	int extentry_size = sizeof (struct cfextra);
372 	int pinfoentry_size = sizeof (struct pinfo);
373 
374 	if ((fd_drb = open(dryrun_bin,
375 	    O_RDWR | O_APPEND | O_TRUNC)) == -1) {
376 		progerr(gettext(ERR_NOOPEN), dryrun_bin);
377 		return;
378 	}
379 
380 	/* Write the dryrun info table. */
381 	if (write(fd_drb, &dr_info, sizeof (struct drinfo)) == -1) {
382 		progerr(gettext(ERR_NOWRITE), dryrun_bin);
383 		return;
384 	}
385 
386 	/* Write out the package instance list. */
387 	pkg_entry = dr_info.packages;
388 	while (pkg_entry) {
389 		if (write(fd_drb, pkg_entry->pkginst, PKGNAMESIZE) == -1) {
390 			progerr(gettext(ERR_NOWRITE), dryrun_bin);
391 			return;
392 		}
393 		pkg_entry = pkg_entry->next;
394 	}
395 
396 	/* Write out the fstable records. */
397 	for (n = 0; n < dr_info.total_fs_recs; n++) {
398 		fs_entry = get_fs_entry(n);
399 
400 		if (write(fd_drb, fs_entry, fsentry_size) == -1) {
401 			progerr(gettext(ERR_NOWRITE), dryrun_bin);
402 			return;
403 		}
404 
405 		if (!write_string(fd_drb, fs_entry->name))
406 			return;
407 
408 		if (!write_string(fd_drb, fs_entry->fstype))
409 			return;
410 
411 		if (!write_string(fd_drb, fs_entry->remote_name))
412 			return;
413 	}
414 
415 	/* Write out the package objects and their attributes. */
416 	for (n = 0; extptr && extptr[n]; n++) {
417 		/* Don't save metafiles. */
418 		if (extptr[n]->cf_ent.ftype == 'i')
419 			continue;
420 
421 		/*
422 		 * If it's a new package object (not left over from the
423 		 * continuation file) and it indicates no changes to the
424 		 * system, skip it. Only files that will change the system
425 		 * are stored.
426 		 */
427 		if (extptr[n]->mstat.preloaded == 0 &&
428 		    !(this_exitcode == 0 &&
429 		    (extptr[n]->mstat.contchg || extptr[n]->mstat.attrchg)))
430 			continue;
431 
432 		if (write(fd_drb, extptr[n], extentry_size) == -1) {
433 			progerr(gettext(ERR_NOWRITE), dryrun_bin);
434 			return;
435 		}
436 
437 		if (!write_string(fd_drb, extptr[n]->cf_ent.path))
438 			return;
439 
440 		if (!write_string(fd_drb, extptr[n]->cf_ent.ainfo.local))
441 			return;
442 
443 		extptr[n]->cf_ent.pinfo = eptstat(&(extptr[n]->cf_ent),
444 		    pkginst, CONFIRM_CONT);
445 
446 		/*
447 		 * Now all of the entries about the various packages that own
448 		 * this entry.
449 		 */
450 		pkginfo = extptr[n]->cf_ent.pinfo;
451 
452 		do {
453 			if (write(fd_drb, pkginfo,
454 			    pinfoentry_size) == -1) {
455 				progerr(gettext(ERR_NOWRITE), dryrun_bin);
456 				return;
457 			}
458 			pkginfo = pkginfo->next;	/* May be several */
459 		} while (pkginfo);
460 	}
461 
462 	(void) close(fd_drb);
463 }
464 
465 static void
init_drinfo(void)466 init_drinfo(void) {
467 
468 	if (dr_info.partial != 0)
469 		dr_info.partial_set = 0;
470 
471 	if (dr_info.runlevel != 0)
472 		dr_info.runlevel_set = 0;
473 
474 	if (dr_info.pkgfiles != 0)
475 		dr_info.pkgfiles_set = 0;
476 
477 	if (dr_info.depend != 0)
478 		dr_info.depend_set = 0;
479 
480 	if (dr_info.space != 0)
481 		dr_info.space_set = 0;
482 
483 	if (dr_info.conflict != 0)
484 		dr_info.conflict_set = 0;
485 
486 	if (dr_info.setuid != 0)
487 		dr_info.setuid_set = 0;
488 
489 	if (dr_info.priv != 0)
490 		dr_info.priv_set = 0;
491 
492 	if (dr_info.pkgdirs != 0)
493 		dr_info.pkgdirs_set = 0;
494 
495 	if (dr_info.reqexit == 0)
496 		dr_info.reqexit_set = 0;
497 
498 	if (dr_info.checkexit == 0)
499 		dr_info.checkexit_set = 0;
500 
501 	dr_info.packages = NULL;
502 	tot_pkgs = dr_info.total_pkgs;
503 	dr_info.total_pkgs = 0;
504 }
505 
506 /*
507  * This function reads in the various continuation file data in order to seed
508  * the internal data structures.
509  */
510 static boolean_t
read_continue_bin(void)511 read_continue_bin(void)
512 {
513 	int n;
514 	int fsentry_size = sizeof (struct fstable);
515 	int extentry_size = sizeof (struct cfextra);
516 	int pinfoentry_size = sizeof (struct pinfo);
517 
518 	pkgobjinit();
519 	if (!init_pkgobjspace())
520 		return (B_FALSE);
521 
522 	if ((fd_cnb = open(continue_bin, O_RDONLY)) == -1) {
523 		progerr(gettext(ERR_NOOPEN), continue_bin);
524 		return (B_FALSE);
525 	}
526 
527 	/* Read the dryrun info structure. */
528 	if (read(fd_cnb, &dr_info, sizeof (struct drinfo)) == -1) {
529 		progerr(gettext(ERR_NOREAD), continue_bin);
530 		return (B_FALSE);
531 	}
532 
533 	init_drinfo();
534 
535 	if (this_type != dr_info.type) {
536 		progerr(gettext(ERR_BADTYPE),
537 		    (this_type == REMOVE_TYPE) ?
538 		    "a remove" : "an install",
539 		    (dr_info.type == REMOVE_TYPE) ?
540 		    "a remove" : "an install");
541 		return (B_FALSE);
542 	}
543 
544 	/* Read in the dryrun package records. */
545 	for (n = 0; n < tot_pkgs; n++) {
546 		char pkg_name[PKGNAMESIZE];
547 
548 		if (read(fd_cnb, &pkg_name, PKGNAMESIZE) == -1) {
549 			progerr(gettext(ERR_NOREAD), continue_bin);
550 			return (B_FALSE);
551 		}
552 
553 		add_pkg_to_list(pkg_name);
554 	}
555 
556 	/* Read in the fstable records. */
557 	for (n = 0; n < dr_info.total_fs_recs; n++) {
558 		struct fstable fs_entry;
559 		char name[PATH_MAX], remote_name[PATH_MAX];
560 		char fstype[200];
561 
562 		if (read(fd_cnb, &fs_entry, fsentry_size) == -1) {
563 			progerr(gettext(ERR_NOREAD), continue_bin);
564 			return (B_FALSE);
565 		}
566 
567 		if (read_string(fd_cnb, &name[0]) == NULL)
568 			return (B_FALSE);
569 
570 		if (read_string(fd_cnb, &fstype[0]) == NULL)
571 			return (B_FALSE);
572 
573 		if (read_string(fd_cnb, &remote_name[0]) == NULL)
574 			return (B_FALSE);
575 
576 		if (load_fsentry(&fs_entry, name, fstype, remote_name)) {
577 			progerr(gettext(ERR_FSFAIL));
578 			return (B_FALSE);
579 		}
580 	}
581 
582 	/* Read in the package objects and their attributes. */
583 	for (n = 0; n < dr_info.total_ext_recs; n++) {
584 		struct cfextra ext_entry;
585 		struct pinfo pinfo_area, *pinfo_ptr;
586 		char path[PATH_MAX], local[PATH_MAX], *local_ptr;
587 
588 		if (read(fd_cnb, &ext_entry, extentry_size) == -1) {
589 			progerr(gettext(ERR_NOREAD), continue_bin);
590 			return (B_FALSE);
591 		}
592 
593 		/*
594 		 * If the previous dryrun replaced a directory with a
595 		 * non-directory and we're going into *another* dryrun, we're
596 		 * stacking errors and continuation should not be permitted.
597 		 */
598 		if (ext_entry.mstat.dir2nondir && dryrun_mode)
599 			dr_info.do_not_continue = 1;
600 
601 		/*
602 		 * Since we just read this from a continuation file; it is,
603 		 * by definition, preloaded.
604 		 */
605 		ext_entry.mstat.preloaded = 1;
606 
607 		if (read_string(fd_cnb, &path[0]) == NULL)
608 			return (B_FALSE);
609 
610 		local_ptr = read_string(fd_cnb, &local[0]);
611 
612 		ext_entry.cf_ent.pinfo = NULL;
613 
614 		/*
615 		 * Now all of the entries about the various packages that own
616 		 * this entry.
617 		 */
618 		do {
619 			if (read(fd_cnb, &pinfo_area, pinfoentry_size) == -1) {
620 				progerr(gettext(ERR_NOREAD), continue_bin);
621 				return (B_FALSE);
622 
623 			}
624 
625 			pinfo_ptr = eptstat(&(ext_entry.cf_ent),
626 			    pinfo_area.pkg, CONFIRM_CONT);
627 
628 			if (pinfo_ptr->next) {
629 				pinfo_ptr = pinfo_ptr->next;
630 			} else {
631 				pinfo_ptr = NULL;
632 			}
633 
634 		} while (pinfo_ptr);
635 
636 		seed_pkgobjmap(&ext_entry, path, local_ptr);
637 	}
638 
639 	(void) close(fd_cnb);
640 
641 	/*
642 	 * Return as reading is done, so pkginstall doesn't
643 	 * read the same info from the system.
644 	 */
645 
646 	return (B_TRUE);
647 }
648 
649 int
in_dryrun_mode(void)650 in_dryrun_mode(void)
651 {
652 	return (dryrun_mode);
653 }
654 
655 void
set_dryrun_mode(void)656 set_dryrun_mode(void)
657 {
658 	dryrun_mode = 1;
659 }
660 
661 int
in_continue_mode(void)662 in_continue_mode(void)
663 {
664 	return (continue_mode);
665 }
666 
667 void
set_continue_mode(void)668 set_continue_mode(void)
669 {
670 	continue_mode = 1;
671 }
672 
673 /*
674  * Initialize a dryrun file by assigning it a name and creating it
675  * empty.
676  */
677 static int
init_drfile(char ** targ_ptr,char * path)678 init_drfile(char **targ_ptr, char *path)
679 {
680 	int n;
681 	char *targ_file;
682 
683 	*targ_ptr = strdup(path);
684 	targ_file = *targ_ptr;
685 
686 	if (access(targ_file, W_OK) == 0) {
687 		(void) unlink(targ_file);
688 	}
689 
690 	n = open(targ_file, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644);
691 	if (n < 0) {
692 		progerr(gettext(ERR_NOCREAT), targ_file);
693 		return (0);
694 	} else {
695 		(void) close(n);
696 	}
697 
698 	return (1);
699 }
700 
701 /*
702  * Initialize all required dryrun files and see that the target directory is
703  * present. If all goes well, we're in dryrun mode. If it doesn't, we're not.
704  */
705 void
init_dryrunfile(char * dr_dir)706 init_dryrunfile(char *dr_dir)
707 {
708 	char temp_path[PATH_MAX];
709 	char *dot_pos = (temp_path+strlen(dr_dir)+7);
710 
711 	/* First create or confirm the directory. */
712 	if (isdir(dr_dir) != 0) {
713 		(void) mkpath(dr_dir);
714 	}
715 
716 	(void) snprintf(temp_path, sizeof (temp_path), "%s/dryrun", dr_dir);
717 
718 	(void) strcpy(dot_pos, ISUMASC_SUFFIX);
719 
720 	if (!init_drfile(&dryrun_sumasc, temp_path))
721 		return;
722 
723 	(void) strcpy(dot_pos, FSASC_SUFFIX);
724 
725 	if (!init_drfile(&dryrun_fsasc, temp_path))
726 		return;
727 
728 	(void) strcpy(dot_pos, IPOASC_SUFFIX);
729 
730 	if (!init_drfile(&dryrun_poasc, temp_path))
731 		return;
732 
733 	(void) strcpy(dot_pos, IBIN_SUFFIX);
734 
735 	if (!init_drfile(&dryrun_bin, temp_path))
736 		return;
737 
738 	dryrun_initialized = 1;
739 }
740 
741 void
init_contfile(char * cn_dir)742 init_contfile(char *cn_dir)
743 {
744 	char temp_path[PATH_MAX];
745 
746 	/* First confirm the directory. */
747 	if (isdir(cn_dir) != 0)
748 		return;		/* no continuation directory */
749 
750 	(void) snprintf(temp_path, sizeof (temp_path),
751 				"%s/dryrun%s", cn_dir, IBIN_SUFFIX);
752 	continue_bin = strdup(temp_path);
753 
754 	if (access(continue_bin, W_OK) != 0) {
755 		free(continue_bin);
756 		return;
757 	}
758 
759 	continue_initialized = 1;
760 }
761 
762 void
set_dr_exitmsg(char * value)763 set_dr_exitmsg(char *value)
764 {
765 	exitmsg = value;
766 }
767 
768 void
set_dr_info(int type,int value)769 set_dr_info(int type, int value)
770 {
771 	switch (type) {
772 	    case PARTIAL:
773 		if (dr_info.partial_set == 0) {
774 			dr_info.partial_set = 1;
775 			dr_info.partial = (value ? 1 : 0);
776 		}
777 		break;
778 
779 	    case RUNLEVEL:
780 		if (dr_info.runlevel_set == 0) {
781 			dr_info.runlevel_set = 1;
782 			dr_info.runlevel = (value ? 1 : 0);
783 		}
784 		break;
785 
786 	    case PKGFILES:
787 		if (dr_info.pkgfiles_set == 0) {
788 			dr_info.pkgfiles_set = 1;
789 			dr_info.pkgfiles = (value ? 1 : 0);
790 		}
791 		break;
792 
793 	    case DEPEND:
794 		if (dr_info.depend_set == 0) {
795 			dr_info.depend_set = 1;
796 			dr_info.depend = (value ? 1 : 0);
797 		}
798 		break;
799 
800 	    case SPACE:
801 		if (dr_info.space_set == 0) {
802 			dr_info.space_set = 1;
803 			dr_info.space = (value ? 1 : 0);
804 		}
805 		break;
806 
807 	    case CONFLICT:
808 		if (dr_info.conflict_set == 0) {
809 			dr_info.conflict_set = 1;
810 			dr_info.conflict = (value ? 1 : 0);
811 		}
812 		break;
813 
814 	    case SETUID:
815 		if (dr_info.setuid_set == 0) {
816 			dr_info.setuid_set = 1;
817 			dr_info.setuid = (value ? 1 : 0);
818 		}
819 		break;
820 
821 	    case PRIV:
822 		if (dr_info.priv_set == 0) {
823 			dr_info.priv_set = 1;
824 			dr_info.priv = (value ? 1 : 0);
825 		}
826 
827 		break;
828 
829 	    case PKGDIRS:
830 		if (dr_info.pkgdirs_set == 0) {
831 			dr_info.pkgdirs_set = 1;
832 			dr_info.pkgdirs = (value ? 1 : 0);
833 		}
834 
835 		break;
836 
837 	    case REQUESTEXITCODE:
838 		if (dr_info.reqexit_set == 0) {
839 			dr_info.reqexit_set = 1;
840 			dr_info.reqexit = value;
841 		}
842 
843 		break;
844 
845 	    case CHECKEXITCODE:
846 		if (dr_info.checkexit_set == 0) {
847 			dr_info.checkexit_set = 1;
848 			dr_info.checkexit = value;
849 		}
850 
851 		break;
852 
853 	    case EXITCODE:
854 		if (dr_info.exitcode == 0) {
855 			dr_info.exitcode = value;
856 		}
857 
858 		this_exitcode = value;
859 
860 		break;
861 
862 	    /* default to install if the value is kookie. */
863 	    case DR_TYPE:
864 		if (value == REMOVE_TYPE)
865 			this_type = REMOVE_TYPE;
866 		else
867 			this_type = INSTALL_TYPE;
868 
869 		break;
870 	}
871 }
872 
873 void
write_dryrun_file(struct cfextra ** extlist)874 write_dryrun_file(struct cfextra **extlist)
875 {
876 	extptr = extlist;
877 
878 	if (dryrun_initialized) {
879 		dr_info.type = this_type;
880 
881 		add_pkg_to_list(pkginst);
882 		write_dryrun_ascii();
883 		write_dryrun_bin();
884 
885 		if (dryrun_mode) {
886 			free(dryrun_sumasc);
887 			free(dryrun_fsasc);
888 			free(dryrun_poasc);
889 			free(dryrun_bin);
890 		}
891 	}
892 }
893 
894 /*
895  * Name:		read_continuation
896  * Description:		If continuation is initialised, reads the
897  *			continuation binary file. The path for the
898  *			same is freed, if set,  as this is the last
899  *			chance to do so.
900  * Sets:		Error condition, through the pointer passed
901  *			if read failed.
902  * Returns:		B_TRUE - if the continuation binary file
903  *			from previous dryrun is read successfully.
904  *			B_FALSE - if either continuation is not initialised
905  *			or read was not successful.
906  */
907 boolean_t
read_continuation(int * error)908 read_continuation(int *error)
909 {
910 	boolean_t ret = B_FALSE;
911 	*error = 0;
912 	if (continue_initialized) {
913 		if (!read_continue_bin()) {
914 			continue_mode = 0;
915 			free(continue_bin);
916 			*error = -1;
917 			return (ret);
918 		}
919 
920 		if (continue_mode) {
921 			free(continue_bin);
922 		}
923 		ret = B_TRUE;
924 	}
925 	return (ret);
926 }
927