diff options
Diffstat (limited to 'usr/src/cmd/svr4pkg/pkginstall/dockspace.c')
| -rw-r--r-- | usr/src/cmd/svr4pkg/pkginstall/dockspace.c | 405 |
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); +} |
