#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;
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;
if (fs_tab->bfree < (LIM_BFREE + fs_tab->bused)) {
warn(TYPE_BLCK, fs_tab->name, fs_tab->bused,
fs_tab->bfree, LIM_BFREE);
error++;
}
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);
if (fs_tab->bsize != 0)
return (0);
if (statvfs64(fs_tab->name, &svfsb)) {
logerr(gettext(WRN_STATVFS), fs_tab->name);
return (1);
}
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);
}
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;
for (i = 0; (ext = extlist[i]) != NULL; i++) {
ept = &(ext->cf_ent);
if (ept->ftype != 'i')
continue;
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 (ext->fsys_value == BADFSYS)
ext->fsys_value = fsys(tpath);
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;
}
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;
}
for (i = 0; (ext = extlist[i]) != NULL; i++) {
ept = &(extlist[i]->cf_ent);
if (ept->ftype == 'i')
continue;
if (ext->mstat.preloaded)
continue;
if (is_remote_fs(ept->path, &(ext->fsys_value)) &&
!is_fs_writeable(ept->path, &(ext->fsys_value)))
continue;
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;
}
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)) {
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 {
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);
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); )
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;
}
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);
}