code to find sysctl names needed to extract per dataset fs statistics
use as ./prog tank/var
(large) parts of the code taken of /usr/src/sbin/sysctl/sysctl.c
use as ./prog tank/var
(large) parts of the code taken of /usr/src/sbin/sysctl/sysctl.c
C:
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <err.h>
#include <errno.h>
#include <sys/sysctl.h>
#include <string.h>
/*
oid = binary oid of kstat.zfs.<poolname>
len = sizeof oid
dataset = dataset name eg tank/var
szbuf = sizeof receiving buffer
buf = buffer to copy resulting string eg kstat.zfs.ntank.dataset.objset-0x46
*/
int find_dataset_sstr(int *oid, int len,char *dataset,size_t szbuf,char *buf)
{
int name1[22], name2[22];
int i, j, si;
size_t l1, l2, sj;
int qoid[24];
char name[256];
name1[0] = 0;
name1[1] = 2;
l1 = 2;
if (len) {
memcpy(name1+2, oid, len * sizeof(int));
l1 += len;
} else {
name1[2] = 1;
l1++;
}
for (;;) {
l2 = sizeof(name2);
j = sysctl(name1, l1, name2, &l2, 0, 0);
if (j < 0) {
if (errno == ENOENT)
return (0);
else
err(1, "sysctl(getnext) %d %zu", j, l2);
}
l2 /= sizeof(int);
if (len < 0 || l2 < (unsigned int)len)
return (0);
for (i = 0; i < len; i++)
if (name2[i] != oid[i])
return (0);
bzero(name, sizeof(name));
qoid[0] = 0;
memcpy(qoid + 2, name2, l2 * sizeof(int));
qoid[1] = 1;
sj = sizeof(name);
si = sysctl(qoid, l2 + 2, name, &sj, 0, 0);
if (si || !sj)
err(1, "sysctl name %d %zu %d", si, sj, errno);
if(strstr(name,"dataset_name")) {
sj = szbuf;
si = sysctl(name2,l2,(void *)buf,&sj,0,0);
if (si || !szbuf)
err(1, "sysctl name %d %zu %d", si, szbuf, errno);
if(!strcmp(dataset,buf)) {
strcpy(buf,name);
char *pp = strrchr(buf,'.');
*pp = 0;
return 1;
}
}
// i = show_var(name2, l2);
memcpy(name1+2, name2, l2 * sizeof(int));
l1 = 2 + l2;
}
return 0;
}
int main(int argc,char **argv)
{
int error,found;
char *pool, *dataset;
char oid_str[256];
int mib[24];
size_t sizep;;
if(argc !=2 ) {
errx(1,"usage %s dataset",argv[0]);
}
dataset = strchr(argv[1],'/');
if(!dataset) {
errx(1,"%s is not in correct format pool/dataset",argv[1]);
}
*dataset = '\0';
pool = argv[1];
sprintf(oid_str,"kstat.zfs.%s",pool);
error = sysctlnametomib(oid_str, mib, &sizep);
//printf("%s %d %zu\n",oid_str,error,sizep);
if(error == -1) {
errx(1,"sysctlnametomib %s invalid",oid_str);
}
*dataset = '/';
found = find_dataset_sstr(mib,sizep,argv[1],256,oid_str);
if(found) {
printf("FOUND %s\n",oid_str);
}
}