diff options
author | Casper H.S. Dik <Casper.Dik@Sun.COM> | 2009-06-15 22:21:13 +0200 |
---|---|---|
committer | Casper H.S. Dik <Casper.Dik@Sun.COM> | 2009-06-15 22:21:13 +0200 |
commit | 62224350e5355e6834f7deb9d8a7d062a50cb7c2 (patch) | |
tree | 843bde4060f38c24d288c9a7b79d9900a6527671 | |
parent | a7e1d0d300de20869e70883ddfa4a5ca867ce135 (diff) | |
download | illumos-joyent-62224350e5355e6834f7deb9d8a7d062a50cb7c2.tar.gz |
PSARC 2009/173 Fasttrack for turbo-charging SVr4 packaging
6820054 Turbocharged SVr4 package commands [PSARC 2009/173]
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 |