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 2004 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27
28/*
29 * System includes
30 */
31
32#include <stdio.h>
33#include <limits.h>
34#include <string.h>
35#include <stdlib.h>
36#include <unistd.h>
37#include <errno.h>
38#include <sys/types.h>
39#include <locale.h>
40#include <libintl.h>
41#include <assert.h>
42
43/*
44 * local pkg command library includes
45 */
46
47#include "libinst.h"
48#include "messages.h"
49
50/*
51 * forward declarations
52 */
53
54static int
55collectError(int *r_numZones, char **r_zoneNames, char *a_packageName,
56	depckl_t *a_dck, int a_depIndex, depckErrorRecord_t *a_eir,
57	int a_errIndex);
58
59/*
60 * *****************************************************************************
61 * global external (public) functions
62 * *****************************************************************************
63 */
64
65int
66depchkReportErrors(depckl_t *a_dck)
67{
68	char	*packageName;
69	char	*zonenames;
70	char	msgbuf[4096];
71	int	err;
72	int	i;
73	int	numzones = 0;
74
75	/* entry assertions */
76
77	assert(a_dck != (depckl_t *)NULL);
78
79	/* entry debugging info */
80
81	echoDebug(DBG_DEPCHK_ENTRY);
82
83	zonenames = (char *)NULL;
84
85	/* go through dependency table, collect, collapse, report errors */
86
87	for (i = 0; a_dck[i].name != (char *)NULL; i++) {
88		int	j;
89		depckError_t	*erc;
90
91		if (zonenames != (char *)NULL) {
92			free(zonenames);
93			zonenames = (char *)NULL;
94		}
95
96		erc = a_dck[i].record;
97		if (erc->er_numEntries == 0) {
98			continue;
99		}
100
101		for (j = 0; j < erc->er_numEntries; j++) {
102			int	k;
103			depckErrorRecord_t *eir;
104
105			if (zonenames != (char *)NULL) {
106				free(zonenames);
107				zonenames = (char *)NULL;
108			}
109
110			eir = &erc->er_theEntries[j];
111			packageName = eir->ier_packageName;
112			for (k = 0; k < eir->ier_numZones; k++) {
113				int err;
114
115				err = collectError(&numzones, &zonenames,
116					packageName, a_dck, i, eir, k);
117				if (err != 0) {
118					if (zonenames != (char *)NULL) {
119						free(zonenames);
120						zonenames = (char *)NULL;
121					}
122					return (err);
123				}
124			}
125
126			if (a_dck[i].ignore_values == (char *)NULL) {
127				continue;
128			}
129
130			if (a_dck[i].err_msg == (char **)NULL) {
131				(void) snprintf(msgbuf, sizeof (msgbuf),
132					ERR_DEPENDENCY_IGNORED, a_dck[i].name,
133					packageName,
134					numzones == 1 ? "zone" : "zones",
135					zonenames ? zonenames : "?");
136			} else {
137				/* LINTED variable format specifier to ... */
138				(void) snprintf(msgbuf, sizeof (msgbuf),
139					*a_dck[i].err_msg, "package",
140					packageName,
141					numzones == 1 ? "zone" : "zones",
142					zonenames ? zonenames : "??");
143			}
144
145			if (a_dck[i].depcklFunc != NULL) {
146				/* call check function */
147				err = (a_dck[i].depcklFunc)(msgbuf,
148					packageName);
149				echoDebug(DBG_DEPCHK_REPORT_ERROR,
150					a_dck[i].ignore_values, err,
151					packageName, msgbuf);
152				if (err != 0) {
153					if (zonenames != (char *)NULL) {
154						free(zonenames);
155						zonenames = (char *)NULL;
156					}
157					return (err);
158				}
159			} else {
160				/* no check function - just report message */
161				echoDebug(DBG_DEPCHK_IGNORE_ERROR,
162					a_dck[i].ignore_values, packageName,
163					msgbuf);
164				ptext(stderr, "\\n%s", msgbuf);
165			}
166		}
167	}
168
169	if (zonenames != (char *)NULL) {
170		free(zonenames);
171		zonenames = (char *)NULL;
172	}
173
174	return (0);
175}
176
177void
178depchkRecordError(depckError_t *a_erc, char *a_pkginst,
179	char *a_zoneName, char *a_value)
180{
181	depckErrorRecord_t *erc;
182	int		i;
183
184	/*
185	 * create new error record and entry if first entry
186	 * record will look like this:
187	 * err->er_#entry=1
188	 * err->entry[0]->record->ier_numZones=1
189	 * err->entry[0]->record->ier_packageName=a_pkginst
190	 * err->entry[0]->record->ier_zones[0]=a_zoneName
191	 * err->entry[0]->record->ier_values[0]=a_value
192	 */
193
194	if (a_erc->er_numEntries == 0) {
195		depckErrorRecord_t	*eir;
196
197		eir = (depckErrorRecord_t *)calloc(1,
198					sizeof (depckErrorRecord_t));
199		eir->ier_packageName = strdup(a_pkginst);
200		eir->ier_numZones = 1;
201		eir->ier_zones = (char **)calloc(1, sizeof (char **));
202		(eir->ier_zones)[eir->ier_numZones-1] = strdup(a_zoneName);
203		eir->ier_values = (char **)calloc(1, sizeof (char *));
204		(eir->ier_values)[eir->ier_numZones-1] = strdup(a_value);
205
206		a_erc->er_numEntries = 1;
207		a_erc->er_theEntries = eir;
208
209		echoDebug(DBG_DEPCHK_RECORD_ERROR, (long)a_erc, a_pkginst,
210					a_zoneName, a_value);
211
212		return;
213	}
214
215	/* see if this package already has an entry if so add zone to list */
216
217	for (i = 0; i < a_erc->er_numEntries; i++) {
218		erc = &a_erc->er_theEntries[i];
219
220		if (strcmp(erc->ier_packageName, a_pkginst) != 0) {
221			continue;
222		}
223
224		echoDebug(DBG_DEPCHK_RECORD_ZERROR, (long)a_erc, a_zoneName,
225			a_value, erc->ier_packageName, erc->ier_numZones,
226			erc->ier_zones[0]);
227
228		/*
229		 * this package already has an entry - add zone to
230		 * existing package entry the modified records will
231		 * look like this:
232		 * err->er_#entry++;
233		 * err->entry[0]->...
234		 * err->entry[i]->
235		 * -------------->record->
236		 * ---------------------->ier_numZones++;
237		 * ---------------------->ier_packageName=a_pkginst
238		 * ---------------------->ier_zones[0]=...
239		 * ---------------------->ier_zones[...]=...
240		 * ---------------------->ier_zones[ier_numZones-1]=a_zoneName
241		 * ---------------------->ier_values[0]=...
242		 * ---------------------->ier_values[...]=...
243		 * ---------------------->ier_values[ier_numZones-1]=a_value
244		 * err->entry[i+1]->...
245		 */
246		erc->ier_numZones++;
247		erc->ier_zones = (char **)realloc(erc->ier_zones,
248					sizeof (char **)*erc->ier_numZones);
249		(erc->ier_zones)[erc->ier_numZones-1] = strdup(a_zoneName);
250		erc->ier_values = (char **)realloc(erc->ier_values,
251					sizeof (char **)*erc->ier_numZones);
252		(erc->ier_values)[erc->ier_numZones-1] = strdup(a_value);
253		return;
254	}
255
256	/*
257	 * this packages does not have an entry - add new package
258	 * entry for this zone the modified records will look like this:
259	 * err->er_#entry++;
260	 * err->entry[0]->record->ier_numZones=...
261	 * err->entry[0]->record->ier_packageName=...
262	 * err->entry[0]->record->ier_zones[0]=...
263	 * err->entry[0]->record->ier_values[0]=...
264	 * err->entry[er_#entry-1]->record->ier_numZones=1
265	 * err->entry[er_#entry-1]->record->ier_packageName=a_pkginst
266	 * err->entry[er_#entry-1]->record->ier_zones[0]=a_zoneName
267	 * err->entry[er_#entry-1]->record->ier_values[0]=a_value
268	 */
269
270	echoDebug(DBG_DEPCHK_RECORD_PERROR, (long)a_erc,
271			a_erc->er_numEntries, a_pkginst, a_zoneName, a_value);
272
273	a_erc->er_numEntries++;
274
275	a_erc->er_theEntries = realloc(a_erc->er_theEntries,
276			sizeof (depckErrorRecord_t)*a_erc->er_numEntries);
277
278	erc = &a_erc->er_theEntries[a_erc->er_numEntries-1];
279
280	erc->ier_packageName = strdup(a_pkginst);
281	erc->ier_numZones = 1;
282	erc->ier_zones = (char **)calloc(1, sizeof (char *));
283	(erc->ier_zones)[erc->ier_numZones-1] = strdup(a_zoneName);
284	erc->ier_values = (char **)calloc(1, sizeof (char *));
285	(erc->ier_values)[erc->ier_numZones-1] = strdup(a_value);
286}
287
288/*
289 * *****************************************************************************
290 * static internal (private) functions
291 * *****************************************************************************
292 */
293
294static int
295collectError(int *r_numZones, char **r_zoneNames, char *a_packageName,
296	depckl_t *a_dck, int a_depIndex, depckErrorRecord_t *a_eir,
297	int a_errIndex)
298{
299	char	msgbuf[4096];
300	char	*zn = *r_zoneNames;
301
302	if (a_dck[a_depIndex].ignore_values == (char *)NULL) {
303		if (a_dck[a_depIndex].err_msg == (char **)NULL) {
304			(void) snprintf(msgbuf, sizeof (msgbuf),
305			ERR_DEPENDENCY_REPORT, a_eir->ier_values[a_errIndex],
306			"package", a_packageName,
307			"zone", a_eir->ier_zones[a_errIndex]);
308		} else {
309			/* LINTED variable format specifier to snprintf(); */
310			(void) snprintf(msgbuf, sizeof (msgbuf),
311			*a_dck[a_depIndex].err_msg,
312			a_eir->ier_values[a_errIndex],
313			"package", a_packageName,
314			"zone", a_eir->ier_zones[a_errIndex]);
315		}
316		if (a_dck[a_depIndex].depcklFunc != NULL) {
317			int	err;
318
319			err = (a_dck[a_depIndex].depcklFunc)(msgbuf,
320							a_packageName);
321			echoDebug(DBG_DEPCHK_COLLECT_ERROR, err, a_packageName,
322					msgbuf);
323			if (err != 0) {
324				return (err);
325			}
326		} else {
327			echoDebug(DBG_DEPCHK_COLLECT_IGNORE, a_packageName,
328					msgbuf);
329			ptext(stderr, "\\n%s", msgbuf);
330		}
331		return (0);
332	}
333
334	*r_numZones = (*r_numZones)+1;
335	if (zn == (char *)NULL) {
336		zn = strdup(a_eir->ier_zones[a_errIndex]);
337	} else {
338		char *p;
339		int len = strlen(zn)+strlen(a_eir->ier_zones[a_errIndex])+3;
340		p = calloc(1, len);
341		(void) snprintf(p, len, "%s, %s", zn,
342			a_eir->ier_zones[a_errIndex]);
343		free(zn);
344		zn = p;
345
346	}
347	*r_zoneNames = zn;
348	return (0);
349}
350