summaryrefslogtreecommitdiff
path: root/usr/src/cmd/svr4pkg/pkginstall/dockspace.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/svr4pkg/pkginstall/dockspace.c')
-rw-r--r--usr/src/cmd/svr4pkg/pkginstall/dockspace.c405
1 files changed, 405 insertions, 0 deletions
diff --git a/usr/src/cmd/svr4pkg/pkginstall/dockspace.c b/usr/src/cmd/svr4pkg/pkginstall/dockspace.c
new file mode 100644
index 0000000000..e306e0dbef
--- /dev/null
+++ b/usr/src/cmd/svr4pkg/pkginstall/dockspace.c
@@ -0,0 +1,405 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <limits.h>
+#include <locale.h>
+#include <libintl.h>
+#include <pkgstrct.h>
+#include "install.h"
+#include <pkglib.h>
+#include "libadm.h"
+#include "libinst.h"
+#include "pkginstall.h"
+
+extern struct cfextra **extlist;
+extern char pkgloc[];
+extern char instdir[];
+
+#define LSIZE 256
+#define LIM_BFREE 150LL
+#define LIM_FFREE 25LL
+
+#define WRN_STATVFS "WARNING: unable to stat filesystem mounted on <%s>"
+
+#define WRN_NOBLKS "The %s filesystem has %llu free blocks. The current " \
+ "installation requires %llu blocks, which includes a " \
+ "required %llu block buffer for open " \
+ "deleted files. %llu more blocks are needed."
+
+#define WRN_NOFILES "The %s filesystem has %llu free file nodes. The " \
+ "current installation requires %llu file nodes, " \
+ "which includes a required %llu file node buffer " \
+ "for temporary files. %llu more file nodes " \
+ "are needed."
+
+#define TYPE_BLCK 0
+#define TYPE_NODE 1
+static void warn(int type, char *name, fsblkcnt_t need, fsblkcnt_t avail,
+ fsblkcnt_t limit);
+static int fsys_stat(int n);
+static int readmap(int *error);
+static int readspace(char *spacefile, int *error);
+
+int
+dockspace(char *spacefile)
+{
+ struct fstable *fs_tab;
+ int i, error;
+
+ error = 0;
+
+ /*
+ * Also, vanilla SVr4 code used the output from popen()
+ * on the "/etc/mount" command. However, we need to get more
+ * information about mounted filesystems, so we use the C
+ * interfaces to the mount table, which also happens to be
+ * much faster than running another process. Since several
+ * of the pkg commands need access to the mount table, this
+ * code is now in libinst. However, mount table info is needed
+ * at the time the base directory is determined, so the call
+ * to get the mount table information is in main.c
+ */
+
+ if (readmap(&error) || readspace(spacefile, &error))
+ return (-1);
+
+ for (i = 0; fs_tab = get_fs_entry(i); ++i) {
+ if ((!fs_tab->fused) && (!fs_tab->bused))
+ continue; /* not used by us */
+
+ if (fs_tab->bfree < (LIM_BFREE + fs_tab->bused)) {
+ warn(TYPE_BLCK, fs_tab->name, fs_tab->bused,
+ fs_tab->bfree, LIM_BFREE);
+ error++;
+ }
+
+ /* bug id 1091292 */
+ if ((long)fs_tab->ffree == -1L)
+ continue;
+ if (fs_tab->ffree < (LIM_FFREE + fs_tab->fused)) {
+ warn(TYPE_NODE, fs_tab->name, fs_tab->fused,
+ fs_tab->ffree, LIM_FFREE);
+ error++;
+ }
+ }
+ return (error);
+}
+
+static void
+warn(int type, char *name, fsblkcnt_t need, fsblkcnt_t avail, fsblkcnt_t limit)
+{
+ logerr(gettext("WARNING:"));
+ if (type == TYPE_BLCK) {
+ logerr(gettext(WRN_NOBLKS), name, avail, (need + limit), limit,
+ (need + limit - avail));
+ } else {
+ logerr(gettext(WRN_NOFILES), name, avail, (need + limit), limit,
+ (need + limit - avail));
+ }
+}
+
+static int
+fsys_stat(int n)
+{
+ struct statvfs64 svfsb;
+ struct fstable *fs_tab;
+
+ if (n == BADFSYS)
+ return (1);
+
+ fs_tab = get_fs_entry(n);
+
+ /*
+ * At this point, we know we need information
+ * about a particular filesystem, so we can do the
+ * statvfs() now. For performance reasons, we only want to
+ * stat the filesystem once, at the first time we need to,
+ * and so we can key on whether or not we have the
+ * block size for that filesystem.
+ */
+ if (fs_tab->bsize != 0)
+ return (0);
+
+ if (statvfs64(fs_tab->name, &svfsb)) {
+ logerr(gettext(WRN_STATVFS), fs_tab->name);
+ return (1);
+ }
+
+ /*
+ * statvfs returns number of fragment size blocks
+ * so will change this to number of 512 byte blocks
+ */
+ fs_tab->bsize = svfsb.f_bsize;
+ fs_tab->frsize = svfsb.f_frsize;
+ fs_tab->bfree = ((svfsb.f_frsize > 0) ?
+ howmany(svfsb.f_frsize, DEV_BSIZE) :
+ howmany(svfsb.f_bsize, DEV_BSIZE)) * svfsb.f_bavail;
+ fs_tab->ffree = (svfsb.f_favail > 0) ? svfsb.f_favail : svfsb.f_ffree;
+ return (0);
+}
+
+/*
+ * This function reads all of the package objects, maps them to their target
+ * filesystems and adds up the amount of space used on each. Wherever you see
+ * "fsys_value", that's the apparent filesystem which could be a temporary
+ * loopback mount for the purpose of constructing the client filesystem. It
+ * isn't necessarily the real target filesystem. Where you see "fsys_base"
+ * that's the real filesystem to which fsys_value may just refer. If this is
+ * installing to a standalone or a server, fsys_value will almost always be
+ * the same as fsys_base.
+ */
+static int
+readmap(int *error)
+{
+ struct fstable *fs_tab;
+ struct cfextra *ext;
+ struct cfent *ept;
+ struct stat statbuf;
+ char tpath[PATH_MAX];
+ fsblkcnt_t blk;
+ int i, n;
+
+ /*
+ * Handle the installation files (ftype i) that are in the
+ * pkgmap/eptlist.
+ */
+ for (i = 0; (ext = extlist[i]) != NULL; i++) {
+ ept = &(ext->cf_ent);
+
+ if (ept->ftype != 'i')
+ continue;
+
+ /*
+ * These paths are treated differently from the others
+ * since their full pathnames are not included in the
+ * pkgmap.
+ */
+ if (strcmp(ept->path, "pkginfo") == 0)
+ (void) sprintf(tpath, "%s/%s", pkgloc, ept->path);
+ else
+ (void) sprintf(tpath, "%s/install/%s", pkgloc,
+ ept->path);
+
+ /* If we haven't done an fsys() series, do one */
+ if (ext->fsys_value == BADFSYS)
+ ext->fsys_value = fsys(tpath);
+
+ /*
+ * Now check if this is a base or apparent filesystem. If
+ * it's just apparent, get the resolved filesystem entry,
+ * otherwise, base and value are the same.
+ */
+ if (use_srvr_map_n(ext->fsys_value))
+ ext->fsys_base = resolved_fsys(tpath);
+ else
+ ext->fsys_base = ext->fsys_value;
+
+ if (fsys_stat(ext->fsys_base)) {
+ (*error)++;
+ continue;
+ }
+
+ /*
+ * Don't accumulate space requirements on read-only
+ * remote filesystems.
+ */
+ if (is_remote_fs_n(ext->fsys_value) &&
+ !is_fs_writeable_n(ext->fsys_value))
+ continue;
+
+ fs_tab = get_fs_entry(ext->fsys_base);
+
+ fs_tab->fused++;
+ if (ept->cinfo.size != BADCONT)
+ blk = nblk(ept->cinfo.size,
+ fs_tab->bsize,
+ fs_tab->frsize);
+ else
+ blk = 0;
+ fs_tab->bused += blk;
+ }
+
+ /*
+ * Handle the other files in the eptlist.
+ */
+ for (i = 0; (ext = extlist[i]) != NULL; i++) {
+ ept = &(extlist[i]->cf_ent);
+
+ if (ept->ftype == 'i')
+ continue;
+
+ /*
+ * Don't recalculate package objects that are already in the
+ * table.
+ */
+ if (ext->mstat.preloaded)
+ continue;
+
+ /*
+ * Don't accumulate space requirements on read-only
+ * remote filesystems.
+ */
+ if (is_remote_fs(ept->path, &(ext->fsys_value)) &&
+ !is_fs_writeable(ept->path, &(ext->fsys_value)))
+ continue;
+
+ /*
+ * Now check if this is a base or apparent filesystem. If
+ * it's just apparent, get the resolved filesystem entry,
+ * otherwise, base and value are the same.
+ */
+ if (use_srvr_map_n(ext->fsys_value))
+ ext->fsys_base = resolved_fsys(tpath);
+ else
+ ext->fsys_base = ext->fsys_value;
+
+ /* At this point we know we have a good fsys_base. */
+ if (fsys_stat(ext->fsys_base)) {
+ (*error)++;
+ continue;
+ }
+
+ /*
+ * We have to stat this path based upon it's real location.
+ * If this is a server-remap, ept->path isn't the real
+ * location.
+ */
+ if (use_srvr_map_n(ext->fsys_value))
+ strcpy(tpath, server_map(ept->path, ext->fsys_value));
+ else
+ strcpy(tpath, ept->path);
+
+ fs_tab = get_fs_entry(ext->fsys_base);
+ if (stat(tpath, &statbuf)) {
+ /* path cannot be accessed */
+ fs_tab->fused++;
+ if (strchr("dxs", ept->ftype))
+ blk =
+ nblk(fs_tab->bsize,
+ fs_tab->bsize,
+ fs_tab->frsize);
+ else if (ept->cinfo.size != BADCONT)
+ blk = nblk(ept->cinfo.size,
+ fs_tab->bsize,
+ fs_tab->frsize);
+ else
+ blk = 0;
+ } else {
+ /* path already exists */
+ if (strchr("dxs", ept->ftype))
+ blk = 0;
+ else if (ept->cinfo.size != BADCONT) {
+ fsblkcnt_t new_size, old_size;
+ new_size = nblk(ept->cinfo.size,
+ fs_tab->bsize,
+ fs_tab->frsize);
+ old_size = nblk(statbuf.st_size,
+ fs_tab->bsize,
+ fs_tab->frsize);
+ /*
+ * negative blocks show room freed, but since
+ * order of installation is uncertain show
+ * 0 blocks usage
+ */
+ if (new_size < old_size)
+ blk = 0;
+ else
+ blk = new_size - old_size;
+ } else
+ blk = 0;
+ }
+ fs_tab->bused += blk;
+ }
+ return (0);
+}
+
+static int
+readspace(char *spacefile, int *error)
+{
+ FILE *fp;
+ char line[LSIZE];
+ long blocks, nodes;
+ int n;
+
+ if (spacefile == NULL)
+ return (0);
+
+ if ((fp = fopen(spacefile, "r")) == NULL) {
+ progerr(gettext("unable to open spacefile %s"), spacefile);
+ return (-1);
+ }
+
+ while (fgets(line, LSIZE, fp)) {
+ struct fstable *fs_tab;
+ char *pt, path[PATH_MAX];
+
+ blocks = nodes = 0;
+ for (pt = line; isspace(*pt); /* void */)
+ pt++;
+ if (*pt == '#' || *pt == '\0')
+ continue;
+
+ (void) sscanf(line, "%s %ld %ld", path, &blocks, &nodes);
+ mappath(2, path);
+ basepath(path, get_basedir(), get_inst_root());
+ canonize(path);
+
+ n = resolved_fsys(path);
+ if (fsys_stat(n)) {
+ (*error)++;
+ continue;
+ }
+
+ /*
+ * Don't accumulate space requirements on read-only
+ * remote filesystems. NOTE: For some reason, this
+ * used to check for !remote && read only. If this
+ * blows up later, then maybe that was correct -- JST
+ */
+ if (is_remote_fs_n(n) && !is_fs_writeable_n(n))
+ continue;
+
+ fs_tab = get_fs_entry(n);
+
+ fs_tab->bused += blocks;
+ fs_tab->fused += nodes;
+ }
+ (void) fclose(fp);
+ return (0);
+}