root/usr/src/cmd/svr4pkg/libinst/depchk.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */


/*
 * System includes
 */

#include <stdio.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <locale.h>
#include <libintl.h>
#include <assert.h>

/*
 * local pkg command library includes
 */

#include "libinst.h"
#include "messages.h"

/*
 * forward declarations
 */

static int
collectError(int *r_numZones, char **r_zoneNames, char *a_packageName,
        depckl_t *a_dck, int a_depIndex, depckErrorRecord_t *a_eir,
        int a_errIndex);

/*
 * *****************************************************************************
 * global external (public) functions
 * *****************************************************************************
 */

int
depchkReportErrors(depckl_t *a_dck)
{
        char    *packageName;
        char    *zonenames;
        char    msgbuf[4096];
        int     err;
        int     i;
        int     numzones = 0;

        /* entry assertions */

        assert(a_dck != (depckl_t *)NULL);

        /* entry debugging info */

        echoDebug(DBG_DEPCHK_ENTRY);

        zonenames = (char *)NULL;

        /* go through dependency table, collect, collapse, report errors */

        for (i = 0; a_dck[i].name != (char *)NULL; i++) {
                int     j;
                depckError_t    *erc;

                if (zonenames != (char *)NULL) {
                        free(zonenames);
                        zonenames = (char *)NULL;
                }

                erc = a_dck[i].record;
                if (erc->er_numEntries == 0) {
                        continue;
                }

                for (j = 0; j < erc->er_numEntries; j++) {
                        int     k;
                        depckErrorRecord_t *eir;

                        if (zonenames != (char *)NULL) {
                                free(zonenames);
                                zonenames = (char *)NULL;
                        }

                        eir = &erc->er_theEntries[j];
                        packageName = eir->ier_packageName;
                        for (k = 0; k < eir->ier_numZones; k++) {
                                int err;

                                err = collectError(&numzones, &zonenames,
                                        packageName, a_dck, i, eir, k);
                                if (err != 0) {
                                        if (zonenames != (char *)NULL) {
                                                free(zonenames);
                                                zonenames = (char *)NULL;
                                        }
                                        return (err);
                                }
                        }

                        if (a_dck[i].ignore_values == (char *)NULL) {
                                continue;
                        }

                        if (a_dck[i].err_msg == (char **)NULL) {
                                (void) snprintf(msgbuf, sizeof (msgbuf),
                                        ERR_DEPENDENCY_IGNORED, a_dck[i].name,
                                        packageName,
                                        numzones == 1 ? "zone" : "zones",
                                        zonenames ? zonenames : "?");
                        } else {
                                /* LINTED variable format specifier to ... */
                                (void) snprintf(msgbuf, sizeof (msgbuf),
                                        *a_dck[i].err_msg, "package",
                                        packageName,
                                        numzones == 1 ? "zone" : "zones",
                                        zonenames ? zonenames : "??");
                        }

                        if (a_dck[i].depcklFunc != NULL) {
                                /* call check function */
                                err = (a_dck[i].depcklFunc)(msgbuf,
                                        packageName);
                                echoDebug(DBG_DEPCHK_REPORT_ERROR,
                                        a_dck[i].ignore_values, err,
                                        packageName, msgbuf);
                                if (err != 0) {
                                        if (zonenames != (char *)NULL) {
                                                free(zonenames);
                                                zonenames = (char *)NULL;
                                        }
                                        return (err);
                                }
                        } else {
                                /* no check function - just report message */
                                echoDebug(DBG_DEPCHK_IGNORE_ERROR,
                                        a_dck[i].ignore_values, packageName,
                                        msgbuf);
                                ptext(stderr, "\\n%s", msgbuf);
                        }
                }
        }

        if (zonenames != (char *)NULL) {
                free(zonenames);
                zonenames = (char *)NULL;
        }

        return (0);
}

void
depchkRecordError(depckError_t *a_erc, char *a_pkginst,
        char *a_zoneName, char *a_value)
{
        depckErrorRecord_t *erc;
        int             i;

        /*
         * create new error record and entry if first entry
         * record will look like this:
         * err->er_#entry=1
         * err->entry[0]->record->ier_numZones=1
         * err->entry[0]->record->ier_packageName=a_pkginst
         * err->entry[0]->record->ier_zones[0]=a_zoneName
         * err->entry[0]->record->ier_values[0]=a_value
         */

        if (a_erc->er_numEntries == 0) {
                depckErrorRecord_t      *eir;

                eir = (depckErrorRecord_t *)calloc(1,
                                        sizeof (depckErrorRecord_t));
                eir->ier_packageName = strdup(a_pkginst);
                eir->ier_numZones = 1;
                eir->ier_zones = (char **)calloc(1, sizeof (char **));
                (eir->ier_zones)[eir->ier_numZones-1] = strdup(a_zoneName);
                eir->ier_values = (char **)calloc(1, sizeof (char *));
                (eir->ier_values)[eir->ier_numZones-1] = strdup(a_value);

                a_erc->er_numEntries = 1;
                a_erc->er_theEntries = eir;

                echoDebug(DBG_DEPCHK_RECORD_ERROR, (long)a_erc, a_pkginst,
                                        a_zoneName, a_value);

                return;
        }

        /* see if this package already has an entry if so add zone to list */

        for (i = 0; i < a_erc->er_numEntries; i++) {
                erc = &a_erc->er_theEntries[i];

                if (strcmp(erc->ier_packageName, a_pkginst) != 0) {
                        continue;
                }

                echoDebug(DBG_DEPCHK_RECORD_ZERROR, (long)a_erc, a_zoneName,
                        a_value, erc->ier_packageName, erc->ier_numZones,
                        erc->ier_zones[0]);

                /*
                 * this package already has an entry - add zone to
                 * existing package entry the modified records will
                 * look like this:
                 * err->er_#entry++;
                 * err->entry[0]->...
                 * err->entry[i]->
                 * -------------->record->
                 * ---------------------->ier_numZones++;
                 * ---------------------->ier_packageName=a_pkginst
                 * ---------------------->ier_zones[0]=...
                 * ---------------------->ier_zones[...]=...
                 * ---------------------->ier_zones[ier_numZones-1]=a_zoneName
                 * ---------------------->ier_values[0]=...
                 * ---------------------->ier_values[...]=...
                 * ---------------------->ier_values[ier_numZones-1]=a_value
                 * err->entry[i+1]->...
                 */
                erc->ier_numZones++;
                erc->ier_zones = (char **)realloc(erc->ier_zones,
                                        sizeof (char **)*erc->ier_numZones);
                (erc->ier_zones)[erc->ier_numZones-1] = strdup(a_zoneName);
                erc->ier_values = (char **)realloc(erc->ier_values,
                                        sizeof (char **)*erc->ier_numZones);
                (erc->ier_values)[erc->ier_numZones-1] = strdup(a_value);
                return;
        }

        /*
         * this packages does not have an entry - add new package
         * entry for this zone the modified records will look like this:
         * err->er_#entry++;
         * err->entry[0]->record->ier_numZones=...
         * err->entry[0]->record->ier_packageName=...
         * err->entry[0]->record->ier_zones[0]=...
         * err->entry[0]->record->ier_values[0]=...
         * err->entry[er_#entry-1]->record->ier_numZones=1
         * err->entry[er_#entry-1]->record->ier_packageName=a_pkginst
         * err->entry[er_#entry-1]->record->ier_zones[0]=a_zoneName
         * err->entry[er_#entry-1]->record->ier_values[0]=a_value
         */

        echoDebug(DBG_DEPCHK_RECORD_PERROR, (long)a_erc,
                        a_erc->er_numEntries, a_pkginst, a_zoneName, a_value);

        a_erc->er_numEntries++;

        a_erc->er_theEntries = realloc(a_erc->er_theEntries,
                        sizeof (depckErrorRecord_t)*a_erc->er_numEntries);

        erc = &a_erc->er_theEntries[a_erc->er_numEntries-1];

        erc->ier_packageName = strdup(a_pkginst);
        erc->ier_numZones = 1;
        erc->ier_zones = (char **)calloc(1, sizeof (char *));
        (erc->ier_zones)[erc->ier_numZones-1] = strdup(a_zoneName);
        erc->ier_values = (char **)calloc(1, sizeof (char *));
        (erc->ier_values)[erc->ier_numZones-1] = strdup(a_value);
}

/*
 * *****************************************************************************
 * static internal (private) functions
 * *****************************************************************************
 */

static int
collectError(int *r_numZones, char **r_zoneNames, char *a_packageName,
        depckl_t *a_dck, int a_depIndex, depckErrorRecord_t *a_eir,
        int a_errIndex)
{
        char    msgbuf[4096];
        char    *zn = *r_zoneNames;

        if (a_dck[a_depIndex].ignore_values == (char *)NULL) {
                if (a_dck[a_depIndex].err_msg == (char **)NULL) {
                        (void) snprintf(msgbuf, sizeof (msgbuf),
                        ERR_DEPENDENCY_REPORT, a_eir->ier_values[a_errIndex],
                        "package", a_packageName,
                        "zone", a_eir->ier_zones[a_errIndex]);
                } else {
                        /* LINTED variable format specifier to snprintf(); */
                        (void) snprintf(msgbuf, sizeof (msgbuf),
                        *a_dck[a_depIndex].err_msg,
                        a_eir->ier_values[a_errIndex],
                        "package", a_packageName,
                        "zone", a_eir->ier_zones[a_errIndex]);
                }
                if (a_dck[a_depIndex].depcklFunc != NULL) {
                        int     err;

                        err = (a_dck[a_depIndex].depcklFunc)(msgbuf,
                                                        a_packageName);
                        echoDebug(DBG_DEPCHK_COLLECT_ERROR, err, a_packageName,
                                        msgbuf);
                        if (err != 0) {
                                return (err);
                        }
                } else {
                        echoDebug(DBG_DEPCHK_COLLECT_IGNORE, a_packageName,
                                        msgbuf);
                        ptext(stderr, "\\n%s", msgbuf);
                }
                return (0);
        }

        *r_numZones = (*r_numZones)+1;
        if (zn == (char *)NULL) {
                zn = strdup(a_eir->ier_zones[a_errIndex]);
        } else {
                char *p;
                int len = strlen(zn)+strlen(a_eir->ier_zones[a_errIndex])+3;
                p = calloc(1, len);
                (void) snprintf(p, len, "%s, %s", zn,
                        a_eir->ier_zones[a_errIndex]);
                free(zn);
                zn = p;

        }
        *r_zoneNames = zn;
        return (0);
}