summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCasper H.S. Dik <Casper.Dik@Sun.COM>2009-06-15 22:21:13 +0200
committerCasper H.S. Dik <Casper.Dik@Sun.COM>2009-06-15 22:21:13 +0200
commit62224350e5355e6834f7deb9d8a7d062a50cb7c2 (patch)
tree843bde4060f38c24d288c9a7b79d9900a6527671
parenta7e1d0d300de20869e70883ddfa4a5ca867ce135 (diff)
downloadillumos-joyent-62224350e5355e6834f7deb9d8a7d062a50cb7c2.tar.gz
PSARC 2009/173 Fasttrack for turbo-charging SVr4 packaging
6820054 Turbocharged SVr4 package commands [PSARC 2009/173]
-rw-r--r--usr/src/cmd/svr4pkg/Makefile1
-rw-r--r--usr/src/cmd/svr4pkg/hdrs/libinst.h12
-rw-r--r--usr/src/cmd/svr4pkg/installf/dofinal.c197
-rw-r--r--usr/src/cmd/svr4pkg/installf/installf.h4
-rw-r--r--usr/src/cmd/svr4pkg/installf/main.c74
-rw-r--r--usr/src/cmd/svr4pkg/libinst/mntinfo.c19
-rw-r--r--usr/src/cmd/svr4pkg/libinst/ocfile.c282
-rw-r--r--usr/src/cmd/svr4pkg/libinst/pkgdbmerg.c340
-rw-r--r--usr/src/cmd/svr4pkg/pkgadd/main.c52
-rw-r--r--usr/src/cmd/svr4pkg/pkgadm/Makefile2
-rw-r--r--usr/src/cmd/svr4pkg/pkgadm/main.c49
-rw-r--r--usr/src/cmd/svr4pkg/pkgadm/pkgadm_msgs.h7
-rw-r--r--usr/src/cmd/svr4pkg/pkgchk/checkmap.c27
-rw-r--r--usr/src/cmd/svr4pkg/pkgchk/ckentry.c101
-rw-r--r--usr/src/cmd/svr4pkg/pkgchk/main.c3
-rw-r--r--usr/src/cmd/svr4pkg/pkginfo/pkginfo.c21
-rw-r--r--usr/src/cmd/svr4pkg/pkginstall/instvol.c44
-rw-r--r--usr/src/cmd/svr4pkg/pkginstall/main.c27
-rw-r--r--usr/src/cmd/svr4pkg/pkginstall/pkginstall.h6
-rw-r--r--usr/src/cmd/svr4pkg/pkginstall/sortmap.c10
-rw-r--r--usr/src/cmd/svr4pkg/pkgremove/delmap.c21
-rw-r--r--usr/src/cmd/svr4pkg/pkgremove/main.c18
-rw-r--r--usr/src/cmd/svr4pkg/pkgrm/main.c33
-rw-r--r--usr/src/cmd/svr4pkg/pkgscripts/Makefile8
-rw-r--r--usr/src/cmd/svr4pkg/pkgscripts/pkgserv.xml86
-rw-r--r--usr/src/cmd/svr4pkg/pkgserv/Makefile41
-rw-r--r--usr/src/cmd/svr4pkg/pkgserv/pkgserv.c1370
-rw-r--r--usr/src/lib/libpkg/Makefile.com2
-rw-r--r--usr/src/lib/libpkg/common/mapfile-vers14
-rw-r--r--usr/src/lib/libpkg/common/pkglib.h74
-rw-r--r--usr/src/lib/libpkg/common/pkgserv.c603
-rw-r--r--usr/src/lib/libpkg/common/srchcfile.c953
-rw-r--r--usr/src/pkgdefs/SUNWpkgcmdsr/prototype_com4
-rw-r--r--usr/src/pkgdefs/SUNWpkgcmdsu/prototype_com1
34 files changed, 2902 insertions, 1604 deletions
diff --git a/usr/src/cmd/svr4pkg/Makefile b/usr/src/cmd/svr4pkg/Makefile
index 5281ca8d30..86a641aaf6 100644
--- a/usr/src/cmd/svr4pkg/Makefile
+++ b/usr/src/cmd/svr4pkg/Makefile
@@ -39,6 +39,7 @@ CMDSUBDIRS= \
pkgremove \
pkgrm \
pkgscripts \
+ pkgserv \
pkgtrans
.PARALLEL= $(CMDSUBDIRS)
diff --git a/usr/src/cmd/svr4pkg/hdrs/libinst.h b/usr/src/cmd/svr4pkg/hdrs/libinst.h
index fda6b1b3c6..a5ec681762 100644
--- a/usr/src/cmd/svr4pkg/hdrs/libinst.h
+++ b/usr/src/cmd/svr4pkg/hdrs/libinst.h
@@ -277,20 +277,20 @@ extern int is_local_host __P((char *hostname));
extern void fs_tab_free __P((void));
/* pkgdbmerg.c */
-extern int pkgdbmerg __P((VFP_T *mapvfp, VFP_T *tmpvfp,
- struct cfextra **extlist, int notify));
+extern int pkgdbmerg __P((PKGserver server, VFP_T *tmpvfp,
+ struct cfextra **extlist));
extern int files_installed __P((void));
-extern void notice __P((int n));
/* ocfile.c */
extern int trunc_tcfile __P((int fd));
-extern int ocfile __P((VFP_T **mapvfp, VFP_T **tmpvfp,
+extern int ocfile __P((PKGserver *serverp, VFP_T **tmpvfp,
fsblkcnt_t map_blks));
-extern int swapcfile __P((VFP_T **a_mapvfp, VFP_T **a_tmpvfp,
+extern int swapcfile __P((PKGserver server, VFP_T **a_tmpvfp,
char *pkginst, int dbchg));
extern int set_cfdir __P((char *cfdir));
-extern int socfile __P((VFP_T **vfp));
+extern int socfile __P((PKGserver *server, boolean_t quiet));
extern int relslock __P((void));
+extern int pkgWlock __P((int verbose));
extern int iscfile __P((void));
extern int vcfile __P((void));
diff --git a/usr/src/cmd/svr4pkg/installf/dofinal.c b/usr/src/cmd/svr4pkg/installf/dofinal.c
index 331ea43810..144bcf3217 100644
--- a/usr/src/cmd/svr4pkg/installf/dofinal.c
+++ b/usr/src/cmd/svr4pkg/installf/dofinal.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -54,7 +54,7 @@ static char *check_db_entry(VFP_T *, struct cfextra *, int, char *, int *);
/*ARGSUSED*/
int
-dofinal(VFP_T *vfp, VFP_T *vfpo, int rmflag, char *myclass, char *prog)
+dofinal(PKGserver server, VFP_T *vfpo, int rmflag, char *myclass, char *prog)
{
struct cfextra entry;
int n, indx, dbchg;
@@ -70,22 +70,22 @@ dofinal(VFP_T *vfp, VFP_T *vfpo, int rmflag, char *myclass, char *prog)
dbchg = 0;
- while (n = srchcfile(&(entry.cf_ent), "*", vfp, vfpo)) {
+ if (pkgopenfilter(server, pkginst) != 0)
+ quit(99);
+
+ while (n = srchcfile(&(entry.cf_ent), "*", server)) {
if (n < 0) {
char *errstr = getErrstr();
- progerr(gettext
- ("bad entry read in contents file"));
- logerr(gettext("pathname=%s"),
- (entry.cf_ent.path &&
- *(entry.cf_ent.path)) ?
- entry.cf_ent.path : "Unknown");
+ progerr(gettext("bad entry read in contents file"));
+ logerr(gettext("pathname=%s"),
+ (entry.cf_ent.path && *(entry.cf_ent.path)) ?
+ entry.cf_ent.path : "Unknown");
logerr(gettext("problem=%s"),
- (errstr && *errstr) ? errstr :
- "Unknown");
+ (errstr && *errstr) ? errstr : "Unknown");
quit(99);
}
- save_path = check_db_entry(
- vfpo, &entry, rmflag, myclass, &dbchg);
+ save_path = check_db_entry(vfpo, &entry, rmflag, myclass,
+ &dbchg);
/* Restore original server-relative path, if needed */
if (save_path != NULL) {
@@ -94,6 +94,8 @@ dofinal(VFP_T *vfp, VFP_T *vfpo, int rmflag, char *myclass, char *prog)
}
}
+ pkgclosefilter(server);
+
return (dbchg);
}
@@ -106,13 +108,11 @@ check_db_entry(VFP_T *vfpo, struct cfextra *entry, int rmflag, char *myclass,
char *save_path = NULL;
char *tp;
- /* write this entry to the contents file */
-
if (myclass && strcmp(myclass, entry->cf_ent.pkg_class)) {
- if (putcvfpfile(&entry->cf_ent, vfpo)) {
- progerr(gettext(ERR_WRITE));
- quit(99);
- }
+ /*
+ * We already have it in the database we don't want
+ * to modify it.
+ */
return (NULL);
}
@@ -131,98 +131,101 @@ check_db_entry(VFP_T *vfpo, struct cfextra *entry, int rmflag, char *myclass,
/*
* If pinfo == NULL at this point, then this file or
* directory isn't part of the package of interest.
- * So the loop below executes only on files in the package
+ * So the code below executes only on files in the package
* of interest.
*/
- save_path = NULL;
+ if (pinfo == NULL)
+ return (NULL);
- if (pinfo) {
- if (rmflag && (pinfo->status == RM_RDY)) {
- *dbchg = 1;
+ if (rmflag && (pinfo->status == RM_RDY)) {
+ *dbchg = 1;
- (void) eptstat(&(entry->cf_ent), pkginst, '@');
+ (void) eptstat(&(entry->cf_ent), pkginst, '@');
- if (entry->cf_ent.npkgs) {
- if (putcvfpfile(&(entry->cf_ent), vfpo)) {
- progerr(gettext(ERR_WRITE));
- quit(99);
- }
+ if (entry->cf_ent.npkgs) {
+ if (putcvfpfile(&(entry->cf_ent), vfpo)) {
+ progerr(gettext(ERR_WRITE));
+ quit(99);
}
- return (NULL);
-
- } else if (!rmflag && (pinfo->status == INST_RDY)) {
- *dbchg = 1;
+ } else if (entry->cf_ent.path != NULL) {
+ (void) vfpSetModified(vfpo);
+ /* add "-<path>" to the file */
+ vfpPutc(vfpo, '-');
+ vfpPuts(vfpo, entry->cf_ent.path);
+ vfpPutc(vfpo, '\n');
+ }
+ return (NULL);
- /* tp is the server-relative path */
- tp = fixpath(entry->cf_ent.path);
- /* save_path is the cmd line path */
- save_path = entry->cf_ent.path;
- /* entry has the server-relative path */
- entry->cf_ent.path = tp;
+ } else if (!rmflag && (pinfo->status == INST_RDY)) {
+ *dbchg = 1;
+
+ /* tp is the server-relative path */
+ tp = fixpath(entry->cf_ent.path);
+ /* save_path is the cmd line path */
+ save_path = entry->cf_ent.path;
+ /* entry has the server-relative path */
+ entry->cf_ent.path = tp;
+
+ /*
+ * The next if statement figures out how
+ * the contents file entry should be
+ * annotated.
+ *
+ * Don't install or verify objects for
+ * remote, read-only filesystems. We
+ * need only verify their presence and
+ * flag them appropriately from some
+ * server. Otherwise, ok to do final
+ * check.
+ */
+ fs_entry = fsys(entry->cf_ent.path);
+
+ if (is_remote_fs_n(fs_entry) && !is_fs_writeable_n(fs_entry)) {
+ /*
+ * Mark it shared whether it's present
+ * or not. life's too funny for me
+ * to explain.
+ */
+ pinfo->status = SERVED_FILE;
/*
- * The next if statement figures out how
- * the contents file entry should be
- * annotated.
- *
- * Don't install or verify objects for
- * remote, read-only filesystems. We
- * need only verify their presence and
- * flag them appropriately from some
- * server. Otherwise, ok to do final
- * check.
+ * restore for now. This may
+ * chg soon.
*/
- fs_entry = fsys(entry->cf_ent.path);
-
- if (is_remote_fs_n(fs_entry) &&
- !is_fs_writeable_n(fs_entry)) {
- /*
- * Mark it shared whether it's present
- * or not. life's too funny for me
- * to explain.
- */
- pinfo->status = SERVED_FILE;
+ entry->cf_ent.path = save_path;
+ } else {
+ /*
+ * If the object is accessible, check
+ * the new entry for existence and
+ * attributes. If there's a problem,
+ * mark it NOT_FND; otherwise,
+ * ENTRY_OK.
+ */
+ if (is_mounted_n(fs_entry)) {
+ int n;
- /*
- * restore for now. This may
- * chg soon.
- */
- entry->cf_ent.path = save_path;
- } else {
- /*
- * If the object is accessible, check
- * the new entry for existence and
- * attributes. If there's a problem,
- * mark it NOT_FND; otherwise,
- * ENTRY_OK.
- */
- if (is_mounted_n(fs_entry)) {
- int n;
-
- n = finalck((&entry->cf_ent), 1, 1,
- B_FALSE);
-
- pinfo->status = ENTRY_OK;
- if (n != 0) {
- pinfo->status = NOT_FND;
- }
- }
+ n = finalck((&entry->cf_ent), 1, 1, B_FALSE);
- /*
- * It's not remote, read-only but it
- * may look that way to the client.
- * If it does, overwrite the above
- * result - mark it shared.
- */
- if (is_served_n(fs_entry))
- pinfo->status = SERVED_FILE;
-
- /* restore original path */
- entry->cf_ent.path = save_path;
- /* and clear save_path */
- save_path = NULL;
+ pinfo->status = ENTRY_OK;
+ if (n != 0) {
+ pinfo->status = NOT_FND;
+ }
}
+
+ /*
+ * It's not remote, read-only but it
+ * may look that way to the client.
+ * If it does, overwrite the above
+ * result - mark it shared.
+ */
+ if (is_served_n(fs_entry))
+ pinfo->status = SERVED_FILE;
+
+ /* restore original path */
+ entry->cf_ent.path = save_path;
+ /* and clear save_path */
+ save_path = NULL;
}
}
diff --git a/usr/src/cmd/svr4pkg/installf/installf.h b/usr/src/cmd/svr4pkg/installf/installf.h
index 6d473aa3af..b553c61425 100644
--- a/usr/src/cmd/svr4pkg/installf/installf.h
+++ b/usr/src/cmd/svr4pkg/installf/installf.h
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -48,7 +48,7 @@ extern void quit(int);
extern void usage(void);
extern void removef(int, char *[]);
extern int installf(int, char *[]);
-extern int dofinal(VFP_T *, VFP_T *, int, char *, char *);
+extern int dofinal(PKGserver, VFP_T *, int, char *, char *);
#ifdef __cplusplus
}
diff --git a/usr/src/cmd/svr4pkg/installf/main.c b/usr/src/cmd/svr4pkg/installf/main.c
index 8c70add8ed..2e1bfed717 100644
--- a/usr/src/cmd/svr4pkg/installf/main.c
+++ b/usr/src/cmd/svr4pkg/installf/main.c
@@ -116,7 +116,6 @@ char *ulim;
char *script;
int eptnum;
-int sortflag;
int nosetuid;
int nocnflct;
int warnflag = 0;
@@ -130,15 +129,12 @@ extern void set_limit(void);
int
main(int argc, char **argv)
{
- FILE *pp;
VFP_T *cfTmpVfp;
- VFP_T *cfVfp;
- char *cmd;
+ PKGserver pkgserver = NULL;
char *tp;
char *prog;
char *pt;
char *vfstab_file = NULL;
- char line[1024];
char outbuf[PATH_MAX];
int c;
int dbchg;
@@ -299,8 +295,6 @@ main(int argc, char **argv)
set_PKGADM(server_map(get_PKGADM(), fsys_value));
}
- sortflag = 0;
-
/*
* get the package name and verify length is not too long
*/
@@ -382,12 +376,12 @@ main(int argc, char **argv)
/* open the package database (contents) file */
- if (!ocfile(&cfVfp, &cfTmpVfp, 0L)) {
+ if (!ocfile(&pkgserver, &cfTmpVfp, 0L)) {
quit(1);
}
if (fflag) {
- dbchg = dofinal(cfVfp, cfTmpVfp, REMOVEF, classname, prog);
+ dbchg = dofinal(pkgserver, cfTmpVfp, REMOVEF, classname, prog);
} else {
if (INSTALF) {
dbst = INST_RDY;
@@ -398,7 +392,7 @@ main(int argc, char **argv)
removef(argc-optind, &argv[optind]);
}
- dbchg = pkgdbmerg(cfVfp, cfTmpVfp, extlist, 0);
+ dbchg = pkgdbmerg(pkgserver, cfTmpVfp, extlist);
if (dbchg < 0) {
progerr(gettext(ERR_MERG));
quit(99);
@@ -406,11 +400,11 @@ main(int argc, char **argv)
}
if (dbchg) {
- if ((n = swapcfile(&cfVfp, &cfTmpVfp, pkginst, 1))
- == RESULT_WRN) {
- warnflag++;
+ if ((n = swapcfile(pkgserver, &cfTmpVfp, pkginst, 1))
+ == RESULT_WRN) {
+ warnflag++;
} else if (n == RESULT_ERR) {
- quit(99);
+ quit(99);
}
}
@@ -442,15 +436,15 @@ main(int argc, char **argv)
if (is_a_cl_basedir() && !is_an_inst_root()) {
c = strlen(get_client_basedir());
(void) snprintf(outbuf, sizeof (outbuf),
- "%s/%s\n", get_basedir(),
- &(ept->path[c]));
+ "%s/%s\n", get_basedir(),
+ &(ept->path[c]));
} else if (is_an_inst_root()) {
(void) snprintf(outbuf, sizeof (outbuf),
- "%s/%s\n", get_inst_root(),
- &(ept->path[c]));
+ "%s/%s\n", get_inst_root(),
+ &(ept->path[c]));
} else {
(void) snprintf(outbuf, sizeof (outbuf),
- "%s\n", &(ept->path[c]));
+ "%s\n", &(ept->path[c]));
}
canonize(outbuf);
(void) printf("%s", outbuf);
@@ -462,50 +456,12 @@ main(int argc, char **argv)
if (strchr("dxcbp", ept->ftype)) {
tp = fixpath(ept->path);
- (void) averify(1, &ept->ftype,
- tp, &ept->ainfo);
+ (void) averify(1, &ept->ftype, tp, &ept->ainfo);
}
}
}
- /* Sort the contents files if needed */
- if (sortflag) {
- int n;
-
- warnflag += (ocfile(&cfVfp, &cfTmpVfp, 0L)) ? 0 : 1;
- if (!warnflag) {
- size_t len;
-
- len = strlen(CMD_SORT) + strlen(get_PKGADM()) +
- strlen("/contents") + 5;
- cmd = (char *)malloc(len);
- (void) snprintf(cmd, len, "%s %s/contents",
- CMD_SORT, get_PKGADM());
- pp = popen(cmd, "r");
- if (pp == NULL) {
- (void) vfpClose(&cfVfp);
- (void) vfpClose(&cfTmpVfp);
- free(cmd);
- progerr(gettext(ERR_SORT));
- quit(1);
- }
- while (fgets(line, 1024, pp) != NULL) {
- if (line[0] != DUP_ENTRY) {
- vfpPuts(cfTmpVfp, line);
- }
- }
- free(cmd);
- (void) pclose(pp);
- n = swapcfile(&cfVfp, &cfTmpVfp, pkginst, 1);
- if (n == RESULT_WRN) {
- warnflag++;
- } else if (n == RESULT_ERR) {
- quit(99);
- }
-
- relslock(); /* Unlock the database. */
- }
- }
+ pkgcloseserver(pkgserver);
z_destroyMountTable();
diff --git a/usr/src/cmd/svr4pkg/libinst/mntinfo.c b/usr/src/cmd/svr4pkg/libinst/mntinfo.c
index a06c1328d9..209faa44e7 100644
--- a/usr/src/cmd/svr4pkg/libinst/mntinfo.c
+++ b/usr/src/cmd/svr4pkg/libinst/mntinfo.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -171,6 +171,10 @@ is_remote_src(char *source)
*src_host_ptr++ = *src_ptr++;
*src_host_ptr = '\0';
+ /* Multiple hosts: failover with multiple servers; this is remote. */
+ if (strchr(source_host, ',') != NULL)
+ return (REAL_REMOTE);
+
if (strncmp(source, host_name, hn_len) == 0 &&
*(source+hn_len) == ':' || is_local_host(source_host))
return (SELF_SERVE); /* Exporting from itself, it's local. */
@@ -702,9 +706,16 @@ construct_mt(struct mnttab *mt)
if ((nfte = fs_tab_init(mt->mnt_mountp, mt->mnt_fstype)) == NULL)
return (1);
- /* See if this is served from another host. */
- if (is_remote_src(mt->mnt_special) == REAL_REMOTE ||
- strcmp(mt->mnt_fstype, MNTTYPE_AUTO) == 0)
+ /*
+ * See if this is served from another host.
+ * Testing the type is cheap; finding the hostname is not.
+ * At this point, we're using the REAL mnttab; since we're not
+ * allowed to mount ourself with "NFS", "NFS" must be remote.
+ * The automount will translate "nfs:self" to a lofs mount.
+ */
+ if (strcmp(mt->mnt_fstype, MNTTYPE_AUTO) == 0 ||
+ strcmp(mt->mnt_fstype, MNTTYPE_NFS) == 0 ||
+ is_remote_src(mt->mnt_special) == REAL_REMOTE)
nfte->remote = 1;
else
nfte->remote = 0;
diff --git a/usr/src/cmd/svr4pkg/libinst/ocfile.c b/usr/src/cmd/svr4pkg/libinst/ocfile.c
index 7f4b701d5c..f2da5402e1 100644
--- a/usr/src/cmd/svr4pkg/libinst/ocfile.c
+++ b/usr/src/cmd/svr4pkg/libinst/ocfile.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -54,11 +54,13 @@
#include "libinst.h"
#include "libadm.h"
-#define LOCKFILE ".pkg.lock"
+#define LOCKFILE ".pkg.lock.client"
+#define LOCKFILESERV ".pkg.lock"
+
#define LOCKWAIT 10 /* seconds between retries */
#define LOCKRETRY 20 /* number of retries for a DB lock */
-#define ERR_TC_WRITE "WARNING: unable to write temp contents file <%s>"
+#define ERR_COMMIT "WARNING: unable to commit contents database update"
#define ERR_NOCLOSE "WARNING: unable to close <%s>"
#define ERR_NOUNLINK_LATENT "WARNING: unable to unlink latent <%s>"
#define ERR_LINK_FAIL "link(%s, %s) failed (errno %d)"
@@ -101,34 +103,9 @@ static int active_lock;
static int lock_fd; /* fd of LOCKFILE. */
static char *pkgadm_dir;
-static int pkgWlock(int verbose);
+int pkgWlock(int verbose);
static int pkgWunlock(void);
-/*
- * This VFP is used to cache the last copy of the contents file that was
- * written out - upon subsequent open if the contents file has not changed
- * since it was last written out, use the last cached copy that is still
- * in memory to avoid re-reading the contents file again. If the contents
- * file has changed since the cached copy was written out, the previous
- * copy is discarded and the new contents file contents are read in.
- */
-
-static VFP_T *contentsVfp = {(VFP_T *)NULL};
-
-/*
- * This defines the maximum number of bytes that can be added to the contents
- * file for a single package - this must be higher than the largest expected
- * pkgmap file will ever be. This controls the amount of memory allocated for
- * the contents file additions. A pkgmap file with an average line length of
- * 128/256/512 bytes could add 62500/31250/15625 entries with this size. This
- * allows the contents file to have a fixed allocation without having to check
- * size and realloc as necessary with the attendant cost of the realloc. The
- * real memory used will only be those pages that are actually touched when
- * the contents file is written.
- */
-
-#define CONTENTS_DELTA (32*1024*1024) /* 32mb */
-
/* forward declarations */
int relslock(void);
@@ -182,9 +159,12 @@ set_cfdir(char *cfdir)
/*
* If there's a contents file there already, copy it
- * over, otherwise initialize one.
+ * over, otherwise initialize one. Make sure that the
+ * server, if running, flushes the contents file.
*/
+ (void) pkgsync(NULL, get_PKGADM(), B_FALSE);
+
/* create new contents file if one does not already exist */
if (access(realcf, F_OK) != 0) {
@@ -193,7 +173,7 @@ set_cfdir(char *cfdir)
n = open(tmpcf, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644);
if (n < 0) {
progerr(gettext(ERR_CREAT_CONT), tmpcf,
- strerror(errno));
+ strerror(errno));
return (99);
}
(void) close(n);
@@ -217,21 +197,17 @@ set_cfdir(char *cfdir)
* It returns 1 if successful, 0 otherwise.
*/
int
-ocfile(VFP_T **r_mapvfp, VFP_T **r_tmpvfp, fsblkcnt_t map_blks)
+ocfile(PKGserver *server, VFP_T **r_tmpvfp, fsblkcnt_t map_blks)
{
struct stat64 statb;
struct statvfs64 svfsb;
fsblkcnt_t free_blocks;
fsblkcnt_t need_blocks;
- VFP_T *mapvfp = (VFP_T *)NULL;
VFP_T *tmpvfp = (VFP_T *)NULL;
char contents[PATH_MAX];
int n;
-
- /* reset return VFP/FILE pointers */
-
- (*r_mapvfp) = (VFP_T *)NULL;
- (*r_tmpvfp) = (VFP_T *)NULL;
+ off_t cdiff_alloc;
+ PKGserver newserver;
/* establish package administration contents directory location */
@@ -249,32 +225,25 @@ ocfile(VFP_T **r_mapvfp, VFP_T **r_tmpvfp, fsblkcnt_t map_blks)
return (0);
}
- /* determine path to the primary contents file */
-
- (void) snprintf(contents, sizeof (contents), "%s/contents", pkgadm_dir);
+ if (*server != NULL) {
+ vfpTruncate(*r_tmpvfp);
+ (void) vfpClearModified(*r_tmpvfp);
- /*
- * open the contents file to read only - if a previous contents file has
- * been cached attempt to use that cached copy for the open, otherwise
- * just open the contents file directly
- */
+ return (1);
+ }
- n = vfpCheckpointOpen(&contentsVfp, &mapvfp, contents, "r", VFP_NONE);
+ newserver = pkgopenserver(NULL, pkgadm_dir, B_FALSE);
- /* return error if contents file cannot be accessed */
+ /* The error has been reported. */
+ if (newserver == NULL)
+ return (0);
- if (n != 0) {
- int lerrno = errno;
+ /* reset return VFP/FILE pointers */
- if (errno == ENOENT) {
- progerr(gettext(ERR_NOCFILE), contents);
- } else {
- progerr(gettext(ERR_NOROPEN), contents);
- }
+ (*r_tmpvfp) = (VFP_T *)NULL;
- logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
- return (0);
- }
+ /* determine path to the primary contents file */
+ (void) snprintf(contents, sizeof (contents), "%s/contents", pkgadm_dir);
/*
* Check and see if there is enough space for the packaging commands
@@ -284,23 +253,23 @@ ocfile(VFP_T **r_mapvfp, VFP_T **r_tmpvfp, fsblkcnt_t map_blks)
/* Get the contents file size */
- if (fstat64(fileno(mapvfp->_vfpFile), &statb) == -1) {
+ if (stat64(contents, &statb) == -1) {
int lerrno = errno;
- progerr(gettext(ERR_NOSTAT), contents);
+ progerr(gettext(ERR_NOCFILE), contents);
logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
- (void) vfpClose(&mapvfp);
+ pkgcloseserver(newserver);
return (0);
}
/* Get the filesystem space */
- if (fstatvfs64(fileno(mapvfp->_vfpFile), &svfsb) == -1) {
+ if (statvfs64(contents, &svfsb) == -1) {
int lerrno = errno;
progerr(gettext(ERR_NOSTATV), contents);
logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
- (void) vfpClose(&mapvfp);
+ pkgcloseserver(newserver);
return (0);
}
@@ -308,22 +277,29 @@ ocfile(VFP_T **r_mapvfp, VFP_T **r_tmpvfp, fsblkcnt_t map_blks)
howmany(svfsb.f_frsize, DEV_BSIZE) :
howmany(svfsb.f_bsize, DEV_BSIZE)) * svfsb.f_bfree;
- if (map_blks == 0LL) {
- map_blks = 10LL;
- }
+ /*
+ * If we're removing a package, then the log might grow to the size
+ * of the full contents file.
+ */
+
+ if (map_blks == 0LL)
+ map_blks = nblk(statb.st_size, svfsb.f_bsize, svfsb.f_frsize);
/*
* Calculate the number of blocks we need to be able to operate on
* the contents file.
*/
need_blocks = map_blks +
+ /* Max of the log file */
+ nblk(MAXLOGFILESIZE, svfsb.f_bsize, svfsb.f_frsize) +
+ /* Current content file */
nblk(statb.st_size, svfsb.f_bsize, svfsb.f_frsize);
if ((need_blocks + 10) > free_blocks) {
progerr(gettext(ERR_CFBACK), contents);
progerr(gettext(ERR_CFBACK1), need_blocks, free_blocks,
DEV_BSIZE);
- (void) vfpClose(&mapvfp);
+ pkgcloseserver(newserver);
return (0);
}
@@ -341,36 +317,38 @@ ocfile(VFP_T **r_mapvfp, VFP_T **r_tmpvfp, fsblkcnt_t map_blks)
progerr(gettext(ERR_NOTMPOPEN));
logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
- (void) vfpClose(&mapvfp);
+ pkgcloseserver(newserver);
return (0);
}
/*
* set size of allocation for temporary contents file - this sets the
* size of the in-memory buffer associated with the open vfp.
+ * We only store the new and changed entries.
+ * We allocate memory depending on the size of the pkgmap; it's not
+ * completely right but <some value + * 1.5 * map_blks * DEV_BSIZE>
+ * seems fine (an install adds the size if the name of the package.)
*/
- if (vfpSetSize(tmpvfp, statb.st_size + CONTENTS_DELTA) != 0) {
+ cdiff_alloc = map_blks * DEV_BSIZE;
+ cdiff_alloc += cdiff_alloc/2;
+ if (cdiff_alloc < 1000000)
+ cdiff_alloc += 1000000;
+
+ if (vfpSetSize(tmpvfp, cdiff_alloc) != 0) {
int lerrno = errno;
progerr(gettext(ERR_NOTMPOPEN));
logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
(void) vfpClose(&tmpvfp);
- (void) vfpClose(&mapvfp);
+ pkgcloseserver(newserver);
return (0);
}
- /*
- * now that the temporary file is opened, advise the vm system to start
- * mapping the real contents file into memory if possible
- */
-
- (void) vfpSetFlags(mapvfp, VFP_NEEDNOW);
-
- /* set return ->s to open vfps */
+ /* set return ->s to open server/vfps */
- (*r_mapvfp) = mapvfp;
(*r_tmpvfp) = tmpvfp;
+ *server = newserver;
return (1); /* All OK */
}
@@ -381,15 +359,11 @@ ocfile(VFP_T **r_mapvfp, VFP_T **r_tmpvfp, fsblkcnt_t map_blks)
* Returns 1 for OK and 0 for "didn't do it".
*/
int
-socfile(VFP_T **r_mapvfp)
+socfile(PKGserver *server, boolean_t quiet)
{
- VFP_T *mapvfp = (VFP_T *)NULL;
- char contents[PATH_MAX];
- int n;
-
- /* reset return VFP/FILE pointer */
-
- (*r_mapvfp) = (VFP_T *)NULL;
+ char contents[PATH_MAX];
+ boolean_t readonly = B_FALSE;
+ PKGserver newserver;
if (pkgadm_dir == NULL) {
if (set_cfdir(NULL) != 0) {
@@ -405,29 +379,16 @@ socfile(VFP_T **r_mapvfp)
*/
if (!pkgWlock(0)) {
- logerr(gettext(MSG_NOLOCK));
+ if (!quiet)
+ logerr(gettext(MSG_NOLOCK));
+ readonly = B_TRUE;
}
- /* open the contents file to read only */
-
- (void) snprintf(contents, sizeof (contents), "%s/contents", pkgadm_dir);
-
- n = vfpCheckpointOpen(&contentsVfp, &mapvfp, contents,
- "r", VFP_NEEDNOW);
- if (n != 0) {
- int lerrno = errno;
-
- if (errno == ENOENT) {
- progerr(gettext(ERR_NOCFILE), contents);
- } else {
- progerr(gettext(ERR_NOROPEN), contents);
- }
- logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
+ newserver = pkgopenserver(NULL, pkgadm_dir, readonly);
+ if (newserver == NULL)
return (0);
- }
-
- *r_mapvfp = mapvfp;
+ *server = newserver;
return (1);
}
@@ -438,11 +399,10 @@ socfile(VFP_T **r_mapvfp)
* contents file with the newly updated temporary contents file.
* The "ocfile()" or "socfile()" functions must be called to re-
* open the real contents file for processing.
- * Arguments: a_cfVfp - (VFP_T **) - [RW, *RW]
- * This is the VFP associated with the real contents file
- * that is being read from and data processed.
+ * Arguments: PKGserver - handle to the package database
* a_cfTmpVfp - (VFP_T **) - [RW, *RW]
- * This is the VFP associated with the temporary contents
+ * This is the VFP associated which contains all the
+ * modifications to be written back to the database.
* file that is being written to.
* pkginst - (char) - [RO, *RO]
* This is the name of the package being operated on;
@@ -467,15 +427,12 @@ socfile(VFP_T **r_mapvfp)
*/
int
-swapcfile(VFP_T **a_cfVfp, VFP_T **a_cfTmpVfp, char *pkginst, int dbchg)
+swapcfile(PKGserver server, VFP_T **a_cfTmpVfp, char *pkginst, int dbchg)
{
char *pe;
char *pl;
char *ps;
- char contentsPath[PATH_MAX] = {'\0'};
char line[256];
- char sContentsPath[PATH_MAX] = {'\0'};
- char tContentsPath[PATH_MAX] = {'\0'};
char timeb[BUFSIZ];
int retval = RESULT_OK;
struct tm *timep;
@@ -488,27 +445,6 @@ swapcfile(VFP_T **a_cfVfp, VFP_T **a_cfTmpVfp, char *pkginst, int dbchg)
pkginst = "<unknown>";
}
- /* cache all paths for the associated open files */
-
- (void) strlcpy(contentsPath, vfpGetPath(*a_cfVfp),
- sizeof (contentsPath));
-
- (void) snprintf(tContentsPath, sizeof (tContentsPath),
- "%s/t.contents", pkgadm_dir);
-
- (void) snprintf(sContentsPath, sizeof (sContentsPath),
- "%s/s.contents", pkgadm_dir);
-
- /* original contents file no longer needed - close */
-
- if (vfpClose(a_cfVfp) != 0) {
- int lerrno = errno;
-
- logerr(gettext(ERR_NOCLOSE), contentsPath);
- logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
- retval = RESULT_WRN;
- }
-
/*
* If no changes were made to the database, checkpoint the temporary
* contents file - if this fails, then just close the file which causes
@@ -516,10 +452,6 @@ swapcfile(VFP_T **a_cfVfp, VFP_T **a_cfTmpVfp, char *pkginst, int dbchg)
*/
if ((dbchg == 0) && (vfpGetModified(*a_cfTmpVfp) == 0)) {
- if (vfpCheckpointFile(&contentsVfp, a_cfTmpVfp,
- contentsPath) != 0) {
- vfpClose(a_cfTmpVfp);
- }
(void) pkgWunlock(); /* Free the database lock. */
return (retval);
}
@@ -570,80 +502,16 @@ swapcfile(VFP_T **a_cfVfp, VFP_T **a_cfTmpVfp, char *pkginst, int dbchg)
/* commit temporary contents file bytes to storage */
- if (vfpWriteToFile(*a_cfTmpVfp, tContentsPath) != 0) {
+ if (pkgservercommitfile(*a_cfTmpVfp, server) != 0) {
int lerrno = errno;
- logerr(gettext(ERR_TC_WRITE), tContentsPath);
- logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
+ logerr(gettext(ERR_COMMIT));
vfpClose(a_cfTmpVfp);
- (void) remove(tContentsPath);
+ pkgcloseserver(server);
(void) pkgWunlock(); /* Free the database lock. */
return (RESULT_ERR);
}
- /*
- * Now we want to make a copy of the old contents file as a
- * fail-safe. In support of that, we create a hard link to
- * s.contents.
- */
-
- if ((access(sContentsPath, F_OK) == 0) && remove(sContentsPath)) {
- int lerrno = errno;
-
- logerr(gettext(ERR_NOUNLINK_LATENT), sContentsPath);
- logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
- (void) remove(tContentsPath);
- (void) pkgWunlock(); /* Free the database lock. */
- vfpClose(a_cfTmpVfp);
- return (RESULT_ERR);
- }
-
- if (link(contentsPath, sContentsPath) != 0) {
- int lerrno = errno;
-
- progerr(gettext(ERR_NOUPD));
- logerr(gettext(ERR_LINK_FAIL), contentsPath, sContentsPath,
- lerrno);
- (void) remove(tContentsPath);
- (void) pkgWunlock(); /* Free the database lock. */
- vfpClose(a_cfTmpVfp);
- return (RESULT_ERR);
- }
-
- if (rename(tContentsPath, contentsPath) != 0) {
- int lerrno = errno;
-
- progerr(gettext(ERR_NORENAME_CONTENTS), contentsPath,
- tContentsPath);
- logerr(gettext(ERR_RENAME_FAIL), tContentsPath,
- contentsPath, lerrno);
- if (rename(sContentsPath, contentsPath)) {
- lerrno = errno;
- progerr(gettext(ERR_RESTORE_FAIL), contentsPath);
- logerr(gettext(ERR_RENAME_FAIL), sContentsPath,
- contentsPath, lerrno);
- }
- (void) remove(tContentsPath);
- }
-
- if (remove(sContentsPath) != 0) {
- int lerrno = errno;
-
- logerr(gettext(ERR_NOUNLINK), sContentsPath);
- logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
- retval = RESULT_WRN;
- }
-
- /*
- * checkpoint the temporary contents file - if this fails, then
- * just close the file which causes the contents file to be reopened
- * and reread if it is needed again
- */
-
- if (vfpCheckpointFile(&contentsVfp, a_cfTmpVfp, contentsPath) != 0) {
- vfpClose(a_cfTmpVfp);
- }
-
return (relslock() == 0 ? RESULT_ERR : retval);
}
@@ -669,7 +537,7 @@ relslock(void)
* success, 0 on failure. The positive logic verbose flag determines whether
* or not the function displays the error message upon failure.
*/
-static int
+int
pkgWlock(int verbose) {
int retry_cnt, retval;
char lockpath[PATH_MAX];
diff --git a/usr/src/cmd/svr4pkg/libinst/pkgdbmerg.c b/usr/src/cmd/svr4pkg/libinst/pkgdbmerg.c
index 17389ab72b..4c0af8810d 100644
--- a/usr/src/cmd/svr4pkg/libinst/pkgdbmerg.c
+++ b/usr/src/cmd/svr4pkg/libinst/pkgdbmerg.c
@@ -90,9 +90,6 @@ int files_installed(void); /* return number of files installed. */
static int errflg = 0;
static int eptnum;
-static VFP_T *fpvfp = {(VFP_T *)NULL};
-static long sizetot;
-static int seconds;
static int installed; /* # of files, already properly installed. */
static struct pinfo *pkgpinfo = (struct pinfo *)0;
@@ -109,275 +106,176 @@ static void set_change(struct cfextra *el_ent);
static void chgclass(struct cfent *cf_ent, struct pinfo *pinfo);
static void output(VFP_T *vfpo, struct cfent *ent, struct pinfo *pinfo);
-/* ARGSUNUSED */
-void
-notice(int n)
-{
-#ifdef lint
- int i = n;
- n = i;
-#endif /* lint */
- (void) signal(SIGALRM, SIG_IGN);
- if (sizetot != 0) {
- echo(gettext(INFO_PROCESS),
- vfpGetBytesRemaining(fpvfp) * 100L / sizetot);
- }
- (void) signal(SIGALRM, notice);
- (void) alarm(seconds);
-}
-
-/* ARGSUSED */
-
/*
- * This scans the extlist (pkgmap) and the package database to the end,
- * copying out the merged contents to the file at tmpfp. It updates the mergstat
+ * This scans the extlist (pkgmap) and matches them to the database, copying
+ * out the modified contents to the file at tmpfp. It updates the mergstat
* structures and deals with administrative defaults regarding setuid and
* conflict.
- *
- * Since both the extlist and the package database entries are in numerical
- * order, they both scan unidirectionally. If the entry in the extlist is
- * found in the package database (by pathname) then do_like_ent() is called.
- * If the extlist entry is not found in the package database then
- * do_new_ent() is called. srchcfile() is responsible for copying out
- * non-matching package database entries. At package database EOF, the
- * eocontents flag is set and the rest of the extlist are assumed to be new
- * entries. At the end of the extlist, the eoextlist flag is set and the
- * remaining package database ends up copied out by srchcfile().
*/
int
-pkgdbmerg(VFP_T *mapvfp, VFP_T *tmpvfp, struct cfextra **extlist, int notify)
+pkgdbmerg(PKGserver server, VFP_T *tmpvfp, struct cfextra **extlist)
{
static struct cfent cf_ent; /* scratch area */
struct cfextra *el_ent; /* extlist entry under review */
- int eocontents = 0;
- int eoextlist = 0;
int n;
int changed;
int assume_ok = 0;
cf_ent.pinfo = (NULL);
errflg = 0;
- eptnum = 0;
installed = changed = 0;
- fpvfp = mapvfp; /* for notice function ...arg! */
-
- if (notify) {
- seconds = notify;
- (void) signal(SIGALRM, notice);
- (void) alarm(seconds);
- }
-
- (void) sighold(SIGALRM);
-
- sizetot = (((ptrdiff_t)(mapvfp->_vfpEnd)) -
- ((ptrdiff_t)(mapvfp->_vfpStart)));
- vfpRewind(mapvfp);
vfpRewind(tmpvfp);
- (void) sigrelse(SIGALRM);
-
- do {
- (void) sighold(SIGALRM);
-
+ for (eptnum = 0; (el_ent = extlist[eptnum]) != NULL; eptnum++) {
/*
* If there's an entry in the extlist at this position,
* process that entry.
*/
- if (!eoextlist && (el_ent = extlist[eptnum])) {
+ /* Metafiles don't get merged. */
+ if ((el_ent->cf_ent.ftype == 'i') ||
+ (el_ent->cf_ent.ftype == 'n')) {
+ continue;
+ }
- /* Metafiles don't get merged. */
- if ((el_ent->cf_ent.ftype == 'i') ||
- (el_ent->cf_ent.ftype == 'n')) {
- continue;
- }
+ /*
+ * Copy cfextra structure for duplicated paths.
+ * This is not just an optimization, it is
+ * necessary for correct operation of algorithm.
+ */
+ if ((eptnum > 0) && (strncmp(el_ent->cf_ent.path,
+ extlist[eptnum-1]->cf_ent.path, PATH_MAX) == 0)) {
+ memcpy(extlist[eptnum], extlist[eptnum-1],
+ sizeof (struct cfextra));
+ continue;
+ }
- /*
- * Copy cfextra structure for duplicated paths.
- * This is not just an optimization, it is
- * necessary for correct operation of algorithm.
- */
- if ((eptnum > 0) && (strncmp(el_ent->cf_ent.path,
- extlist[eptnum-1]->cf_ent.path, PATH_MAX) == 0)) {
- memcpy(extlist[eptnum], extlist[eptnum-1],
- sizeof (struct cfextra));
- continue;
+ /*
+ * Normally dbst comes to us from installf() or
+ * removef() in order to specify their special
+ * database status codes. They cannot implement a
+ * quick verify (it just doesn't make sense). For
+ * that reason, we can test to see if we already have
+ * a special database status. If we don't (it's from
+ * pkgadd) then we can test to see if this is calling
+ * for a quick verify wherein we assume the install
+ * will work and fix it if it doesn't. In that case
+ * we set our own dbst to be ENTRY_OK.
+ */
+ if (dbst == '\0') {
+ if (cl_dvfy(el_ent->cf_ent.pkg_class_idx) ==
+ QKVERIFY) {
+ assume_ok = 1;
}
-
+ } else {
/*
- * Normally dbst comes to us from installf() or
- * removef() in order to specify their special
- * database status codes. They cannot implement a
- * quick verify (it just doesn't make sense). For
- * that reason, we can test to see if we already have
- * a special database status. If we don't (it's from
- * pkgadd) then we can test to see if this is calling
- * for a quick verify wherein we assume the install
- * will work and fix it if it doesn't. In that case
- * we set our own dbst to be ENTRY_OK.
+ * If we DO end up with an installf/quick
+ * verify combination, we fix that by simply
+ * denying the quick verify for this class.
+ * This forces everything to come out alright
+ * by forcing the standard assumptions as
+ * regards package database for the rest of
+ * the load.
*/
- if (dbst == '\0') {
- if (cl_dvfy(el_ent->cf_ent.pkg_class_idx) ==
- QKVERIFY) {
- assume_ok = 1;
- }
- } else {
+ if (cl_dvfy(el_ent->cf_ent.pkg_class_idx) ==
+ QKVERIFY) {
+ logerr(gettext(WRN_ODDVERIFY),
+ cl_nam(el_ent->cf_ent.pkg_class_idx));
/*
- * If we DO end up with an installf/quick
- * verify combination, we fix that by simply
- * denying the quick verify for this class.
- * This forces everything to come out alright
- * by forcing the standard assumptions as
- * regards package database for the rest of
- * the load.
+ * Set destination verification to
+ * default.
*/
- if (cl_dvfy(el_ent->cf_ent.pkg_class_idx) ==
- QKVERIFY) {
- logerr(gettext(WRN_ODDVERIFY),
- cl_nam(
- el_ent->cf_ent.pkg_class_idx));
- /*
- * Set destination verification to
- * default.
- */
- cl_def_dverify(
- el_ent->cf_ent.pkg_class_idx);
- }
- }
-
- /*
- * Comply with administrative requirements regarding
- * setuid/setgid processes.
- */
- if (is_setuid(&(el_ent->cf_ent))) {
- el_ent->mstat.setuid = 1;
- }
- if (is_setgid(&(el_ent->cf_ent))) {
- el_ent->mstat.setgid = 1;
+ cl_def_dverify(el_ent->cf_ent.pkg_class_idx);
}
+ }
- /*
- * If setuid/setgid processes are not allowed, reset
- * those bits.
- */
- if (nosetuid && (el_ent->mstat.setgid ||
- el_ent->mstat.setuid)) {
- el_ent->cf_ent.ainfo.mode &=
- ~(S_ISUID | S_ISGID);
- }
- } else {
- eoextlist = 1; /* end of extlist[] */
+ /*
+ * Comply with administrative requirements regarding
+ * setuid/setgid processes.
+ */
+ if (is_setuid(&(el_ent->cf_ent))) {
+ el_ent->mstat.setuid = 1;
+ }
+ if (is_setgid(&(el_ent->cf_ent))) {
+ el_ent->mstat.setgid = 1;
}
/*
- * If we're not at the end of the package database, get the
- * next entry for comparison.
+ * If setuid/setgid processes are not allowed, reset
+ * those bits.
*/
- if (!eocontents) {
+ if (nosetuid && (el_ent->mstat.setgid ||
+ el_ent->mstat.setuid)) {
+ el_ent->cf_ent.ainfo.mode &= ~(S_ISUID | S_ISGID);
+ }
- /* Search package database for this entry. */
- n = srchcfile(&cf_ent, el_ent ?
- el_ent->cf_ent.path : NULL,
- mapvfp, tmpvfp);
+ /* Search package database for this entry. */
+ n = srchcfile(&cf_ent, el_ent->cf_ent.path, server);
+ /*
+ * If there was an error, note it and return an error
+ * flag.
+ */
+ if (n < 0) {
+ char *errstr = getErrstr();
+ progerr(ERR_CFBAD);
+ logerr(gettext("pathname: %s"),
+ (cf_ent.path && *cf_ent.path) ?
+ cf_ent.path : "Unknown");
+ logerr(gettext("problem: %s"),
+ (errstr && *errstr) ? errstr : "Unknown");
+ return (-1);
+ /*
+ * If there was a match, then merge them into a
+ * single entry.
+ */
+ } else if (n == 1) {
/*
- * If there was an error, note it and return an error
- * flag.
+ * If this package is overwriting a setuid or
+ * setgid process, set the status bits so we
+ * can inform the administrator.
*/
- if (n < 0) {
- char *errstr = getErrstr();
- logerr(gettext(
- "bad entry read from contents file"));
- logerr(gettext("- pathname: %s"),
- (cf_ent.path && *cf_ent.path) ?
- cf_ent.path : "Unknown");
- logerr(gettext("- problem: %s"),
- (errstr && *errstr) ? errstr : "Unknown");
- return (-1);
+ if (is_setuid(&cf_ent)) {
+ el_ent->mstat.osetuid = 1;
+ }
+
+ if (is_setgid(&cf_ent)) {
+ el_ent->mstat.osetgid = 1;
+ }
/*
- * If there was a match, then merge them into a
- * single entry.
+ * Detect if a symlink has changed to directory
+ * If so mark all the files/dir supposed to be
+ * iniside this dir, so that they are not miss
+ * understood by do_new_ent later as already
+ * installed.
*/
- } else if (n == 1) {
- /*
- * If this package is overwriting a setuid or
- * setgid process, set the status bits so we
- * can inform the administrator.
- */
- if (is_setuid(&cf_ent)) {
- el_ent->mstat.osetuid = 1;
- }
-
- if (is_setgid(&cf_ent)) {
- el_ent->mstat.osetgid = 1;
- }
- /*
- * Detect if a symlink has changed to directory
- * If so mark all the files/dir supposed to be
- * iniside this dir, so that they are not miss
- * understood by do_new_ent later as already
- * installed.
- */
- if ((!eoextlist) && (cf_ent.ftype == 's') &&
- (el_ent->cf_ent.ftype == 'd')) {
- int i;
- int plen = strlen(el_ent->cf_ent.path);
- for (i = eptnum + 1; extlist[i]; i++) {
- if (strncmp(el_ent->cf_ent.path,
- extlist[i]->cf_ent.path,
- plen) != 0)
- break;
- extlist[i]->mstat.parentsyml2dir
- = 1;
- }
+ if ((cf_ent.ftype == 's') &&
+ (el_ent->cf_ent.ftype == 'd')) {
+ int i;
+ int plen = strlen(el_ent->cf_ent.path);
+ for (i = eptnum + 1; extlist[i]; i++) {
+ if (strncmp(el_ent->cf_ent.path,
+ extlist[i]->cf_ent.path,
+ plen) != 0)
+ break;
+ extlist[i]->mstat.parentsyml2dir
+ = 1;
}
+ }
- if (do_like_ent(tmpvfp, el_ent, &cf_ent,
- assume_ok)) {
- changed++;
- }
+ if (do_like_ent(tmpvfp, el_ent, &cf_ent, assume_ok)) {
+ changed++;
+ }
+ } else {
/*
- * If the alphabetical position in the package
- * database is unfilled, then this will be a new
- * entry. If n == 0, then we're also at the end of
- * the contents file.
+ * The file doesn't exist in the database.
*/
- } else {
- if (n == 0) {
- eocontents++;
- }
-
- /*
- * If there is an extlist entry in the
- * hopper, insert it at the end of the
- * package database.
- */
- if (!eoextlist) {
- if (do_new_ent(tmpvfp, el_ent,
- assume_ok)) {
- changed++;
- }
- }
- }
- /*
- * We have passed the last entry in the package database,
- * tagging these extlist entries onto the end.
- */
- } else if (!eoextlist) {
if (do_new_ent(tmpvfp, el_ent, assume_ok)) {
changed++;
}
}
- /* Else, we'll drop out of the loop. */
-
- (void) sigrelse(SIGALRM);
- } while (eptnum++, (!eocontents || !eoextlist));
-
- if (notify) {
- (void) alarm(0);
- (void) signal(SIGALRM, SIG_IGN);
}
return (errflg ? -1 : changed);
diff --git a/usr/src/cmd/svr4pkg/pkgadd/main.c b/usr/src/cmd/svr4pkg/pkgadd/main.c
index a6f91b8b15..b1907d7f43 100644
--- a/usr/src/cmd/svr4pkg/pkgadd/main.c
+++ b/usr/src/cmd/svr4pkg/pkgadd/main.c
@@ -218,7 +218,7 @@ static void pkginstall_check_in_one_zone(char **a_inheritedPkgDirs,
char *a_zoneName, char *a_idsName,
char *a_zoneAdminFile, char *a_zoneTempDir,
char *a_altBinDir, char *a_scratchName,
- zone_state_t a_zoneState);
+ zone_state_t a_zoneState, boolean_t a_tmpzn);
static void ckreturn(int retcode);
static void create_zone_adminfile(char **r_zoneAdminFile,
char *a_zoneTempDir, char *a_admnfile);
@@ -227,7 +227,8 @@ static void create_zone_tempdir(char **r_zoneTempDir,
static void install_in_one_zone(char **a_inheritedPkgDirs,
char *a_zoneName, char *a_idsName,
char *a_zoneAdminFile, char *a_zoneTempDir,
- char *a_altBinDir, zone_state_t a_zoneState);
+ char *a_altBinDir, zone_state_t a_zoneState,
+ boolean_t a_tmpzn);
static int pkginstall_check_in_zones(zoneList_t a_zlst,
char *a_idsName, char *a_altBinDir,
char *a_zoneAdminFile, char *a_zoneTempDir);
@@ -240,12 +241,13 @@ static int pkgZoneCheckInstall(char *a_zoneName,
char **a_inheritedPkgDirs,
zone_state_t a_zoneState,
char *a_idsName, char *a_altBinDir,
- char *a_adminFile, char *a_stdoutPath);
+ char *a_adminFile, char *a_stdoutPath,
+ boolean_t a_tmpzn);
static int pkgZoneInstall(char *a_zoneName,
char **a_inheritedPkgDirs,
zone_state_t a_zoneState,
char *a_idsName, char *a_altBinDir,
- char *a_adminFile);
+ char *a_adminFile, boolean_t a_tmpzn);
static void resetreturn();
static void usage(void);
static boolean_t add_packages(char **a_pkgList, char *a_uri,
@@ -374,6 +376,8 @@ main(int argc, char **argv)
progerr(ERR_CANNOT_ENABLE_LOCAL_FS);
}
+ pkgserversetmode(DEFAULTMODE);
+
/*
* ********************************************************************
* parse command line options
@@ -1508,6 +1512,8 @@ main(int argc, char **argv)
* into which all output written by pkginstall to stdout
* is stored.
* If this is == NULL stdout is redirected to /dev/null
+ * a_tmpzn - B_TRUE when this zone is booted by the package
+ * command or B_FALSE if it was running before.
* Returns: int (see ckreturn() function for details)
* 0 - success
* 1 - package operation failed (fatal error)
@@ -1522,7 +1528,7 @@ main(int argc, char **argv)
static int
pkgZoneCheckInstall(char *a_zoneName, char **a_inheritedPkgDirs,
zone_state_t a_zoneState, char *a_idsName, char *a_altBinDir,
- char *a_adminFile, char *a_stdoutPath)
+ char *a_adminFile, char *a_stdoutPath, boolean_t a_tmpzn)
{
char *arg[MAXARGS];
char *p;
@@ -1748,6 +1754,10 @@ pkgZoneCheckInstall(char *a_zoneName, char **a_inheritedPkgDirs,
arg[nargs++] = strdup(zn);
}
+ /* Add the pkgserv options */
+ arg[nargs++] = "-O";
+ arg[nargs++] = pkgmodeargument(a_tmpzn ? RUN_ONCE : pkgservergetmode());
+
/* add in the package stream file */
if (a_idsName != NULL) {
@@ -1837,6 +1847,8 @@ pkgZoneCheckInstall(char *a_zoneName, char **a_inheritedPkgDirs,
* into which all output written by pkginstall to stdout
* is stored.
* If this is == NULL stdout is redirected to /dev/null
+ * a_tmpzn - B_TRUE when this zone is booted by the package
+ * command or B_FALSE if it was running before.
* Returns: int (see ckreturn() function for details)
* 0 - success
* 1 - package operation failed (fatal error)
@@ -1851,7 +1863,7 @@ pkgZoneCheckInstall(char *a_zoneName, char **a_inheritedPkgDirs,
static int
pkgZoneInstall(char *a_zoneName, char **a_inheritedPkgDirs,
zone_state_t a_zoneState, char *a_idsName, char *a_altBinDir,
- char *a_adminFile)
+ char *a_adminFile, boolean_t a_tmpzn)
{
char *arg[MAXARGS];
char *p;
@@ -2107,6 +2119,10 @@ pkgZoneInstall(char *a_zoneName, char **a_inheritedPkgDirs,
arg[nargs++] = strdup(zn);
}
+ /* Add the pkgserv options */
+ arg[nargs++] = "-O";
+ arg[nargs++] = pkgmodeargument(a_tmpzn ? RUN_ONCE : pkgservergetmode());
+
/* add in the package stream file */
if (a_idsName != NULL) {
@@ -2257,6 +2273,9 @@ pkgInstall(char *a_altRoot, char *a_idsName, char *a_pkgDir, char *a_altBinDir,
}
}
+ arg[nargs++] = "-O";
+ arg[nargs++] = pkgmodeargument(pkgservergetmode());
+
/*
* pkgadd -G: pass -G to pkginstall if:
* - the -G option is specified on the pkgadd command line
@@ -3403,6 +3422,8 @@ get_package_list(char ***r_pkgList, char **a_argv, char *a_categories,
* a_scratchName - pointer to string representing the name of the
* scratch zone to use for installation.
* a_zoneState - state of the zone; must be mounted or running.
+ * a_tmpzn - B_TRUE when this zone is booted by the package
+ * command or B_FALSE if it was running before.
* Returns: void
* NOTE: As a side effect, "ckreturn" is called on the result returned
* from running 'pkginstall' in the zone; this sets several global
@@ -3413,7 +3434,7 @@ get_package_list(char ***r_pkgList, char **a_argv, char *a_categories,
static void
install_in_one_zone(char **a_inheritedPkgDirs, char *a_zoneName,
char *a_idsName, char *a_zoneAdminFile, char *a_zoneTempDir,
- char *a_altBinDir, zone_state_t a_zoneState)
+ char *a_altBinDir, zone_state_t a_zoneState, boolean_t a_tmpzn)
{
char zoneStreamName[PATH_MAX] = {'\0'};
int n;
@@ -3449,7 +3470,7 @@ install_in_one_zone(char **a_inheritedPkgDirs, char *a_zoneName,
echoDebug(DBG_INSTALL_IN_ZONE, pkginst, a_zoneName, zoneStreamName);
n = pkgZoneInstall(a_zoneName, a_inheritedPkgDirs, a_zoneState,
- zoneStreamName, a_altBinDir, a_zoneAdminFile);
+ zoneStreamName, a_altBinDir, a_zoneAdminFile, a_tmpzn);
/* set success/fail condition variables */
@@ -3528,7 +3549,7 @@ install_in_zones(zoneList_t a_zlst, char *a_idsName, char *a_altBinDir,
install_in_one_zone(inheritedPkgDirs,
z_zlist_get_scratch(a_zlst, zoneIndex), a_idsName,
- a_zoneAdminFile, a_zoneTempDir, a_altBinDir, zst);
+ a_zoneAdminFile, a_zoneTempDir, a_altBinDir, zst, B_FALSE);
}
return (zonesSkipped);
@@ -3625,7 +3646,7 @@ boot_and_install_in_zones(zoneList_t a_zlst, char *a_idsName, char *a_altBinDir,
install_in_one_zone(inheritedPkgDirs,
z_zlist_get_scratch(a_zlst, zoneIndex), a_idsName,
a_zoneAdminFile, a_zoneTempDir, a_altBinDir,
- ZONE_STATE_MOUNTED);
+ ZONE_STATE_MOUNTED, B_TRUE);
/* restore original state of zone */
@@ -3664,6 +3685,8 @@ boot_and_install_in_zones(zoneList_t a_zlst, char *a_idsName, char *a_altBinDir,
* a_scratchName - pointer to string representing the name of the
* scratch zone to use for installation.
* a_zoneState - state of the zone; must be mounted or running.
+ * a_tmpzn - B_TRUE when this zone is booted by the package
+ * command or B_FALSE if it was running before.
* Returns: void
* NOTE: As a side effect, "ckreturn" is called on the result returned
* from running 'pkginstall' in the zone; this sets several global
@@ -3674,7 +3697,8 @@ boot_and_install_in_zones(zoneList_t a_zlst, char *a_idsName, char *a_altBinDir,
static void
pkginstall_check_in_one_zone(char **a_inheritedPkgDirs, char *a_zoneName,
char *a_idsName, char *a_zoneAdminFile, char *a_zoneTempDir,
- char *a_altBinDir, char *a_scratchName, zone_state_t a_zoneState)
+ char *a_altBinDir, char *a_scratchName, zone_state_t a_zoneState,
+ boolean_t a_tmpzn)
{
char preinstallcheckPath[PATH_MAX+1];
char zoneStreamName[PATH_MAX] = {'\0'};
@@ -3701,7 +3725,7 @@ pkginstall_check_in_one_zone(char **a_inheritedPkgDirs, char *a_zoneName,
n = pkgZoneCheckInstall(a_scratchName, a_inheritedPkgDirs,
a_zoneState, zoneStreamName, a_altBinDir, a_zoneAdminFile,
- preinstallcheckPath);
+ preinstallcheckPath, a_tmpzn);
/* set success/fail condition variables */
@@ -3761,7 +3785,7 @@ pkginstall_check_in_zones(zoneList_t a_zlst, char *a_idsName, char *a_altBinDir,
pkginstall_check_in_one_zone(inheritedPkgDirs, zoneName,
a_idsName, a_zoneAdminFile, a_zoneTempDir, a_altBinDir,
- z_zlist_get_scratch(a_zlst, zoneIndex), zst);
+ z_zlist_get_scratch(a_zlst, zoneIndex), zst, B_FALSE);
}
return (zonesSkipped);
@@ -3859,7 +3883,7 @@ boot_and_pkginstall_check_in_zones(zoneList_t a_zlst, char *a_idsName,
pkginstall_check_in_one_zone(inheritedPkgDirs, zoneName,
a_idsName, a_zoneAdminFile, a_zoneTempDir, a_altBinDir,
z_zlist_get_scratch(a_zlst, zoneIndex),
- ZONE_STATE_MOUNTED);
+ ZONE_STATE_MOUNTED, B_TRUE);
/* restore original state of zone */
diff --git a/usr/src/cmd/svr4pkg/pkgadm/Makefile b/usr/src/cmd/svr4pkg/pkgadm/Makefile
index f110c4f0de..620e32cf0d 100644
--- a/usr/src/cmd/svr4pkg/pkgadm/Makefile
+++ b/usr/src/cmd/svr4pkg/pkgadm/Makefile
@@ -35,7 +35,7 @@ OBJS= addcert.o \
include $(SRC)/cmd/svr4pkg/Makefile.svr4pkg
-LDLIBS += -lpkg -lcrypto -lgen
+LDLIBS += -lpkg -ladm -lcrypto -lgen
.KEEP_STATE:
all: $(PROG)
diff --git a/usr/src/cmd/svr4pkg/pkgadm/main.c b/usr/src/cmd/svr4pkg/pkgadm/main.c
index 6e5cb17b62..4d6859fd93 100644
--- a/usr/src/cmd/svr4pkg/pkgadm/main.c
+++ b/usr/src/cmd/svr4pkg/pkgadm/main.c
@@ -42,6 +42,7 @@
#include <keystore.h>
#include "pkgadm.h"
#include "pkgadm_msgs.h"
+#include "libadm.h"
/* initial error message buffer size */
@@ -51,6 +52,7 @@
static void print_version();
int get_dbstatus(int argc, char **argv);
+int sync_server(int argc, char **argv);
/* holds subcommands and their definitions */
struct cmd {
@@ -61,6 +63,7 @@ struct cmd {
struct cmd cmds[] = {
{ "dbstatus", get_dbstatus},
{ "lock", admin_lock},
+ { "sync", sync_server},
/* last one must be all NULLs */
{ NULL, NULL }
};
@@ -99,7 +102,7 @@ main(int argc, char **argv)
(void) textdomain(TEXT_DOMAIN);
if (getenv("PKGADM_VERBOSE")) {
- set_verbose(B_TRUE);
+ set_verbose(B_TRUE);
}
/* Superficial check of the arguments. */
@@ -245,3 +248,47 @@ get_dbstatus(int argc, char **argv)
return (0);
}
+
+/*
+ * sync
+ *
+ * Use the command line to determine if there is an alternate root.
+ *
+ * Return: 0 on success, nonzero on failure
+ * Flush the pkgserv's log.
+ */
+int
+sync_server(int argc, char **argv)
+{
+ int c;
+ char *root = NULL;
+ boolean_t quit = B_FALSE;
+
+ while ((c = getopt(argc, argv, "R:q")) != EOF) {
+ switch (c) {
+ case 'R':
+ root = optarg;
+ break;
+ case 'q':
+ quit = B_TRUE;
+ break;
+ default:
+ return (usage());
+ }
+ }
+
+ if (!pkgsync_needed(root, NULL, quit))
+ return (0);
+
+ set_PKGpaths(root);
+ set_cfdir(NULL);
+
+ if (pkgWlock(1) == 1) {
+ /* Flush the log file */
+ (void) pkgsync(root, NULL, quit);
+ (void) relslock();
+ return (0);
+ }
+
+ return (1);
+}
diff --git a/usr/src/cmd/svr4pkg/pkgadm/pkgadm_msgs.h b/usr/src/cmd/svr4pkg/pkgadm/pkgadm_msgs.h
index 6fbe10c438..4175a5a038 100644
--- a/usr/src/cmd/svr4pkg/pkgadm/pkgadm_msgs.h
+++ b/usr/src/cmd/svr4pkg/pkgadm/pkgadm_msgs.h
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -71,6 +71,11 @@ extern "C" {
"\t- Returns 'text' - the text install database in use since Solaris 2.0\n" \
"\t is the current install database in use.\n" \
"\n" \
+"pkgadm sync [-R rootpath] [-q]\n" \
+"\n" \
+"\t- Writes the contents file and rolls the contents log file.\n" \
+"\t- Optionally forces the contents file server to quit [-q].\n" \
+"\n" \
"pkgadm -V\n" \
"\t- Displays packaging tools version\n" \
"\n" \
diff --git a/usr/src/cmd/svr4pkg/pkgchk/checkmap.c b/usr/src/cmd/svr4pkg/pkgchk/checkmap.c
index a3be26e263..9bfcd3c620 100644
--- a/usr/src/cmd/svr4pkg/pkgchk/checkmap.c
+++ b/usr/src/cmd/svr4pkg/pkgchk/checkmap.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -55,15 +55,11 @@ extern char *basedir, *pathlist[], *ppathlist[], **pkg, **environ;
extern short used[];
extern struct cfent **eptlist;
-/* ocfile.c */
-extern int socfile(VFP_T **vfp); /* simple open & lock of DB. */
-extern int relslock(void); /* unlock the database. */
-
/* ckentry.c */
-extern int ckentry(int envflag, int maptyp, struct cfent *ept, VFP_T *vfp);
+extern int ckentry(int, int, struct cfent *, VFP_T *, PKGserver);
-#define NXTENTRY(P, VFP) \
- (maptyp ? srchcfile((P), "*", (VFP), (VFP_T *)NULL) : \
+#define NXTENTRY(P, VFP, SRV) \
+ (maptyp ? srchcfile((P), "*", (SRV)) : \
gpkgmapvfp((P), (VFP)))
#define MSG_ARCHIVE "NOTE: some pathnames are in private formats " \
@@ -106,6 +102,7 @@ checkmap(int maptyp, int uninst, char *mapfile, char *envfile,
int selected;
struct pinfo *pinfo;
VFP_T *vfp = (VFP_T *)NULL;
+ PKGserver server;
if (envfile != NULL) {
if ((fp = fopen(envfile, "r")) == NULL) {
@@ -151,7 +148,8 @@ checkmap(int maptyp, int uninst, char *mapfile, char *envfile,
* on some unknown medium so we don't bother.
*/
if (maptyp) { /* If this is the contents file */
- if (!socfile(&vfp)) {
+ if (!socfile(&server, B_FALSE) ||
+ pkgopenfilter(server, pkgcnt == 1 ? pkginst : NULL) != 0) {
progerr(gettext(ERR_PKGMAP), "contents");
return (-1);
}
@@ -168,7 +166,7 @@ checkmap(int maptyp, int uninst, char *mapfile, char *envfile,
errflg = count = 0;
do {
- if ((n = NXTENTRY(&entry, vfp)) == 0) {
+ if ((n = NXTENTRY(&entry, vfp, server)) == 0) {
break;
}
/*
@@ -179,8 +177,7 @@ checkmap(int maptyp, int uninst, char *mapfile, char *envfile,
if (is_partial_path_in_DB(entry.path, path)) {
/* Check this entry */
;
- } else if (entry.ftype == 's' ||
- entry.ftype == 'l') {
+ } else if (entry.ftype == 's' || entry.ftype == 'l') {
if (is_partial_path_in_DB(
/* LINTED warning: statement has no consequen */
entry.ainfo.local, path)) {
@@ -260,14 +257,14 @@ checkmap(int maptyp, int uninst, char *mapfile, char *envfile,
continue;
count++;
- if (ckentry((envfile ? 1 : 0), maptyp, &entry, vfp))
+ if (ckentry((envfile ? 1 : 0), maptyp, &entry, vfp, server))
errflg++;
} while (n != 0);
- (void) vfpClose(&vfp);
-
if (maptyp)
relslock();
+ else
+ (void) vfpClose(&vfp);
if (environ) {
/* free up environment resources */
diff --git a/usr/src/cmd/svr4pkg/pkgchk/ckentry.c b/usr/src/cmd/svr4pkg/pkgchk/ckentry.c
index ba971c2211..ab470ac8fc 100644
--- a/usr/src/cmd/svr4pkg/pkgchk/ckentry.c
+++ b/usr/src/cmd/svr4pkg/pkgchk/ckentry.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -48,9 +48,7 @@
extern int Lflag, lflag, aflag, cflag, fflag, qflag, nflag, xflag, vflag;
extern char *basedir, *device, pkgspool[];
-#define NXTENTRY(P, VFP) \
- (maptyp ? srchcfile((P), "*", (VFP), (VFP_T *)NULL) :\
- gpkgmapvfp((P), (VFP)))
+#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."
@@ -58,10 +56,11 @@ extern char *basedir, *device, pkgspool[];
#define ERR_HIDDEN "ERROR: hidden file in exclusive directory"
static char *findspool(struct cfent *ept);
-static int xdir(int maptyp, VFP_T *vfp, char *dirname);
+static int xdir(int maptyp, VFP_T *vfp, PKGserver server, char *dirname);
int
-ckentry(int envflag, int maptyp, struct cfent *ept, VFP_T *vfp)
+ckentry(int envflag, int maptyp, struct cfent *ept, VFP_T *vfp,
+ PKGserver server)
{
int a_err, c_err,
errflg;
@@ -188,7 +187,7 @@ ckentry(int envflag, int maptyp, struct cfent *ept, VFP_T *vfp)
if (xflag && (ept->ftype == 'x')) {
/* must do verbose here since ept->path will change */
path = strdup(ept->path);
- if (xdir(maptyp, vfp, path))
+ if (xdir(maptyp, vfp, server, path))
errflg++;
(void) strcpy(ept->path, path);
free(path);
@@ -200,10 +199,10 @@ ckentry(int envflag, int maptyp, struct cfent *ept, VFP_T *vfp)
}
static int
-xdir(int maptyp, VFP_T *vfp, char *dirname)
+xdir(int maptyp, VFP_T *vfp, PKGserver server, char *dirname)
{
DIR *dirfp;
- char badpath[PATH_MAX+1];
+ char badpath[PATH_MAX];
int dirfound;
int errflg;
int len;
@@ -213,7 +212,8 @@ xdir(int maptyp, VFP_T *vfp, char *dirname)
struct pinfo *pinfo;
void *pos;
- pos = vfpGetCurrCharPtr(vfp); /* get current position in file */
+ if (!maptyp)
+ pos = vfpGetCurrCharPtr(vfp); /* get current position in file */
if ((dirfp = opendir(dirname)) == NULL) {
progerr(gettext("unable to open directory <%s>"), dirname);
@@ -227,51 +227,56 @@ xdir(int maptyp, VFP_T *vfp, char *dirname)
if (strcmp(drp->d_name, ".") == NULL ||
strcmp(drp->d_name, "..") == NULL)
continue;
- 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]) == NULL) {
- dirfound++;
- break;
+ (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;
+ vfpGetCurrCharPtr(vfp) = pos;
- if (!dirfound) {
- (void) snprintf(badpath, sizeof (badpath),
- "%s/%s", dirname, drp->d_name);
- if (fflag) {
- if (unlink(badpath)) {
- errflg++;
- logerr(gettext("ERROR: %s"), badpath);
- logerr(gettext(ERR_RMHIDDEN));
+ if (dirfound)
+ continue;
+ } else {
+ if (srchcfile(&mine, badpath, server) == 1) {
+ while ((pinfo = mine.pinfo) != NULL) {
+ mine.pinfo = pinfo->next;
+ free((char *)pinfo);
}
- } else {
- errflg++;
- logerr(gettext("ERROR: %s"), badpath);
- logerr(gettext(ERR_HIDDEN));
+ continue;
}
}
- }
- if (maptyp) {
- /* clear memory we've used */
- while ((pinfo = mine.pinfo) != NULL) {
- mine.pinfo = pinfo->next;
- free((char *)pinfo);
+ 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));
}
}
diff --git a/usr/src/cmd/svr4pkg/pkgchk/main.c b/usr/src/cmd/svr4pkg/pkgchk/main.c
index 18ef6bbf7a..c8659d5731 100644
--- a/usr/src/cmd/svr4pkg/pkgchk/main.c
+++ b/usr/src/cmd/svr4pkg/pkgchk/main.c
@@ -372,6 +372,9 @@ main(int argc, char *argv[])
pkgcnt = (argc - optind);
}
+ /* read the environment for the pkgserver */
+ pkgserversetmode(DEFAULTMODE);
+
environ = NULL; /* Sever the parent environment. */
if (vcfile() == 0) {
diff --git a/usr/src/cmd/svr4pkg/pkginfo/pkginfo.c b/usr/src/cmd/svr4pkg/pkginfo/pkginfo.c
index e30a1c53f0..c2bcf8bc3a 100644
--- a/usr/src/cmd/svr4pkg/pkginfo/pkginfo.c
+++ b/usr/src/cmd/svr4pkg/pkginfo/pkginfo.c
@@ -100,7 +100,6 @@ static char *parmlst[] = {
"EMAIL", NULL
};
-static char contents[PATH_MAX];
static int errflg = 0;
static int qflag = 0;
static int iflag = -1;
@@ -290,18 +289,14 @@ main(int argc, char **argv)
/*
* If we are to inspect a spooled package we are only interested in
- * the pkginfo file in the spooled pkg so we skip any Reg 4 DB
- * lookups and use the old algorithm. We have a spooled pkg if
+ * the pkginfo file in the spooled pkg. We have a spooled pkg if
* device is not NULL.
*/
-
look_for_installed();
- if (lflag && strcmp(pkgdir, get_PKGLOC()) == NULL) {
+ if (lflag && strcmp(pkgdir, get_PKGLOC()) == 0) {
/* look at contents file */
- (void) snprintf(contents, sizeof (contents),
- "%s/contents", get_PKGADM());
rdcontents();
}
@@ -690,18 +685,17 @@ selectp(char *p)
static void
rdcontents(void)
{
- VFP_T *vfp;
struct cfstat *dp;
struct pinfo *pinfo;
int n;
+ PKGserver server;
- if (vfpOpen(&vfp, contents, "r", VFP_NEEDNOW) != 0) {
- progerr(gettext("unable to open \"%s\" for reading"), contents);
+ if (!socfile(&server, B_TRUE) ||
+ pkgopenfilter(server, pkgcnt == 1 ? pkg[0] : NULL) != 0)
exit(1);
- }
/* check the contents file to look for referenced packages */
- while ((n = srchcfile(&entry, "*", vfp, (VFP_T *)NULL)) > 0) {
+ while ((n = srchcfile(&entry, "*", server)) > 0) {
for (pinfo = entry.pinfo; pinfo; pinfo = pinfo->next) {
/* see if entry is used by indicated packaged */
if (pkgcnt && (selectp(pinfo->pkg) < 0))
@@ -738,8 +732,7 @@ rdcontents(void)
(errstr && *errstr) ? errstr : "Unknown");
exit(1);
}
-
- (void) vfpClose(&vfp);
+ pkgcloseserver(server);
}
static void
diff --git a/usr/src/cmd/svr4pkg/pkginstall/instvol.c b/usr/src/cmd/svr4pkg/pkginstall/instvol.c
index 803538a700..f475833d58 100644
--- a/usr/src/cmd/svr4pkg/pkginstall/instvol.c
+++ b/usr/src/cmd/svr4pkg/pkginstall/instvol.c
@@ -111,7 +111,7 @@ static int domerg(struct cfextra **extlist, int part, int nparts,
char **r_updated, char **r_skipped,
char **r_anyPathLocal);
static void endofclass(struct cfextra **extlist, int myclass,
- int ckflag, VFP_T **a_cfVfp, VFP_T **a_cfTmpVfp);
+ int ckflag, PKGserver server, VFP_T **a_cfTmpVfp);
static int fix_attributes(struct cfextra **, int);
static int dir_is_populated(char *dirpath);
static boolean_t absolutepath(char *path);
@@ -137,7 +137,7 @@ static struct reg_files *regfiles_head = NULL;
*/
void
instvol(struct cfextra **extlist, char *srcinst, int part,
- int nparts, VFP_T **a_cfVfp, VFP_T **a_cfTmpVfp,
+ int nparts, PKGserver pkgserver, VFP_T **a_cfTmpVfp,
char **r_updated, char **r_skipped,
char *a_zoneName)
{
@@ -858,7 +858,7 @@ instvol(struct cfextra **extlist, char *srcinst, int part,
*/
(void) endofclass(extlist, classidx,
(cl_iscript(classidx) ? 0 : 1),
- a_cfVfp, a_cfTmpVfp);
+ pkgserver, a_cfTmpVfp);
}
}
}
@@ -1060,12 +1060,12 @@ domerg(struct cfextra **extlist, int part, int nparts,
if (ept->pkg_class_idx == -1) {
progerr(ERR_CLIDX, ept->pkg_class_idx,
(ept->path && *ept->path) ? ept->path : "unknown");
- logerr(gettext("pathname=%s\n"),
+ logerr(gettext("pathname=%s"),
(ept->path && *ept->path) ? ept->path : "unknown");
- logerr(gettext("class=<%s>\n"),
+ logerr(gettext("class=<%s>"),
(ept->pkg_class && *ept->pkg_class) ?
ept->pkg_class : "Unknown");
- logerr(gettext("CLASSES=<%s>\n"),
+ logerr(gettext("CLASSES=<%s>"),
getenv("CLASSES") ? getenv("CLASSES") : "Not Set");
quit(99);
}
@@ -1372,7 +1372,7 @@ dir_is_populated(char *dirpath) {
*/
static void
endofclass(struct cfextra **extlist, int myclass, int ckflag,
- VFP_T **a_cfVfp, VFP_T **a_cfTmpVfp)
+ PKGserver pkgserver, VFP_T **a_cfTmpVfp)
{
char *temppath;
char *pspool_loc;
@@ -1388,7 +1388,7 @@ endofclass(struct cfextra **extlist, int myclass, int ckflag,
/* open the package database (contents) file */
- if (!ocfile(a_cfVfp, a_cfTmpVfp, pkgmap_blks)) {
+ if (!ocfile(&pkgserver, a_cfTmpVfp, pkgmap_blks)) {
quit(99);
}
@@ -1404,41 +1404,31 @@ endofclass(struct cfextra **extlist, int myclass, int ckflag,
idx++;
}
- if (extlist[idx] == NULL) {
- /* finish copying contents file and exit loop */
- (void) srchcfile(&(entry.cf_ent), NULL,
- *a_cfVfp, *a_cfTmpVfp);
+ if (extlist[idx] == NULL)
break;
- }
+
ept = &(extlist[idx]->cf_ent);
mstat = &(extlist[idx]->mstat);
- temppath =
- extlist[idx] ? extlist[idx]->client_path :
- NULL;
+ temppath = extlist[idx]->client_path;
/*
* At this point the only difference between the entry
* in the contents file and the entry in extlist[] is
* that the status indicator contains CONFIRM_CONT.
- * So for the new DB we use this knowledge and just
- * verify everything in accordance with extlist without
- * trying to retrieve the entry from the DB.
+ * This function should return one or something is wrong.
*/
- n = srchcfile(&(entry.cf_ent),
- (ept ? temppath : NULL), *a_cfVfp, *a_cfTmpVfp);
+ n = srchcfile(&(entry.cf_ent), temppath, pkgserver);
- if (n == 0) {
- break;
- } else if (n < 0) {
+ if (n < 0) {
char *errstr = getErrstr();
progerr(ERR_CFBAD);
- logerr(gettext("pathname=%s\n"),
+ logerr(gettext("pathname=%s"),
entry.cf_ent.path && *entry.cf_ent.path ?
entry.cf_ent.path : "Unknown");
- logerr(gettext("problem=%s\n"),
+ logerr(gettext("problem=%s"),
(errstr && *errstr) ? errstr : "Unknown");
quit(99);
} else if (n != 1) {
@@ -1601,7 +1591,7 @@ endofclass(struct cfextra **extlist, int myclass, int ckflag,
}
}
- n = swapcfile(a_cfVfp, a_cfTmpVfp, pkginst, dbchg);
+ n = swapcfile(pkgserver, a_cfTmpVfp, pkginst, dbchg);
if (n == RESULT_WRN) {
warnflag++;
} else if (n == RESULT_ERR) {
diff --git a/usr/src/cmd/svr4pkg/pkginstall/main.c b/usr/src/cmd/svr4pkg/pkginstall/main.c
index 2a6e7fb6cb..6bc5207b2e 100644
--- a/usr/src/cmd/svr4pkg/pkginstall/main.c
+++ b/usr/src/cmd/svr4pkg/pkginstall/main.c
@@ -246,8 +246,7 @@ static char *cpio_names[] = {
int
main(int argc, char *argv[])
{
- VFP_T *cfTmpVfp = (VFP_T *)NULL; /* t.contents */
- VFP_T *cfVfp = (VFP_T *)NULL; /* contents */
+ VFP_T *cfTmpVfp = NULL; /* temporary */
VFP_T *pkgmapVfp; /* "../pkgmap" file */
boolean_t run_request_as_root = B_FALSE;
char **np;
@@ -291,6 +290,7 @@ main(int argc, char *argv[])
struct stat statb;
struct statvfs64 svfsb;
time_t clock;
+ PKGserver pkgserver = NULL;
/* reset contents of all default paths */
@@ -351,6 +351,8 @@ main(int argc, char *argv[])
exit(1);
}
+ pkgserversetmode(DEFAULTMODE);
+
/* parse command line options */
while ((c = getopt(argc, argv,
@@ -689,6 +691,13 @@ main(int argc, char *argv[])
continue;
}
+ if (strncmp(p, PKGSERV_MODE,
+ PKGSERV_MODE_LEN) == 0) {
+ pkgserversetmode(pkgparsemode(p +
+ PKGSERV_MODE_LEN));
+ continue;
+ }
+
/* option not recognized - issue warning */
progerr(ERR_INVALID_O_OPTION, p);
@@ -842,7 +851,7 @@ main(int argc, char *argv[])
echoDebug(DBG_ENTRY_IN_GZ, prog_full_name);
} else {
echoDebug(DBG_ENTRY_IN_LZ, prog_full_name, getzoneid(),
- z_get_zonename());
+ z_get_zonename());
}
if (in_continue_mode() && !in_dryrun_mode()) {
@@ -1811,7 +1820,7 @@ main(int argc, char *argv[])
/*NOTREACHED*/
}
}
- if (!ocfile(&cfVfp, &cfTmpVfp, pkgmap_blks)) {
+ if (!ocfile(&pkgserver, &cfTmpVfp, pkgmap_blks)) {
quit(99);
/*NOTREACHED*/
}
@@ -1844,7 +1853,7 @@ main(int argc, char *argv[])
* how they should look after the merg is complete
*/
- nparts = sortmap(&extlist, pkgmapVfp, cfVfp, cfTmpVfp, zoneName);
+ nparts = sortmap(&extlist, pkgmapVfp, pkgserver, cfTmpVfp, zoneName);
if ((n = files_installed()) > 0) {
if (n > 1) {
@@ -1976,7 +1985,7 @@ main(int argc, char *argv[])
*/
if (rprcflag) {
- nparts = sortmap(&extlist, pkgmapVfp, cfVfp,
+ nparts = sortmap(&extlist, pkgmapVfp, pkgserver,
cfTmpVfp, zoneName);
}
@@ -2003,7 +2012,7 @@ main(int argc, char *argv[])
* reviewed.
*/
- n = swapcfile(&cfVfp, &cfTmpVfp, pkginst, dbchg);
+ n = swapcfile(pkgserver, &cfTmpVfp, pkginst, dbchg);
if (n == RESULT_WRN) {
warnflag++;
} else if (n == RESULT_ERR) {
@@ -2146,7 +2155,7 @@ main(int argc, char *argv[])
}
instvol(extlist, srcinst, part, nparts,
- &cfVfp, &cfTmpVfp, &updated,
+ pkgserver, &cfTmpVfp, &updated,
&skipped, zoneName);
if (part++ >= nparts) {
@@ -2245,6 +2254,8 @@ main(int argc, char *argv[])
(void) unlockinst();
+ pkgcloseserver(pkgserver);
+
quit(0);
/* LINTED: no return */
}
diff --git a/usr/src/cmd/svr4pkg/pkginstall/pkginstall.h b/usr/src/cmd/svr4pkg/pkginstall/pkginstall.h
index 3779f24f60..e04a7c7152 100644
--- a/usr/src/cmd/svr4pkg/pkginstall/pkginstall.h
+++ b/usr/src/cmd/svr4pkg/pkginstall/pkginstall.h
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -62,12 +62,12 @@ extern void pkgvolume __P((struct pkgdev *devp, char *pkg, int part,
extern void quit __P((int exitval));
extern void ckreturn __P((int retcode, char *msg));
extern int sortmap __P((struct cfextra ***extlist, VFP_T *pkgmapVfp,
- VFP_T *mapvfp, VFP_T *tmpvfp, char *a_zoneName));
+ PKGserver serv, VFP_T *tmpvfp, char *a_zoneName));
extern void merginfo __P((struct cl_attr **pclass, int install_from_pspool));
extern void set_infoloc __P((char *real_pkgsav));
extern int pkgenv __P((char *pkginst, char *p_pkginfo, char *p_pkgmap));
extern void instvol __P((struct cfextra **extlist, char *srcinst, int part,
- int nparts, VFP_T **a_cfVfp, VFP_T **a_cfTmpVfp,
+ int nparts, PKGserver server, VFP_T **a_cfTmpVfp,
char **r_updated, char **r_skipped,
char *a_zoneName));
extern int reqexec __P((int update, char *script, int non_abi_scripts,
diff --git a/usr/src/cmd/svr4pkg/pkginstall/sortmap.c b/usr/src/cmd/svr4pkg/pkginstall/sortmap.c
index a30ac15c60..3901d4bfbd 100644
--- a/usr/src/cmd/svr4pkg/pkginstall/sortmap.c
+++ b/usr/src/cmd/svr4pkg/pkginstall/sortmap.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -59,7 +59,7 @@ static int server_refer(struct cfextra **ext);
int
sortmap(struct cfextra ***extlist, VFP_T *pkgmapVfp,
- VFP_T *mapvfp, VFP_T *tmpvfp, char *a_zoneName)
+ PKGserver pkgserver, VFP_T *tmpvfp, char *a_zoneName)
{
int i, n, nparts;
char *db_mrg = "unable to merge package and system information";
@@ -68,7 +68,7 @@ sortmap(struct cfextra ***extlist, VFP_T *pkgmapVfp,
echo(gettext("## Processing package information."));
} else {
echo(gettext("## Processing package information in zone <%s>."),
- a_zoneName);
+ a_zoneName);
}
/*
@@ -107,7 +107,7 @@ sortmap(struct cfextra ***extlist, VFP_T *pkgmapVfp,
echo(gettext("## Processing system information."));
} else {
echo(gettext("## Processing system information in zone <%s>."),
- a_zoneName);
+ a_zoneName);
}
/*
@@ -125,7 +125,7 @@ sortmap(struct cfextra ***extlist, VFP_T *pkgmapVfp,
vfpTruncate(tmpvfp);
- dbchg = pkgdbmerg(mapvfp, tmpvfp, *extlist, 60);
+ dbchg = pkgdbmerg(pkgserver, tmpvfp, *extlist);
if (dbchg < 0) {
progerr(gettext(db_mrg));
quit(99);
diff --git a/usr/src/cmd/svr4pkg/pkgremove/delmap.c b/usr/src/cmd/svr4pkg/pkgremove/delmap.c
index 807d7bfd72..0b76b50c62 100644
--- a/usr/src/cmd/svr4pkg/pkgremove/delmap.c
+++ b/usr/src/cmd/svr4pkg/pkgremove/delmap.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -56,17 +56,16 @@ extern struct cfent **eptlist;
extern int eptnum;
int
-delmap(int flag, char *pkginst)
+delmap(int flag, char *pkginst, PKGserver *pkgserver, VFP_T **tmpfp)
{
struct cfent *ept;
struct pinfo *pinfo;
- VFP_T *vfp;
- VFP_T *vfpo;
int n;
char *unknown = "Unknown";
- if (!ocfile(&vfp, &vfpo, 0L)) {
+ if (!ocfile(pkgserver, tmpfp, 0L) ||
+ pkgopenfilter(*pkgserver, pkginst) != 0) {
quit(99);
}
@@ -90,7 +89,7 @@ delmap(int flag, char *pkginst)
}
eptnum = 0;
- while (n = srchcfile(ept, "*", vfp, (VFP_T *)NULL)) {
+ while (n = srchcfile(ept, "*", *pkgserver)) {
if (n < 0) {
char *errstr = getErrstr();
progerr(gettext("bad read of contents file"));
@@ -103,10 +102,16 @@ delmap(int flag, char *pkginst)
}
pinfo = eptstat(ept, pkginst, (flag ? '@' : '-'));
if (ept->npkgs > 0) {
- if (putcvfpfile(ept, vfpo)) {
+ if (putcvfpfile(ept, *tmpfp)) {
progerr(gettext(ERR_WRENT), errno);
quit(99);
}
+ } else if (ept->path != NULL) {
+ (void) vfpSetModified(*tmpfp);
+ /* add "-<path>" to the file */
+ vfpPutc(*tmpfp, '-');
+ vfpPuts(*tmpfp, ept->path);
+ vfpPutc(*tmpfp, '\n');
}
if (flag || (pinfo == NULL))
@@ -148,7 +153,7 @@ delmap(int flag, char *pkginst)
eptlist[eptnum] = (struct cfent *)NULL;
- n = swapcfile(&vfp, &vfpo, pkginst, dbchg);
+ n = swapcfile(*pkgserver, tmpfp, pkginst, dbchg);
if (n == RESULT_WRN) {
warnflag++;
} else if (n == RESULT_ERR) {
diff --git a/usr/src/cmd/svr4pkg/pkgremove/main.c b/usr/src/cmd/svr4pkg/pkgremove/main.c
index 6e484d6676..1a3fd869bb 100644
--- a/usr/src/cmd/svr4pkg/pkgremove/main.c
+++ b/usr/src/cmd/svr4pkg/pkgremove/main.c
@@ -76,7 +76,7 @@ extern int rckrunlevel(void);
extern void predepend(char *oldpkg);
/* delmap.c */
-extern int delmap(int flag, char *pkginst);
+extern int delmap(int flag, char *pkginst, PKGserver *server, VFP_T **tfp);
#define DEFPATH "/sbin:/usr/sbin:/usr/bin"
@@ -188,6 +188,8 @@ main(int argc, char *argv[])
int pkgrmremote = 0; /* dont remove remote objects */
struct sigaction nact;
struct sigaction oact;
+ PKGserver pkgserver = NULL;
+ VFP_T *tmpfp;
/* reset contents of all default paths */
@@ -222,6 +224,8 @@ main(int argc, char *argv[])
exit(1);
}
+ pkgserversetmode(DEFAULTMODE);
+
/* parse command line options */
while ((c = getopt(argc, argv, "?Aa:b:FMN:nO:oR:V:vy")) != EOF) {
@@ -402,6 +406,12 @@ main(int argc, char *argv[])
continue;
}
+ if (strncmp(p, PKGSERV_MODE,
+ PKGSERV_MODE_LEN) == 0) {
+ pkgserversetmode(pkgparsemode(p +
+ PKGSERV_MODE_LEN));
+ continue;
+ }
/* option not recognized - issue warning */
progerr(ERR_INVALID_O_OPTION, p);
@@ -954,7 +964,7 @@ main(int argc, char *argv[])
echoDebug(DBG_PKGREMOVE_PROCPKG_LZ, pkginst, rlockfile,
zoneName);
}
- if (delmap(0, pkginst) != 0) {
+ if (delmap(0, pkginst, &pkgserver, &tmpfp) != 0) {
progerr(ERR_DB_QUERY, pkginst);
quit(99);
}
@@ -1103,7 +1113,7 @@ main(int argc, char *argv[])
echo(MSG_PKGREMOVE_UPDINF_LZ, zoneName);
}
- if (delmap(1, pkginst) != 0) {
+ if (delmap(1, pkginst, &pkgserver, &tmpfp) != 0) {
progerr(ERR_DB_QUERY, pkginst);
quit(99);
}
@@ -1131,6 +1141,8 @@ main(int argc, char *argv[])
(void) unlockinst();
+ pkgcloseserver(pkgserver);
+
quit(0);
/* LINTED: no return */
}
diff --git a/usr/src/cmd/svr4pkg/pkgrm/main.c b/usr/src/cmd/svr4pkg/pkgrm/main.c
index 92cb448251..e95cd88f82 100644
--- a/usr/src/cmd/svr4pkg/pkgrm/main.c
+++ b/usr/src/cmd/svr4pkg/pkgrm/main.c
@@ -189,11 +189,11 @@ static int pkgRemove(int a_nodelete, char *a_altBinDir,
static int pkgZoneCheckRemove(char *a_zoneName,
char **a_inheritedPkgDirs, char *a_altBinDir,
char *a_adminFile, char *a_stdoutPath,
- zone_state_t a_zoneState);
+ zone_state_t a_zoneState, boolean_t tmpzone);
static int pkgZoneRemove(char *a_zoneName,
char **a_inheritedPkgDirs, int a_nodelete,
char *a_altBinDir, char *a_adminFile,
- zone_state_t a_zoneState);
+ zone_state_t a_zoneState, boolean_t tmpzone);
static void resetreturn();
static void usage(void);
static boolean_t check_applicability(char *a_packageDir,
@@ -287,6 +287,8 @@ main(int argc, char **argv)
progerr(ERR_CANNOT_ENABLE_LOCAL_FS);
}
+ pkgserversetmode(DEFAULTMODE);
+
/*
* ********************************************************************
* parse command line options
@@ -1017,7 +1019,7 @@ doRemove(int a_nodelete, char *a_altBinDir, int a_longestPkg, char *a_adminFile,
n = pkgZoneRemove(z_zlist_get_scratch(a_zlst, zoneIndex),
inheritedPkgDirs, a_nodelete, a_altBinDir,
- a_zoneAdminFile, zst);
+ a_zoneAdminFile, zst, B_FALSE);
/* set success/fail condition variables */
@@ -1085,7 +1087,7 @@ doRemove(int a_nodelete, char *a_altBinDir, int a_longestPkg, char *a_adminFile,
n = pkgZoneRemove(z_zlist_get_scratch(a_zlst,
zoneIndex), inheritedPkgDirs,
a_nodelete, a_altBinDir, a_zoneAdminFile,
- ZONE_STATE_MOUNTED);
+ ZONE_STATE_MOUNTED, B_TRUE);
/* set success/fail condition variables */
@@ -1213,7 +1215,7 @@ ckreturn(int retcode)
static int
pkgZoneCheckRemove(char *a_zoneName, char **a_inheritedPkgDirs,
char *a_altBinDir, char *a_adminFile, char *a_stdoutPath,
- zone_state_t a_zoneState)
+ zone_state_t a_zoneState, boolean_t tmpzone)
{
char *arg[MAXARGS];
char *p;
@@ -1394,6 +1396,11 @@ pkgZoneCheckRemove(char *a_zoneName, char **a_inheritedPkgDirs,
arg[nargs++] = strdup(zn);
}
+ /* Add arguments how to start the pkgserv */
+
+ arg[nargs++] = "-O";
+ arg[nargs++] = pkgmodeargument(tmpzone ? RUN_ONCE : pkgservergetmode());
+
/* pass -N to pkgremove: program name to report */
arg[nargs++] = "-N";
@@ -1445,7 +1452,7 @@ pkgZoneCheckRemove(char *a_zoneName, char **a_inheritedPkgDirs,
static int
pkgZoneRemove(char *a_zoneName, char **a_inheritedPkgDirs,
int a_nodelete, char *a_altBinDir, char *a_adminFile,
- zone_state_t a_zoneState)
+ zone_state_t a_zoneState, boolean_t tmpzone)
{
char *arg[MAXARGS];
char *p;
@@ -1630,6 +1637,11 @@ pkgZoneRemove(char *a_zoneName, char **a_inheritedPkgDirs,
arg[nargs++] = strdup(zn);
}
+ /* Add arguments how to start the pkgserv */
+
+ arg[nargs++] = "-O";
+ arg[nargs++] = pkgmodeargument(tmpzone ? RUN_ONCE : pkgservergetmode());
+
/* pass -N to pkgremove: program name to report */
arg[nargs++] = "-N";
@@ -1738,6 +1750,11 @@ pkgRemove(int a_nodelete, char *a_altBinDir, char *a_adminFile,
arg[nargs++] = "debug";
}
+ /* Add arguments how to start the pkgserv */
+
+ arg[nargs++] = "-O";
+ arg[nargs++] = pkgmodeargument(pkgservergetmode());
+
/* pkgrm -b dir: pass -b to pkgremove */
if (a_altBinDir != (char *)NULL) {
@@ -2058,7 +2075,7 @@ static char *zoneAdminFile = (char *)NULL;
n = pkgZoneCheckRemove(scratchName, inheritedPkgDirs,
a_altBinDir, admnfile, preremovecheckPath,
- zst);
+ zst, B_FALSE);
/* set success/fail condition variables */
@@ -2139,7 +2156,7 @@ static char *zoneAdminFile = (char *)NULL;
n = pkgZoneCheckRemove(scratchName, inheritedPkgDirs,
a_altBinDir, admnfile, preremovecheckPath,
- ZONE_STATE_MOUNTED);
+ ZONE_STATE_MOUNTED, B_TRUE);
/* set success/fail condition variables */
diff --git a/usr/src/cmd/svr4pkg/pkgscripts/Makefile b/usr/src/cmd/svr4pkg/pkgscripts/Makefile
index dd2ad4b3b3..fb758a4e88 100644
--- a/usr/src/cmd/svr4pkg/pkgscripts/Makefile
+++ b/usr/src/cmd/svr4pkg/pkgscripts/Makefile
@@ -38,6 +38,11 @@ CLASS_ACTION_SCRIPTS = i.awk \
r.sed
ADMINFILE = default
+ROOTPKGMNFSTDIR=$(ROOT)/var/svc/manifest/system
+ROOTPKGMNFST= $(ROOTPKGMNFSTDIR)/pkgserv.xml
+
+$(ROOTPKGMNFST) := FILEMODE = 0444
+
# cmdexec also installed in usr/sadm/install/scripts
SCRIPTS = $(CLASS_ACTION_SCRIPTS) $(PROG)
@@ -49,6 +54,7 @@ LDLIBS += -lpkg
.KEEP_STATE:
all: $(PROG) $(CLASS_ACTION_SCRIPTS)
-install: all $(ROOTCLASS_SCR_FILES) $(ROOTADMIN_SRC_FILE)
+install: all $(ROOTCLASS_SCR_FILES) $(ROOTADMIN_SRC_FILE) \
+ $(ROOTPKGMNFST)
include $(SRC)/cmd/svr4pkg/Makefile.svr4pkg.targ
diff --git a/usr/src/cmd/svr4pkg/pkgscripts/pkgserv.xml b/usr/src/cmd/svr4pkg/pkgscripts/pkgserv.xml
new file mode 100644
index 0000000000..fdc2102d7c
--- /dev/null
+++ b/usr/src/cmd/svr4pkg/pkgscripts/pkgserv.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0"?>
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+<!--
+
+
+ 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.
+
+ NOTE: This service manifest is not editable; its contents will
+ be overwritten by package or patch operations, including
+ operating system upgrade. Make customizations in a different
+ file.
+-->
+
+<service_bundle type='manifest' name='SUNWpkgcmdsr:pkgserv'>
+
+<service
+ name='system/pkgserv'
+ type='service'
+ version='1'>
+
+ <create_default_instance enabled='true' />
+
+ <single_instance />
+
+ <dependency
+ name='usr'
+ type='service'
+ grouping='require_all'
+ restart_on='none'>
+ <service_fmri value='svc:/system/filesystem/minimal' />
+ </dependency>
+
+ <exec_method
+ type='method'
+ name='start'
+ exec='/usr/bin/pkgadm sync'
+ timeout_seconds='300'>
+ </exec_method>
+
+ <exec_method
+ type='method'
+ name='stop'
+ exec='/usr/bin/pkgadm sync'
+ timeout_seconds='300'>
+ </exec_method>
+
+ <property_group name='startd' type='framework'>
+ <propval name='duration' type='astring'
+ value='transient' />
+ </property_group>
+
+ <property_group name='options' type='application'>
+ </property_group>
+
+ <stability value='Unstable' />
+
+ <template>
+ <common_name>
+ <loctext xml:lang='C'>
+ Flush package command database to disk (see pkgadm(1m)).
+ </loctext>
+ </common_name>
+ </template>
+</service>
+
+</service_bundle>
diff --git a/usr/src/cmd/svr4pkg/pkgserv/Makefile b/usr/src/cmd/svr4pkg/pkgserv/Makefile
new file mode 100644
index 0000000000..fbb5a51465
--- /dev/null
+++ b/usr/src/cmd/svr4pkg/pkgserv/Makefile
@@ -0,0 +1,41 @@
+#
+# 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.
+#
+
+PROG= pkgserv
+
+OBJS= pkgserv.o
+
+include $(SRC)/cmd/svr4pkg/Makefile.svr4pkg
+
+LDLIBS += -lpkg -lumem -lavl
+
+
+.KEEP_STATE:
+all: $(PROG)
+
+install: all $(ROOTPKGBINPROG)
+
+include $(SRC)/cmd/svr4pkg/Makefile.svr4pkg.targ
diff --git a/usr/src/cmd/svr4pkg/pkgserv/pkgserv.c b/usr/src/cmd/svr4pkg/pkgserv/pkgserv.c
new file mode 100644
index 0000000000..dfb4e76eb9
--- /dev/null
+++ b/usr/src/cmd/svr4pkg/pkgserv/pkgserv.c
@@ -0,0 +1,1370 @@
+/*
+ * 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.
+ */
+
+/*
+ * The Solaris package installer in-memory database server.
+ *
+ * We'll keep the contents file as before; but we cache it
+ * and we don't write it as often. Instead, we log all
+ * modifications to the log file.
+ * Using the contents file and the logfile, the pkgserv can
+ * rebuild the up-to-date contents file.
+ * The logfile is constructed so that rebuilding the
+ * contents file with the logfile is idempotent.
+ *
+ * The libpkg will start the daemon.
+ *
+ * The pkgserv will daemonize itself; the parent process
+ * waits until the child process has initialized and will
+ * start the door server.
+ * If any error occurs during start-up, the error messages
+ * are printed to stderr and the daemon will exit.
+ * After start-up, any further errors are logged to syslog.
+ * The parent pkgserv will exit with:
+ * 0 - We've started
+ * 1 - We couldn't start (locked)
+ * 2 - Other problems (error on stderr)
+ * 99 - Nothing reported; the caller must report.
+ *
+ * The daemon will timeout, by default. It will write the
+ * contents file after a first timeout; and after a further
+ * timeout, the daemon will exit.
+ *
+ * The daemon will only timeout if the current "client" has exited;
+ * to this end, we always look at the pid of the last caller.
+ * If the last client is no longer around, we record the new client.
+ * In the typical case of running installf/removef from a post/preinstall
+ * script, we continue to follow the pkginstall/pkgremove client's pid.
+ *
+ * In the particular case of install, we make sure the daemon
+ * sticks around. (Install == install, (live)upgrade, zone install)
+ */
+
+#ifdef lint
+#undef _FILE_OFFSET_BITS
+#endif
+
+#include <door.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <synch.h>
+#include <sys/avl.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <syslog.h>
+#include <limits.h>
+#include <thread.h>
+#include <ucred.h>
+#include <umem.h>
+#include <unistd.h>
+#include <libintl.h>
+#include <locale.h>
+
+#include <pkglib.h>
+
+#define SADM_DIR "/var/sadm/install"
+
+#define LOCK ".pkg.lock"
+#define CLIENTLOCK ".pkg.lock.client"
+#define CONTENTS "contents"
+#define TCONTENTS "t.contents"
+#define BADCONTENTS "contents.badXXXXXX"
+
+#define LLNANOSEC ((int64_t)NANOSEC)
+
+#define DUMPTIMEOUT 60
+#define EXITTIMEOUT 300
+
+/*
+ * Contents file storage format. At install time, the amount of memory
+ * might be limited, so we make sure that we use as little memory
+ * as possible. The package tools modify the entries; so we install the
+ * single lines. We also remember the length of the path; this is needed
+ * for avlcmp and we return it to the tools. This saves time.
+ *
+ * All strings are allocated using umem_alloc.
+ */
+typedef struct pkgentry {
+ char *line; /* The contents line for the file */
+ avl_node_t avl; /* The avl header */
+ int pkgoff; /* Where the packages live; start with SP */
+ int pathlen; /* The length of the pathname */
+ int len; /* Length of the line (incl NUL) */
+} pkgentry_t;
+
+static char IS_ST0[256];
+static char IS_ST0Q[256];
+
+static void pkg_door_srv(void *, char *, size_t, door_desc_t *, uint_t);
+static char *file_find(pkgfilter_t *, int *);
+static void parse_contents(void);
+static int parse_log(void);
+static void pkgdump(void);
+static int logflush(void);
+static int avlcmp(const void *, const void *);
+static void freeentry(pkgentry_t *);
+static void swapentry(pkgentry_t *, pkgentry_t *);
+static int establish_lock(char *);
+static int no_memory_abort(void);
+static int pkgfilter(pkgfilter_t *, door_desc_t *);
+static int pkgaddlines(pkgfilter_t *);
+static void finish(void);
+static void signal_handler(int);
+static void my_cond_reltimedwait(hrtime_t, int);
+static hrtime_t time_since_(hrtime_t);
+
+/*
+ * Server actions
+ * - set mode (contents file, log file)
+ * - roll log
+ * - remove package
+ * - merge package entries
+ */
+
+static FILE *log;
+static char *door = PKGDOOR;
+
+static avl_tree_t listp, *list = &listp;
+
+/* Keep the "the last command modified the contents file ... */
+static char *ccmnt[2];
+static int cind = 0;
+
+static mutex_t mtx = DEFAULTMUTEX;
+static cond_t cv = DEFAULTCV;
+
+static int flushbeforemark = 1;
+static int logerrcnt = 0;
+static int loglines = 0;
+static int suppressed = 0;
+static int logcount;
+static int ndumps;
+static int ncalls;
+static int changes;
+static hrtime_t lastchange;
+static hrtime_t lastcall;
+static volatile int want_to_quit;
+static boolean_t read_only = B_FALSE;
+static boolean_t permanent = B_FALSE;
+static boolean_t one_shot = B_FALSE;
+static int write_locked;
+static pid_t client_pid;
+static int verbose = 1;
+static hrtime_t dumptimeout = DUMPTIMEOUT;
+static boolean_t sync_needed = B_FALSE;
+
+static uid_t myuid;
+
+static char marker[] = "###Marker\n";
+
+static umem_cache_t *ecache;
+
+static char pkgdir[PATH_MAX];
+
+static void
+server_main(int argc, char **argv)
+{
+ int did;
+ int c;
+ struct statvfs vfsbuf;
+ int imexit = 0;
+ pid_t parent;
+ char *root = NULL;
+ char *sadmdir = NULL;
+ hrtime_t delta;
+ int dir = 0;
+ int dfd;
+
+ (void) set_prog_name("pkgserv");
+
+ openlog("pkgserv", LOG_PID | LOG_ODELAY, LOG_DAEMON);
+
+ while ((c = getopt(argc, argv, "d:eoN:pP:R:r:")) != EOF) {
+ switch (c) {
+ case 'e':
+ imexit = 1;
+ break;
+ case 'd':
+ sadmdir = optarg;
+ if (*sadmdir != '/' || strlen(sadmdir) >= PATH_MAX ||
+ access(sadmdir, X_OK) != 0)
+ exit(99);
+ break;
+ case 'N':
+ (void) set_prog_name(optarg);
+ break;
+ case 'o':
+ one_shot = B_TRUE;
+ verbose = 0;
+ break;
+ case 'p':
+ /*
+ * We are updating possibly many zones; so we're not
+ * dumping based on a short timeout and we will not
+ * exit.
+ */
+ permanent = B_TRUE;
+ dumptimeout = 3600;
+ break;
+ case 'P':
+ client_pid = atoi(optarg);
+ break;
+ case 'R':
+ root = optarg;
+ if (*root != '/' || strlen(root) >= PATH_MAX ||
+ access(root, X_OK) != 0)
+ exit(99);
+ break;
+ case 'r':
+ read_only = B_TRUE;
+ one_shot = B_TRUE;
+ verbose = 0;
+ door = optarg;
+ break;
+ default:
+ exit(99);
+ }
+ }
+
+ if (one_shot && permanent) {
+ progerr(gettext("Incorrect Usage"));
+ exit(99);
+ }
+
+ umem_nofail_callback(no_memory_abort);
+
+ if (root != NULL && strcmp(root, "/") != 0) {
+ if (snprintf(pkgdir, PATH_MAX, "%s%s", root,
+ sadmdir == NULL ? SADM_DIR : sadmdir) >= PATH_MAX) {
+ exit(99);
+ }
+ } else {
+ if (sadmdir == NULL)
+ (void) strcpy(pkgdir, SADM_DIR);
+ else
+ (void) strcpy(pkgdir, sadmdir);
+ }
+
+ if (chdir(pkgdir) != 0) {
+ progerr(gettext("can't chdir to %s"), pkgdir);
+ exit(2);
+ }
+
+ closefrom(3);
+
+ if (!read_only && establish_lock(LOCK) < 0) {
+ progerr(gettext(
+ "couldn't lock in %s (server running?): %s"),
+ pkgdir, strerror(errno));
+ exit(1);
+ }
+
+ did = door_create(pkg_door_srv, 0, DOOR_REFUSE_DESC);
+ if (did == -1) {
+ progerr("door_create: %s", strerror(errno));
+ exit(2);
+ }
+
+ (void) fdetach(door);
+
+ if ((dfd = creat(door, 0644)) < 0 || close(dfd) < 0) {
+ progerr("door_create: %s", strerror(errno));
+ exit(2);
+ }
+
+ (void) mutex_lock(&mtx);
+
+ myuid = geteuid();
+
+ (void) sigset(SIGHUP, signal_handler);
+ (void) sigset(SIGTERM, signal_handler);
+ (void) sigset(SIGINT, signal_handler);
+ (void) sigset(SIGQUIT, signal_handler);
+
+ (void) signal(SIGPIPE, SIG_IGN);
+
+ (void) atexit(finish);
+
+ if (fattach(did, door) != 0) {
+ progerr(gettext("attach door: %s"), strerror(errno));
+ exit(2);
+ }
+ (void) close(did);
+
+ ecache = umem_cache_create("entry", sizeof (pkgentry_t),
+ sizeof (char *), NULL, NULL, NULL, NULL, NULL, 0);
+
+ avl_create(list, avlcmp, sizeof (pkgentry_t),
+ offsetof(pkgentry_t, avl));
+
+ IS_ST0['\0'] = 1;
+ IS_ST0[' '] = 1;
+ IS_ST0['\t'] = 1;
+
+ IS_ST0Q['\0'] = 1;
+ IS_ST0Q[' '] = 1;
+ IS_ST0Q['\t'] = 1;
+ IS_ST0Q['='] = 1;
+
+ parse_contents();
+ if (parse_log() > 0)
+ pkgdump();
+
+ if (imexit)
+ exit(0);
+
+ if (statvfs(".", &vfsbuf) != 0) {
+ progerr(gettext("statvfs: %s"), strerror(errno));
+ exit(2);
+ }
+
+ if (strcmp(vfsbuf.f_basetype, "zfs") == 0)
+ flushbeforemark = 0;
+
+ /* We've started, tell the parent */
+ parent = getppid();
+ if (parent != 1)
+ (void) kill(parent, SIGUSR1);
+
+ if (!one_shot) {
+ int fd;
+ (void) setsid();
+ fd = open("/dev/null", O_RDWR, 0);
+ if (fd >= 0) {
+ (void) dup2(fd, STDIN_FILENO);
+ (void) dup2(fd, STDOUT_FILENO);
+ (void) dup2(fd, STDERR_FILENO);
+ if (fd > 2)
+ (void) close(fd);
+ }
+ }
+
+ lastcall = lastchange = gethrtime();
+
+ /*
+ * Start the main thread, here is where we unlock the mutex.
+ */
+ for (;;) {
+ if (want_to_quit) {
+ pkgdump();
+ exit(0);
+ }
+ /* Wait forever when root or when there's a running filter */
+ if (write_locked ||
+ (!one_shot && permanent && dir == changes)) {
+ (void) cond_wait(&cv, &mtx);
+ continue;
+ }
+ delta = time_since_(lastchange);
+ /* Wait until DUMPTIMEOUT after last change before we pkgdump */
+ if (delta < dumptimeout * LLNANOSEC) {
+ my_cond_reltimedwait(delta, dumptimeout);
+ continue;
+ }
+ /* Client still around? Just wait then. */
+ if (client_pid > 1 && kill(client_pid, 0) == 0) {
+ lastchange = lastcall = gethrtime();
+ continue;
+ }
+ /* Wait for another EXITTIMEOUT seconds before we exit */
+ if ((one_shot || !permanent) && dir == changes) {
+ delta = time_since_(lastcall);
+ if (delta < EXITTIMEOUT * LLNANOSEC) {
+ my_cond_reltimedwait(delta, EXITTIMEOUT);
+ continue;
+ }
+ exit(0);
+ }
+ pkgdump();
+ dir = changes;
+ }
+
+ /*NOTREACHED*/
+}
+
+/*ARGSUSED*/
+static void
+nothing(int sig)
+{
+}
+
+int
+main(int argc, char **argv)
+{
+ int sig;
+ sigset_t sset;
+ int stat;
+
+ /*
+ * We're starting the daemon; this process exits when the door
+ * server is established or when it fails to establish.
+ * We wait until the child process sends a SIGUSR1 or when it
+ * exits.
+ * We keep around who started us and as long as it lives, we don't
+ * exit.
+ */
+
+ (void) setlocale(LC_ALL, "");
+ (void) textdomain(TEXT_DOMAIN);
+
+ client_pid = getppid();
+
+ (void) sigemptyset(&sset);
+ (void) sigaddset(&sset, SIGUSR1);
+ (void) sigaddset(&sset, SIGCLD);
+
+ /* We need to catch the SIGCLD before we can sigwait for it. */
+ (void) sigset(SIGCLD, nothing);
+ /* We need to make sure that SIGUSR1 is not ignored. */
+ (void) sigset(SIGUSR1, SIG_DFL);
+ (void) sigprocmask(SIG_BLOCK, &sset, NULL);
+
+ /* We install the contents file readable. */
+ (void) umask(022);
+
+ switch (fork()) {
+ case -1:
+ exit(99);
+ /*NOTREACHED*/
+ case 0:
+ server_main(argc, argv);
+ /*NOTREACHED*/
+ default:
+ /* In the parent */
+ break;
+ }
+
+ for (;;) {
+ sig = sigwait(&sset);
+
+ switch (sig) {
+ case SIGCLD:
+ if (wait(&stat) > 0) {
+ if (WIFEXITED(stat))
+ _exit(WEXITSTATUS(stat));
+ else if (WIFSIGNALED(stat))
+ _exit(99);
+ }
+ break;
+ case SIGUSR1:
+ _exit(0);
+ }
+ }
+}
+
+/*ARGSUSED*/
+static void
+pkg_door_srv(void *cookie, char *argp, size_t asz, door_desc_t *dp,
+ uint_t ndesc)
+{
+ char *p = NULL;
+ pkgcmd_t *pcmd = (pkgcmd_t *)argp;
+ ucred_t *uc = NULL;
+ uid_t caller;
+ pid_t pcaller;
+ door_desc_t ddp;
+ int dnum = 0;
+ int one = 1;
+ int len = -1;
+
+ if (asz < sizeof (pkgcmd_t)) {
+ (void) door_return(NULL, 0, NULL, 0);
+ return;
+ }
+
+ if (door_ucred(&uc) != 0) {
+ (void) door_return(NULL, 0, NULL, 0);
+ return;
+ }
+
+ caller = ucred_geteuid(uc);
+ pcaller = ucred_getpid(uc);
+ ucred_free(uc);
+
+ if (caller != myuid) {
+ (void) door_return(NULL, 0, NULL, 0);
+ return;
+ }
+
+ (void) mutex_lock(&mtx);
+ ncalls++;
+
+ if (pcaller != client_pid && pcaller != -1 &&
+ (client_pid == 1 || kill(client_pid, 0) != 0)) {
+ client_pid = pcaller;
+ }
+
+ if (PKG_WRITE_COMMAND(pcmd->cmd))
+ while (write_locked > 0)
+ (void) cond_wait(&cv, &mtx);
+
+ switch (pcmd->cmd) {
+ case PKG_FINDFILE:
+ p = file_find((pkgfilter_t *)argp, &len);
+ break;
+ case PKG_DUMP:
+ if (read_only)
+ goto err;
+ if (logcount > 0)
+ pkgdump();
+ break;
+ case PKG_EXIT:
+ if (logcount > 0)
+ pkgdump();
+ exit(0);
+ /*NOTREACHED*/
+ case PKG_PKGSYNC:
+ if (read_only || logflush() != 0)
+ goto err;
+ break;
+ case PKG_FILTER:
+ if (pkgfilter((pkgfilter_t *)argp, &ddp) == 0)
+ dnum = 1;
+ break;
+ case PKG_ADDLINES:
+ if (read_only)
+ goto err;
+ changes++;
+
+ if (pkgaddlines((pkgfilter_t *)argp) != 0)
+ goto err;
+ /* If we've updated the database, tell the dump thread */
+ lastchange = gethrtime();
+ (void) cond_broadcast(&cv);
+ break;
+ case PKG_NOP:
+ /* Do nothing but register the current client's pid. */
+ break;
+ default:
+ goto err;
+ }
+
+ lastcall = gethrtime();
+ (void) mutex_unlock(&mtx);
+ (void) door_return(p, len != -1 ? len : p == NULL ? 0 : strlen(p) + 1,
+ dnum == 0 ? NULL : &ddp, dnum);
+ return;
+
+err:
+ (void) mutex_unlock(&mtx);
+ (void) door_return((void *)&one, 4, NULL, NULL);
+}
+
+/*
+ * This function returns the length of the string including exactly
+ * nf fields.
+ */
+static ptrdiff_t
+fieldoff(char *info, int nf)
+{
+ char *q = info;
+
+ while (nf > 0) {
+ if (IS_ST0[(unsigned char)*q++]) {
+ if (q[-1] == 0)
+ break;
+ nf--;
+ }
+ }
+ return (q - info - 1);
+}
+
+/*
+ * The buf points into list of \n delimited lines. We copy it,
+ * removing the newline and adding a \0.
+ */
+static char *
+mystrcpy(char *buf, int len)
+{
+ char *res = umem_alloc(len, UMEM_NOFAIL);
+
+ (void) memcpy(res, buf, len - 1);
+ res[len - 1] = '\0';
+ return (res);
+}
+
+/*
+ * Entry: a single line without the NEWLINE
+ * Return: the package entry with the path determined.
+ */
+static pkgentry_t *
+parse_line(char *buf, int blen, boolean_t full)
+{
+ char *t;
+ pkgentry_t *p;
+ int nfields;
+
+ p = umem_cache_alloc(ecache, UMEM_NOFAIL);
+ buf = p->line = mystrcpy(buf, blen + 1);
+ p->len = blen + 1;
+
+ t = buf;
+
+ while (!IS_ST0Q[(unsigned char)*t++])
+ ;
+
+ p->pathlen = t - buf - 1;
+ if (p->pathlen == 0 || p->pathlen >= PATH_MAX) {
+ progerr("bad entry read in contents file");
+ logerr("pathname: Unknown");
+ logerr("problem: unable to read pathname field");
+ if (one_shot)
+ exit(2);
+ }
+ if (t[-1] == '=')
+ while (!IS_ST0[(unsigned char)*t++])
+ ;
+
+ /* Partial as found in the "-" entries for log */
+ if (t[-1] == '\0') {
+ if (full)
+ goto badline;
+
+ p->pkgoff = -1;
+ return (p);
+ }
+
+ switch (*t) {
+ case '?':
+ nfields = 0;
+ break;
+ case 's':
+ case 'l':
+ /* Fields: class */
+ nfields = 1;
+ break;
+ case 'p':
+ case 'x':
+ case 'd':
+ /* class mode owner group */
+ nfields = 4;
+ break;
+ case 'f':
+ case 'e':
+ case 'v':
+ /* class mode owner group size csum time */
+ nfields = 7;
+ break;
+ case 'c':
+ case 'b':
+ /* class major minor mode owner group */
+ nfields = 6;
+ break;
+ default:
+ progerr("bad entry read in contents file");
+ logerr("pathname: %.*s", p->pathlen, p->line);
+ logerr("problem: unknown ftype");
+ freeentry(p);
+ if (one_shot)
+ exit(2);
+ return (NULL);
+ }
+
+ p->pkgoff = t + fieldoff(t, nfields + 1) - buf;
+
+ if (p->line[p->pkgoff] != '\0' || p->pkgoff == p->len - 1)
+ return (p);
+
+badline:
+ progerr(gettext("bad entry read in contents file"));
+ logerr(gettext("pathname: Unknown"));
+ logerr(gettext("problem: unknown ftype"));
+ freeentry(p);
+ if (one_shot)
+ exit(2);
+ return (NULL);
+}
+
+static void
+handle_comments(char *buf, int len)
+{
+ if (cind >= 2)
+ return;
+
+ if (buf[0] != '#')
+ return;
+
+ if (ccmnt[cind] != NULL)
+ umem_free(ccmnt[cind], strlen(ccmnt[cind]) + 1);
+ ccmnt[cind] = mystrcpy(buf, len);
+ cind++;
+}
+
+static void
+parse_contents(void)
+{
+ int cnt;
+ pkgentry_t *ent, *e2;
+ avl_index_t where;
+ int num = 0;
+ struct stat stb;
+ ptrdiff_t off;
+ char *p, *q, *map;
+ pkgentry_t *lastentry = NULL;
+ int d;
+ int cntserrs = 0;
+
+ cnt = open(CONTENTS, O_RDONLY);
+
+ cind = 0;
+
+ if (cnt == -1) {
+ if (errno == ENOENT)
+ return;
+ exit(99);
+ }
+
+ if (fstat(cnt, &stb) != 0) {
+ (void) close(cnt);
+ exit(99);
+ }
+ if (stb.st_size == 0) {
+ (void) close(cnt);
+ return;
+ }
+
+ map = mmap(0, stb.st_size, PROT_READ, MAP_PRIVATE, cnt, 0);
+ (void) close(cnt);
+ if (map == (char *)-1)
+ return;
+
+ (void) madvise(map, stb.st_size, MADV_WILLNEED);
+
+ for (off = 0; off < stb.st_size; off += q - p) {
+ p = map + off;
+ q = memchr(p, '\n', stb.st_size - off);
+ if (q == NULL)
+ break;
+
+ q++;
+ num++;
+ if (p[0] == '#' || p[0] == '\n') {
+ handle_comments(p, q - p);
+ continue;
+ }
+ ent = parse_line(p, q - p - 1, B_TRUE);
+
+ if (ent == NULL) {
+ cntserrs++;
+ continue;
+ }
+
+ /*
+ * We save time by assuming the database is sorted; by
+ * using avl_insert_here(), building the tree is nearly free.
+ * lastentry always contains the last entry in the AVL tree.
+ */
+ if (lastentry == NULL) {
+ avl_add(list, ent);
+ lastentry = ent;
+ } else if ((d = avlcmp(ent, lastentry)) == 1) {
+ avl_insert_here(list, ent, lastentry, AVL_AFTER);
+ lastentry = ent;
+ } else if (d == 0 ||
+ (e2 = avl_find(list, ent, &where)) != NULL) {
+ /*
+ * This can only happen if the contents file is bad;
+ * this can, e.g., happen with the old SQL contents DB,
+ * it didn't sort properly. Assume the first one
+ * is the correct one, but who knows?
+ */
+ if (d == 0)
+ e2 = lastentry;
+ if (strcmp(ent->line, e2->line) != 0) {
+ progerr(gettext("two entries for %.*s"),
+ ent->pathlen, ent->line);
+ cntserrs++;
+ }
+ freeentry(ent);
+ } else {
+ /* Out of order: not an error for us, really. */
+ progerr(gettext("bad read of contents file"));
+ logerr(gettext("pathname: Unknown"));
+ logerr(gettext(
+ "problem: unable to read pathname field"));
+ if (one_shot)
+ exit(2);
+ avl_insert(list, ent, where);
+ }
+ }
+
+ cind = 0;
+
+ (void) munmap(map, stb.st_size);
+
+ /* By default, we ignore bad lines, keep them in a copy. */
+ if (cntserrs > 0 && stb.st_nlink == 1) {
+ char bcf[sizeof (BADCONTENTS)];
+
+ (void) strcpy(bcf, BADCONTENTS);
+ if (mktemp(bcf) != NULL) {
+ (void) link(CONTENTS, bcf);
+ syslog(LOG_WARNING, "A bad contents file was saved: %s",
+ bcf);
+ }
+ }
+}
+
+static int
+parse_log(void)
+{
+ pkgentry_t *ent, *look;
+ avl_index_t where;
+ int num = 0;
+ int logfd;
+ struct stat stb;
+ int mlen = strlen(marker);
+ off_t realend;
+ ptrdiff_t off;
+ char *p, *q, *map;
+
+ logfd = open(PKGLOG, O_RDONLY);
+
+ if (logfd < 0) {
+ if (errno == ENOENT)
+ return (0);
+ progerr(gettext("cannot read "PKGLOG": %s"), strerror(errno));
+ exit(2);
+ }
+
+ if (fstat(logfd, &stb) != 0) {
+ progerr(gettext("cannot stat "PKGLOG": %s"), strerror(errno));
+ exit(2);
+ }
+
+ if (stb.st_size == 0) {
+ (void) close(logfd);
+ /* Force pkgdump && remove of the logfile. */
+ return (1);
+ }
+
+ /* We're making sure that we end with a NUL or more for strstr() */
+ map = mmap(0, stb.st_size + getpagesize(), PROT_READ, MAP_PRIVATE,
+ logfd, 0);
+ (void) close(logfd);
+ if (map == (char *)-1) {
+ progerr(gettext("Cannot mmap the "PKGLOG": %s"),
+ strerror(errno));
+ exit(2);
+ }
+
+ cind = 0;
+
+ realend = stb.st_size;
+
+ if (memcmp(map + realend - mlen, marker, mlen) != 0) {
+ progerr(gettext(PKGLOG" is not complete"));
+
+ realend = 0;
+ for (p = map; q = strstr(p, marker); ) {
+ if (q == map || q[-1] == '\n')
+ realend = q - map + mlen;
+ p = q + mlen;
+ }
+ progerr(gettext("Ignoring %ld bytes from log"),
+ (long)(stb.st_size - realend));
+ }
+
+ for (off = 0; off < realend; off += q - p) {
+ p = map + off;
+ q = memchr(p, '\n', realend - off);
+ if (q == NULL)
+ break;
+
+ q++;
+ num++;
+ if (p[0] == '#' || p[0] == '\n') {
+ if (memcmp(marker, p, mlen) == 0)
+ cind = 0;
+ else
+ handle_comments(p, q - p);
+ continue;
+ }
+
+ ent = parse_line(p + 1, q - (p + 1) - 1, p[0] != '-');
+ if (ent == NULL)
+ continue;
+ look = avl_find(list, ent, &where);
+ /*
+ * The log can be replayed; so any value of "look" is
+ * not unexpected.
+ */
+ switch (p[0]) {
+ case '+':
+ case '=':
+ if (look != NULL)
+ swapentry(look, ent);
+ else
+ avl_insert(list, ent, where);
+ break;
+ case '-':
+ if (look != NULL) {
+ avl_remove(list, look);
+ freeentry(look);
+ }
+ freeentry(ent);
+ break;
+ default:
+ freeentry(ent);
+ progerr(gettext("log %d: bad line"), num);
+ break;
+ }
+ }
+ (void) munmap(map, stb.st_size);
+
+ /* Force pkgdump && remove of the logfile if there are no valid mods. */
+ return (num == 0 ? 1 : num);
+}
+
+static char *
+file_find(pkgfilter_t *cmd, int *len)
+{
+ pkgentry_t p;
+ pkgentry_t *look;
+
+ p.line = cmd->buf;
+ p.pathlen = cmd->len;
+
+ look = avl_find(list, &p, NULL);
+
+ if (look == NULL)
+ return (NULL);
+
+ *len = look->len;
+ return (look->line);
+}
+
+static void
+pkgdump(void)
+{
+ FILE *cnts;
+ int err = 0;
+ pkgentry_t *p;
+
+ if (read_only)
+ return;
+
+ /* We cannot dump when the current transaction is not complete. */
+ if (sync_needed)
+ return;
+
+ cnts = fopen(TCONTENTS, "w");
+
+ if (cnts == NULL)
+ exit(99);
+
+ for (p = avl_first(list); p != NULL; p = AVL_NEXT(list, p)) {
+ if (fprintf(cnts, "%s\n", p->line) < 0)
+ err++;
+ }
+
+ if (ccmnt[0] != NULL)
+ (void) fprintf(cnts, "%s\n", ccmnt[0]);
+ if (ccmnt[1] != NULL)
+ (void) fprintf(cnts, "%s\n", ccmnt[1]);
+
+ if (err != 0 || fflush(cnts) == EOF || fsync(fileno(cnts)) != 0 ||
+ fclose(cnts) == EOF || rename(TCONTENTS, CONTENTS) != 0) {
+ err++;
+ }
+
+ if (err != 0) {
+ progerr("cannot rewrite the contents file");
+ exit(2);
+ }
+
+ (void) fclose(log);
+ (void) unlink(PKGLOG);
+ log = NULL;
+ ndumps++;
+ logcount = 0;
+}
+
+static void
+freeentry(pkgentry_t *p)
+{
+ umem_free(p->line, p->len);
+ umem_cache_free(ecache, p);
+}
+
+static void
+swapentry(pkgentry_t *cur, pkgentry_t *new)
+{
+ if (cur->len == new->len &&
+ strcmp(cur->line + cur->pathlen,
+ new->line + new->pathlen) == 0) {
+ suppressed++;
+ freeentry(new);
+ return;
+ }
+
+ /* Free old line */
+ umem_free(cur->line, cur->len);
+
+ /* Copy new value: pathlen is the same and avl is kept */
+ cur->line = new->line;
+ cur->len = new->len;
+ cur->pkgoff = new->pkgoff;
+
+ umem_cache_free(ecache, new);
+}
+
+static int
+logentry(char type, pkgentry_t *p)
+{
+ int len;
+
+ if (type == '-')
+ len = fprintf(log, "-%.*s\n", p->pathlen, p->line);
+ else
+ len = fprintf(log, "%c%s\n", type, p->line);
+
+ loglines++;
+ if (len < 0) {
+ logerrcnt++;
+ return (-1);
+ }
+ logcount += len;
+ return (0);
+}
+
+static int
+logflush(void)
+{
+ int len;
+ static int lastflush;
+
+ if (log == NULL)
+ return (0);
+
+ if (lastflush == logcount)
+ return (0);
+
+ if (cind == 2) {
+ (void) fprintf(log, "%s\n", ccmnt[0]);
+ (void) fprintf(log, "%s\n", ccmnt[1]);
+ cind = 0;
+ }
+
+ /*
+ * When using zfs, if the mark is there, then so is the rest before
+ * it. But with ufs, we need to flush twice.
+ */
+ if (flushbeforemark) {
+ if (fflush(log) == EOF)
+ logerrcnt++;
+ }
+ /* Anything before the last marker found in the log will be valid */
+ len = fprintf(log, "%s", marker);
+ if (len < 0)
+ logerrcnt++;
+ else
+ logcount += len;
+
+ if (fflush(log) == EOF)
+ logerrcnt++;
+
+ sync_needed = B_FALSE;
+
+ if (logerrcnt > 0 || logcount > MAXLOGFILESIZE)
+ pkgdump();
+
+ if (logerrcnt > 0)
+ return (-1);
+
+ lastflush = logcount;
+
+ return (0);
+}
+
+static int
+avlcmp(const void *ca, const void *cb)
+{
+ const pkgentry_t *a = ca;
+ const pkgentry_t *b = cb;
+ int i = memcmp(a->line, b->line,
+ a->pathlen > b->pathlen ? b->pathlen : a->pathlen);
+
+ if (i < 0)
+ return (-1);
+ else if (i > 0)
+ return (1);
+ else if (a->pathlen == b->pathlen)
+ return (0);
+ else if (a->pathlen > b->pathlen)
+ return (1);
+ else
+ return (-1);
+}
+
+/*
+ * Returns:
+ * 0 - if we can get the lock
+ * -1 - we can't lock
+ */
+
+static int
+establish_lock(char *lock)
+{
+ int fd = open(lock, O_RDWR|O_CREAT, 0644);
+ int i;
+
+ if (fd < 0)
+ return (-1);
+
+ for (i = 0; i < 5; i++) {
+ if (lockf(fd, F_TLOCK, 0) == 0)
+ return (0);
+ (void) sleep(1);
+ }
+
+ (void) close(fd);
+ return (-1);
+}
+
+static int
+no_memory_abort(void)
+{
+ return (UMEM_CALLBACK_EXIT(99));
+}
+
+/*
+ * Dump a part of the contents file in a pipe; grep for the "filter".
+ * It doesn't matter if we return too much.
+ */
+
+static void *
+thr_pkgfilter(void *v)
+{
+ pkgfilter_t *pf = v;
+ pkgentry_t *p;
+ int nums[2];
+ FILE *cnts;
+
+ cnts = fdopen(pf->cmd, "w");
+ if (cnts == NULL)
+ goto free;
+
+ /* Remove wild card: don't care about extra matches */
+ if (pf->len > 0) {
+ char *p;
+
+ for (p = pf->buf; *p; p++) {
+ if (*p == '*') {
+ *p = 0;
+ break;
+ }
+ }
+ }
+
+ /* Disable modifications while the filter is running */
+ (void) mutex_lock(&mtx);
+ write_locked++;
+ (void) mutex_unlock(&mtx);
+ /*
+ * The protocol for the contents file for the clients:
+ * <int:len><int:pathlen><line + 0>
+ */
+
+ for (p = avl_first(list); p != NULL; p = AVL_NEXT(list, p)) {
+ if (pf->len > 0 && strstr(p->line, pf->buf) == NULL)
+ continue;
+
+ nums[0] = p->len;
+ nums[1] = p->pathlen;
+ if (fwrite(nums, sizeof (int), 2, cnts) != 2)
+ break;
+ if (fwrite(p->line, 1, p->len, cnts) != p->len)
+ break;
+ }
+
+ (void) mutex_lock(&mtx);
+ lastcall = gethrtime();
+ write_locked--;
+ (void) cond_broadcast(&cv);
+ (void) mutex_unlock(&mtx);
+ (void) fclose(cnts);
+
+free:
+ umem_free(pf, sizeof (pkgfilter_t) + pf->len);
+ return (NULL);
+}
+
+static hrtime_t
+time_since_(hrtime_t last)
+{
+ return (gethrtime() - last);
+}
+
+static void
+my_cond_reltimedwait(hrtime_t delta, int sec)
+{
+ hrtime_t wait = sec * LLNANOSEC - delta;
+ timestruc_t waitfor;
+
+ waitfor.tv_nsec = wait % LLNANOSEC;
+ waitfor.tv_sec = wait / LLNANOSEC;
+ (void) cond_reltimedwait(&cv, &mtx, &waitfor);
+}
+
+static int
+pkgfilter(pkgfilter_t *pf, door_desc_t *dp)
+{
+
+ int p[2];
+ thread_t tid;
+ pkgfilter_t *cpf;
+
+ if (pipe(p) != 0)
+ return (-1);
+
+ cpf = umem_alloc(sizeof (pkgfilter_t) + pf->len, UMEM_NOFAIL);
+
+ (void) memcpy(cpf, pf, sizeof (pkgfilter_t) + pf->len);
+
+ /* Copy the file descriptor in the command field */
+ cpf->cmd = p[1];
+
+ if (thr_create(NULL, NULL, thr_pkgfilter, cpf, THR_DETACHED,
+ &tid) != 0) {
+ (void) close(p[0]);
+ (void) close(p[1]);
+ umem_free(cpf, sizeof (pkgfilter_t) + pf->len);
+ return (-1);
+ }
+ (void) memset(dp, 0, sizeof (*dp));
+ dp->d_attributes = DOOR_DESCRIPTOR | DOOR_RELEASE;
+ dp->d_data.d_desc.d_descriptor = p[0];
+
+ return (0);
+}
+
+static int
+pkgaddlines(pkgfilter_t *pf)
+{
+ char *map = pf->buf;
+ int len = pf->len;
+ int off;
+ pkgentry_t *ent, *look;
+ avl_index_t where;
+ char *q, *p;
+ char c;
+ int r = 0;
+
+ if (log == NULL) {
+ log = fopen(PKGLOG, "w");
+ if (log == NULL)
+ return (-1);
+ }
+
+ for (off = 0; off < len; off += q - p) {
+ p = map + off;
+ q = memchr(p, '\n', len - off);
+
+ if (q == NULL)
+ break;
+
+ q++;
+
+ if (p[0] == '#' || p[0] == '\n') {
+ handle_comments(p, q - p);
+ continue;
+ }
+
+ if (*p == '-')
+ ent = parse_line(p + 1, q - (p + 1) - 1, B_FALSE);
+ else
+ ent = parse_line(p, q - p - 1, B_TRUE);
+
+ if (ent == NULL) {
+ r++;
+ continue;
+ }
+
+ look = avl_find(list, ent, &where);
+ if (look != NULL) {
+ c = *p == '-' ? '-' : '=';
+ if (c == '=') {
+ swapentry(look, ent);
+ ent = look;
+ } else {
+ avl_remove(list, look);
+ freeentry(look);
+ }
+ } else if (*p == '-') {
+ /* Remove something which isn't there: no-op */
+ freeentry(ent);
+ continue;
+ } else {
+ avl_insert(list, ent, where);
+ c = '+';
+ }
+
+ sync_needed = B_TRUE;
+ r += logentry(c, ent);
+ if (c == '-')
+ freeentry(ent);
+ }
+
+ return (r);
+}
+
+static void
+finish(void)
+{
+ if (verbose) {
+ syslog(LOG_DEBUG,
+ "finished: calls %d, pkgdumps %d, loglines %d "
+ "(suppressed %d)\n",
+ ncalls, ndumps, loglines, suppressed);
+ }
+ (void) fdetach(door);
+ if (read_only)
+ (void) unlink(door);
+}
+
+/*
+ * Tell the wait thread to wake up and quit.
+ */
+/* ARGSUSED */
+static void
+signal_handler(int sig)
+{
+ if (read_only)
+ exit(0);
+ want_to_quit = 1;
+ (void) cond_broadcast(&cv);
+}
diff --git a/usr/src/lib/libpkg/Makefile.com b/usr/src/lib/libpkg/Makefile.com
index d89458c437..d2f77fff33 100644
--- a/usr/src/lib/libpkg/Makefile.com
+++ b/usr/src/lib/libpkg/Makefile.com
@@ -40,7 +40,7 @@ OBJECTS= \
verify.o security.o pkgweb.o \
pkgerr.o keystore.o p12lib.o \
vfpops.o fmkdir.o pkgstr.o \
- handlelocalfs.o
+ handlelocalfs.o pkgserv.o
# include library definitions
diff --git a/usr/src/lib/libpkg/common/mapfile-vers b/usr/src/lib/libpkg/common/mapfile-vers
index 7cb5ad56f3..f1fd2a8001 100644
--- a/usr/src/lib/libpkg/common/mapfile-vers
+++ b/usr/src/lib/libpkg/common/mapfile-vers
@@ -132,6 +132,9 @@ SUNWprivate {
path_valid;
pkg_passphrase_cb;
pkgalias;
+ pkgclosefilter;
+ pkgcloseserver;
+ pkgcmd;
pkgerr;
pkgerr_add;
pkgerr_clear;
@@ -142,9 +145,18 @@ SUNWprivate {
pkgerr_num;
pkgexecl;
pkgexecv;
+ pkggetentry;
+ pkggetentry_named;
pkghead;
pkglist_cont;
+ pkgmodeargument;
pkgmount;
+ pkgopenfilter;
+ pkgopenserver;
+ pkgparsemode;
+ pkgservercommitfile;
+ pkgservergetmode;
+ pkgserversetmode;
pkgstrAddToken;
pkgstrContainsToken;
pkgstrConvertPathToBasename;
@@ -160,6 +172,8 @@ SUNWprivate {
pkgstrRemoveLeadingWhitespace;
pkgstrRemoveToken;
pkgstrScaleNumericString;
+ pkgsync;
+ pkgsync_needed;
pkgtrans;
pkgumount;
ppkgmap;
diff --git a/usr/src/lib/libpkg/common/pkglib.h b/usr/src/lib/libpkg/common/pkglib.h
index 418cf632f7..04b17730ca 100644
--- a/usr/src/lib/libpkg/common/pkglib.h
+++ b/usr/src/lib/libpkg/common/pkglib.h
@@ -49,6 +49,58 @@ extern "C" {
#include "cfext.h"
/*
+ * The contents database file interface.
+ */
+
+typedef struct pkg_server *PKGserver;
+
+/* Some commands modify the internal database: add them here */
+#define PKG_WRITE_COMMAND(cmd) ((cmd) == PKG_ADDLINES)
+
+#define PKG_EXIT 0x0
+#define PKG_FINDFILE 0x1
+#define PKG_DUMP 0x2
+#define PKG_PKGSYNC 0x3
+#define PKG_FILTER 0x4
+#define PKG_ADDLINES 0x5
+#define PKG_NOP 0x6
+
+#define SUNW_PKG_SERVERMODE "SUNW_PKG_SERVERMODE"
+
+#define PKGSERV_MODE "pkg-server-mode="
+#define PKGSERV_MODE_LEN (sizeof (PKGSERV_MODE) - 1)
+
+#define MODE_PERMANENT "permanent"
+#define MODE_RUN_ONCE "run_once"
+#define MODE_TIMEOUT "timeout"
+
+#define MAXLOGFILESIZE (20 * 1024 * 1024)
+
+#define PKGLOG "pkglog"
+#define PKGDOOR ".door"
+
+typedef enum {
+ INVALID, /* Not initialized */
+ NEVER, /* Don't start, does check if it is running. */
+ FLUSH_LOG, /* Run it once to incorporate the log. */
+ RUN_ONCE, /* Run until the current client stops. */
+ TIMEOUT, /* Run until a timeout occurs. */
+ PERMANENT, /* Run until it is externally terminated. */
+ DEFAULTMODE = TIMEOUT /* The default mode, must come last */
+} start_mode_t;
+
+typedef struct pkgcmd {
+ int cmd;
+ char buf[1];
+} pkgcmd_t;
+
+typedef struct pkgfilter {
+ int cmd;
+ int len;
+ char buf[1];
+} pkgfilter_t;
+
+/*
* Virtual File Protocol definitions
*/
@@ -428,8 +480,7 @@ extern void set_passphrase_prompt(char *);
extern void set_passphrase_passarg(char *);
extern int pkg_passphrase_cb(char *, int, int, void *);
-extern int srchcfile(struct cfent *ept, char *path, VFP_T *vfp,
- VFP_T *vfpout);
+extern int srchcfile(struct cfent *ept, char *path, PKGserver server);
extern struct group *cgrgid(gid_t gid);
extern struct group *cgrnam(char *nam);
extern struct passwd *cpwnam(char *nam);
@@ -518,6 +569,25 @@ extern int vfpWriteToFile(VFP_T *a_vfp, char *a_path);
boolean_t enable_local_fs(void);
boolean_t restore_local_fs(void);
+/* pkgserv.c */
+extern PKGserver pkgopenserver(const char *, const char *, boolean_t);
+extern void pkgcloseserver(PKGserver);
+extern int pkgcmd(PKGserver, void *, size_t, char **, size_t *,
+ int *);
+extern boolean_t pkgsync_needed(const char *, const char *, boolean_t);
+extern int pkgsync(const char *, const char *, boolean_t);
+extern int pkgservercommitfile(VFP_T *, PKGserver);
+extern int pkgopenfilter(PKGserver server, const char *pkginst);
+extern void pkgclosefilter(PKGserver);
+extern char *pkggetentry(PKGserver, int *, int *);
+extern char *pkggetentry_named(PKGserver, const char *, int *,
+ int *);
+extern void pkgserversetmode(start_mode_t);
+extern start_mode_t pkgservergetmode(void);
+extern start_mode_t pkgparsemode(const char *);
+extern char *pkgmodeargument(start_mode_t);
+
+
#else /* __STDC__ */
extern FILE *epopen();
diff --git a/usr/src/lib/libpkg/common/pkgserv.c b/usr/src/lib/libpkg/common/pkgserv.c
new file mode 100644
index 0000000000..729f3c02a8
--- /dev/null
+++ b/usr/src/lib/libpkg/common/pkgserv.c
@@ -0,0 +1,603 @@
+/*
+ * 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.
+ */
+
+#include <pkglib.h>
+
+#include <alloca.h>
+#include <assert.h>
+#include <door.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <spawn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <libintl.h>
+
+#define PKGADD_MAX (512 * 1024)
+
+#define SADM_DIR "/var/sadm/install"
+
+#define PKGSERV_PATH "/usr/sadm/install/bin/pkgserv"
+
+#define ERR_PATH_TOO_BIG "alternate root path is too long"
+#define ERR_OPEN_DOOR "cannot open pkgserv door"
+#define ERR_START_SERVER "cannot start pkgserv daemon: %s"
+#define ERR_START_FILTER "cannot enumerate database entries"
+
+struct pkg_server {
+ FILE *fp;
+ char *curbuf;
+ int buflen;
+ int door;
+ boolean_t onetime;
+};
+
+static PKGserver current_server;
+
+static start_mode_t defmode = INVALID;
+static boolean_t registered = B_FALSE;
+static pid_t master_pid = -1;
+
+static void
+pkgfilename(char path[PATH_MAX], const char *root, const char *sadmdir,
+ const char *file)
+{
+ if (snprintf(path, PATH_MAX, "%s%s/%s", root == NULL ? "" : root,
+ sadmdir == NULL ? SADM_DIR : sadmdir, file) >= PATH_MAX) {
+ progerr(gettext(ERR_PATH_TOO_BIG));
+ exit(99);
+ }
+}
+
+static void
+pkgexit_close(void)
+{
+ if (current_server != NULL)
+ pkgcloseserver(current_server);
+}
+
+static PKGserver
+pkgopenserver_i(const char *root, const char *sadmdir, boolean_t readonly,
+ start_mode_t mode)
+{
+ PKGserver server;
+ struct door_info di;
+ pid_t pid;
+ int stat;
+ int first = B_TRUE;
+ char *cmd[16];
+ int args;
+ char pkgdoor[PATH_MAX];
+ extern char **environ;
+ char *prog;
+ char pidbuf[12];
+
+ if (current_server != NULL)
+ return (current_server);
+
+ if (!registered) {
+ registered = B_TRUE;
+ (void) atexit(pkgexit_close);
+ }
+ if (readonly) {
+ int fd;
+
+ (void) strcpy(pkgdoor, "/tmp/pkgdoor.XXXXXX");
+ if ((fd = mkstemp(pkgdoor)) < 0) {
+ progerr(gettext(ERR_OPEN_DOOR));
+ return (NULL);
+ }
+ (void) close(fd);
+ } else {
+ pkgfilename(pkgdoor, root, sadmdir, PKGDOOR);
+ }
+
+ server = malloc(sizeof (*server));
+
+ if (server == NULL)
+ goto return_null;
+
+ server->fp = NULL;
+ server->onetime = readonly;
+
+openserver:
+ server->door = open(pkgdoor, O_RDWR);
+
+ if (server->door >= 0) {
+ if (door_info(server->door, &di) == 0 && di.di_target >= 0) {
+ pkgcmd_t n;
+ n.cmd = PKG_NOP;
+ server->buflen = 1024;
+ server->curbuf = malloc(1024);
+ if (server->curbuf == NULL ||
+ pkgcmd(server, &n, sizeof (n), NULL, NULL, NULL)) {
+ pkgcloseserver(server);
+ return (NULL);
+ }
+ return (current_server = server);
+ }
+
+ (void) close(server->door);
+ }
+
+ if (!first || mode == NEVER)
+ goto return_null;
+
+ first = B_FALSE;
+
+ args = 0;
+ cmd[args++] = strrchr(PKGSERV_PATH, '/') + 1;
+ if (root != NULL && strcmp(root, "/") != 0) {
+ cmd[args++] = "-R";
+ cmd[args++] = (char *)root;
+ }
+ if (sadmdir != NULL && strcmp(sadmdir, SADM_DIR) != 0) {
+ cmd[args++] = "-d";
+ cmd[args++] = (char *)sadmdir;
+ }
+ if (readonly) {
+ cmd[args++] = "-r";
+ cmd[args++] = pkgdoor;
+ }
+ prog = get_prog_name();
+ if (prog != NULL) {
+ cmd[args++] = "-N";
+ cmd[args++] = prog;
+ }
+
+ switch (mode) {
+ case FLUSH_LOG:
+ cmd[args++] = "-e";
+ break;
+ case RUN_ONCE:
+ cmd[args++] = "-o";
+ break;
+ case PERMANENT:
+ cmd[args++] = "-p";
+ break;
+ default:
+ break;
+ }
+
+ if (master_pid != -1) {
+ cmd[args++] = "-P";
+ (void) snprintf(pidbuf, sizeof (pidbuf), "%d", master_pid);
+ cmd[args++] = pidbuf;
+ }
+ cmd[args++] = NULL;
+ assert(args <= sizeof (cmd)/sizeof (char *));
+
+ if (posix_spawn(&pid, PKGSERV_PATH, NULL, NULL, cmd, environ) == 0) {
+ server->onetime |= mode == RUN_ONCE;
+ while (wait4(pid, &stat, 0, NULL) != -1) {
+ if (WIFEXITED(stat)) {
+ int s = WEXITSTATUS(stat);
+ if (s == 0 || s == 1)
+ if (mode == FLUSH_LOG)
+ goto return_null;
+ else
+ goto openserver;
+ if (s == 2)
+ goto return_null;
+ break;
+ } else if (WIFSIGNALED(stat)) {
+ break;
+ }
+ }
+ }
+
+ progerr(gettext(ERR_START_SERVER), strerror(errno));
+
+return_null:
+ if (readonly)
+ (void) unlink(pkgdoor);
+ free(server);
+ return (NULL);
+}
+
+PKGserver
+pkgopenserver(const char *root, const char *sadmdir, boolean_t ro)
+{
+ return (pkgopenserver_i(root, sadmdir, ro, pkgservergetmode()));
+}
+
+start_mode_t
+pkgparsemode(const char *mode)
+{
+ if (strcasecmp(mode, MODE_PERMANENT) == 0) {
+ return (PERMANENT);
+ } else if (strncasecmp(mode, MODE_TIMEOUT,
+ sizeof (MODE_TIMEOUT) - 1) == 0) {
+ const char *pidstr = mode + sizeof (MODE_TIMEOUT) - 1;
+ if (pidstr[0] != '\0') {
+ master_pid = atoi(pidstr);
+ if (master_pid <= 1 || kill(master_pid, 0) != 0)
+ master_pid = -1;
+ }
+
+ return (TIMEOUT);
+ } else if (strcasecmp(mode, MODE_RUN_ONCE) == 0) {
+ return (RUN_ONCE);
+ } else {
+ progerr(gettext("invalid pkgserver mode: %s"), mode);
+ exit(99);
+ /*NOTREACHED*/
+ }
+}
+
+char *
+pkgmodeargument(start_mode_t mode)
+{
+ static char timebuf[sizeof (PKGSERV_MODE) + sizeof (MODE_TIMEOUT) + 10];
+
+ switch (mode) {
+ case PERMANENT:
+ return (PKGSERV_MODE MODE_PERMANENT);
+ case TIMEOUT:
+ (void) snprintf(timebuf, sizeof (timebuf),
+ PKGSERV_MODE MODE_TIMEOUT "%d",
+ (master_pid > 1 && kill(master_pid, 0) == 0) ? master_pid :
+ getpid());
+ return (timebuf);
+ case RUN_ONCE:
+ return (PKGSERV_MODE MODE_RUN_ONCE);
+ }
+ progerr(gettext("Bad pkgserv mode: %d"), (int)mode);
+ exit(99);
+}
+
+void
+pkgserversetmode(start_mode_t mode)
+{
+ if (mode == DEFAULTMODE || mode == INVALID) {
+ char *var = getenv(SUNW_PKG_SERVERMODE);
+
+ if (var != NULL)
+ defmode = pkgparsemode(var);
+ else
+ defmode = DEFAULTMODE;
+ } else {
+ defmode = mode;
+ }
+}
+
+start_mode_t
+pkgservergetmode(void)
+{
+ if (defmode == INVALID)
+ pkgserversetmode(DEFAULTMODE);
+ return (defmode);
+}
+
+void
+pkgcloseserver(PKGserver server)
+{
+
+ if (server->fp != NULL)
+ (void) fclose(server->fp);
+ free(server->curbuf);
+ if (server->onetime) {
+ pkgcmd_t cmd;
+ cmd.cmd = PKG_EXIT;
+ (void) pkgcmd(server, &cmd, sizeof (cmd), NULL, NULL, NULL);
+ }
+ (void) close(server->door);
+ if (server == current_server)
+ current_server = NULL;
+ free(server);
+}
+
+int
+pkgcmd(PKGserver srv, void *cmd, size_t len, char **result, size_t *rlen,
+ int *fd)
+{
+ door_arg_t da;
+
+ da.data_ptr = cmd;
+ da.data_size = len;
+ da.desc_ptr = NULL;
+ da.desc_num = 0;
+ da.rbuf = result == NULL ? NULL : *result;
+ da.rsize = rlen == NULL ? 0 : *rlen;
+
+ if (door_call(srv->door, &da) != 0) {
+ if (((pkgcmd_t *)cmd)->cmd == PKG_EXIT && errno == EINTR)
+ return (0);
+ return (-1);
+ }
+
+ if (da.desc_ptr != NULL) {
+ int i = 0;
+ if (fd != NULL)
+ *fd = da.desc_ptr[i++].d_data.d_desc.d_descriptor;
+ for (; i < da.desc_num; i++)
+ (void) close(da.desc_ptr[i].d_data.d_desc.d_descriptor);
+ }
+ /* Error return */
+ if (da.data_size == sizeof (int)) {
+ int x = *(int *)da.data_ptr;
+ if (x != 0) {
+ if (result == NULL || da.rbuf != *result)
+ (void) munmap(da.rbuf, da.rsize);
+ return (x);
+ }
+ }
+
+ /* Other result */
+ if (result != NULL) {
+ /* Make sure that the result is at the start of the buffer. */
+ if (da.data_ptr != NULL && da.rbuf != da.data_ptr)
+ (void) memmove(da.rbuf, da.data_ptr, da.data_size);
+ *result = da.rbuf;
+ *rlen = da.data_size;
+ } else if (da.rbuf != NULL) {
+ (void) munmap(da.rbuf, da.rsize);
+ }
+ return (0);
+}
+
+/*
+ * Pkgsync:
+ * If the server is running, make sure that the contents
+ * file is written.
+ * If the server is not running, check for the log file;
+ * if there's a non-empty log file, we need to start the server
+ * as it will incorporate the log file into the contents file.
+ * And then check if the door is present. If it doesn't, we don't
+ * need to call it.
+ */
+
+boolean_t
+pkgsync_needed(const char *root, const char *sadmdir, boolean_t want_quit)
+{
+ struct stat pbuf;
+ char pkgfile[PATH_MAX];
+ boolean_t sync_needed, running;
+ int fd;
+ struct door_info di;
+
+ pkgfilename(pkgfile, root, sadmdir, PKGLOG);
+
+ sync_needed = stat(pkgfile, &pbuf) == 0 && pbuf.st_size > 0;
+
+ if (!sync_needed && !want_quit)
+ return (B_FALSE);
+
+ pkgfilename(pkgfile, root, sadmdir, PKGDOOR);
+
+ /* sync_needed == B_TRUE || want_quit == B_TRUE */
+ running = B_FALSE;
+
+ fd = open(pkgfile, O_RDWR);
+
+ if (fd >= 0) {
+ if (door_info(fd, &di) == 0) {
+ /* It's mounted, so the server is likely there */
+ running = B_TRUE;
+ }
+ (void) close(fd);
+ }
+ return (running || sync_needed);
+}
+
+int
+pkgsync(const char *root, const char *sadmdir, boolean_t force_quit)
+{
+ void *server;
+ pkgcmd_t cmd;
+
+ /* No need to write contents file; don't start if not running */
+ if (!pkgsync_needed(root, sadmdir, force_quit))
+ return (0);
+
+ server = pkgopenserver_i(root, sadmdir, B_FALSE, FLUSH_LOG);
+ /*
+ * We're assuming that it started the server and exited immediately.
+ * If that didn't work, there's nothing we can do.
+ */
+ if (server == NULL)
+ return (0);
+
+ cmd.cmd = force_quit ? PKG_EXIT : PKG_DUMP;
+
+ (void) pkgcmd(server, &cmd, sizeof (cmd), NULL, NULL, NULL);
+ (void) pkgcloseserver(server);
+ return (0);
+}
+
+int
+pkgservercommitfile(VFP_T *a_vfp, PKGserver server)
+{
+ size_t len = vfpGetModifiedLen(a_vfp);
+ ssize_t rem = len;
+ size_t off;
+ pkgfilter_t *pcmd;
+ char *map = a_vfp->_vfpStart;
+
+ if (len < PKGADD_MAX)
+ pcmd = alloca(sizeof (*pcmd) + len);
+ else
+ pcmd = alloca(sizeof (*pcmd) + PKGADD_MAX);
+
+
+ off = 0;
+ pcmd->cmd = PKG_ADDLINES;
+ while (rem > 0) {
+ char *p = map + off;
+ len = rem;
+
+ if (len >= PKGADD_MAX) {
+ len = PKGADD_MAX - 1;
+ while (p[len] != '\n' && len > 0)
+ len--;
+ if (p[len] != '\n')
+ return (-1);
+ len++;
+ }
+ (void) memcpy(&pcmd->buf[0], p, len);
+ pcmd->len = len;
+
+ if (pkgcmd(server, pcmd, sizeof (*pcmd) + len - 1,
+ NULL, NULL, NULL) != 0) {
+ return (-1);
+ }
+ rem -= len;
+ off += len;
+ }
+ pcmd->len = 0;
+ pcmd->cmd = PKG_PKGSYNC;
+ if (pkgcmd(server, pcmd, sizeof (*pcmd), NULL, NULL, NULL) != 0)
+ return (-1);
+
+ /* Mark it unmodified. */
+ vfpTruncate(a_vfp);
+ (void) vfpClearModified(a_vfp);
+
+ return (0);
+}
+
+int
+pkgopenfilter(PKGserver server, const char *filt)
+{
+ int fd;
+ pkgfilter_t *pfcmd;
+ int clen = filt == NULL ? 0 : strlen(filt);
+ int len = sizeof (*pfcmd) + clen;
+
+ pfcmd = alloca(len);
+
+ if (server->fp != NULL) {
+ (void) fclose(server->fp);
+ server->fp = NULL;
+ }
+
+ pfcmd->cmd = PKG_FILTER;
+ pfcmd->len = clen;
+ if (filt != NULL)
+ (void) strcpy(pfcmd->buf, filt);
+
+ fd = -1;
+
+ if (pkgcmd(server, pfcmd, len, NULL, NULL, &fd) != 0 || fd == -1) {
+ progerr(gettext(ERR_START_FILTER));
+ return (-1);
+ }
+ (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
+
+ server->fp = fdopen(fd, "r");
+ if (server->fp == NULL) {
+ (void) close(fd);
+ progerr(gettext(ERR_START_FILTER));
+ return (-1);
+ }
+ return (0);
+}
+
+void
+pkgclosefilter(PKGserver server)
+{
+ if (server->fp != NULL) {
+ (void) fclose(server->fp);
+ server->fp = NULL;
+ }
+}
+
+/*
+ * Report the next entry from the contents file.
+ */
+char *
+pkggetentry(PKGserver server, int *len, int *pathlen)
+{
+ int num[2];
+
+ if (server->fp == NULL)
+ return (NULL);
+
+ if (feof(server->fp) || ferror(server->fp))
+ return (NULL);
+
+ if (fread(num, sizeof (int), 2, server->fp) != 2)
+ return (NULL);
+
+ if (num[0] > server->buflen) {
+ free(server->curbuf);
+ server->buflen = num[0];
+ server->curbuf = malloc(server->buflen);
+ if (server->curbuf == NULL)
+ return (NULL);
+ }
+ if (fread(server->curbuf, 1, num[0], server->fp) != num[0])
+ return (NULL);
+
+ *len = num[0];
+ *pathlen = num[1];
+
+ return (server->curbuf);
+}
+
+char *
+pkggetentry_named(PKGserver server, const char *path, int *len, int *pathlen)
+{
+ int plen = strlen(path);
+ pkgfilter_t *pcmd = alloca(sizeof (*pcmd) + plen);
+ char *result;
+ unsigned int rlen;
+
+ pcmd->cmd = PKG_FINDFILE;
+ *pathlen = pcmd->len = plen;
+ (void) memcpy(pcmd->buf, path, pcmd->len + 1);
+
+ result = server->curbuf;
+ rlen = server->buflen;
+
+ if (pkgcmd(server, pcmd, sizeof (*pcmd) + pcmd->len,
+ &result, &rlen, NULL) != 0) {
+ return (NULL);
+ }
+ if (rlen == 0)
+ return (NULL);
+
+ /* Result too big */
+ if (result != server->curbuf) {
+ free(server->curbuf);
+ server->buflen = rlen;
+ server->curbuf = malloc(server->buflen);
+ if (server->curbuf == NULL)
+ return (NULL);
+ (void) memcpy(server->curbuf, result, rlen);
+ (void) munmap(result, rlen);
+ }
+ *len = rlen;
+
+ return (server->curbuf);
+}
diff --git a/usr/src/lib/libpkg/common/srchcfile.c b/usr/src/lib/libpkg/common/srchcfile.c
index dd24a855cd..bacfc5c622 100644
--- a/usr/src/lib/libpkg/common/srchcfile.c
+++ b/usr/src/lib/libpkg/common/srchcfile.c
@@ -27,8 +27,6 @@
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
-
-
#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
@@ -46,7 +44,6 @@
* Forward declarations
*/
-static void findend(char **cp);
static int getend(char **cp);
static int getstr(char **cp, int n, char *str, int separator[]);
@@ -66,31 +63,10 @@ static int decisionTableInit = 0;
* These arrays must be indexable by an unsigned char.
*/
-static int ISPKGPATHSEP[UCHAR_MAX+1];
static int ISWORDSEP[UCHAR_MAX+1];
static int ISPKGNAMESEP[UCHAR_MAX+1];
/*
- * Name: WRITEDATA
- * Description: write out data to VFP_T given start and end pointers
- * Arguments: VFP - (VFP_T *) - [RO, *RW]
- * Contents file VFP to narrow search on
- * FIRSTPOS - (char *) - [RO, *RO]
- * Pointer to first byte to write out
- * LASTPOS - (char *) - [RO, *RO]
- * Pointer to last byte to write out
- */
-
-#define WRITEDATA(VFP, FIRSTPOS, LASTPOS) \
- { \
- ssize_t XXlenXX; \
- /* compute number of bytes skipped */ \
- XXlenXX = (ptrdiff_t)(LASTPOS) - (ptrdiff_t)(FIRSTPOS); \
- /* write the bytes out */ \
- vfpPutBytes((VFP), (FIRSTPOS), XXlenXX); \
- }
-
-/*
* Name: COPYPATH
* Description: copy path limiting size to destination capacity
* Arguments: DEST - (char []) - [RW]
@@ -112,214 +88,6 @@ static int ISPKGNAMESEP[UCHAR_MAX+1];
}
/*
- * Name: narrowSearch
- * Description: narrow the search location for a specified path
- * The contents and package map files are always sorted by path.
- * This function is given a target path to search for given the
- * current location in a contents file. It is assured that the
- * target path has not been searched for yet in the contents file
- * so the current location in the contents file is guaranteed to
- * be less than the location of the target path (if present).
- * Given this employ a binary search to speed up the search for
- * the path nearest to a specified target path.
- * Arguments: a_vfp - (VFP_T *) - [RO, *RW]
- * Contents file VFP to narrow search on
- * a_path - (char *) - [RO, *RO]
- * Pointer to path to search for
- * a_pathLen - (size_t) - [RO]
- * Length of string (a_path)
- * Returns: char * - pointer to first byte of entry in contents file that
- * is guaranteed to be the closest match to the specified
- * a_path without being "greater than" the path.
- * == (char *)NULL if no entry found
- */
-
-static char *
-narrowSearch(VFP_T *a_vfp, char *a_path, size_t a_pathLen)
-{
- char *phigh;
- char *plow;
- char *pmid;
- int n;
- size_t plen;
-
- /* if no path to compare, start at beginning */
-
- if ((a_path == (char *)NULL) || (*a_path == '\0')) {
- return ((char *)NULL);
- }
-
- /* if the contents file is empty, resort to sequential search */
-
- if (vfpGetBytesRemaining(a_vfp) <= 1) {
- return ((char *)NULL);
- }
-
- /*
- * test against first path - if the path specified is less than the
- * first path in the contents file, then the path can be inserted
- * before the first entry in the contents file.
- */
-
- /* locate start of first line */
-
- plow = vfpGetCurrCharPtr(a_vfp);
- pmid = plow;
-
- /* if first path not absolute, resort to sequential search */
-
- if (*pmid != '/') {
- return ((char *)NULL);
- }
-
- /* find end of path */
-
- while (ISPKGPATHSEP[(int)*pmid] == 0) {
- pmid++;
- }
-
- /* determine length of path */
-
- plen = (ptrdiff_t)pmid - (ptrdiff_t)plow;
-
- /* compare target path with current path */
-
- n = strncmp(a_path, plow, plen);
- if (n == 0) {
- /* if lengths same exact match return position found */
- if (a_pathLen == plen) {
- return (plow);
- }
- /* not exact match - a_path > pm */
- n = a_pathLen;
- }
-
- /* return if target is less than or equal to first entry */
-
- if (n <= 0) {
- return (plow);
- }
-
- /*
- * test against last path - if the path specified is greater than the
- * last path in the contents file, then the path can be appended after
- * the last entry in the contents file.
- */
-
- /* locate start of last line */
-
- plow = vfpGetCurrCharPtr(a_vfp);
- pmid = vfpGetLastCharPtr(a_vfp);
-
- while ((pmid > plow) && (!((pmid[0] == '/') && (pmid[-1] == '\n')))) {
- pmid--;
- }
-
- /* if absolute path, do comparison */
-
- if ((pmid > plow) && (*pmid == '/')) {
- plow = pmid;
-
- /* find end of path */
-
- while (ISPKGPATHSEP[(int)*pmid] == 0) {
- pmid++;
- }
-
- /* determine length of path */
-
- plen = (ptrdiff_t)pmid - (ptrdiff_t)plow;
-
- /* compare target path with current path */
-
- n = strncmp(a_path, plow, plen);
- if (n == 0) {
- /* if lengths same exact match return position found */
- if (a_pathLen == plen) {
- return (plow);
- }
- /* not exact match - a_path > pm */
- n = a_pathLen;
- }
-
- /* return if target is greater than or equal to entry */
-
- if (n >= 0) {
- return (plow);
- }
- }
- /*
- * firstPath < targetpath < lastPath:
- * binary search looking for closest "less than" match
- */
-
- plow = vfpGetCurrCharPtr(a_vfp);
- phigh = vfpGetLastCharPtr(a_vfp);
-
- for (;;) {
- char *pm;
-
- /* determine number of bytes left in search area */
-
- plen = (ptrdiff_t)phigh - (ptrdiff_t)plow;
-
- /* calculate mid point between current low and high points */
-
- pmid = plow + (plen >> 1);
-
- /* backup and find first "\n/" -or- start of buffer */
-
- while ((pmid > plow) &&
- (!((pmid[0] == '/') && (pmid[-1] == '\n')))) {
- pmid--;
- }
-
- /* return lowest line found if current line not past that */
-
- if (pmid <= plow) {
- return (plow);
- }
-
- /* remember start of this line */
-
- pm = pmid;
-
- /* find end of path */
-
- while (ISPKGPATHSEP[(int)*pmid] == 0) {
- pmid++;
- }
-
- /* determine length of path */
-
- plen = (ptrdiff_t)pmid - (ptrdiff_t)pm;
-
- /* compare target path with current path */
-
- n = strncmp(a_path, pm, plen);
-
- if (n == 0) {
- /* if lengths same exact match return position found */
- if (a_pathLen == plen) {
- return (pm);
- }
- /* not exact match - a_path > pm */
- n = a_pathLen;
- }
-
-
- /* not exact match - determine which watermark to split */
-
- if (n > 0) { /* a_path > pm */
- plow = pm;
- } else { /* a_path < pm */
- phigh = pm;
- }
- }
- /*NOTREACHED*/
-}
-
-/*
* Name: srchcfile
* Description: search contents file looking for closest match to entry,
* creating a new contents file if output contents file specified
@@ -329,34 +97,20 @@ narrowSearch(VFP_T *a_vfp, char *a_path, size_t a_pathLen)
* - path to search for in contents file
* - If path is "*", then the next entry is returned;
* the next entry always matches this path
- * - If the path is (char *)NULL or "", then all remaining
- * entries are processed and copied out to the
- * file specified by cfTmpVFp
- * cfVfp - (VFP_T *) - [RO, *RW]
- * - VFP_T open on contents file to search
- * cfTmpVfp - (VFP_T *) - [RO, *RW]
- * - VFP_T open on temporary contents file to populate
+ * PKGserver
+ * - our door to the database server.
+ *
* Returns: int
* < 0 - error occurred
* - Use getErrstr to retrieve character-string describing
* the reason for failure
* == 0 - no match found
* - specified path not in the contents file
- * - all contents of cfVfp copied to cfTmpVfp
- * - current character of cfVfp is at end of file
* == 1 - exact match found
* - specified path found in contents file
- * - contents of cfVfp up to entry found copied to cfTmpVfp
- * - current character of cfVfp is first character of
- * entry found
* - this value is always returned if path is "*" and the
- * next entry is returned - -1 is returned when no more
+ * next entry is returned - 0 is returned when no more
* entries are left to process
- * == 2 - entry found which is GREATER than path specified
- * - specified path would fit BEFORE entry found
- * - contents of cfVfp up to entry found copied to cfTmpVfp
- * - current character of cfVfp is first character of
- * entry found
* Side Effects:
* - The ept structure supplied is filled in with a description of
* the item that caused the search to terminate, except in the
@@ -368,23 +122,19 @@ narrowSearch(VFP_T *a_vfp, char *a_path, size_t a_pathLen)
*/
int
-srchcfile(struct cfent *ept, char *path, VFP_T *cfVfp, VFP_T *cfTmpVfp)
+srchcfile(struct cfent *ept, char *path, PKGserver server)
{
- char *cpath_start = (char *)NULL;
- char *firstPos = vfpGetCurrCharPtr(cfVfp);
- char *lastPos = NULL;
- char *pos;
+ char *cpath_start = NULL;
char classname[CLSSIZ+1];
char pkgname[PKGSIZ+1];
int anypath = 0;
int c;
- int dataSkipped = 0;
- int n;
- int rdpath;
- size_t cpath_len = 0;
- size_t pathLength;
+ int cpath_len = 0;
struct pinfo *lastpinfo;
struct pinfo *pinfo;
+ char *p;
+ char *curbuf;
+ int linelen; /* includes NUL */
/*
* this code does not use nested subroutines because execution time
@@ -394,7 +144,6 @@ srchcfile(struct cfent *ept, char *path, VFP_T *cfVfp, VFP_T *cfTmpVfp)
/* initialize local variables */
setErrstr(NULL); /* no error message currently cached */
- pathLength = (path == (char *)NULL ? 0 : strlen(path));
lpath[0] = '\0';
lpath[sizeof (lpath)-1] = '\0';
@@ -431,17 +180,6 @@ srchcfile(struct cfent *ept, char *path, VFP_T *cfVfp, VFP_T *cfTmpVfp)
*/
/*
- * Separators for path names, normal space and =
- * for linked filenames
- */
- bzero(ISPKGPATHSEP, sizeof (ISPKGPATHSEP));
- ISPKGPATHSEP['='] = 1; /* = */
- ISPKGPATHSEP[' '] = 1; /* space */
- ISPKGPATHSEP['\t'] = 1; /* horizontal-tab */
- ISPKGPATHSEP['\n'] = 1; /* new-line */
- ISPKGPATHSEP['\0'] = 1; /* NULL character */
-
- /*
* Separators for normal words
*/
bzero(ISWORDSEP, sizeof (ISWORDSEP));
@@ -465,16 +203,10 @@ srchcfile(struct cfent *ept, char *path, VFP_T *cfVfp, VFP_T *cfTmpVfp)
decisionTableInit = 1;
}
- /* if no bytes in contents file, return 0 */
-
- if (vfpGetBytesRemaining(cfVfp) <= 1) {
- return (0);
- }
-
/* if the path to scan for is empty, act like no path was specified */
- if ((path != (char *)NULL) && (*path == '\0')) {
- path = (char *)NULL;
+ if ((path != NULL) && (*path == '\0')) {
+ path = NULL;
}
/*
@@ -482,7 +214,7 @@ srchcfile(struct cfent *ept, char *path, VFP_T *cfVfp, VFP_T *cfTmpVfp)
* we encounter as a match, otherwise we return an error
*/
- if ((path != (char *)NULL) && (path[0] != '/')) {
+ if ((path != NULL) && (path[0] != '/')) {
if (strcmp(path, "*") != 0) {
setErrstr(pkg_gt(ERR_ILLEGAL_SEARCH_PATH));
return (-1);
@@ -492,497 +224,100 @@ srchcfile(struct cfent *ept, char *path, VFP_T *cfVfp, VFP_T *cfTmpVfp)
/* attempt to narrow down the search for the specified path */
- if (anypath == 0) {
- char *np;
-
- np = narrowSearch(cfVfp, path, pathLength);
- if (np != (char *)NULL) {
- dataSkipped = 1;
- lastPos = np;
- vfpSetCurrCharPtr(cfVfp, np);
- }
- }
+ if (anypath == 0 && path == NULL)
+ return (0);
- /*
- * If the path to search for in the source contents file is NULL, then
- * this is a request to scan to the end of the source contents file. If
- * there is a temporary contents file to copy entries to, all that needs
- * to be done is to copy the data remaining from the current location in
- * the source contents file to the end of the temporary contents file.
- * if there is no temporary contents file to copy to, then all that
- * needs to be done is to seek to the end of the source contents file.
- */
+ /* determine first character of the next entry */
+ if (anypath == 0)
+ curbuf = pkggetentry_named(server, path, &linelen, &cpath_len);
+ else
+ curbuf = pkggetentry(server, &linelen, &cpath_len);
- if ((anypath == 0) && (path == (char *)NULL)) {
- if (cfTmpVfp != (VFP_T *)NULL) {
- if (vfpGetBytesRemaining(cfVfp) > 0) {
- WRITEDATA(cfTmpVfp, firstPos,
- vfpGetLastCharPtr(cfVfp)+1);
- }
- *vfpGetLastCharPtr(cfTmpVfp) = '\0';
- }
- vfpSeekToEnd(cfVfp);
+ if (curbuf == NULL)
return (0);
- }
/*
- * *********************************************************************
- * main loop processing entries from the contents file looking for
- * the specified path
- * *********************************************************************
+ * current entry DOES start with absolute path
+ * set ept->path to point to lpath
+ * set cpath_start/cpath_len to point to the file name
*/
- for (;;) {
- char *p;
-
- /* not reading old style entry */
-
- rdpath = 0;
-
- /* determine first character of the next entry */
-
- if (vfpGetBytesRemaining(cfVfp) <= 0) {
- /* no bytes in contents file current char is NULL */
-
- c = '\0';
- } else {
- /* grab path from first entry */
-
- c = vfpGetcNoInc(cfVfp);
- }
-
- /* save current position in file */
-
- pos = vfpGetCurrCharPtr(cfVfp);
-
- /*
- * =============================================================
- * at the first character of the next entry in the contents file
- * if not absolute path check for exceptions and old style entry
- * --> if end of contents file write out skipped data and return
- * --> if comment character skip to end of line and restart loop
- * --> else process "old style entry: ftype class path"
- * =============================================================
- */
-
- if (c != '/') {
- /* if NULL character then end of contents file found */
-
- if (c == '\0') {
- /* write out skipped data before returning */
- if (dataSkipped &&
- (cfTmpVfp != (VFP_T *)NULL)) {
- WRITEDATA(cfTmpVfp, firstPos, lastPos);
- *vfpGetLastCharPtr(cfTmpVfp) = '\0';
- }
-
- return (0); /* no more entries */
- }
-
- /* ignore lines that begin with #, : or a "space" */
-
- if ((isspace(c) != 0) || (c == '#') || (c == ':')) {
- /* line is a comment */
- findend(&vfpGetCurrCharPtr(cfVfp));
- continue;
- }
-
- /*
- * old style entry - format is:
- * ftype class path
- * set ept->ftype to the type
- * set ept->class to the class
- * set ept->path to point to lpath
- * set cpath_start/cpath_len to point to the file name
- * set rdpath to '1' to indicate old style entry parsed
- */
-
- while (isspace((c = vfpGetc(cfVfp))))
- ;
-
- switch (c) {
- case '?': case 'f': case 'v': case 'e': case 'l':
- case 's': case 'p': case 'c': case 'b': case 'd':
- case 'x':
- /* save ftype */
- ept->ftype = (char)c;
-
- /* save class */
- if (getstr(&vfpGetCurrCharPtr(cfVfp), CLSSIZ,
- ept->pkg_class, ISWORDSEP)) {
- setErrstr(ERR_CANNOT_READ_CLASS_TOKEN);
- findend(&vfpGetCurrCharPtr(cfVfp));
- return (-1);
- }
-
- /*
- * locate file name up to "=", set cpath_start
- * and cpath_len to point to the file name
- */
- cpath_start = vfpGetCurrCharPtr(cfVfp);
- p = vfpGetCurrCharPtr(cfVfp);
-
- /*
- * skip past all bytes until first '= \t\n\0':
- */
- while (ISPKGPATHSEP[(int)*p] == 0) {
- p++;
- }
-
- cpath_len = vfpGetCurrPtrDelta(cfVfp, p);
-
- /*
- * if the path is zero bytes, line is corrupted
- */
-
- if (cpath_len < 1) {
- setErrstr(ERR_CANNOT_READ_PATHNAME_FLD);
- findend(&vfpGetCurrCharPtr(cfVfp));
- return (-1);
- }
-
- vfpIncCurrPtrBy(cfVfp, cpath_len);
-
- /* set path to point to local path cache */
- ept->path = lpath;
-
- /* set flag indicating path already parsed */
- rdpath = 1;
- break;
-
- case '\0':
- /* end of line before new-line seen */
- vfpDecCurrPtr(cfVfp);
- setErrstr(ERR_INCOMPLETE_ENTRY);
- return (-1);
-
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- /* volume number seen */
- setErrstr(ERR_VOLUMENO_UNEXPECTED);
- findend(&vfpGetCurrCharPtr(cfVfp));
- return (-1);
-
- case 'i':
- /* type i files are not cataloged */
- setErrstr(ERR_FTYPE_I_UNEXPECTED);
- findend(&vfpGetCurrCharPtr(cfVfp));
- return (-1);
-
- default:
- /* unknown ftype */
- setErrstr(ERR_UNKNOWN_FTYPE);
- findend(&vfpGetCurrCharPtr(cfVfp));
- return (-1);
- }
- } else {
- /*
- * current entry DOES start with absolute path
- * set ept->path to point to lpath
- * set cpath_start/cpath_len to point to the file name
- */
- /* copy first token into path element of passed structure */
-
- cpath_start = vfpGetCurrCharPtr(cfVfp);
-
- p = cpath_start;
-
- /*
- * skip past all bytes until first from '= \t\n\0':
- */
-
- while (ISPKGPATHSEP[(int)*p] == 0) {
- p++;
- }
-
- cpath_len = vfpGetCurrPtrDelta(cfVfp, p);
-
- vfpIncCurrPtrBy(cfVfp, cpath_len);
-
- if (vfpGetcNoInc(cfVfp) == '\0') {
- setErrstr(ERR_INCOMPLETE_ENTRY);
- findend(&vfpGetCurrCharPtr(cfVfp));
- return (-1);
- }
-
- ept->path = lpath;
- }
-
- /*
- * =============================================================
- * if absolute path then the path is collected and we are at the
- * first byte following the absolute path name;
- * if not an absolute path then an old style entry, ept has been
- * filled with the type and class and path name.
- * determine if we have read the pathname which identifies
- * the entry we are searching for
- * =============================================================
- */
-
- if (anypath != 0) {
- n = 0; /* next entry is "equal to" */
- } else if (path == (char *)NULL) {
- n = 1; /* next entry is "greater than" */
- } else {
- n = strncmp(path, cpath_start, cpath_len);
- if ((n == 0) && (cpath_len != pathLength)) {
- n = cpath_len;
- }
- }
+ /* copy first token into path element of passed structure */
- /* get first character following the end of the path */
+ cpath_start = curbuf;
- c = vfpGetc(cfVfp);
+ p = cpath_start + cpath_len;
- /*
- * if an exact match, always parse out the local path
- */
+ ept->path = lpath;
- if (n == 0) {
- /*
- * we want to return information about this path in
- * the structure provided, so parse any local path
- * and jump to code which parses rest of the input line
- */
- if (c == '=') {
- /* parse local path specification */
- if (getstr(&vfpGetCurrCharPtr(cfVfp), PATH_MAX,
- mylocal, ISWORDSEP)) {
-
- /* copy path found to 'lpath' */
- COPYPATH(lpath, cpath_start, cpath_len);
-
- setErrstr(ERR_CANNOT_READ_LL_PATH);
- findend(&vfpGetCurrCharPtr(cfVfp));
- return (-1);
- }
- ept->ainfo.local = mylocal;
- }
- }
-
- /*
- * if an exact match and processing a new style entry, read the
- * remaining information from the new style entry - if this is
- * an old style entry (rdpath != 0) then the existing info has
- * already been processed as it exists before the pathname and
- * not after like a new style entry
- */
-
- if (n == 0 && rdpath == 0) {
- while (isspace((c = vfpGetc(cfVfp))))
- ;
-
- switch (c) {
- case '?': case 'f': case 'v': case 'e': case 'l':
- case 's': case 'p': case 'c': case 'b': case 'd':
- case 'x':
- /* save ftype */
- ept->ftype = (char)c;
-
- /* save class */
- if (getstr(&vfpGetCurrCharPtr(cfVfp), CLSSIZ,
- ept->pkg_class, ISWORDSEP)) {
-
- /* copy path found to 'lpath' */
- COPYPATH(lpath, cpath_start, cpath_len);
-
- setErrstr(ERR_CANNOT_READ_CLASS_TOKEN);
- findend(&vfpGetCurrCharPtr(cfVfp));
- return (-1);
- }
- break; /* we already read the pathname */
-
- case '\0':
- /* end of line before new-line seen */
- vfpDecCurrPtr(cfVfp);
-
- /* copy path found to 'lpath' */
- COPYPATH(lpath, cpath_start, cpath_len);
-
- setErrstr(ERR_INCOMPLETE_ENTRY);
- return (-1);
-
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
-
- /* copy path found to 'lpath' */
- COPYPATH(lpath, cpath_start, cpath_len);
-
- setErrstr(ERR_VOLUMENO_UNEXPECTED);
- findend(&vfpGetCurrCharPtr(cfVfp));
- return (-1);
-
- case 'i':
-
- /* copy path found to 'lpath' */
- COPYPATH(lpath, cpath_start, cpath_len);
-
- setErrstr(ERR_FTYPE_I_UNEXPECTED);
- findend(&vfpGetCurrCharPtr(cfVfp));
- return (-1);
-
- default:
- /* unknown ftype */
+ /* copy path found to 'lpath' */
+ COPYPATH(lpath, cpath_start, cpath_len);
- /* copy path found to 'lpath' */
- COPYPATH(lpath, cpath_start, cpath_len);
+ /* get first character following the end of the path */
- setErrstr(ERR_UNKNOWN_FTYPE);
- findend(&vfpGetCurrCharPtr(cfVfp));
- return (-1);
- }
- }
+ c = *p++;
- /*
- * if an exact match all processing is completed; break out of
- * the main processing loop and finish processing this entry
- * prior to returning to the caller.
- */
-
- if (n == 0) {
- break;
+ /*
+ * we want to return information about this path in
+ * the structure provided, so parse any local path
+ * and jump to code which parses rest of the input line
+ */
+ if (c == '=') {
+ /* parse local path specification */
+ if (getstr(&p, PATH_MAX, mylocal, ISWORDSEP)) {
+ setErrstr(ERR_CANNOT_READ_LL_PATH);
+ return (-1);
}
+ ept->ainfo.local = mylocal;
+ }
- /*
- * this entry is not an exact match for the path being searched
- * for - if this entry is GREATER THAN the path being searched
- * for then finish processing and return GREATER THAN result
- * to the caller so the entry for the path being searched for
- * can be added to the contents file.
- */
-
- if (n < 0) {
- /*
- * the entry we want would fit BEFORE the one we just
- * read, so we need to unread what we've read by
- * seeking back to the start of this entry
- */
-
- vfpSetCurrCharPtr(cfVfp, pos);
+ /*
+ * if an exact match and processing a new style entry, read the
+ * remaining information from the new style entry.
+ */
- /* copy path found to 'lpath' */
- COPYPATH(lpath, cpath_start, cpath_len);
+ while (isspace((c = *p++)))
+ ;
- /* write out any skipped data before returning */
- if (dataSkipped && (cfTmpVfp != (VFP_T *)NULL)) {
- WRITEDATA(cfTmpVfp, firstPos, lastPos);
- }
+ switch (c) {
+ case '?': case 'f': case 'v': case 'e': case 'l':
+ case 's': case 'p': case 'c': case 'b': case 'd':
+ case 'x':
+ /* save ftype */
+ ept->ftype = (char)c;
- return (2); /* path would insert here */
+ /* save class */
+ if (getstr(&p, CLSSIZ, ept->pkg_class, ISWORDSEP)) {
+ setErrstr(ERR_CANNOT_READ_CLASS_TOKEN);
+ return (-1);
}
+ break; /* we already read the pathname */
- /*
- * This entry is "LESS THAN" the specified path to search for
- * need to process the next entry from the contents file. First,
- * if writing to new contents file, update new contents file if
- * processing old style entry; otherwise, update skipped data
- * information to remember current last byte of skipped data.
- */
-
- if (cfTmpVfp != (VFP_T *)NULL) {
- char *px;
- ssize_t len;
-
- if (rdpath != 0) {
- /* modify record: write out any skipped data */
- if (dataSkipped) {
- WRITEDATA(cfTmpVfp, firstPos, lastPos);
- }
-
- /*
- * copy what we've read and the rest of this
- * line onto the specified output stream
- */
- vfpPutBytes(cfTmpVfp, cpath_start, cpath_len);
- vfpPutc(cfTmpVfp, c);
- vfpPutc(cfTmpVfp, ept->ftype);
- vfpPutc(cfTmpVfp, ' ');
- vfpPuts(cfTmpVfp, ept->pkg_class);
-
- px = strchr(vfpGetCurrCharPtr(cfVfp), '\n');
-
- if (px == (char *)NULL) {
- len = vfpGetBytesRemaining(cfVfp);
- vfpPutBytes(cfTmpVfp,
- vfpGetCurrCharPtr(cfVfp), len);
- vfpPutc(cfTmpVfp, '\n');
- vfpSeekToEnd(cfVfp);
- } else {
- len = vfpGetCurrPtrDelta(cfVfp, px);
- vfpPutBytes(cfTmpVfp,
- vfpGetCurrCharPtr(cfVfp), len);
- vfpIncCurrPtrBy(cfVfp, len);
- }
-
- /* reset skiped bytes if any data skipped */
- if (dataSkipped) {
- dataSkipped = 0;
- lastPos = (char *)NULL;
- firstPos = vfpGetCurrCharPtr(cfVfp);
- }
- } else {
- /* skip data */
- dataSkipped = 1;
-
- px = strchr(vfpGetCurrCharPtr(cfVfp), '\n');
-
- if (px == (char *)NULL) {
- vfpSeekToEnd(cfVfp);
- } else {
- len = vfpGetCurrPtrDelta(cfVfp, px)+1;
- vfpIncCurrPtrBy(cfVfp, len);
- }
- lastPos = vfpGetCurrCharPtr(cfVfp);
- }
- } else {
- /*
- * since this isn't the entry we want, just read the
- * stream until we find the end of this entry and
- * then start this search loop again
- */
- char *px;
-
- px = strchr(vfpGetCurrCharPtr(cfVfp), '\n');
-
- if (px == (char *)NULL) {
- vfpSeekToEnd(cfVfp);
+ case '\0':
+ /* end of line before new-line seen */
+ setErrstr(ERR_INCOMPLETE_ENTRY);
+ return (-1);
- /* copy path found to 'lpath' */
- COPYPATH(lpath, cpath_start, cpath_len);
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ setErrstr(ERR_VOLUMENO_UNEXPECTED);
+ return (-1);
- setErrstr(pkg_gt(ERR_MISSING_NEWLINE));
- findend(&vfpGetCurrCharPtr(cfVfp));
- return (-1);
- } else {
- ssize_t len;
+ case 'i':
+ setErrstr(ERR_FTYPE_I_UNEXPECTED);
+ return (-1);
- len = vfpGetCurrPtrDelta(cfVfp, px)+1;
- vfpIncCurrPtrBy(cfVfp, len);
- }
- }
+ default:
+ /* unknown ftype */
+ setErrstr(ERR_UNKNOWN_FTYPE);
+ return (-1);
}
- /*
- * *********************************************************************
- * end of main loop processing entries from contents file
- * the loop is broken out of when an exact match for the
- * path being searched for has been found and the type is one of:
- * - ?fvelspcbdx
- * at this point parsing is at the first character past the full path
- * name on an exact match for the path being looked for - parse the
- * remainder of the entries information into the ept structure.
- * *********************************************************************
- */
-
/* link/symbolic link must have link destination */
if (((ept->ftype == 's') || (ept->ftype == 'l')) &&
- (ept->ainfo.local == NULL)) {
- /* copy path found to 'lpath' */
- COPYPATH(lpath, cpath_start, cpath_len);
-
+ (ept->ainfo.local == NULL)) {
setErrstr(ERR_NO_LINK_SOURCE_SPECIFIED);
- findend(&vfpGetCurrCharPtr(cfVfp));
return (-1);
}
@@ -991,15 +326,9 @@ srchcfile(struct cfent *ept, char *path, VFP_T *cfVfp, VFP_T *cfTmpVfp)
if (((ept->ftype == 'c') || (ept->ftype == 'b'))) {
ept->ainfo.major = BADMAJOR;
ept->ainfo.minor = BADMINOR;
- if (getnumvfp(&vfpGetCurrCharPtr(cfVfp), 10,
- (long *)&ept->ainfo.major, BADMAJOR) ||
- getnumvfp(&vfpGetCurrCharPtr(cfVfp), 10,
- (long *)&ept->ainfo.minor, BADMINOR)) {
- /* copy path found to 'lpath' */
- COPYPATH(lpath, cpath_start, cpath_len);
-
+ if (getnumvfp(&p, 10, (long *)&ept->ainfo.major, BADMAJOR) ||
+ getnumvfp(&p, 10, (long *)&ept->ainfo.minor, BADMINOR)) {
setErrstr(pkg_gt(ERR_CANNOT_READ_MM_NUMS));
- findend(&vfpGetCurrCharPtr(cfVfp));
return (-1);
}
}
@@ -1007,21 +336,16 @@ srchcfile(struct cfent *ept, char *path, VFP_T *cfVfp, VFP_T *cfTmpVfp)
/* most types have mode, owner, group identification components */
if ((ept->ftype == 'd') || (ept->ftype == 'x') || (ept->ftype == 'c') ||
- (ept->ftype == 'b') || (ept->ftype == 'p') ||
- (ept->ftype == 'f') || (ept->ftype == 'v') ||
- (ept->ftype == 'e')) {
+ (ept->ftype == 'b') || (ept->ftype == 'p') ||
+ (ept->ftype == 'f') || (ept->ftype == 'v') ||
+ (ept->ftype == 'e')) {
/* mode, owner, group should be here */
- if (getnumvfp(&vfpGetCurrCharPtr(cfVfp), 8,
- (long *)&ept->ainfo.mode, BADMODE) ||
- getstr(&vfpGetCurrCharPtr(cfVfp), sizeof (ept->ainfo.owner),
- ept->ainfo.owner, ISWORDSEP) ||
- getstr(&vfpGetCurrCharPtr(cfVfp), sizeof (ept->ainfo.group),
- ept->ainfo.group, ISWORDSEP)) {
- /* copy path found to 'lpath' */
- COPYPATH(lpath, cpath_start, cpath_len);
-
+ if (getnumvfp(&p, 8, (long *)&ept->ainfo.mode, BADMODE) ||
+ getstr(&p, sizeof (ept->ainfo.owner), ept->ainfo.owner,
+ ISWORDSEP) ||
+ getstr(&p, sizeof (ept->ainfo.group), ept->ainfo.group,
+ ISWORDSEP)) {
setErrstr(ERR_CANNOT_READ_MOG);
- findend(&vfpGetCurrCharPtr(cfVfp));
return (-1);
}
}
@@ -1029,19 +353,13 @@ srchcfile(struct cfent *ept, char *path, VFP_T *cfVfp, VFP_T *cfTmpVfp)
/* i/f/v/e have size, checksum, modification time components */
if ((ept->ftype == 'i') || (ept->ftype == 'f') ||
- (ept->ftype == 'v') || (ept->ftype == 'e')) {
+ (ept->ftype == 'v') || (ept->ftype == 'e')) {
/* look for content description */
- if (getlnumvfp(&vfpGetCurrCharPtr(cfVfp), 10,
- (fsblkcnt_t *)&ept->cinfo.size, BADCONT) ||
- getnumvfp(&vfpGetCurrCharPtr(cfVfp), 10,
- (long *)&ept->cinfo.cksum, BADCONT) ||
- getnumvfp(&vfpGetCurrCharPtr(cfVfp), 10,
- (long *)&ept->cinfo.modtime, BADCONT)) {
- /* copy path found to 'lpath' */
- COPYPATH(lpath, cpath_start, cpath_len);
-
+ if (getlnumvfp(&p, 10, (fsblkcnt_t *)&ept->cinfo.size,
+ BADCONT) ||
+ getnumvfp(&p, 10, (long *)&ept->cinfo.cksum, BADCONT) ||
+ getnumvfp(&p, 10, (long *)&ept->cinfo.modtime, BADCONT)) {
setErrstr(ERR_CANNOT_READ_CONTENT_INFO);
- findend(&vfpGetCurrCharPtr(cfVfp));
return (-1);
}
}
@@ -1049,22 +367,6 @@ srchcfile(struct cfent *ept, char *path, VFP_T *cfVfp, VFP_T *cfTmpVfp)
/* i files processing is completed - return 'exact match found' */
if (ept->ftype == 'i') {
- /* copy path found to 'lpath' */
- COPYPATH(lpath, cpath_start, cpath_len);
-
- if (getend(&vfpGetCurrCharPtr(cfVfp))) {
- /* copy path found to 'lpath' */
- COPYPATH(lpath, cpath_start, cpath_len);
-
- setErrstr(ERR_EXTRA_TOKENS);
- return (-1);
- }
-
- /* write out any skipped data before returning */
- if (dataSkipped && (cfTmpVfp != (VFP_T *)NULL)) {
- WRITEDATA(cfTmpVfp, firstPos, lastPos);
- }
-
return (1);
}
@@ -1073,16 +375,11 @@ srchcfile(struct cfent *ept, char *path, VFP_T *cfVfp, VFP_T *cfTmpVfp)
*/
lastpinfo = (struct pinfo *)NULL;
- while ((c = getstr(&vfpGetCurrCharPtr(cfVfp), sizeof (pkgname),
- pkgname, ISPKGNAMESEP)) <= 0) {
+ while ((c = getstr(&p, sizeof (pkgname), pkgname, ISPKGNAMESEP)) <= 0) {
/* if c < 0 the string was too long to fix in the buffer */
if (c < 0) {
- /* copy path found to 'lpath' */
- COPYPATH(lpath, cpath_start, cpath_len);
-
setErrstr(ERR_PACKAGE_NAME_TOO_LONG);
- findend(&vfpGetCurrCharPtr(cfVfp));
return (-1);
}
@@ -1090,11 +387,7 @@ srchcfile(struct cfent *ept, char *path, VFP_T *cfVfp, VFP_T *cfTmpVfp)
pinfo = (struct pinfo *)calloc(1, sizeof (struct pinfo));
if (!pinfo) {
- /* copy path found to 'lpath' */
- COPYPATH(lpath, cpath_start, cpath_len);
-
setErrstr(ERR_NO_MEMORY);
- findend(&vfpGetCurrCharPtr(cfVfp));
return (-1);
}
if (!lastpinfo) {
@@ -1105,31 +398,31 @@ srchcfile(struct cfent *ept, char *path, VFP_T *cfVfp, VFP_T *cfTmpVfp)
lastpinfo = pinfo;
if ((pkgname[0] == '-') || (pkgname[0] == '+') ||
- (pkgname[0] == '*') || (pkgname[0] == '~') ||
- (pkgname[0] == '!') || (pkgname[0] == '%')) {
+ (pkgname[0] == '*') || (pkgname[0] == '~') ||
+ (pkgname[0] == '!') || (pkgname[0] == '%')) {
pinfo->status = pkgname[0];
(void) strlcpy(pinfo->pkg, pkgname+1,
- sizeof (pinfo->pkg));
+ sizeof (pinfo->pkg));
} else {
(void) strlcpy(pinfo->pkg, pkgname,
- sizeof (pinfo->pkg));
+ sizeof (pinfo->pkg));
}
/* pkg/[:[ftype][:class] */
- c = (vfpGetc(cfVfp));
+ c = *p++;
if (c == '\\') {
/* get alternate ftype */
pinfo->editflag++;
- c = (vfpGetc(cfVfp));
+ c = *p++;
}
if (c == ':') {
/* get special classname */
- (void) getstr(&vfpGetCurrCharPtr(cfVfp),
- sizeof (classname), classname, ISWORDSEP);
+ (void) getstr(&p, sizeof (classname), classname,
+ ISWORDSEP);
(void) strlcpy(pinfo->aclass, classname,
- sizeof (pinfo->aclass));
- c = (vfpGetc(cfVfp));
+ sizeof (pinfo->aclass));
+ c = *p++;
}
ept->npkgs++;
@@ -1142,11 +435,7 @@ srchcfile(struct cfent *ept, char *path, VFP_T *cfVfp, VFP_T *cfTmpVfp)
/* if package not separated by a space return an error */
if (!isspace(c)) {
- /* copy path found to 'lpath' */
- COPYPATH(lpath, cpath_start, cpath_len);
-
setErrstr(ERR_BAD_ENTRY_END);
- findend(&vfpGetCurrCharPtr(cfVfp));
return (-1);
}
}
@@ -1155,18 +444,10 @@ srchcfile(struct cfent *ept, char *path, VFP_T *cfVfp, VFP_T *cfTmpVfp)
* parsing of the entry is complete
*/
- /* copy path found to 'lpath' */
- COPYPATH(lpath, cpath_start, cpath_len);
-
- /* write out any skipped data before returning */
- if (dataSkipped && (cfTmpVfp != (VFP_T *)NULL)) {
- WRITEDATA(cfTmpVfp, firstPos, lastPos);
- }
-
/* if not at the end of the entry, make it so */
if ((c != '\n') && (c != '\0')) {
- if (getend(&vfpGetCurrCharPtr(cfVfp)) && ept->pinfo) {
+ if (getend(&p) && ept->pinfo) {
setErrstr(ERR_EXTRA_TOKENS);
return (-1);
}
@@ -1202,7 +483,7 @@ getstr(char **cp, int n, char *str, int separator[])
/* compute length based on delimiter found or not */
p1 = p;
- while (separator[(int)*p1] == 0) {
+ while (separator[(int)(*(unsigned char *)p1)] == 0) {
p1++;
}
@@ -1252,27 +533,3 @@ getend(char **cp)
*cp = ++p;
return (n);
}
-
-static void
-findend(char **cp)
-{
- char *p1;
- char *p = *cp;
-
- /* if at end of buffer return no more characters left */
-
- if (*p == '\0') {
- return;
- }
-
- /* find the end of the line */
-
- p1 = strchr(p, '\n');
-
- if (p1 != (char *)NULL) {
- *cp = ++p1;
- return;
- }
-
- *cp = strchr(p, '\0');
-}
diff --git a/usr/src/pkgdefs/SUNWpkgcmdsr/prototype_com b/usr/src/pkgdefs/SUNWpkgcmdsr/prototype_com
index 74964b9525..c013b5eb7c 100644
--- a/usr/src/pkgdefs/SUNWpkgcmdsr/prototype_com
+++ b/usr/src/pkgdefs/SUNWpkgcmdsr/prototype_com
@@ -48,5 +48,9 @@ f none var/sadm/install/admin/default 444 root sys
d none var/sadm/install/logs 555 root bin
d none var/sadm/pkg 555 root sys
d none var/sadm/security 555 root sys
+d none var/svc 0755 root sys
+d none var/svc/manifest 0755 root sys
+d none var/svc/manifest/system 0755 root sys
+f none var/svc/manifest/system/pkgserv.xml 0444 root sys
d none var/spool 755 root bin
d none var/spool/pkg 1777 root bin
diff --git a/usr/src/pkgdefs/SUNWpkgcmdsu/prototype_com b/usr/src/pkgdefs/SUNWpkgcmdsu/prototype_com
index e033135608..9c382712c7 100644
--- a/usr/src/pkgdefs/SUNWpkgcmdsu/prototype_com
+++ b/usr/src/pkgdefs/SUNWpkgcmdsu/prototype_com
@@ -58,6 +58,7 @@ d none usr/sadm/install/bin 755 root bin
f none usr/sadm/install/bin/pkginstall 555 root sys
f none usr/sadm/install/bin/pkgname 555 root sys
f none usr/sadm/install/bin/pkgremove 555 root sys
+f none usr/sadm/install/bin/pkgserv 555 root sys
d none usr/sadm/install/scripts 755 root bin
f none usr/sadm/install/scripts/cmdexec 555 root sys
f none usr/sadm/install/scripts/i.CompCpio 555 root sys