1
0
Files
irix-657m-src/eoe/cmd/swap/swap.c
2022-09-29 17:59:04 +03:00

860 lines
19 KiB
C

/* Copyright (c) 1984 AT&T */
/* All Rights Reserved */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
/* The copyright notice above does not evidence any */
/* actual or intended publication of such source code. */
#ident "$Revision: 1.28 $"
/* Swap administrative interface
* Used to add/delete/list swap devices in use by paging.
*/
#include <stdio.h>
#include <fcntl.h>
#include <mountinfo.h>
#include <limits.h>
#include <unistd.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/swap.h>
#include <sys/stat.h>
#include <sys/mkdev.h>
#include <ustat.h>
#include <getopt.h>
#include <diskinfo.h>
#include <mntent.h>
#include <sys/capability.h>
#define LFLAG 1
#define DFLAG 2
#define AFLAG 3
#define SFLAG 4
#define MFLAG 5
#define UFLAG 6
extern int list(int, int);
extern int olist(void);
extern int addall(void);
extern int delall(void);
extern void getmntdef(xswapres_t *xsr);
extern int getlist(swaptbl_t **stp, int *nsw);
extern void printsz(pgno_t sz, int fw, int inblocks);
extern int doswap(int inblocks);
extern int nopt(struct mntent *mnt, char *opt, __uint64_t *val);
extern void usage(void);
extern int add(xswapres_t *xsr, int lookedup, off_t swapfile_offset);
extern int sdelete(char *path, off_t offset);
int check_overlaps(char *, off_t);
int safe = 1; /* perform fs safety checks */
int Debug = 0;
char *mntfile = MNTTAB;
int pgsz;
int
main(int argc, char **argv)
{
off_t low;
int flag = 0, c, ret;
char *pathname;
xswapres_t xsr;
char *sptr;
int fulllist = 0;
int inblocks = 0;
int newlist = 0;
off_t swapfile_offset = -1;
if (argc < 2) {
usage();
exit(1);
}
pgsz = getpagesize();
xsr.sr_pri = -1;
xsr.sr_maxlength = -1;
xsr.sr_length = -1;
xsr.sr_vlength = -1;
xsr.sr_start = -1;
while ((c = getopt(argc, argv, "nbfM:Duimsldap:v:")) != EOF) {
switch(c) {
case 'n':
newlist = 1;
break;
case 'f':
fulllist = 1;
break;
case 'b':
inblocks = 1;
break;
case 'i':
safe = 0;
break;
case 'p':
xsr.sr_pri = (char)strtol(optarg, &sptr, 0);
if (sptr == optarg) {
fprintf(stderr, "swap:Invalid # for priority: %s\n",
optarg);
exit(1);
}
break;
case 'v':
xsr.sr_vlength = strtoll(optarg, &sptr, 0);
if (sptr == optarg) {
fprintf(stderr, "swap:Invalid # for vlength: %s\n",
optarg);
exit(1);
}
break;
case 'u': /* delete all in fstab */
if (flag) {
usage();
exit(1);
}
flag |= UFLAG;
break;
case 'm': /* add all in fstab */
if (flag) {
usage();
exit(1);
}
flag |= MFLAG;
break;
case 's':
if (flag) {
usage();
exit(1);
}
flag |= SFLAG;
break;
case 'l':
if (flag) {
usage();
exit(1);
}
flag |= LFLAG;
break;
case 'd':
if (getuid() != 0) {
fprintf(stderr, "Must be superuser to add or delete swap.\n");
exit(1);
}
if (flag) {
usage();
exit(1);
}
flag |= DFLAG;
break;
case 'a':
if (getuid() != 0) {
fprintf(stderr, "Must be superuser to add or delete swap.\n");
exit(1);
}
if (flag) {
usage();
exit(1);
}
flag |= AFLAG;
break;
case 'D':
Debug++;
break;
case 'M':
mntfile = optarg;
break;
}
}
if (flag == LFLAG) {
if ((argc - optind) != 0) {
usage();
exit(1);
}
if (newlist)
ret = list(fulllist, inblocks);
else
ret = olist();
} else if (flag == DFLAG) {
if ((argc - optind) == 1) {
pathname = argv[optind];
low = -1;
} else if ((argc - optind) == 2) {
pathname = argv[optind];
low = strtoll(argv[++optind], &sptr, 0);
if (sptr == argv[optind]) {
fprintf(stderr, "swap:Invalid # for start: %s\n",
argv[optind]);
exit(1);
}
} else {
usage();
exit(1);
}
ret = sdelete(pathname, low);
} else if (flag == AFLAG) {
if ((argc - optind) < 1) {
usage();
exit(1);
}
xsr.sr_name = argv[optind++];
if ((argc - optind) >= 1) {
xsr.sr_start = strtoll(argv[optind], &sptr, 0);
swapfile_offset = xsr.sr_start;
if (sptr == argv[optind]) {
fprintf(stderr, "swap:Invalid # for start: %s\n",
argv[optind]);
exit(1);
}
optind++;
}
if ((argc - optind) >= 1) {
xsr.sr_length = strtoll(argv[optind], &sptr, 0);
if (sptr == argv[optind]) {
fprintf(stderr, "swap:Invalid # for length: %s\n",
argv[optind]);
exit(1);
}
optind++;
}
if ((argc - optind) >= 1) {
usage();
exit(1);
}
ret = add(&xsr, 0, swapfile_offset);
} else if (flag == UFLAG) {
ret = delall();
} else if (flag == MFLAG) {
ret = addall();
} else if (flag == SFLAG) {
ret = doswap(inblocks);
} else {
usage();
exit(1);
}
exit(ret);
/* NOTREACHED */
}
void
usage(void)
{
printf("usage:\tswap -l[nfb]\n");
printf("\tswap -m\n");
printf("\tswap -u\n");
printf("\tswap -s[b]\n");
printf("\tswap -d <file name / lswap#> [<low block>]\n");
printf("\tswap -a [-i] [-p pri] [-v vlen] <file name> [<low block> [<nbr of blocks>]]\n");
}
int
list(int fulllist, int inblocks)
{
register int i;
int error, nswap;
swaptbl_t *st;
swapent_t *se;
mode_t type;
struct stat statbuf;
int maxlen = 0;
if (error = getlist(&st, &nswap))
return error;
else if (nswap == 0) {
printf("No swap devices configured\n");
return(0);
}
se = st->swt_ent;
for (i = 0; i < nswap; i++, se++) {
int l;
if ((l = strlen(se->ste_path)) > maxlen)
maxlen = l;
}
maxlen += 2;
if (fulllist)
printf(" # %-*s dev pri swaplo pswap free maxswap vswap\n",
maxlen, "path");
else
printf(" # %-*spri pswap free maxswap vswap\n",
maxlen, "path");
se = st->swt_ent;
for (i = 0; i < nswap; i++, se++) {
printf("%2d %-*s", se->ste_lswap, maxlen, se->ste_path);
if (fulllist) {
if (stat(se->ste_path, &statbuf) < 0)
printf(" ?,? ");
else {
type = (statbuf.st_mode & (S_IFBLK | S_IFCHR));
printf("%4d,%-5d",
type ? major(statbuf.st_rdev) : major(statbuf.st_dev),
type ? minor(statbuf.st_rdev) : minor(statbuf.st_dev));
}
}
printf(" %1d", se->ste_pri);
if (fulllist)
printf(" %6lld", (off64_t)se->ste_start);
printsz(se->ste_pages, 8, inblocks);
printsz(se->ste_free, 8, inblocks);
printsz(se->ste_maxpages, 8, inblocks);
printsz(se->ste_vpages, 8, inblocks);
if (se->ste_flags & ST_INDEL)
printf(" INDEL");
if (se->ste_flags & ST_STALE)
printf(" ESTALE");
if (se->ste_flags & ST_EACCES)
printf(" EACCES");
if (se->ste_flags & ST_IOERR)
printf(" IOERR");
printf("\n");
}
return 0;
}
/*
* For compatability reasons we must continue to ship a old stupid
* format for list.
* The -n flag causes a better one to be output..
*/
int
olist(void)
{
register int i;
int error, nswap;
swaptbl_t *st;
swapent_t *se;
mode_t type;
struct stat statbuf;
if (error = getlist(&st, &nswap))
return error;
else if (nswap == 0) {
printf("No swap devices configured\n");
return(0);
}
printf("lswap %-8s\t dev pri swaplo blocks free maxswap vswap\n", "path");
se = st->swt_ent;
for (i = 0; i < nswap; i++, se++) {
printf("%5d %s\n\t\t", se->ste_lswap, se->ste_path);
if (stat(se->ste_path, &statbuf) < 0)
printf(" ?,? ");
else {
type = (statbuf.st_mode & (S_IFBLK | S_IFCHR));
printf("%4d,%-5d",
type ? major(statbuf.st_rdev) : major(statbuf.st_dev),
type ? minor(statbuf.st_rdev) : minor(statbuf.st_dev));
}
printf(" %1d %6lld", se->ste_pri, (off64_t)se->ste_start);
printsz(se->ste_pages, 8, 1);
printsz(se->ste_free, 8, 1);
printsz(se->ste_maxpages, 8, 1);
printsz(se->ste_vpages, 8, 1);
if (se->ste_flags & ST_INDEL)
printf(" INDEL");
if (se->ste_flags & ST_STALE)
printf(" ESTALE");
if (se->ste_flags & ST_EACCES)
printf(" EACCES");
if (se->ste_flags & ST_IOERR)
printf(" IOERR");
printf("\n");
}
return 0;
}
int
getlist(swaptbl_t **stp, int *nsw)
{
char *path;
register int i;
int nswap;
swaptbl_t *st;
swapent_t *se;
if ((nswap = swapctl(SC_GETNSWP)) < 0) {
perror("swap:swapctl(SC_GETNSWAP)");
return(1);
} else if (nswap == 0) {
*nsw = 0;
return(0);
}
st = malloc(sizeof(*st) + ((nswap-1) * sizeof(swapent_t)));
st->swt_n = nswap;
path = malloc(nswap * PATH_MAX);
for (i = 0, se = st->swt_ent; i < nswap; i++, se++) {
se->ste_path = path;
path += PATH_MAX;
}
if ((nswap = swapctl(SC_LIST, st)) < 0) {
perror("swap:swapctl(SC_LIST)");
return(3);
}
*nsw = nswap;
*stp = st;
return 0;
}
/*
* Print swap stats - note that since we can allocate up to the SUM
* of phys mem and swap, that the amount reserved can exceed the
* size of swap ..
* We opt to print 'logical' swap - thus these figures include the amount
* of physical memory and virtual swap available
* Note that the 'reserved' amount is really reserved minus allocated
* since ALL blocks that are allocated have already been reserved.
*/
int
doswap(int inblocks)
{
auto off_t tot, free, resv, lmax;
off_t nalloc;
#define topg(a) \
((pgno_t) (((long long)(a) * 512) / pgsz))
swapctl(SC_GETSWAPTOT, &tot);
swapctl(SC_GETFREESWAP, &free);
swapctl(SC_GETRESVSWAP, &resv);
swapctl(SC_GETLSWAPTOT, &lmax);
nalloc = tot - free;
printf("total:");
printsz(topg(nalloc), 1, inblocks);
printf(" allocated +");
printsz(topg(resv - nalloc), 1, inblocks);
printf(" add'l reserved =");
printsz(topg(resv), 1, inblocks);
if (inblocks)
printf(" blocks used,");
else
printf(" bytes used,");
printsz(topg(lmax - resv), 1, inblocks);
if (inblocks)
printf(" blocks available\n");
else
printf(" bytes available\n");
return 0;
}
int
sdelete(char *path, off_t offset)
{
register swapres_t *si;
swapres_t swpi;
unsigned long lswap;
char *ptr;
cap_t ocap;
cap_value_t cap_swap_mgt = CAP_SWAP_MGT;
lswap = strtoul(path, &ptr, 0);
if (ptr != path) {
/* its a number - use it as a logical swap index */
ocap = cap_acquire(1, &cap_swap_mgt);
if (swapctl(SC_LREMOVE, lswap) < 0) {
cap_surrender(ocap);
fprintf(stderr, "swap:swap delete failed for logical swap # ");
perror(path);
return(3);
}
cap_surrender(ocap);
} else {
if (offset == -1)
offset = 0;
si = &swpi;
si->sr_name = path;
si->sr_start = offset;
ocap = cap_acquire(1, &cap_swap_mgt);
if (swapctl(SC_REMOVE, si) < 0) {
cap_surrender(ocap);
fprintf(stderr, "swap:swap delete failed for ");
perror(path);
return(3);
}
cap_surrender(ocap);
}
return(0);
}
int
add(xswapres_t *xsr, int lookedup, off_t swapfile_offset)
{
char *path = xsr->sr_name;
char npath[PATH_MAX];
cap_t ocap;
cap_value_t cap_swap_mgt = CAP_SWAP_MGT;
if (*path != '/') {
/* make into full path */
if (getcwd(npath, PATH_MAX) &&
((strlen(npath) + strlen(path) + 2) < PATH_MAX)) {
strcat(npath, "/");
strcat(npath, path);
path = npath;
xsr->sr_name = npath;
}
}
if (safe)
if (check_overlaps(path, swapfile_offset)) {
fprintf(stderr, "swap:swapadd ignored for %s\n",
path);
return 2;
}
if (Debug) {
printf("Would have added <%s>\n", xsr->sr_name);
return 0;
}
/* pick up any defaults from fstab */
if (!lookedup)
getmntdef(xsr);
/*
* provider any base level defaults for things not
* specified
*/
if (xsr->sr_maxlength == -1)
xsr->sr_maxlength = xsr->sr_length;
if (xsr->sr_vlength == -1)
xsr->sr_vlength = xsr->sr_maxlength;
if (xsr->sr_start == -1)
xsr->sr_start = 0;
ocap = cap_acquire(1, &cap_swap_mgt);
if (swapctl(SC_SGIADD, xsr) < 0) {
cap_surrender(ocap);
fprintf(stderr, "swap:swapadd failed for ");
perror(path);
return(3);
}
cap_surrender(ocap);
return(0);
}
/*
* Check for overlap with mounted fs
* Returns 1 if something overlaps or is mounted. This includes
* partitions reserved in /etc/fstab via 'ignore' entries to raw
* devices.
*/
int
check_overlaps(char *special, off_t swapfile_offset)
{
struct stat sbuf;
mnt_check_state_t *check_state;
int check_return;
if (stat(special, &sbuf) == -1)
return(0);
if (!S_ISBLK(sbuf.st_mode))
return(0);
/*
* if there's an offset skip the mount check, someone might
* actually want an fs on the device (miniroot).
*/
if (swapfile_offset > 0) {
return(0);
}
/* call libdisk to check for overlaps, reservations, etc. */
if (mnt_check_init(&check_state) == -1) {
fprintf(stderr, "swap: unable to init mount check routines, "
"skipping %s\n", special);
return(0);
}
check_return = mnt_find_mount_conflicts(check_state, special);
if (check_return > 0) {
if (mnt_causes_test(check_state, MNT_CAUSE_MOUNTED)) {
(void) fprintf(stderr, "swap: %s is already in use.\n",
special);
} else if (mnt_causes_test(check_state, MNT_CAUSE_OVERLAP)) {
(void) fprintf(stderr, "swap: %s overlaps a partition already in use.\n", special);
} else {
mnt_causes_show(check_state, stderr, "swap");
}
(void) fprintf(stderr, "\n");
(void) fflush(stderr);
mnt_plist_show(check_state, stderr, "swap");
(void) fprintf(stderr, "\n");
}
mnt_check_end(check_state);
if (check_return > 0)
return(1);
/* if -1 then we just ingore and let the devopen fail */
return(0);
}
/*
* addall - add all swap devices found in fstab
* Note that the libdisk uses the mnttab also - so we must
* save all info and collect them all before adding anything
*/
int
addall(void)
{
struct stat mnttab_stat;
off_t mnttab_size;
int count;
FILE *mnttab;
struct mntent *mntp;
xswapres_t *xsr = NULL;
xswapres_t *xsrp;
__uint64_t val;
int error, rv, i, nent = 0;
off_t swapfile_offset = -1;
mnttab = setmntent(mntfile, "r");
if (mnttab == NULL) {
(void) fprintf(stderr, "swap: ");
perror(mntfile);
exit(1);
}
if (fstat(fileno(mnttab), &mnttab_stat) == -1) {
(void) fprintf(stderr, "swap: ");
perror(mntfile);
exit(1);
}
mnttab_size = mnttab_stat.st_size;
for (count = 1; ; count++) {
if ((mntp = getmntent(mnttab)) == NULL) {
if (ftell(mnttab) >= mnttab_size)
break; /* it's EOF */
(void) fprintf(stderr,
"mount: %s: illegal entry on line %d\n",
mntfile, count);
continue;
}
if ((strcmp(mntp->mnt_type, MNTTYPE_SWAP) != 0) ||
hasmntopt(mntp, MNTOPT_NOAUTO) ||
(strcmp(mntp->mnt_fsname, "/dev/swap") == 0) ) {
continue;
}
nent++;
xsr = realloc(xsr, nent * sizeof(*xsr));
xsrp = xsr + (nent - 1);
xsrp->sr_name = strdup(mntp->mnt_fsname);
xsrp->sr_pri = -1;
xsrp->sr_maxlength = -1;
xsrp->sr_length = -1;
xsrp->sr_vlength = -1;
xsrp->sr_start = -1;
error = 0;
if ((rv = nopt(mntp, MNTOPT_SWPLO, &val)) > 0)
xsrp->sr_start = swapfile_offset = val;
else if (rv < 0)
error++;
if ((rv = nopt(mntp, MNTOPT_LENGTH, &val)) > 0)
xsrp->sr_length = val;
else if (rv < 0)
error++;
if ((rv = nopt(mntp, MNTOPT_MAXLENGTH, &val)) > 0)
xsrp->sr_maxlength = val;
else if (rv < 0)
error++;
if ((rv = nopt(mntp, MNTOPT_VLENGTH, &val)) > 0)
xsrp->sr_vlength = val;
else if (rv < 0)
error++;
if ((rv = nopt(mntp, MNTOPT_PRI, &val)) > 0)
xsrp->sr_pri = val;
else if (rv < 0)
error++;
if (error) {
fprintf(stderr, "swap: <%s> ignored due to errors.\n",
xsrp->sr_name);
nent--;
}
}
(void) endmntent(mnttab);
rv = 0;
for (i = 0; i < nent; i++)
rv += add(xsr + i, 1, swapfile_offset);
return rv;
}
int
delall(void)
{
register int i;
int error, nswap;
swaptbl_t *st;
swapent_t *se;
int rv = 0;
cap_t ocap;
cap_value_t cap_swap_mgt = CAP_SWAP_MGT;
if (error = getlist(&st, &nswap))
return error;
else if (nswap == 0)
return(0);
se = st->swt_ent;
for (i = 0; i < nswap; i++, se++) {
if (se->ste_flags & (ST_INDEL|ST_BOOTSWAP|ST_NOTREADY))
continue;
ocap = cap_acquire(1, &cap_swap_mgt);
if (error = swapctl(SC_LREMOVE, se->ste_lswap)) {
fprintf(stderr, "swap: remove of logical swap %d failed:",
se->ste_lswap);
perror("");
rv++;
}
cap_surrender(ocap);
}
return rv;
}
void
getmntdef(xswapres_t *xsr)
{
struct stat mnttab_stat;
off_t mnttab_size;
int count;
FILE *mnttab;
struct mntent *mntp;
__uint64_t val;
int rv, error;
mnttab = setmntent(mntfile, "r");
if (mnttab == NULL) {
(void) fprintf(stderr, "swap: ");
perror(mntfile);
exit(1);
}
if (fstat(fileno(mnttab), &mnttab_stat) == -1) {
(void) fprintf(stderr, "swap: ");
perror(mntfile);
exit(1);
}
mnttab_size = mnttab_stat.st_size;
for (count = 1; ; count++) {
if ((mntp = getmntent(mnttab)) == NULL) {
if (ftell(mnttab) >= mnttab_size)
break; /* it's EOF */
(void) fprintf(stderr,
"swap: %s: illegal entry on entry %d\n",
mntfile, count);
continue;
}
if ((strcmp(mntp->mnt_type, MNTTYPE_SWAP) != 0) ||
(strcmp(mntp->mnt_fsname, xsr->sr_name) != 0)) {
continue;
}
error = 0;
if (xsr->sr_start == -1) {
if ((rv = nopt(mntp, MNTOPT_SWPLO, &val)) > 0)
xsr->sr_start = val;
else if (rv < 0)
error++;
}
if (xsr->sr_length == -1) {
if ((rv = nopt(mntp, MNTOPT_LENGTH, &val)) > 0)
xsr->sr_length = val;
else if (rv < 0)
error++;
}
if (xsr->sr_maxlength == -1) {
if ((rv = nopt(mntp, MNTOPT_MAXLENGTH, &val)) > 0)
xsr->sr_maxlength = val;
else if (rv < 0)
error++;
}
if (xsr->sr_vlength == -1) {
if ((rv = nopt(mntp, MNTOPT_VLENGTH, &val)) > 0)
xsr->sr_vlength = val;
else if (rv < 0)
error++;
}
if (xsr->sr_pri == -1) {
if ((rv = nopt(mntp, MNTOPT_PRI, &val)) > 0)
xsr->sr_pri = val;
else if (rv < 0)
error++;
}
if (error) {
fprintf(stderr, "swap: <%s> ignored due to errors.\n",
xsr->sr_name);
exit(1);
}
break;
}
(void) endmntent(mnttab);
return;
}
/*
* Return the value of a numeric option of the form foo=x, if
* If the option is found and is valid, return 1;
* if no option is found return 0.
* If an invalid setting is found, return -1
*/
int
nopt(struct mntent *mnt, char *opt, __uint64_t *val)
{
char *str;
char *equal;
str = hasmntopt(mnt, opt);
if (str == NULL)
return (0);
equal = str + strlen(opt);
if (*equal != '=') {
(void) fprintf(stderr,
"swap: <%s> missing value for option '%s'\n",
mnt->mnt_fsname, str);
return (-1);
}
if (sscanf(equal + 1, "%llu", val) != 1) {
(void) fprintf(stderr,
"swap: <%s> illegal value for option '%s'\n",
mnt->mnt_fsname, str);
return (-1);
}
return (1);
}
void
printsz(pgno_t sz, int fw, int inblocks)
{
off_t csz;
float fsz;
char suff;
if (inblocks) {
csz = sz * (pgsz / 512);
printf(" %*lld", fw, csz);
} else {
if (sz < (1024*1024 / pgsz)) {
suff = 'k';
fsz = (float)sz * pgsz / (1024.);
} else if (sz < (1024 * 1024 * 1024) / pgsz) {
suff = 'm';
fsz = (float)sz * pgsz / (1024. * 1024.);
} else {
suff = 'g';
fsz = (float)sz * pgsz / (1024. * 1024. * 1024.);
}
printf(" %*.2f%c", fw - 1, fsz, suff);
}
}