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.
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.
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]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
37 #include <sys/types.h>
48 #include <instzones_api.h>
50 extern int npkgs
; /* the number of packages yet to be installed */
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.
59 extern struct admin adm
;
62 * each one of these represents a single kind of dependency check
65 static depckError_t er_depsonme
= {0, (depckErrorRecord_t
*)NULL
};
66 static depckError_t er_prenci
= {0, (depckErrorRecord_t
*)NULL
};
67 static depckError_t er_prereq
= {0, (depckErrorRecord_t
*)NULL
};
68 static depckError_t er_rckdepend
= {0, (depckErrorRecord_t
*)NULL
};
69 static depckError_t er_rckpriv
= {0, (depckErrorRecord_t
*)NULL
};
70 static depckError_t er_rckrunlevel
= {0, (depckErrorRecord_t
*)NULL
};
71 static depckError_t er_runlevel
= {0, (depckErrorRecord_t
*)NULL
};
74 * each one of these represents a localized message for a single kind
78 static char *IMSG_PKGRMCHK_CKRUNLVL
= (char *)NULL
;
79 static char *IMSG_PKGRMCHK_DEPEND
= (char *)NULL
;
80 static char *IMSG_PKGRMCHK_DEPSONME
= (char *)NULL
;
81 static char *IMSG_PKGRMCHK_PRENCI
= (char *)NULL
;
82 static char *IMSG_PKGRMCHK_PREREQ
= (char *)NULL
;
83 static char *IMSG_PKGRMCHK_PRIV
= (char *)NULL
;
84 static char *IMSG_PKGRMCHK_RUNLEVEL
= (char *)NULL
;
87 * each one of these represents a function to handle a single kind of
91 static int rckdepend(char *a_msg
, char *a_pkg
);
92 static int rckdepsonme(char *a_msg
, char *a_pkg
);
93 static int rckprenci(char *a_msg
, char *a_pkg
);
94 static int rckprereq(char *a_msg
, char *a_pkg
);
95 static int rckpriv(char *a_msg
, char *a_pkg
);
96 static int rckrunlevel(char *a_msg
, char *a_pkg
);
98 static depckl_t DEPCKL
[] = {
103 * --- rckpriv=%d ****
105 * -- prerequisite-incomplete=%s
107 * -- dependsonme=%s:%s
108 * -- prerequisite-installed=%s
109 * ---rckdepend=%d ****
112 /* name, ignore_values, err_msg, depcklFunc, recrd */
114 * package and zone information is collected in the "record" object for
115 * each occurance - then a message is constructed for each zone that
116 * reported the condition - the message includes that portion of the
117 * check past the "=" - then the specified "depcklFunc" is called to
118 * process each message.
122 * value, "package", package-name, "zone/zones", zone-name
125 { "dependsonme=", NULL
, &IMSG_PKGRMCHK_DEPSONME
,
126 &rckdepsonme
, &er_depsonme
128 { "dependonme=", NULL
, &IMSG_PKGRMCHK_DEPSONME
,
129 &rckdepsonme
, &er_depsonme
131 { "prerequisite-incomplete=", NULL
, &IMSG_PKGRMCHK_PRENCI
,
132 &rckprenci
, &er_prenci
134 { "prerequisite-installed=", NULL
, &IMSG_PKGRMCHK_PREREQ
,
135 &rckprereq
, &er_prereq
137 { "runlevel=", NULL
, &IMSG_PKGRMCHK_RUNLEVEL
,
142 * these checks are ignored if they return one of the listed values
143 * if they do NOT return one of the listed values, then the package
144 * and zone information is collected in the "record" object for each
145 * occurance - then a single unified message is constructed for all
146 * zones that report the same condition; then the specified "depcklFunc"
147 * is called to process the resulting combined message.
151 * "package", package-name, "zone/zones", zone-name(s)
154 { "rckdepend=", "0", &IMSG_PKGRMCHK_DEPEND
,
155 &rckdepend
, &er_rckdepend
157 { "rckpriv=", "0", &IMSG_PKGRMCHK_PRIV
,
158 &rckpriv
, &er_rckpriv
160 { "rckrunlevel=", "0", &IMSG_PKGRMCHK_CKRUNLVL
,
161 &rckrunlevel
, &er_rckrunlevel
165 * same as above BUT no check to ignore is done; message always reported
174 * Name: preremove_verify
175 * Description: verify results of preremoval dependency checking
176 * Arguments: a_pkglist - pointer to array of strings representing the names
177 * of all the packages that have been checked
178 * a_zlst - list of zones that dependencies were checked on
179 * a_zoneTempDir - pointer to string representing the path where
180 * the files containing the preremoval dependency
181 * check data are located
183 * == 0 - continue processing
184 * != 0 - do not continue processing
188 preremove_verify(char **a_pkglist
, zoneList_t a_zlst
, char *a_zoneTempDir
)
192 int savenpkgs
= npkgs
;
198 assert(a_pkglist
!= (char **)NULL
);
199 assert(a_zlst
!= (zoneList_t
)NULL
);
200 assert(a_zoneTempDir
!= (char *)NULL
);
203 * entry debugging info
206 echoDebug(DBG_PRERVFY_ENTRY
);
212 IMSG_PKGRMCHK_DEPSONME
= MSG_PKGRMCHK_DEPSONME
;
213 IMSG_PKGRMCHK_PRENCI
= MSG_PKGRMCHK_PRENCI
;
214 IMSG_PKGRMCHK_PREREQ
= MSG_PKGRMCHK_PREREQ
;
215 IMSG_PKGRMCHK_RUNLEVEL
= MSG_PKGRMCHK_RUNLEVEL
;
216 IMSG_PKGRMCHK_DEPEND
= MSG_PKGRMCHK_DEPEND
;
217 IMSG_PKGRMCHK_PRIV
= MSG_PKGRMCHK_PRIV
;
218 IMSG_PKGRMCHK_CKRUNLVL
= MSG_PKGRMCHK_CKRUNLVL
;
221 * outer loop - process each package first
224 for (i
= 0; (pkginst
= a_pkglist
[i
]) != NULL
; i
++) {
230 * inner loop - for each package process each zone second
233 if (pkgIsPkgInGzOnly(get_inst_root(), pkginst
) == B_TRUE
) {
238 (zoneName
= z_zlist_get_zonename(a_zlst
, zoneIndex
)) !=
239 (char *)NULL
; zoneIndex
++) {
242 char line
[PATH_MAX
+1];
243 char preremovecheckPath
[PATH_MAX
+1];
246 /* skip the zone if it is NOT bootable */
248 if (z_zlist_is_zone_runnable(a_zlst
,
249 zoneIndex
) == B_FALSE
) {
253 /* create path to this packages preremove check data */
255 len
= snprintf(preremovecheckPath
,
256 sizeof (preremovecheckPath
),
257 "%s/%s.%s.preremovecheck.txt",
258 a_zoneTempDir
, pkginst
,
259 z_zlist_get_scratch(a_zlst
, zoneIndex
));
261 if (len
> sizeof (preremovecheckPath
)) {
262 progerr(ERR_CREATE_PATH_3
, a_zoneTempDir
,
267 /* error if preremove check data path is not a file */
269 if (isfile((char *)NULL
, preremovecheckPath
) != 0) {
270 echoDebug(DBG_PRERVFY_NOFILE
, pkginst
, zoneName
,
271 preremovecheckPath
, strerror(errno
));
272 progerr(ERR_PRERVFY_NOFILE
, pkginst
, zoneName
);
276 /* open the preremove check data file */
278 fp
= fopen(preremovecheckPath
, "r");
279 if (fp
== (FILE *)NULL
) {
280 progerr(ERR_PRERVFY_OPEN_FILE
,
281 preremovecheckPath
, pkginst
, zoneName
,
286 /* read and process each preremove check data line */
288 while (fgets(line
, sizeof (line
), fp
) != (char *)NULL
) {
292 /* remove all new-lines from end of line */
295 while ((len
> 0) && (line
[len
-1] == '\n')) {
299 /* ignore comment lines */
301 if (line
[0] == '#') {
305 /* ignore empty lines */
307 if (line
[0] == '\0') {
311 /* scan dependency list for this item */
314 DEPCKL
[j
].name
!= (char *)NULL
; j
++) {
315 len
= strlen(DEPCKL
[j
].name
);
317 if (strncmp(line
, DEPCKL
[j
].name
,
323 echoDebug(DBG_PRERVFY_SCAN
, line
, pkginst
,
326 /* ignore line if not found */
328 if (DEPCKL
[j
].name
== (char *)NULL
) {
329 progerr(ERR_PRERVFY_UNKNOWN_LINE
, line
,
334 if ((DEPCKL
[j
].ignore_values
!= (char *)NULL
) &&
335 (*(DEPCKL
[j
].ignore_values
) != '\0') &&
336 (strchr(DEPCKL
[j
].ignore_values
,
337 line
[len
]) != (char *)NULL
)) {
340 /* found match - record this dependency issue */
342 depchkRecordError(DEPCKL
[j
].record
, pkginst
,
343 zoneName
, &line
[len
]);
346 /* close preremove check data file */
353 * all dependency issues have been recorded; report results
356 i
= depchkReportErrors(DEPCKL
);
358 /* restore "npkgs" */
362 /* return continue/dont dontinue results */
369 * Description: Deliver dependency check reason; ask question; return response
370 * Arguments: a_msg - pointer to string representing the message to output
371 * such as 'The package <..> contains <...>'
372 * a_pkg - pointer to string representing the package for which
373 * the question is being asked
374 * a_nocheck - should the message be output?
375 * == 0 - do not output the message
376 * != 0 - output the message
377 * a_quit - should the question NOT be asked?
378 * == 0 - ask the question
379 * != 0 - do not ask the question - return "no"
380 * a_helpMsg - pointer to string representing help message to be
381 * made available if the question is asked
382 * == NULL - no help message is available
383 * a_adminMsg - pointer to string representing the dependency check
384 * failure 'reason' - such as "Privilege checking failed."
385 * == NULL - no failure reason is available
386 * Returns: int - results of question/response actions
389 * 2 - undefined error
390 * 3 - answer was not "y"/was "q"
391 * 4 - quit action taken
392 * 5 - interactive mode required
396 getyorn(char *a_msg
, char *a_pkg
, int a_nocheck
, int a_quit
,
397 char *a_helpMsg
, char *a_adminMsg
)
400 char ask_cont
[MSG_MAX
];
408 assert(a_pkg
!= (char *)NULL
);
409 assert(*a_pkg
!= '\0');
412 * entry debugging info
415 echoDebug(DBG_PRERVFY_GETYORN_ARGS
, a_pkg
, a_nocheck
, a_quit
, a_msg
,
416 a_adminMsg
? a_adminMsg
: "");
418 /* return success (0) if "nocheck" is non-zero */
420 if (a_nocheck
!= 0) {
421 echoDebug(DBG_PRERVFY_GETYORN_NOCHECK
, a_pkg
);
425 /* output reason for this particular failure */
427 if ((a_msg
!= (char *)NULL
) && (*a_msg
!= '\0')) {
428 ptext(stderr
, "%s", a_msg
);
431 /* return "4 (administration)" if "quit" is non-zero */
434 /* output failure "admin reason" if available */
435 if ((a_adminMsg
!= (char *)NULL
) && (*a_adminMsg
!= '\0')) {
436 ptext(stderr
, a_adminMsg
);
438 echoDebug(DBG_PRERVFY_GETYORN_QUIT
, a_pkg
);
442 /* return "5 (administration interaction required)" if -n */
444 if (echoGetFlag() == B_FALSE
) {
445 ptext(stderr
, MSG_PRERVFY_GETYORN_SUSP
, a_pkg
);
446 echoDebug(DBG_PRERVFY_GETYORN_QUIT_USER
, a_pkg
);
450 /* prepare question to ask "continue with removal of pkg <xxx>?" */
452 (void) snprintf(ask_cont
, sizeof (ask_cont
), gettext(ASK_PKGRMCHK_CONT
),
460 n
= ckyorn(ans
, NULL
, NULL
, a_helpMsg
, ask_cont
);
465 ptext(stderr
, MSG_PRERVFY_GETYORN_TERM
, a_pkg
);
466 echoDebug(DBG_PRERVFY_GETYORN_CKYORN
, a_pkg
, n
);
470 /* return "3 (interruption) if not "y" or "Y" */
472 if (strchr("yY", *ans
) == NULL
) {
473 ptext(stderr
, MSG_PRERVFY_GETYORN_TERM_USER
, a_pkg
);
474 echoDebug(DBG_PRERVFY_GETYORN_NOT_Y
, a_pkg
, ans
);
478 /* return "0 - success" */
480 echoDebug(DBG_PRERVFY_GETYORN_SUCCESS
, a_pkg
);
486 * Trigger: dependsonme=<<package>>
487 * Sequence: - one or more: dependsonme=<<package>>
488 * - one: rckdepend=<<n>>
489 * Actions: Output message if "rdepend!=nocheck"
491 * Terminate when 'rckdepend' processed
495 rckdepsonme(char *a_msg
, char *a_pkg
)
497 echoDebug(DBG_PRERVFY_RCKDEPSONME
, a_pkg
, a_msg
);
499 if (!(ADM(rdepend
, "nocheck"))) {
500 ptext(stderr
, "%s", a_msg
);
507 * Trigger: prerequisite-incomplete=<<package>>
508 * Sequence: - one or more: prerequisite-incomplete=<<package>>
509 * - one: rckdepend=<<n>>
510 * Actions: Output message if "rdepend!=nocheck"
512 * Terminate when 'rckdepend' processed
516 rckprenci(char *a_msg
, char *a_pkg
)
518 echoDebug(DBG_PRERVFY_RCKPRENCI
, a_pkg
, a_msg
);
520 if (!(ADM(rdepend
, "nocheck"))) {
521 ptext(stderr
, "%s", a_msg
);
528 * Trigger: prerequisite-installed=<<package>>
529 * Sequence: - one or more: prerequisite-installed=<<package>>
530 * - one: rckdepend=<<n>>
531 * Actions: Output message if "rdepend!=nocheck"
533 * Terminate when 'rckdepend' processed
537 rckprereq(char *a_msg
, char *a_pkg
)
539 echoDebug(DBG_PRERVFY_RCKPREREQ
, a_pkg
, a_msg
);
541 if (!(ADM(rdepend
, "nocheck"))) {
542 ptext(stderr
, "%s", a_msg
);
552 * 2 - undefined error
553 * 3 - answer was not "y"/was "q"
554 * 4 - quit action taken
555 * 5 - interactive mode required
560 rckrunlevel(char *a_msg
, char *a_pkg
)
562 echoDebug(DBG_PRERVFY_RCKRUNLEVEL
, a_pkg
, a_msg
);
564 * For now, we are ignoring runlevel removal issues within
565 * non-global zones. This is questionable, but the RSTATES
566 * feature is rarely used and known uses within Solaris are
567 * effectively no-ops as of this time
573 * Trigger: rckdepend=<<n>>
574 * Sequence: - one or more of:
575 * -- incompat=<<package>>
576 * -- prerequisite-incomplete=<<package>>
577 * -- prerequisite-installed=<<package>>
578 * -- dependson=<<package>>
579 * -- dependsonme=<<package>>
580 * - one: ckpdepend=<<n>>
581 * Actions: process according to settings
585 * 2 - undefined error
586 * 3 - answer was not "y"/was "q"
587 * 4 - quit action taken
588 * 5 - interactive mode required
592 rckdepend(char *a_msg
, char *a_pkg
)
594 echoDebug(DBG_PRERVFY_RCKDEPEND
, a_pkg
, a_msg
);
596 return (getyorn(a_msg
, a_pkg
, ADM(rdepend
, "nocheck"),
597 ADM(rdepend
, "quit"), HLP_PKGRMCHK_DEPEND
,
598 ERR_PKGRMCHK_DEPFAILED
));
602 * Trigger: rckpriv=<<n>>
603 * Sequence: - one: rckpriv=<<n>>
604 * Actions: process according to settings
608 * 2 - undefined error
609 * 3 - answer was not "y"/was "q"
610 * 4 - quit action taken
611 * 5 - interactive mode required
615 rckpriv(char *a_msg
, char *a_pkg
)
617 echoDebug(DBG_PRERVFY_RCKPRIV
, a_pkg
, a_msg
);
619 return (getyorn(a_msg
, a_pkg
, ADM(action
, "nocheck"),
620 ADM(action
, "quit"), HLP_PKGRMCHK_PRIV
,
621 ERR_PKGRMCHK_PRIVFAILED
));