xref: /illumos-gate/usr/src/cmd/svr4pkg/pkgadd/check.c (revision 4eaa471005973e11a6110b69fe990530b3b95a38)
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 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <stdio.h>
28 #include <limits.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <sys/stat.h>
32 #include <unistd.h>
33 #include <errno.h>
34 #include <dirent.h>
35 #include <sys/types.h>
36 #include <locale.h>
37 #include <libintl.h>
38 #include <pkgstrct.h>
39 #include <pkglocs.h>
40 #include <assert.h>
41 
42 #include <instzones_api.h>
43 #include <pkglib.h>
44 #include <messages.h>
45 
46 #include <install.h>
47 #include <libinst.h>
48 #include <libadm.h>
49 
50 extern int	npkgs;	/* the number of packages yet to be installed */
51 
52 /*
53  * ckquit is a global that controls 'ckyorn' (defined in libadm)
54  * If ckquit is non-zero, then "quit" is allowed as an answer when
55  * ckyorn is called. If is it zero, then "quit" is not an allowed answer.
56  */
57 extern int	ckquit;
58 
59 extern struct admin adm;
60 
61 /*
62  * each one of these represents a single kind of dependency check
63  */
64 
65 static depckError_t er_ckconflict = {0, (depckErrorRecord_t *)NULL};
66 static depckError_t er_ckdepend = {0, (depckErrorRecord_t *)NULL};
67 static depckError_t er_ckcfcontent = {0, (depckErrorRecord_t *)NULL};
68 static depckError_t er_ckinstance = {0, (depckErrorRecord_t *)NULL};
69 static depckError_t er_ckdirs = {0, (depckErrorRecord_t *)NULL};
70 static depckError_t er_ckpartinst = {0, (depckErrorRecord_t *)NULL};
71 static depckError_t er_ckpartrem = {0, (depckErrorRecord_t *)NULL};
72 static depckError_t er_ckpkgdirs = {0, (depckErrorRecord_t *)NULL};
73 static depckError_t er_ckpkgfilebad = {0, (depckErrorRecord_t *)NULL};
74 static depckError_t er_ckpkgfiles = {0, (depckErrorRecord_t *)NULL};
75 static depckError_t er_ckpriv = {0, (depckErrorRecord_t *)NULL};
76 static depckError_t er_ckrunlevel = {0, (depckErrorRecord_t *)NULL};
77 static depckError_t er_cksetuid = {0, (depckErrorRecord_t *)NULL};
78 static depckError_t er_ckspace = {0, (depckErrorRecord_t *)NULL};
79 static depckError_t er_newonly = {0, (depckErrorRecord_t *)NULL};
80 static depckError_t er_prereqinc = {0, (depckErrorRecord_t *)NULL};
81 static depckError_t er_prereqinst = {0, (depckErrorRecord_t *)NULL};
82 static depckError_t er_runlevel = {0, (depckErrorRecord_t *)NULL};
83 static depckError_t er_same = {0, (depckErrorRecord_t *)NULL};
84 static depckError_t er_overwrite = {0, (depckErrorRecord_t *)NULL};
85 static depckError_t er_uniq1 = {0, (depckErrorRecord_t *)NULL};
86 static depckError_t er_attrib = {0, NULL};
87 static depckError_t er_setuidf = {0, NULL};
88 static depckError_t er_setgidf = {0, NULL};
89 static depckError_t er_overwr = {0, NULL};
90 
91 /*
92  * each one of these represents a localized message for a single kind
93  * of dependency check
94  */
95 
96 static char *IMSG_ABADFILE = (char *)NULL;
97 static char *IMSG_BADFILE = (char *)NULL;
98 static char *IMSG_CKRUNLVL = (char *)NULL;
99 static char *IMSG_CNFFAILED = (char *)NULL;
100 static char *IMSG_DEPEND = (char *)NULL;
101 static char *IMSG_CFCONTENT = (char *)NULL;
102 static char *IMSG_INSTANCE = "INSTANCE %s <%s> on %s <%s>";
103 static char *IMSG_DIRS  = (char *)NULL;
104 static char *IMSG_NEWONLY = (char *)NULL;
105 static char *IMSG_PARTINST = (char *)NULL;
106 static char *IMSG_PARTREM = (char *)NULL;
107 static char *IMSG_PKGDIRS = (char *)NULL;
108 static char *IMSG_PRENCI  = (char *)NULL;
109 static char *IMSG_PREREQ  = (char *)NULL;
110 static char *IMSG_PRIV = (char *)NULL;
111 static char *IMSG_RUNLEVEL = (char *)NULL;
112 static char *IMSG_SAME = (char *)NULL;
113 static char *IMSG_OVERWRITE = (char *)NULL;
114 static char *IMSG_UNIQ1 = (char *)NULL;
115 static char *IMSG_SETUID = (char *)NULL;
116 static char *IMSG_SPCFAILED = (char *)NULL;
117 static char *IMSG_ATTRIB;
118 static char *IMSG_SETUIDF;
119 static char *IMSG_SETGIDF;
120 static char *IMSG_OVERWR;
121 
122 /*
123  * each one of these represents a function to handle a single kind of
124  * dependency check
125  */
126 
127 static int ckconflict(char *a_msg, char *a_pkg);
128 static int ckdepend(char *a_msg, char *a_pkg);
129 static int ckcfcontent(char *a_msg, char *a_pkg);
130 static int ckinstance(char *a_msg, char *a_pkg);
131 static int ckdirs(char *a_msg, char *a_pkg);
132 static int ckpartinst(char *a_msg, char *a_pkg);
133 static int ckpartrem(char *a_msg, char *a_pkg);
134 static int ckpkgfilebad(char *a_msg, char *a_pkg);
135 static int ckpkgdirs(char *a_msg, char *a_pkg);
136 static int ckpkgfiles(char *a_msg, char *a_pkg);
137 static int ckprereqinc(char *a_msg, char *a_pkg);
138 static int ckprereqinst(char *a_msg, char *a_pkg);
139 static int ckpriv(char *a_msg, char *a_pkg);
140 static int ckrunlevel(char *a_msg, char *a_pkg);
141 static int cksetuid(char *a_msg, char *a_pkg);
142 static int ckspace(char *a_msg, char *a_pkg);
143 static int attrib(char *a_msg, char *a_pkg);
144 static int setuidf(char *a_msg, char *a_pkg);
145 static int setgidf(char *a_msg, char *a_pkg);
146 static int overwr(char *a_msg, char *a_pkg);
147 
148 static depckl_t DEPCKL[] = {
149 	/*
150 	 * name,	ignore_values,	err_msg,	depcklFunc,	recrd
151 	 * ---
152 	 * ignore_values == NULL:
153 	 * package and zone information is collected in the "record" object for
154 	 * each occurance - then a message is constructed for each zone that
155 	 * reported the condition - the message includes that portion of the
156 	 * check past the "=" - then the specified "depcklFunc" is called to
157 	 * process each message.
158 	 * Message format:
159 	 * 	%s %s <%s> %s <%s>
160 	 * Message arguments:
161 	 *	value, "package", package-name, "zone/zones", zone-name
162 	 * ---
163 	 * ignore-values == "???":
164 	 * these checks are ignored if they return one of the listed values
165 	 * if they do NOT return one of the listed values, then the package
166 	 * and zone information is collected in the "record" object for each
167 	 * occurance - then a single unified message is constructed for all
168 	 * zones that report the same condition; then the specified "depcklFunc"
169 	 * is called to process the resulting combined message.
170 	 * Message format:
171 	 * 	%s <%s> %s <%s>
172 	 * Message arguments:
173 	 *	"package", package-name, "zone/zones", zone-name(s)
174 	 * ---
175 	 * ignore-values="":
176 	 * same as above BUT no check to ignore is done; message always reported
177 	 */
178 
179 	{ "install-same-instance=true",	"",		&IMSG_SAME,
180 					NULL,		&er_same
181 	},
182 	{ "ckpkgfilebad=",		NULL,		&IMSG_ABADFILE,
183 					&ckpkgfilebad,	&er_ckpkgfilebad
184 	},
185 	{ "ckdirs=",			NULL,		&IMSG_DIRS,
186 					&ckdirs,	&er_ckdirs
187 	},
188 	{ "prerequisite-incomplete=",	NULL,		&IMSG_PRENCI,
189 					&ckprereqinc,	&er_prereqinc
190 	},
191 	{ "prerequisite-installed=",	NULL,		&IMSG_PREREQ,
192 					&ckprereqinst,	&er_prereqinst
193 	},
194 	{ "runlevel=",			NULL,		&IMSG_RUNLEVEL,
195 					NULL,		&er_runlevel
196 	},
197 	{ "conflict-contents=",		NULL,		&IMSG_CFCONTENT,
198 					&ckcfcontent,	&er_ckcfcontent
199 	},
200 	{ "ckconflict=",		"0",		&IMSG_CNFFAILED,
201 					&ckconflict,	&er_ckconflict
202 	},
203 	{ "ckdepend=",			"0",		&IMSG_DEPEND,
204 					&ckdepend,	&er_ckdepend
205 	},
206 	{ "ckpartialinstall=",		"0",		&IMSG_PARTINST,
207 					&ckpartinst,	&er_ckpartinst
208 	},
209 	{ "ckpartialremove=",		"0",		&IMSG_PARTREM,
210 					&ckpartrem,	&er_ckpartrem
211 	},
212 	{ "ckpkgdirs=",			"0",		&IMSG_PKGDIRS,
213 					&ckpkgdirs,	&er_ckpkgdirs
214 	},
215 	{ "ckpkgfiles=",		"0",		&IMSG_BADFILE,
216 					&ckpkgfiles,	&er_ckpkgfiles
217 	},
218 	{ "ckpriv=",			"0",		&IMSG_PRIV,
219 					&ckpriv,	&er_ckpriv
220 	},
221 	{ "ckrunlevel=",		"0",		&IMSG_CKRUNLVL,
222 					&ckrunlevel,	&er_ckrunlevel
223 	},
224 	{ "cksetuid=",			"0",		&IMSG_SETUID,
225 					&cksetuid,	&er_cksetuid
226 	},
227 	{ "ckspace=",			"0",		&IMSG_SPCFAILED,
228 					&ckspace,	&er_ckspace
229 	},
230 	{ "install-new-only=true",	"",		&IMSG_NEWONLY,
231 					NULL,		&er_newonly
232 	},
233 	{ "install-ovewrite=true",	"",		&IMSG_OVERWRITE,
234 					NULL,		&er_overwrite
235 	},
236 	{ "install-too-many-instances=true",	"",	&IMSG_UNIQ1,
237 					NULL,		&er_uniq1
238 	},
239 	{ "ckinstance=",		"0",		&IMSG_INSTANCE,
240 					&ckinstance,	&er_ckinstance
241 	},
242 	{ "conflict-attributes=",	NULL,		&IMSG_ATTRIB,
243 					&attrib,	&er_attrib
244 	},
245 	{ "setuid=",			NULL,		&IMSG_SETUIDF,
246 					&setuidf,	&er_setuidf
247 	},
248 	{ "setgid=",			NULL,		&IMSG_SETGIDF,
249 					&setgidf,	&er_setgidf
250 	},
251 	{ "setuid-overwrite=true",	"",		&IMSG_OVERWR,
252 					&overwr,	&er_overwr
253 	},
254 
255 	{ NULL,				NULL,	NULL,
256 				NULL,		NULL }
257 };
258 
259 /*
260  * Name:	preinstall_verify
261  * Description:	verify results of preinstallation dependency checking
262  * Arguments:	a_pkglist - pointer to array of strings representing the names
263  *			of all the packages that have been checked
264  *		a_zlst - list of zones that dependencies were checked on
265  *		a_zoneTempDir - pointer to string representing the path where
266  *			the files containing the preinstallation dependency
267  *			check data are located
268  * Returns:	int
269  *		== 0 - continue processing
270  *		!= 0 - do not continue processing
271  */
272 
273 int
274 preinstall_verify(char **a_pkglist, zoneList_t a_zlst, char *a_zoneTempDir)
275 {
276 	char		*pkginst;
277 	int		i;
278 	int		savenpkgs = npkgs;
279 
280 	/*
281 	 * entry assertions
282 	 */
283 
284 	assert(a_pkglist != (char **)NULL);
285 	assert(a_zlst != (zoneList_t)NULL);
286 	assert(a_zoneTempDir != (char *)NULL);
287 
288 	/*
289 	 * entry debugging info
290 	 */
291 
292 	echoDebug(DBG_PREIVFY_ENTRY);
293 
294 	/*
295 	 * localize messages
296 	 */
297 
298 	IMSG_ABADFILE = MSG_PKGADDCHK_ABADFILE;
299 	IMSG_BADFILE = MSG_PKGADDCHK_BADFILE;
300 	IMSG_CFCONTENT = MSG_PKGADDCHK_CFCONTENT;
301 	IMSG_CKRUNLVL = MSG_PKGADDCHK_CKRUNLVL;
302 	IMSG_CNFFAILED = MSG_PKGADDCHK_CNFFAILED;
303 	IMSG_DEPEND = MSG_PKGADDCHK_DEPEND;
304 	IMSG_DIRS  = MSG_PKGADDCHK_DIRS;
305 	IMSG_NEWONLY = MSG_PKGADDCHK_NEWONLY;
306 	IMSG_OVERWRITE = MSG_PKGADDCHK_OVERWRITE;
307 	IMSG_PARTINST = MSG_PKGADDCHK_PARTINST;
308 	IMSG_PARTREM = MSG_PKGADDCHK_PARTREM;
309 	IMSG_PKGDIRS = MSG_PKGADDCHK_PKGDIRS;
310 	IMSG_PRENCI  = MSG_PKGADDCHK_PRENCI;
311 	IMSG_PREREQ  = MSG_PKGADDCHK_PREREQ;
312 	IMSG_PRIV = MSG_PKGADDCHK_PRIV;
313 	IMSG_RUNLEVEL = MSG_PKGADDCHK_RUNLEVEL;
314 	IMSG_SAME = MSG_PKGADDCHK_SAME;
315 	IMSG_SETUID = MSG_PKGADDCHK_SETUID;
316 	IMSG_SPCFAILED = MSG_PKGADDCHK_SPCFAILED;
317 	IMSG_UNIQ1 = MSG_PKGADDCHK_UNIQ1;
318 	IMSG_ATTRIB = gettext("\\nattribute change for %s <%s> on %s <%s>\n");
319 	IMSG_SETUIDF = gettext("\\nsetuid %s in %s <%s> on %s <%s>\n");
320 	IMSG_SETGIDF = gettext("\\nsetgid %s in %s <%s> on %s <%s>\n");
321 	IMSG_OVERWR = gettext("\\nFiles that are setuid will be overwritten "
322 	    "by installation of %s\n<%s> on %s <%s>.\n");
323 
324 	/*
325 	 * outer loop - process each package first
326 	 */
327 
328 	for (i = 0; (pkginst = a_pkglist[i]) != NULL; i++) {
329 
330 		char	*zoneName;
331 		int	zoneIndex;
332 
333 		/*
334 		 * if this package is marked "install in this zone only", then
335 		 * do not check dependencies in any zone
336 		 */
337 
338 		if (pkgPackageIsThisZone(pkginst) == B_TRUE) {
339 			echoDebug(DBG_PREIVFY_SKIP_THISZONE, pkginst);
340 			continue;
341 		}
342 
343 		/*
344 		 * inner loop - for each package process each zone second
345 		 */
346 
347 		for (zoneIndex = 0;
348 			(zoneName = z_zlist_get_zonename(a_zlst, zoneIndex)) !=
349 				(char *)NULL; zoneIndex++) {
350 
351 			FILE	*fp;
352 			char	line[PATH_MAX+1];
353 			char	preinstallcheckPath[PATH_MAX+1];
354 			int	len;
355 
356 			/* skip the zone if it is NOT bootable */
357 
358 			if (z_zlist_is_zone_runnable(a_zlst,
359 							zoneIndex) == B_FALSE) {
360 				continue;
361 			}
362 
363 			/* create path to this packages preinstall check data */
364 
365 			len = snprintf(preinstallcheckPath,
366 				sizeof (preinstallcheckPath),
367 				"%s/%s.%s.preinstallcheck.txt", a_zoneTempDir,
368 				pkginst, zoneName);
369 
370 			if (len > sizeof (preinstallcheckPath)) {
371 				progerr(ERR_CREATE_PATH_3, a_zoneTempDir,
372 					pkginst, zoneName);
373 				continue;
374 			}
375 
376 			/* error if preinstall check data path is not a file */
377 
378 			if (isfile((char *)NULL, preinstallcheckPath) != 0) {
379 				echoDebug(DBG_PREIVFY_NOFILE,
380 					pkginst, zoneName, preinstallcheckPath,
381 					strerror(errno));
382 				progerr(ERR_PREIVFY_NOFILE,
383 					pkginst, zoneName);
384 				continue;
385 			}
386 
387 			/* open the preinstall check data file */
388 
389 			fp = fopen(preinstallcheckPath, "r");
390 			if (fp == (FILE *)NULL) {
391 				progerr(ERR_PREIVFY_OPEN_FILE,
392 					preinstallcheckPath, pkginst, zoneName,
393 					strerror(errno));
394 				continue;
395 			}
396 
397 			/* read and process each preinstall check data line */
398 
399 			while (fgets(line, sizeof (line), fp) != (char *)NULL) {
400 				int	j;
401 				int	len;
402 
403 				/* remove all new-lines from end of line */
404 
405 				len = strlen(line);
406 				while ((len > 0) && (line[len-1] == '\n')) {
407 					line[--len] = '\0';
408 				}
409 
410 				/* ignore comment lines */
411 
412 				if (line[0] == '#') {
413 					continue;
414 				}
415 
416 				/* ignore empty lines */
417 
418 				if (line[0] == '\0') {
419 					continue;
420 				}
421 
422 				/* scan dependency list for this item */
423 
424 				for (j = 0;
425 					DEPCKL[j].name != (char *)NULL; j++) {
426 					len = strlen(DEPCKL[j].name);
427 
428 					if (strncmp(line, DEPCKL[j].name,
429 							len) == 0) {
430 						break;
431 					}
432 				}
433 
434 				echoDebug(DBG_PREIVFY_SCAN, line, pkginst,
435 						zoneName);
436 
437 				/* ignore line if not found */
438 
439 				if (DEPCKL[j].name == (char *)NULL) {
440 					progerr(ERR_PREIVFY_UNKNOWN_LINE, line,
441 							pkginst, zoneName);
442 					continue;
443 				}
444 
445 				if ((DEPCKL[j].ignore_values != (char *)NULL) &&
446 					(*(DEPCKL[j].ignore_values) != '\0') &&
447 					(strchr(DEPCKL[j].ignore_values,
448 						line[len]) != (char *)NULL)) {
449 						continue;
450 				}
451 
452 				/* found match - record this dependency issue */
453 
454 				depchkRecordError(DEPCKL[j].record, pkginst,
455 					zoneName, &line[len]);
456 			}
457 
458 			/* close preinstall check data file */
459 
460 			(void) fclose(fp);
461 		}
462 	}
463 
464 	/*
465 	 * all dependency issues have been recorded; report results
466 	 */
467 
468 	i = depchkReportErrors(DEPCKL);
469 
470 	/* restore "npkgs" */
471 
472 	npkgs = savenpkgs;
473 
474 	/* return continue/dont dontinue results */
475 
476 	return (i);
477 }
478 
479 /*
480  * Name:	getyorn
481  * Description:	Deliver dependency check reason; ask question; return response
482  * Arguments:	a_msg - pointer to string representing the message to output
483  *			such as 'The package <..> contains <...>'
484  *		a_pkg - pointer to string representing the package for which
485  *			the question is being asked
486  *		a_nocheck - should the message be output?
487  *			== 0 - do not output the message
488  *			!= 0 - output the message
489  *		a_quit - should the question NOT be asked?
490  *			== 0 - ask the question
491  *			!= 0 - do not ask the question - return "no"
492  *		a_helpMsg - pointer to string representing help message to be
493  *			made available if the question is asked
494  *			== NULL - no help message is available
495  *		a_adminMsg - pointer to string representing the dependency check
496  *			failure 'reason' - such as "Privilege checking failed."
497  *			== NULL - no failure reason is available
498  * Returns:	int - results of question/response actions
499  *			0 - success
500  *			1 - end of file
501  *			2 - undefined error
502  *			3 - answer was not "y"/was "q"
503  *			4 - quit action taken
504  *			5 - interactive mode required
505  */
506 
507 static int
508 getyorn(char *a_msg, char *a_pkg, int a_nocheck, int a_quit,
509 	char *a_helpMsg, char *a_adminMsg)
510 {
511 	char	ans[MAX_INPUT];
512 	char	ask_cont[MSG_MAX];
513 	int	n;
514 	int	saveCkquit;
515 
516 	/*
517 	 * entry assertions
518 	 */
519 
520 	assert(a_pkg != (char *)NULL);
521 	assert(*a_pkg != '\0');
522 
523 	/*
524 	 * entry debugging info
525 	 */
526 
527 	echoDebug(DBG_PREIVFY_GETYORN_ARGS, a_pkg, a_nocheck, a_quit, a_msg,
528 			a_adminMsg ? a_adminMsg : "");
529 
530 	/* return success (0) if "nocheck" is non-zero */
531 
532 	if (a_nocheck != 0) {
533 		echoDebug(DBG_PREIVFY_GETYORN_NOCHECK, a_pkg);
534 		return (0);
535 	}
536 
537 	/* output reason for this particular failure */
538 
539 	if ((a_msg != (char *)NULL) && (*a_msg != '\0')) {
540 		ptext(stderr, "%s", a_msg);
541 	}
542 
543 	/* return "4 (administration)" if "quit" is non-zero */
544 
545 	if (a_quit != 0) {
546 		/* output failure "admin reason" if available */
547 		if ((a_adminMsg != (char *)NULL) && (*a_adminMsg != '\0')) {
548 			ptext(stderr, a_adminMsg);
549 		}
550 		echoDebug(DBG_PREIVFY_GETYORN_QUIT, a_pkg);
551 		return (4);
552 	}
553 
554 	/* return "5 (administration interaction required)" if -n */
555 
556 	if (echoGetFlag() == B_FALSE) {
557 		ptext(stderr, MSG_PREIVFY_GETYORN_SUSP, a_pkg);
558 		echoDebug(DBG_PREIVFY_GETYORN_QUIT_USER, a_pkg);
559 		return (5);
560 	}
561 
562 	/* prepare question to ask "continue with pkg <xxx>?" */
563 
564 	(void) snprintf(ask_cont, sizeof (ask_cont), gettext(ASK_CONT), a_pkg);
565 
566 	/* ask question */
567 
568 	saveCkquit = ckquit;
569 	ckquit = 0;
570 
571 	n = ckyorn(ans, NULL, NULL, a_helpMsg, ask_cont);
572 
573 	ckquit = saveCkquit;
574 
575 	if (n != 0) {
576 		ptext(stderr, MSG_PREIVFY_GETYORN_TERM, a_pkg);
577 		echoDebug(DBG_PREIVFY_GETYORN_CKYORN, a_pkg, n);
578 		return (n);
579 	}
580 
581 	/* return "3 (interruption) if not "y" or "Y" */
582 
583 	if (strchr("yY", *ans) == NULL) {
584 		ptext(stderr, MSG_PREIVFY_GETYORN_TERM_USER, a_pkg);
585 		echoDebug(DBG_PREIVFY_GETYORN_NOT_Y, a_pkg, ans);
586 		return (3);
587 	}
588 
589 	/* return "0 - success" */
590 
591 	echoDebug(DBG_PREIVFY_GETYORN_SUCCESS, a_pkg);
592 
593 	return (0);
594 }
595 
596 /*
597  * Trigger:	prerequisite-incomplete=<<package>>
598  * Sequence:	- one or more: prerequisite-incomplete=<<package>>
599  *		- one: ckdepend=<<n>>
600  * Actions:	Output message if "idepend!=nocheck"
601  *		Return 0
602  *		Terminate when 'ckdepend' processed
603  */
604 
605 static int
606 ckprereqinc(char *a_msg, char *a_pkg)
607 {
608 	echoDebug(DBG_PREIVFY_CKPRENCI, a_pkg, a_msg);
609 
610 	if (!(ADM(idepend, "nocheck"))) {
611 		ptext(stderr, "%s", a_msg);
612 	}
613 
614 	return (0);
615 }
616 
617 /*
618  * Trigger:	prerequisite-installed=<<package>>
619  * Sequence:	- one or more: prerequisite-installed=<<package>>
620  *		- one: ckdepend=<<n>>
621  * Actions:	Output message if "idepend!=nocheck"
622  *		Return 0
623  *		Terminate when 'ckdepend' processed
624  */
625 
626 static int
627 ckprereqinst(char *a_msg, char *a_pkg)
628 {
629 	echoDebug(DBG_PREIVFY_CKPREREQ, a_pkg, a_msg);
630 
631 	if (!(ADM(idepend, "nocheck"))) {
632 		ptext(stderr, "%s", a_msg);
633 	}
634 
635 	return (0);
636 }
637 
638 /*
639  * Trigger:	ckpartialinstall=<<n>>
640  * Sequence:	- one: ckpartialinstall=<<n>>
641  * Actions:	process according to settings
642  * Return value:	int
643  *			0 - success
644  *			1 - end of file
645  *			2 - undefined error
646  *			3 - answer was not "y"/was "q"
647  *			4 - quit action taken
648  *			5 - interactive mode required
649  */
650 
651 static int
652 ckpartinst(char *a_msg, char *a_pkg)
653 {
654 	echoDebug(DBG_PREIVFY_CKPARTIALINSTALL, a_pkg, a_msg);
655 
656 	return (getyorn(a_msg, a_pkg, ADM(partial, "nocheck"),
657 			ADM(partial, "quit"), HLP_PKGADDCHK_PARTIAL, NULL));
658 }
659 
660 /*
661  * Trigger:	ckpartialremove=<<n>>
662  * Sequence:	- one: ckpartialremove=<<n>>
663  * Actions:	process according to settings
664  * Return value:	int
665  *			0 - success
666  *			1 - end of file
667  *			2 - undefined error
668  *			3 - answer was not "y"/was "q"
669  *			4 - quit action taken
670  *			5 - interactive mode required
671  */
672 
673 static int
674 ckpartrem(char *a_msg, char *a_pkg)
675 {
676 	echoDebug(DBG_PREIVFY_CKPARTIALREMOVE, a_pkg, a_msg);
677 
678 	return (getyorn(a_msg, a_pkg, ADM(partial, "nocheck"),
679 		ADM(partial, "quit"), HLP_PKGADDCHK_PARTIAL, NULL));
680 }
681 
682 /*
683  * Return value:	int
684  *			0 - success
685  *			1 - end of file
686  *			2 - undefined error
687  *			3 - answer was not "y"/was "q"
688  *			4 - quit action taken
689  *			5 - interactive mode required
690  *			99 - fatal error
691  */
692 
693 static int
694 ckrunlevel(char *a_msg, char *a_pkg)
695 {
696 	echoDebug(DBG_PREIVFY_CKRUNLEVEL, a_pkg, a_msg);
697 	return (0);
698 }
699 
700 /*
701  * Trigger:	conflict-contents=<<n>>
702  * Sequence:	- one or more of:
703  *		-- conflict-contents=<<path>>
704  *		-- conflict-attributes=<<path>>
705  *		- one: ckconflict=<<n>>
706  * Actions:	output message
707  * Return value:	int
708  *			0 - success
709  */
710 
711 static int
712 ckcfcontent(char *a_msg, char *a_pkg)
713 {
714 	echoDebug(DBG_PREIVFY_CKCFCONTENT, a_pkg, a_msg);
715 
716 	ptext(stderr, "%s", a_msg);
717 
718 	return (0);
719 }
720 
721 /*
722  * Trigger:	ckinstance=<<n>>
723  * Sequence:	- one or more of:
724  *		-- install-instance=true
725  *		-- install-new-only=true\n
726  *		-- install-same-instance=true\n
727  *		-- install-ovewrite=true\n
728  *		-- install-too-many-instances=true\n
729  *		-- install-new-instance=true\n
730  *		- one: ckpdepend=<<n>>
731  * Actions:	process according to settings
732  * Return value:	int
733  *			0 - success
734  *			1 - end of file
735  *			2 - undefined error
736  *			3 - answer was not "y"/was "q"
737  *			4 - quit action taken
738  *			5 - interactive mode required
739  */
740 
741 static int
742 ckinstance(char *a_msg, char *a_pkg)
743 {
744 	echoDebug(DBG_PREIVFY_CKINSTANCE, a_pkg, a_msg);
745 
746 	return (getyorn(a_msg, a_pkg, ADM(instance, "nocheck"),
747 		ADM(instance, "quit"), HLP_PKGADDCHK_DEPEND,
748 		ERR_PKGADDCHK_DEPFAILED));
749 }
750 
751 /*
752  * Trigger:	ckdepend=<<n>>
753  * Sequence:	- one or more of:
754  *		-- incompat=<<package>>
755  *		-- prerequisite-incomplete=<<package>>
756  *		-- prerequisite-installed=<<package>>
757  *		-- dependson=<<package>>
758  *		-- dependsonme=<<package>>
759  *		- one: ckpdepend=<<n>>
760  * Actions:	process according to settings
761  * Return value:	int
762  *			0 - success
763  *			1 - end of file
764  *			2 - undefined error
765  *			3 - answer was not "y"/was "q"
766  *			4 - quit action taken
767  *			5 - interactive mode required
768  */
769 
770 static int
771 ckdepend(char *a_msg, char *a_pkg)
772 {
773 	echoDebug(DBG_PREIVFY_CKDEPEND, a_pkg, a_msg);
774 
775 	return (getyorn(a_msg, a_pkg, ADM(idepend, "nocheck"),
776 		ADM(idepend, "quit"), HLP_PKGADDCHK_DEPEND,
777 		ERR_PKGADDCHK_DEPFAILED));
778 }
779 
780 /*
781  * Trigger:	ckspace=<<n>>
782  * Sequence:	- one: ckspace=<<n>>
783  * Actions:	process according to settings
784  * Return value:	int
785  *			0 - success
786  *			1 - end of file
787  *			2 - undefined error
788  *			3 - answer was not "y"/was "q"
789  *			4 - quit action taken
790  *			5 - interactive mode required
791  */
792 
793 static int
794 ckspace(char *a_msg, char *a_pkg)
795 {
796 	echoDebug(DBG_PREIVFY_CKSPACE, a_pkg, a_msg);
797 
798 	return (getyorn(a_msg, a_pkg, ADM(space, "nocheck"),
799 		ADM(space, "quit"), HLP_PKGADDCHK_SPACE,
800 		ERR_PKGADDCHK_SPCFAILED));
801 }
802 
803 /*
804  * Trigger:	ckpkgdirs=<<n>>
805  * Sequence:	- one: ckpkgdirs=<<n>>
806  * Actions:	output message
807  *		Return 4
808  */
809 
810 static int
811 ckpkgdirs(char *a_msg, char *a_pkg)
812 {
813 	echoDebug(DBG_PREIVFY_CKPKGDIRS, a_pkg, a_msg);
814 
815 	ptext(stderr, "%s", a_msg);
816 
817 	return (4);
818 }
819 
820 /*
821  * Trigger:	ckdirs=<<path>>
822  * Sequence:	- one: ckdirs=<<path>>
823  * Actions:	output message
824  *		Return 4
825  */
826 
827 static int
828 ckdirs(char *a_msg, char *a_pkg)
829 {
830 	echoDebug(DBG_PREIVFY_CKDIRS, a_pkg, a_msg);
831 
832 	ptext(stderr, "%s", a_msg);
833 
834 	ptext(stderr, ERR_PKGADDCHK_MKPKGDIR);
835 
836 	return (4);
837 }
838 
839 /*
840  * Trigger:	ckpkgfilebad=<<path>>
841  * Sequence:	- one or more:
842  *		-- ckpkgfilebad=<<path>>
843  *		- one ckpkgfiles=<n>
844  * Actions:	output message
845  *		Return 0
846  */
847 
848 static int
849 ckpkgfilebad(char *a_msg, char *a_pkg)
850 {
851 	echoDebug(DBG_PREIVFY_CKPKGFILEBAD, a_pkg, a_msg);
852 
853 	ptext(stderr, "%s", a_msg);
854 
855 	return (0);
856 }
857 
858 /*
859  * Trigger:	ckconflict=<<n>>
860  * Sequence:	- one or more:
861  *		-- conflict-contents=<<path>>
862  *		-- conflict-attributes=<<path>>
863  *		- one: ckconflict=<<n>>
864  * Actions:	process according to settings
865  * Return value:	int
866  *			0 - success
867  *			1 - end of file
868  *			2 - undefined error
869  *			3 - answer was not "y"/was "q"
870  *			4 - quit action taken
871  *			5 - interactive mode required
872  */
873 
874 static int
875 ckconflict(char *a_msg, char *a_pkg)
876 {
877 	echoDebug(DBG_PREIVFY_CKCONFLICT, a_pkg, a_msg);
878 
879 	return (getyorn(a_msg, a_pkg, ADM(conflict, "nocheck"),
880 		ADM(conflict, "quit"), HLP_PKGADDCHK_CONFLICT,
881 		ERR_PKGADDCHK_CNFFAILED));
882 }
883 
884 /*
885  * Trigger:	cksetuid=<<n>>
886  * Sequence:	- one or more:
887  *		-- setuid=<path>:<owner>
888  *		-- setgid=<path>:<group>
889  *		-- setuid-overwrite=true
890  *		- one: cksetuid=<<n>>
891  * Actions:	process according to settings
892  * Return value:	int
893  *			0 - success
894  *			1 - end of file
895  *			2 - undefined error
896  *			3 - answer was not "y"/was "q"
897  *			4 - quit action taken
898  *			5 - interactive mode required
899  */
900 
901 static int
902 cksetuid(char *a_msg, char *a_pkg)
903 {
904 	char	ans[MAX_INPUT];
905 	char	ask_cont[MSG_MAX];
906 	int	n;
907 	int	saveCkquit;
908 
909 	echoDebug(DBG_PREIVFY_CKSETUID, a_pkg, a_msg);
910 
911 	n = getyorn(a_msg, a_pkg, ADM(setuid, "nocheck"),
912 		ADM(setuid, "quit"), HLP_PKGADDCHK_SETUID, NULL);
913 
914 	/* if user did not answer "n" return answer given */
915 
916 	if (n != 3) {
917 		return (n);
918 	}
919 
920 	(void) snprintf(ask_cont, sizeof (ask_cont), gettext(ASK_CONT), a_pkg);
921 
922 	saveCkquit = ckquit;
923 	ckquit = 0;
924 
925 	n = ckyorn(ans, NULL, NULL, gettext(HLP_PKGADDCHK_CONT), ask_cont);
926 
927 	ckquit = saveCkquit;
928 
929 	if (n != 0) {
930 		ptext(stderr, MSG_PREIVFY_GETYORN_TERM, a_pkg);
931 		echoDebug(DBG_PREIVFY_GETYORN_CKYORN, a_pkg, n);
932 		return (n);
933 	}
934 
935 	/* return "3 (interruption) if not "y" or "Y" */
936 
937 	if (strchr("yY", *ans) == NULL) {
938 		ptext(stderr, MSG_PREIVFY_GETYORN_TERM_USER, a_pkg);
939 		echoDebug(DBG_PREIVFY_GETYORN_NOT_Y, a_pkg, ans);
940 		return (3);
941 	}
942 
943 	/* return "0 - success" */
944 
945 	echoDebug(DBG_PREIVFY_GETYORN_SUCCESS, a_pkg);
946 
947 	return (0);
948 }
949 
950 /*
951  * Trigger:	ckpriv=<<n>>
952  * Sequence:	- one: ckpriv=<<n>>
953  * Actions:	process according to settings
954  * Return value:	int
955  *			0 - success
956  *			1 - end of file
957  *			2 - undefined error
958  *			3 - answer was not "y"/was "q"
959  *			4 - quit action taken
960  *			5 - interactive mode required
961  */
962 
963 static int
964 ckpriv(char *a_msg, char *a_pkg)
965 {
966 	echoDebug(DBG_PREIVFY_CKPRIV, a_pkg, a_msg);
967 
968 	return (getyorn(a_msg, a_pkg, ADM(action, "nocheck"),
969 		ADM(action, "quit"), HLP_PKGADDCHK_PRIV,
970 		ERR_PKGADDCHK_PRIVFAILED));
971 }
972 
973 /*
974  * Trigger:	ckpkgfiles=<<n>>
975  * Sequence:	- one or more:
976  *		-- ckpkgfilebad=<path>
977  *		- one: ckpkgfiles=<<n>>
978  * Return value:	int
979  *			0 - success
980  *			4 - failure
981  */
982 
983 static int
984 ckpkgfiles(char *a_msg, char *a_pkg)
985 {
986 	echoDebug(DBG_PREIVFY_CKPKGFILES, a_pkg, a_msg);
987 
988 	ptext(stderr, "%s", a_msg);
989 
990 	return (4);
991 }
992 
993 static int
994 attrib(char *a_msg, char *a_pkg)
995 {
996 	return (getyorn(a_msg, a_pkg, ADM(instance, "nocheck"),
997 		ADM(instance, "quit"), HLP_PKGADDCHK_CONT,
998 		ERR_PKGADDCHK_DEPFAILED));
999 }
1000 
1001 /* ARGSUSED1 */
1002 static int
1003 setuidf(char *a_msg, char *a_pkg)
1004 {
1005 	char *cp;
1006 
1007 	if ((cp = strchr(a_msg, ':')) != NULL)
1008 		*cp = ' ';
1009 	return (0);
1010 }
1011 
1012 /* ARGSUSED1 */
1013 static int
1014 setgidf(char *a_msg, char *a_pkg)
1015 {
1016 	char *cp;
1017 
1018 	if ((cp = strchr(a_msg, ':')) != NULL)
1019 		*cp = ' ';
1020 	return (0);
1021 }
1022 
1023 static int
1024 overwr(char *a_msg, char *a_pkg)
1025 {
1026 	return (getyorn(a_msg, a_pkg, ADM(instance, "nocheck"),
1027 		ADM(instance, "quit"), HLP_PKGADDCHK_SETUID,
1028 		ERR_PKGADDCHK_DEPFAILED));
1029 }
1030