/*
* 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 (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
#include <stdio.h>
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <dirent.h>
#include <sys/types.h>
#include <pkgstrct.h>
#include <pkginfo.h>
#include <locale.h>
#include <libintl.h>
#include <pkglib.h>
#include "libinst.h"
#include "libadm.h"
#include "messages.h"
#define LSIZE 256
#define NVERS 50
/*
* internal global variables
*/
static struct pkginfo info;
static char type;
static char *alist[NVERS];
static char *rmpkginst;
static char *vlist[NVERS];
static char file[128];
static char name[128];
static char rmpkg[PKGSIZ+1];
static char wabbrev[128];
static int errflg = 0;
static int nlist;
static int pkgexist;
static int pkgokay;
static int is_update;
/*
* IMPORTANT NOTE: THE SIZE OF 'abbrev' IS HARD CODED INTO THE CHARACTER
* ARRAY SSCANF_FORMAT -- YOU MUST UPDATE BOTH VALUES AT THE SAME TIME!!
*/
static char abbrev[128+1];
static char *SSCANF_FORMAT = "%c %128s %[^\n]";
/*
* forward declarations
*/
static void ckrdeps(boolean_t a_preinstallCheck);
static void ckpreq(FILE *fp, char *dname, boolean_t a_preinstallCheck);
static void deponme(char *pkginst, char *pkgname,
boolean_t a_preinstallCheck);
static void prereq(char *pkginst, char *pkgname,
boolean_t a_preinstallCheck);
static void incompat(char *pkginst, char *pkgname,
boolean_t a_preinstallCheck);
static int getaline(FILE *fp);
/*
* *****************************************************************************
* global external (public) functions
* *****************************************************************************
*/
int
dockdeps(char *a_depfile, int a_removeFlag, boolean_t a_preinstallCheck)
{
FILE *fp;
int i;
char *inst;
if (a_removeFlag) {
/* check removal dependencies */
rmpkginst = a_depfile;
(void) strncpy(rmpkg, rmpkginst, PKGSIZ);
(void) strtok(rmpkg, ".");
(void) snprintf(file, sizeof (file),
"%s/%s/%s", pkgdir, rmpkginst, DEPEND_FILE);
if ((fp = fopen(file, "r")) == NULL)
goto done;
} else {
if ((fp = fopen(a_depfile, "r")) == NULL) {
progerr(ERR_CANNOT_OPEN_DEPEND_FILE, a_depfile,
strerror(errno));
quit(99);
}
}
while (getaline(fp)) {
switch (type) {
case 'I':
case 'P':
if (a_removeFlag) {
continue;
}
break;
case 'R':
if (!a_removeFlag) {
continue;
}
break;
default:
errflg++;
progerr(ERR_UNKNOWN_DEPENDENCY, type);
break;
}
/* check to see if any versions listed are installed */
pkgexist = pkgokay = 0;
i = 0;
if (strchr(abbrev, '.')) {
progerr(ERR_PKGABRV, abbrev);
}
(void) snprintf(wabbrev, sizeof (wabbrev), "%s.*", abbrev);
do {
inst = fpkginst(wabbrev, alist[i], vlist[i]);
if (inst && (pkginfo(&info, inst, NULL, NULL) == 0)) {
pkgexist++;
if (info.status == PI_INSTALLED)
pkgokay++;
}
} while (++i < nlist);
(void) fpkginst(NULL); /* force closing/rewind of files */
if (!info.name) {
info.name = name;
}
switch (type) {
case 'I':
incompat(abbrev, info.name, a_preinstallCheck);
break;
case 'P':
prereq(abbrev, name, a_preinstallCheck);
break;
case 'R':
deponme(abbrev, info.name, a_preinstallCheck);
}
}
(void) fclose(fp);
done:
if (a_removeFlag) {
ckrdeps(a_preinstallCheck);
}
return (errflg);
}
void
setUpdate(void)
{
is_update = 1;
}
int
isUpdate(void)
{
return ((is_update) ? 1 : 0);
}
/*
* *****************************************************************************
* static internal (private) functions
* *****************************************************************************
*/
static void
incompat(char *pkginst, char *pkgname, boolean_t a_preinstallCheck)
{
char buf[512];
if (!pkgexist)
return;
errflg++;
if (a_preinstallCheck == B_TRUE) {
(void) fprintf(stdout, "incompat=%s\n", pkginst);
return;
}
logerr(ERR_WARNING);
(void) snprintf(buf, sizeof (buf), ERR_INCOMP_VERS, pkginst, pkgname);
puttext(stderr, buf, 4, 0);
(void) putc('\n', stderr);
}
static void
prereq(char *pkginst, char *pkgname, boolean_t a_preinstallCheck)
{
register int i;
char buf[512];
if (pkgokay) {
return;
}
errflg++;
if (a_preinstallCheck == B_TRUE) {
if (pkgexist) {
(void) fprintf(stdout,
"prerequisite-incomplete=%s\n", pkginst);
} else {
(void) fprintf(stdout,
"prerequisite-installed=%s\n", pkginst);
}
return;
}
logerr(ERR_WARNING);
if (pkgexist) {
(void) snprintf(buf, sizeof (buf), ERR_PRENCI, pkginst,
pkgname);
puttext(stderr, buf, 4, 0);
(void) putc('\n', stderr);
} else {
(void) snprintf(buf, sizeof (buf), ERR_PREREQ, pkginst,
pkgname);
if (nlist) {
(void) strcat(buf, ERR_VALINST);
}
puttext(stderr, buf, 4, 0);
(void) putc('\n', stderr);
for (i = 0; i < nlist; i++) {
(void) printf(" ");
if (alist[i])
(void) printf("(%s) ", alist[i]);
if (vlist[i])
(void) printf("%s", vlist[i]);
(void) printf("\n");
}
}
}
static void
deponme(char *pkginst, char *pkgname, boolean_t a_preinstallCheck)
{
char buf[512];
if (!pkgexist)
return;
errflg++;
if (a_preinstallCheck == B_TRUE) {
if (!pkgname || !pkgname[0]) {
(void) snprintf(buf, sizeof (buf),
"dependonme=%s", pkginst);
} else {
(void) snprintf(buf, sizeof (buf),
"dependsonme=%s:%s", pkginst, pkgname);
}
(void) fprintf(stdout, "%s\n", buf);
return;
}
logerr(ERR_WARNING);
if (!pkgname || !pkgname[0]) {
(void) snprintf(buf, sizeof (buf), ERR_DEPONME, pkginst);
} else {
(void) snprintf(buf, sizeof (buf), ERR_DEPNAM, pkginst,
pkgname);
}
puttext(stderr, buf, 4, 0);
(void) putc('\n', stderr);
}
static int
getaline(FILE *fp)
{
register int i, c, found;
char *pt, *new, line[LSIZE];
abbrev[0] = name[0] = type = '\0';
for (i = 0; i < nlist; i++) {
if (alist[i]) {
free(alist[i]);
alist[i] = NULL;
}
if (vlist[i]) {
free(vlist[i]);
vlist[i] = NULL;
}
}
alist[0] = vlist[0] = NULL;
found = (-1);
nlist = 0;
while ((c = getc(fp)) != EOF) {
(void) ungetc(c, fp);
if ((found >= 0) && !isspace(c))
return (1);
if (!fgets(line, LSIZE, fp))
break;
for (pt = line; isspace(*pt); /* void */)
pt++;
if (!*pt || (*pt == '#'))
continue;
if (pt == line) {
/* begin new definition */
/* LINTED variable format specifier to sscanf(): */
(void) sscanf(line, SSCANF_FORMAT, &type, abbrev, name);
found++;
continue;
}
if (found < 0)
return (0);
if (*pt == '(') {
/* architecture is specified */
if (new = strchr(pt, ')'))
*new++ = '\0';
else
return (-1); /* bad specification */
alist[found] = qstrdup(pt+1);
pt = new;
}
while (isspace(*pt))
pt++;
if (*pt) {
vlist[found] = qstrdup(pt);
if (pt = strchr(vlist[found], '\n'))
*pt = '\0';
}
found++;
nlist++;
}
return ((found >= 0) ? 1 : 0);
}
static void
ckrdeps(boolean_t a_preinstallCheck)
{
struct dirent *drp;
DIR *dirfp;
FILE *fp;
char depfile[PATH_MAX+1];
if ((dirfp = opendir(pkgdir)) == NULL)
return;
while ((drp = readdir(dirfp)) != NULL) {
if (drp->d_name[0] == '.')
continue;
if (strcmp(drp->d_name, rmpkginst) == 0)
continue; /* others don't include me */
(void) snprintf(depfile, sizeof (depfile),
"%s/%s/%s", pkgdir, drp->d_name, DEPEND_FILE);
if ((fp = fopen(depfile, "r")) == NULL)
continue;
ckpreq(fp, drp->d_name, a_preinstallCheck);
}
(void) closedir(dirfp);
}
static void
ckpreq(FILE *fp, char *dname, boolean_t a_preinstallCheck)
{
register int i;
char *inst;
while (getaline(fp)) {
if (type != 'P')
continue;
if (strcmp(abbrev, rmpkg))
continue;
/* see if package is installed */
i = 0;
if (strchr(abbrev, '.') == 0) {
(void) strcat(abbrev, ".*");
}
pkgexist = 1;
do {
if (inst = fpkginst(abbrev, alist[i], vlist[i])) {
if (strcmp(inst, rmpkginst) == 0) {
deponme(dname, "", a_preinstallCheck);
(void) fclose(fp);
(void) fpkginst(NULL);
return;
}
}
} while (++i < nlist);
(void) fpkginst(NULL);
}
(void) fclose(fp);
}