From: guy@Auspex.COM (Guy Harris)
Newsgroups: comp.unix.solaris,comp.sys.sun.misc,comp.unix.programmer
Subject: Re: swapctl() problems
Keywords: swap swapctl
Date: 16 Sep 92 00:29:06 GMT
Followup-To: comp.unix.solaris
Organization: Auspex Systems, Santa Clara

> 	The specific problem is that function seems to want you to
> define a struct which has as one of its members an array of structs. 
> However, the struct declaration in /usr/include/swap.h declares that
> array to be of length 1.  This causes no end of problems which I can't
> seem to get around.

A fairly standard C-language trick; take a look at the SV message queue
stuff, for example.

Standard C doesn't support the notion of variable-length arrays, so you
can't declare a structure that contains such an array, which is what the
structure filled in by the SC_LIST call *really* is.  So, instead, such
a structure is declared with a fixed-length array, and you have to
depend on compile-time array-bounds checking not being done; you also
have to create such a structure yourself, e.g. by dynamically
allocating it.

Furthermore, standard C doesn't support zero-element arrays, so a data
structure with a variable-length array as the last element is often
declared as having a one-element array.

Assuming that there's one entry in "swt_ent" for every swap resource,
you can use SC_GETNSWP to find out how many entries there are:

	int n_swap_entries;

	n_swap_entries - swapctl(SC_GETNSWP, NULL);
	if (n_swap_entries == -1)
		complain and quit;
	if (n_swap_entries == 0)
		note that there are, miraculously, no swap entries, and quit;

Then allocate a table to hold that many entries:

	swaptbl_t *swaptbl;

	swaptbl = (swaptbl_t *)malloc(
	    sizeof (swaptbl_t) + (n_swap_entries - 1)*sizeof (struct swapent));

It's "n_swap_entries - 1" because the first entry is accounted for by
"sizeof (swaptbl_t)".

Then put the number of elements into the structure:

	swaptbl->swt_n = n_swap_entries;

Then fetch the entries:

	n_swap_entries = swapctl(SC_LIST, (void *)swaptbl);
	if (n_swap_entries == -1) {
		if (errno == ENOMEM)
			try again, with a bigger array;
		else
			complain and quit;
	}

and loop through them.

NOTE: "complain" in "complain and quit" doesn't mean "print some typical
dumb UNIX error message saying that the call failed", it means "print
some atypical *useful* error message that prints the error string
associated with 'errno' - using 'perror()' or 'strerror()' - so that if
it fails you have a clue as to why".  (It doesn't mean "print some
typical only-marginally-less-dumb UNIX error message giving the
numerical value of 'errno'", either; computers are at *least* as good as
humans at translating cryptic numeric values such as that into error
messages.)

"Try again, with a bigger array" deals with the case where a new entry
was added to the table between the two "swapctl()" calls.

If SC_GETNSWP *doesn't* return the number of entries you should expect
to get back from SC_LIST (although, if not, I've no idea why the hell
SC_GETNSWP exists), you'll have to go through some more pain, starting
at some fixed table size and, for example, doubling it each time the
SC_LIST call fails with ENOMEM.  Hopefully, that's not the case....

(No, I don't have a SunOS 5.0 system with a C compiler handy on which to
try the above, so you'll have to do it yourself.)
Xref: sparky comp.unix.solaris:214 gnu.gcc.help:2121