summaryrefslogtreecommitdiff
path: root/usr/src/lib/libpkg
diff options
context:
space:
mode:
authorCasper H.S. Dik <Casper.Dik@Sun.COM>2010-02-26 11:45:28 +0100
committerCasper H.S. Dik <Casper.Dik@Sun.COM>2010-02-26 11:45:28 +0100
commit7706a9bf5155da553880e1d88bef039daa6fc46c (patch)
tree2fe5696d4fae21718d0bd106f9799d0943ad66d3 /usr/src/lib/libpkg
parent4ba231cedd10104ba0c43236736c7a3b1bbc1143 (diff)
downloadillumos-gate-7706a9bf5155da553880e1d88bef039daa6fc46c.tar.gz
6914269 Patch 119254-70/119254-71 breaks pkgchk -l and Pkgchk -l -p
6920685 pkgserv cannot always recover from a crash when the logfile is not on ZFS. 6927931 svr4 pkglib should try harder to find the canonical sadm directory.
Diffstat (limited to 'usr/src/lib/libpkg')
-rw-r--r--usr/src/lib/libpkg/common/pkgserv.c162
1 files changed, 161 insertions, 1 deletions
diff --git a/usr/src/lib/libpkg/common/pkgserv.c b/usr/src/lib/libpkg/common/pkgserv.c
index 729f3c02a8..176600e7b3 100644
--- a/usr/src/lib/libpkg/common/pkgserv.c
+++ b/usr/src/lib/libpkg/common/pkgserv.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -42,6 +42,8 @@
#include <sys/wait.h>
#include <unistd.h>
#include <libintl.h>
+#include <sys/mnttab.h>
+#include <sys/mkdev.h>
#define PKGADD_MAX (512 * 1024)
@@ -53,6 +55,7 @@
#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"
+#define ERR_FIND_SADM "cannot find sadm directory"
struct pkg_server {
FILE *fp;
@@ -80,6 +83,160 @@ pkgfilename(char path[PATH_MAX], const char *root, const char *sadmdir,
}
static void
+free_xmnt(struct extmnttab *xmnt)
+{
+ free(xmnt->mnt_special);
+ free(xmnt->mnt_mountp);
+ free(xmnt->mnt_fstype);
+}
+
+static void
+copy_xmnt(const struct extmnttab *xmnt, struct extmnttab *saved)
+{
+
+ free_xmnt(saved);
+
+ /*
+ * Copy everything and then strdup the strings we later use and NULL
+ * the ones we don't.
+ */
+ *saved = *xmnt;
+
+ if (saved->mnt_special != NULL)
+ saved->mnt_special = strdup(saved->mnt_special);
+ if (saved->mnt_mountp != NULL)
+ saved->mnt_mountp = strdup(saved->mnt_mountp);
+ if (saved->mnt_fstype != NULL)
+ saved->mnt_fstype = strdup(saved->mnt_fstype);
+
+ saved->mnt_mntopts = NULL;
+ saved->mnt_time = NULL;
+}
+
+static int
+testdoor(char *path)
+{
+ int dir;
+ int fd;
+ struct door_info di;
+ int res;
+
+ dir = open(path, O_RDONLY);
+
+ if (dir == -1)
+ return (-1);
+
+ fd = openat(dir, PKGDOOR, O_RDWR);
+ (void) close(dir);
+ if (fd == -1)
+ return (-1);
+
+ res = door_info(fd, &di);
+ (void) close(fd);
+ return (res);
+}
+
+/*
+ * We need to make sure that we can locate the pkgserv and the door;
+ * lofs mounts makes this more difficult: "nosub" mounts don't propagate
+ * the door and doors created in lofs mounts are not propagated back to
+ * the original filesystem.
+ * Here we peel off the lofs mount points until we're
+ * at /var/sadm/install or
+ * we find a working door or
+ * there's nothing more to peel off.
+ * The fullpath parameter is used to return the result (stored in *sadmdir),
+ * root is used but returned in the computed sadmdir and so the caller should
+ * not use "root" any longer or set it to NULL.
+ */
+static void
+pkgfindrealsadmdir(char fullpath[PATH_MAX], const char *root,
+ const char **sadmdir)
+{
+ struct stat buf;
+ struct extmnttab xmnt;
+ FILE *mnttab = NULL;
+ char temp[PATH_MAX];
+ struct extmnttab saved = {NULL, NULL, NULL, NULL, NULL, 0, 0};
+
+ if (snprintf(temp, PATH_MAX, "%s%s",
+ root == NULL ? "" : root,
+ *sadmdir == NULL ? SADM_DIR : *sadmdir) >= PATH_MAX) {
+ progerr(gettext(ERR_PATH_TOO_BIG));
+ exit(99);
+ }
+
+ if (stat(temp, &buf) != 0) {
+ progerr(gettext(ERR_FIND_SADM));
+ exit(99);
+ }
+
+ /*
+ * To find the underlying mount point, you will need to
+ * search the mnttab and find our mountpoint and the underlying
+ * filesystem.
+ * To find the mount point: use the longest prefix but limit
+ * us to the filesystems with the same major/minor numbers.
+ * To find the underlying mount point: find a non-lofs file
+ * system or a <mnt> <mnt> entry (fake mountpoint for zones).
+ */
+ for (;;) {
+ size_t max = 0;
+
+ if (realpath(temp, fullpath) == NULL) {
+ progerr(gettext(ERR_FIND_SADM));
+ exit(99);
+ }
+
+ if (strcmp(fullpath, SADM_DIR) == 0)
+ break;
+
+ if (testdoor(fullpath) == 0)
+ break;
+
+ if (mnttab == NULL)
+ mnttab = fopen(MNTTAB, "r");
+ else
+ resetmnttab(mnttab);
+
+ while (getextmntent(mnttab, &xmnt, 0) == 0) {
+ size_t len;
+
+ if (major(buf.st_dev) != xmnt.mnt_major ||
+ minor(buf.st_dev) != xmnt.mnt_minor)
+ continue;
+
+ len = strlen(xmnt.mnt_mountp);
+ if (len < max)
+ continue;
+
+ if (strncmp(xmnt.mnt_mountp, fullpath, len) == 0 &&
+ (len == 1 || fullpath[len] == '/' ||
+ fullpath[len] == '\0')) {
+ max = len;
+ copy_xmnt(&xmnt, &saved);
+ }
+ }
+ if (strcmp(saved.mnt_fstype, "lofs") != 0 ||
+ strcmp(saved.mnt_mountp, saved.mnt_special) == 0) {
+ break;
+ }
+ /* Create a new path in the underlying filesystem. */
+ if (snprintf(temp, PATH_MAX, "%s%s", saved.mnt_special,
+ &fullpath[max]) >= PATH_MAX) {
+ progerr(gettext(ERR_PATH_TOO_BIG));
+ exit(99);
+ }
+ }
+
+ if (mnttab != NULL) {
+ free_xmnt(&saved);
+ (void) fclose(mnttab);
+ }
+ *sadmdir = fullpath;
+}
+
+static void
pkgexit_close(void)
{
if (current_server != NULL)
@@ -98,6 +255,7 @@ pkgopenserver_i(const char *root, const char *sadmdir, boolean_t readonly,
char *cmd[16];
int args;
char pkgdoor[PATH_MAX];
+ char realsadmdir[PATH_MAX];
extern char **environ;
char *prog;
char pidbuf[12];
@@ -119,6 +277,8 @@ pkgopenserver_i(const char *root, const char *sadmdir, boolean_t readonly,
}
(void) close(fd);
} else {
+ pkgfindrealsadmdir(realsadmdir, root, &sadmdir);
+ root = NULL;
pkgfilename(pkgdoor, root, sadmdir, PKGDOOR);
}