/*
* 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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
#include <stdio.h>
#include <memory.h>
#include <string.h>
#include <limits.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pkgstrct.h>
#include <locale.h>
#include <libintl.h>
#include <unistd.h>
#include <stdlib.h>
#include "pkglib.h"
#include "install.h"
#include "libadm.h"
#include "libinst.h"
extern int Lflag, lflag, aflag, cflag, fflag, qflag, nflag, xflag, vflag;
extern char *basedir, *device, pkgspool[];
#define NXTENTRY(P, VFP) (gpkgmapvfp((P), (VFP)))
#define ERR_SPOOLED "ERROR: unable to locate spooled object <%s>"
#define MSG_NET_OBJ "It is remote and may be available from the network."
#define ERR_RMHIDDEN "unable to remove hidden file"
#define ERR_HIDDEN "ERROR: hidden file in exclusive directory"
static char *findspool(struct cfent *ept);
static int xdir(int maptyp, VFP_T *vfp, PKGserver server, char *dirname);
int
ckentry(int envflag, int maptyp, struct cfent *ept, VFP_T *vfp,
PKGserver server)
{
int a_err, c_err,
errflg;
char *path;
char *ir = get_inst_root();
if (ept->ftype != 'i') {
if (envflag)
mappath(2, ept->path);
if (!device)
basepath(ept->path, maptyp ? NULL : basedir, ir);
}
canonize(ept->path);
if (strchr("sl", ept->ftype)) {
if (envflag) /* -e option */
mappath(2, ept->ainfo.local);
if (!RELATIVE(ept->ainfo.local)) { /* Absolute Path */
if (!device) {
if (ept->ftype == 'l') /* Hard Link */
basepath(ept->ainfo.local, NULL, ir);
}
}
if (!RELATIVE(ept->ainfo.local)) /* Absolute Path */
canonize(ept->ainfo.local);
}
if (envflag) {
if (!strchr("isl", ept->ftype)) {
mapvar(2, ept->ainfo.owner);
mapvar(2, ept->ainfo.group);
}
}
if (lflag) {
tputcfent(ept, stdout);
return (0);
} else if (Lflag)
return (putcfile(ept, stdout));
errflg = 0;
if (device) {
if (strchr("dxslcbp", ept->ftype))
return (0);
if ((path = findspool(ept)) == NULL) {
logerr(gettext(ERR_SPOOLED), ept->path);
return (-1);
}
/*
* If the package file attributes are to be sync'd up with
* the pkgmap, we fix the attributes here.
*/
if (fflag) {
a_err = 0;
/* Clear dangerous bits. */
ept->ainfo.mode = (ept->ainfo.mode & S_IAMB);
/*
* Make sure the file is readable by the world and
* writeable by root.
*/
ept->ainfo.mode |= 0644;
if (!strchr("in", ept->ftype)) {
/* Set the safe attributes. */
if (a_err = averify(fflag, &ept->ftype,
path, &ept->ainfo)) {
errflg++;
if (!qflag || (a_err != VE_EXIST)) {
logerr(gettext("ERROR: %s"),
ept->path);
logerr(getErrbufAddr());
}
if (a_err == VE_EXIST)
return (-1);
}
}
}
/* Report invalid modtimes by passing cverify a -1 */
c_err = cverify((!fflag ? (-1) : fflag), &ept->ftype, path,
&ept->cinfo, 1);
if (c_err) {
logerr(gettext("ERROR: %s"), path);
logerr(getErrbufAddr());
return (-1);
}
} else {
a_err = 0;
if (aflag && !strchr("in", ept->ftype)) {
/* validate attributes */
if (a_err = averify(fflag, &ept->ftype, ept->path,
&ept->ainfo)) {
errflg++;
if (!qflag || (a_err != VE_EXIST)) {
logerr(gettext("ERROR: %s"),
ept->path);
logerr(getErrbufAddr());
if (maptyp && ept->pinfo->status ==
SERVED_FILE)
logerr(gettext(MSG_NET_OBJ));
}
if (a_err == VE_EXIST)
return (-1);
}
}
if (cflag && strchr("fev", ept->ftype) &&
(!nflag || ept->ftype != 'v') && /* bug # 1082144 */
(!nflag || ept->ftype != 'e')) {
/* validate contents */
/* Report invalid modtimes by passing cverify a -1 */
if (c_err = cverify((!fflag ? (-1) : fflag),
&ept->ftype, ept->path, &ept->cinfo, 1)) {
errflg++;
if (!qflag || (c_err != VE_EXIST)) {
if (!a_err)
logerr(gettext("ERROR: %s"),
ept->path);
logerr(getErrbufAddr());
if (maptyp && ept->pinfo->status ==
SERVED_FILE)
logerr(gettext(MSG_NET_OBJ));
}
if (c_err == VE_EXIST)
return (-1);
}
}
if (xflag && (ept->ftype == 'x')) {
/* must do verbose here since ept->path will change */
path = strdup(ept->path);
if (xdir(maptyp, vfp, server, path))
errflg++;
(void) strcpy(ept->path, path);
free(path);
}
}
if (vflag)
(void) fprintf(stderr, "%s\n", ept->path);
return (errflg);
}
static int
xdir(int maptyp, VFP_T *vfp, PKGserver server, char *dirname)
{
DIR *dirfp;
char badpath[PATH_MAX];
int dirfound;
int errflg;
int len;
int n;
struct cfent mine;
struct dirent *drp;
struct pinfo *pinfo;
void *pos;
if (!maptyp)
pos = vfpGetCurrCharPtr(vfp); /* get current position in file */
if ((dirfp = opendir(dirname)) == NULL) {
progerr(gettext("unable to open directory <%s>"), dirname);
return (-1);
}
len = strlen(dirname);
errflg = 0;
(void) memset((char *)&mine, '\0', sizeof (struct cfent));
while ((drp = readdir(dirfp)) != NULL) {
if (strcmp(drp->d_name, ".") == NULL ||
strcmp(drp->d_name, "..") == NULL)
continue;
(void) snprintf(badpath, sizeof (badpath), "%s/%s",
dirname, drp->d_name);
if (!maptyp) {
dirfound = 0;
while ((n = NXTENTRY(&mine, vfp)) != 0) {
if (n < 0) {
char *errstr = getErrstr();
logerr(gettext("ERROR: garbled entry"));
logerr(gettext("pathname: %s"),
(mine.path && *mine.path) ?
mine.path : "Unknown");
logerr(gettext("problem: %s"),
(errstr && *errstr) ? errstr :
"Unknown");
exit(99);
}
if (strncmp(mine.path, dirname, len) ||
(mine.path[len] != '/'))
break;
if (strcmp(drp->d_name, &mine.path[len+1]) ==
0) {
dirfound++;
break;
}
}
vfpGetCurrCharPtr(vfp) = pos;
if (dirfound)
continue;
} else {
if (srchcfile(&mine, badpath, server) == 1) {
while ((pinfo = mine.pinfo) != NULL) {
mine.pinfo = pinfo->next;
free((char *)pinfo);
}
continue;
}
}
if (fflag) {
if (unlink(badpath)) {
errflg++;
logerr(gettext("ERROR: %s"), badpath);
logerr(gettext(ERR_RMHIDDEN));
}
} else {
errflg++;
logerr(gettext("ERROR: %s"), badpath);
logerr(gettext(ERR_HIDDEN));
}
}
(void) closedir(dirfp);
return (errflg);
}
static char *
findspool(struct cfent *ept)
{
static char path[2*PATH_MAX+1];
char host[PATH_MAX+1];
(void) strcpy(host, pkgspool);
if (ept->ftype == 'i') {
if (strcmp(ept->path, "pkginfo"))
(void) strcat(host, "/install");
} else if (ept->path[0] == '/') {
(void) strcat(host, "/root");
} else {
(void) strcat(host, "/reloc");
}
(void) snprintf(path, sizeof (path), "%s/%s", host,
ept->path + (ept->path[0] == '/'));
if (access(path, 0) == 0) {
return (path);
}
if ((ept->ftype != 'i') && (ept->volno > 0)) {
(void) snprintf(path, sizeof (path),
"%s.%d/%s", host, ept->volno,
ept->path + (ept->path[0] == '/'));
if (access(path, 0) == 0) {
return (path);
}
}
return (NULL);
}