1
0
This repository has been archived on 2024-07-22. You can view files and clone it, but cannot push or open issues or pull requests.
TP-Link_Archer-XR500v/EN7526G_3.18Kernel_SDK/apps/public/tools/sysstat-9.0.4/ioconf.c
2024-07-22 01:58:46 -03:00

504 lines
12 KiB
C
Executable File

/*
* ioconf: ioconf configuration file handling code
* Original code (C) 2004 by Red Hat (Charlie Bennett <ccb@redhat.com>)
*
* Modified and maintained by Sebastien GODARD (sysstat <at> orange.fr)
*
***************************************************************************
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation; either version 2 of the License, or (at your *
* option) any later version. *
* *
* This program is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without the implied warranty of MERCHANTABILITY *
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
* for more details. *
* *
* You should have received a copy of the GNU General Public License along *
* with this program; if not, write to the Free Software Foundation, Inc., *
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
***************************************************************************
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <dirent.h>
#include <sys/stat.h>
#include "ioconf.h"
#include "common.h"
#ifdef USE_NLS
#include <locale.h>
#include <libintl.h>
#define _(string) gettext(string)
#else
#define _(string) (string)
#endif
static unsigned int ioc_parsed = 0;
static struct ioc_entry *ioconf[MAX_BLKDEV + 1];
/*
***************************************************************************
* Free ioc_entry structures
***************************************************************************
*/
static void ioc_free(void)
{
unsigned int i;
struct ioc_entry **p;
/* Take out all of the references first */
for (i = 0, p = ioconf; i < MAX_BLKDEV; ++i, ++p) {
if ((*p == NULL) || ((*p)->live))
continue;
if ((*p)->desc != (*p)->blkp->desc) {
/* Not a shared description */
free((*p)->desc);
}
free(*p);
*p = NULL;
}
/* Now the live ones */
for (i = 0, p = ioconf; i < MAX_BLKDEV; ++i, ++p) {
if (*p == NULL)
continue;
free((*p)->blkp);
free(*p);
*p = NULL;
}
}
/*
***************************************************************************
* ioc_conv - Turn a number into a string in radix <radix> using symbol
* set (and ordering) syms. Use nozero to generate strings
* in which the number system uses a single sym for the
* radix value (not 2, like decimal) and adds a column only
* at radix+1. If decimal were like this:
*
* (no zero) 1 2 3 4 5 6 7 8 9 0 11 12 13 14 15 16 17 18 19 10 ...
***************************************************************************
*/
static char *ioc_conv(int radix, int nozero, const char *syms,
unsigned int val)
{
static char out[17];
char *p;
int j;
*(p = out + 16) = '\0';
val += nozero;
if (val == 0) {
if (!nozero) {
*--p = '0';
}
return (p); /* Empty string if nozero radix gets val == 0 */
}
while (val > 0) {
*--p = syms[j = val % radix];
val /= radix;
if (nozero && (j == 0)) {
/* Comp for 10 in nozero bases */
--val;
}
}
return (p);
}
char *ioc_ito10(unsigned int n)
{
return (ioc_conv(10, 0, "0123456789", n));
}
char *ioc_ito26(unsigned int n)
{
return (ioc_conv(26, 1, "zabcdefghijklmnopqrstuvwxy", n));
}
/*
***************************************************************************
* ioc_init() - internalize the ioconf file
*
* given: void
* does: parses IOCONF into ioconf, an array of ioc_entry *
* Only entries having lines in IOCONF will have valid pointers
* return: 1 on success
* 0 on failure
***************************************************************************
*/
int ioc_init(void)
{
FILE *fp;
unsigned int i, major, indirect, count = 0;
char buf[IOC_LINESIZ + 1];
char cfmt[IOC_FMTLEN + 1];
char dfmt[IOC_FMTLEN + 1];
char pfmt[IOC_FMTLEN + 1];
char desc[IOC_DESCLEN + 1];
struct ioc_entry *iocp = NULL;
struct blk_config *blkp = NULL;
char ioconf_name[64];
if ((fp = fopen(IOCONF, "r")) == NULL) {
if ((fp = fopen(LOCAL_IOCONF, "r")) == NULL)
return 0;
strncpy(ioconf_name, LOCAL_IOCONF, 64);
}
else {
strncpy(ioconf_name, IOCONF, 64);
}
ioconf_name[63] = '\0';
while (fgets(buf, IOC_LINESIZ, fp)) {
if ((*buf == '#') || (*buf == '\n'))
continue;
/*
* Preallocate some (probably) needed data structures
*/
IOC_ALLOC(blkp, struct blk_config, BLK_CONFIG_SIZE);
IOC_ALLOC(iocp, struct ioc_entry, IOC_ENTRY_SIZE);
memset(blkp, 0, BLK_CONFIG_SIZE);
memset(iocp, 0, IOC_ENTRY_SIZE);
i = sscanf(buf, "%u:%u:%u:%s",
&major, &indirect, &iocp->ctrlno, desc);
if (i != 4) {
i = sscanf(buf, "%u:%u:%u",
&major, &indirect, &iocp->ctrlno);
}
if ((i == 3) || (i == 4)) {
/* indirect record */
if (indirect == 0) {
/* conventional usage for unsupported device */
continue;
}
if (indirect >= MAX_BLKDEV) {
fprintf(stderr, "%s: Indirect major #%u out of range\n",
ioconf_name, indirect);
continue;
}
if (ioconf[indirect] == NULL) {
fprintf(stderr,
"%s: Indirect record '%u:%u:%u:...'"
" references not yet seen major %u\n",
ioconf_name, major, indirect, iocp->ctrlno, major);
continue;
}
/*
* Cool. Point this device at its referent.
* Skip last: (last field my be empty...)
* if it was empty and : was in the sscanf spec
* we'd only see 3 fields...
*/
if (i == 3) {
/* reference the mothership */
iocp->desc = ioconf[indirect]->blkp->desc;
}
else {
IOC_ALLOC(iocp->desc, char, IOC_DESCLEN + 1);
strncpy(iocp->desc, desc, IOC_DESCLEN);
}
ioconf[major] = iocp;
iocp->blkp = ioconf[indirect]->blkp;
iocp->live = 0;
iocp = NULL;
continue;
/* all done with indirect record */
}
/* maybe it's a full record? */
i = sscanf(buf, "%u:%[^:]:%[^:]:%d:%[^:]:%u:%[^:]:%u:%s",
&major, blkp->name,
cfmt, &iocp->ctrlno,
dfmt, &blkp->dcount,
pfmt, &blkp->pcount,
desc);
if (i != 9) {
fprintf(stderr, "%s: Malformed %d field record: %s\n",
ioconf_name, i, buf);
continue;
}
/* this is a full-fledged direct record */
if ((major == 0) || (major >= MAX_BLKDEV)) {
fprintf(stderr, "%s: major #%u out of range\n",
__FUNCTION__, major);
continue;
}
/* is this an exception record? */
if (*cfmt == 'x') {
struct blk_config *xblkp;
/*
* device has an aliased minor
* for now we only support on exception per major
* (catering to initrd: (1,250))
*/
if (ioconf[major] == NULL) {
fprintf(stderr, "%s: type 'x' record for"
" major #%u must follow the base record - ignored\n",
ioconf_name, major);
continue;
}
xblkp = ioconf[major]->blkp;
if (xblkp->ext) {
/*
* Enforce one minor exception per major policy
* note: this applies to each major number and
* all of it's indirect (short form) majors
*/
fprintf(stderr, "%s: duplicate 'x' record for"
" major #%u - ignored\ninput line: %s\n",
ioconf_name, major, buf);
continue;
}
/*
* Decorate the base major struct with the
* exception info
*/
xblkp->ext_minor = iocp->ctrlno;
strcpy(xblkp->ext_name, blkp->name);
xblkp->ext = 1;
continue;
}
/*
* Preformat the sprintf format strings for generating
* c-d-p info in ioc_name()
*/
/* basename of device + provided string + controller # */
if (*cfmt == '*') {
strcpy(blkp->cfmt, blkp->name);
}
else {
sprintf(blkp->cfmt, "%s%s%%d", blkp->name, cfmt);
++(blkp->ctrl_explicit);
}
/* Disk */
*blkp->dfmt = '\0';
switch (*dfmt) {
case 'a':
blkp->cconv = ioc_ito26;
strcpy(blkp->dfmt, "%s");
break;
case '%':
strcpy(blkp->dfmt, dfmt + 1);
case 'd':
blkp->cconv = ioc_ito10;
strcat(blkp->dfmt, "%s");
break;
}
/* Partition */
sprintf(blkp->pfmt, "%s%%d", (*pfmt == '*') ? "" : pfmt);
/*
* We're good to go.
* Stuff the ioc_entry and ref it.
*/
iocp->live = 1;
iocp->blkp = blkp;
iocp->desc = NULL;
ioconf[major] = iocp;
strncpy(blkp->desc, desc, IOC_DESCLEN);
blkp = NULL; iocp = NULL;
++count;
}
fclose(fp);
/*
* These will become leaks if we ever 'continue'
* after IOC_ALLOC( blkp->desc ... ).
* Right Now, we don't.
*/
if (blkp != NULL)
free(blkp);
if (iocp != NULL)
free(iocp);
/* Indicate that ioconf file has been parsed */
ioc_parsed = 1;
return (count);
}
/*
***************************************************************************
* ioc_name() - Generate a name from a maj,min pair
*
* IN:
* @major Device major number.
* @minor Device minor number.
*
* RETURNS:
* Returns NULL if major or minor are out of range
* otherwise returns a pointer to a static string containing
* the generated name.
***************************************************************************
*/
char *ioc_name(unsigned int major, unsigned int minor)
{
static char name[IOC_DEVLEN + 1];
struct ioc_entry *p;
int base, offset;
if ((MAX_BLKDEV <= major) || (IOC_MAXMINOR <= minor)) {
return (NULL);
}
if (!ioc_parsed && !ioc_init())
return (NULL);
p = ioconf[major];
/* Invalid major or minor numbers? */
if ((p == NULL) || (minor >= (p->blkp->dcount * p->blkp->pcount))) {
/*
* That minor test is only there for IDE-style devices
* that have no minors over 128.
*/
strcpy(name, K_NODEV);
return (name);
}
/* Is this an extension record? */
if (p->blkp->ext && (p->blkp->ext_minor == minor)) {
strcpy(name, p->blkp->ext_name);
return (name);
}
/* OK. we're doing an actual device name... */
/*
* Assemble base + optional controller info
* this is of course too clever by half
* the parser has already cooked cfmt, dfmt to make this easy
* (we parse once but may generate lots of names)
*/
base = p->ctrlno * p->blkp->dcount;
offset = minor / p->blkp->pcount;
if (!p->blkp->ctrl_explicit)
offset += base;
/*
* These sprintfs can't be coalesced because the first might
* ignore its first arg
*/
sprintf(name, p->blkp->cfmt, p->ctrlno);
sprintf(name + strlen(name), p->blkp->dfmt, p->blkp->cconv(offset));
if (!IS_WHOLE(major, minor)) {
/*
* Tack on partition info, format string cooked (curried?) by
* the parser
*/
sprintf(name + strlen(name), p->blkp->pfmt, minor % p->blkp->pcount);
}
return (name);
}
/*
***************************************************************************
* Check whether a device is a whole disk device or not.
*
* IN:
* @major Device major number.
* @minor Device minor number.
*
* RETURNS:
* Predicate: Returns 1 if dev (major,minor) is a whole disk device.
* Returns 0 otherwise.
***************************************************************************
*/
int ioc_iswhole(unsigned int major, unsigned int minor)
{
if (!ioc_parsed && !ioc_init())
return 0;
if (major >= MAX_BLKDEV)
/*
* Later: Handle Linux long major numbers here.
* Now: This is an error.
*/
return 0;
if (ioconf[major] == NULL)
/* Device not registered */
return 0 ;
return (IS_WHOLE(major, minor));
}
/*
***************************************************************************
* Transform device mapper name: Get the user assigned name of the logical
* device instead of the internal device mapper numbering.
*
* IN:
* @major Device major number.
* @minor Device minor number.
*
* RETURNS:
* Assigned name of the logical device.
***************************************************************************
*/
char *transform_devmapname(unsigned int major, unsigned int minor)
{
DIR *dm_dir;
struct dirent *dp;
char filen[MAX_FILE_LEN];
char *dm_name = NULL;
struct stat aux;
unsigned int dm_major, dm_minor;
if ((dm_dir = opendir(DEVMAP_DIR)) == NULL) {
fprintf(stderr, _("Cannot open %s: %s\n"), DEVMAP_DIR, strerror(errno));
exit(4);
}
while ((dp = readdir(dm_dir)) != NULL) {
/* For each file in DEVMAP_DIR */
snprintf(filen, MAX_FILE_LEN, "%s/%s", DEVMAP_DIR, dp->d_name);
filen[MAX_FILE_LEN - 1] = '\0';
if (stat(filen, &aux) == 0) {
/* Get its minor and major numbers */
dm_major = ((aux.st_rdev >> 8) & 0xff);
dm_minor = (aux.st_rdev & 0xff);
if ((dm_minor == minor) && (dm_major == major)) {
dm_name = dp->d_name;
break;
}
}
}
closedir(dm_dir);
return dm_name;
}