NetBSD/sbin/raidctl/rf_configure.c

648 lines
18 KiB
C
Raw Permalink Normal View History

/* $NetBSD: rf_configure.c,v 1.37 2022/07/21 09:19:53 kre Exp $ */
2000-05-23 05:03:05 +04:00
/*
* Copyright (c) 1995 Carnegie-Mellon University.
* All rights reserved.
*
* Author: Mark Holland
*
* Permission to use, copy, modify and distribute this software and
* its documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*/
/***************************************************************
*
* rf_configure.c -- code related to configuring the raidframe system
*
* configuration is complicated by the fact that we want the same
* driver to work both in the kernel and at user level. In the
* kernel, we can't read the configuration file, so we configure
* by running a user-level program that reads the config file,
* creates a data structure describing the configuration and
* passes it into the kernel via an ioctl. Since we want the config
* code to be common between the two versions of the driver, we
* configure using the same two-step process when running at
* user level. Of course, at user level, the config structure is
* passed directly to the config routine, rather than via ioctl.
*
* This file is not compiled into the kernel, so we have no
* need for KERNEL ifdefs.
*
**************************************************************/
2003-06-23 15:53:35 +04:00
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: rf_configure.c,v 1.37 2022/07/21 09:19:53 kre Exp $");
2003-06-23 15:53:35 +04:00
#endif
#include <stdio.h>
#include <stdlib.h>
1999-01-13 01:58:10 +03:00
#include <errno.h>
#include <strings.h>
2010-01-27 21:34:02 +03:00
#include <err.h>
#include <util.h>
Fix some config file parsing. First, and what got me started on this set of cleanups, the queue length in the "queue" section (START queue) is limited to what will fit in a char without losing accuracy (I tried setting it to 200, rather than the more common (universal?) 100 and found that the value configured into the array was -56 instead. Why the value needs to be passed through a char variable I have no idea (it is an int in the filesystem raidframe headers) - but that's the way it is done, and changing it would be an ABI change I believe (and so need versioning to alter) and that isn't worth it for this (or not now, IMO). Instead check that the value in the char is the same value as was read from the config file, and complain if not. Those of you with unsigned chars will be able to have queue lengths up to 255, the rest of us are limited to 127. While looking at that, I noticed some code that obviously fails to understand that scanf("%s") will never return a string containing spaces, and proceeded to attempt to remove trailing spaces from the result ... amusingly, after having used the result for its intended purpose (non existent trailing spaces unremoved), after which that buffer was never used again. That code is now gone (but for now, just #if 0'd rather than actually deleted - it should be cleaned up sometime). Then I saw some other issues with how the config was parsed - a simple (unbounded) scanf("%s") into a buffer, which hypothetically might not be large enough (not a security issue really, raidctl has no special privs, and it isn't likely that root could easily be tricked into running it on a bogus config file - or not without looking first anyway, and a huge long string would rather stand out). Bound the string length to something reasonable, and assert() that the buffer is big enough to contain it. Lastly, in the event of one particular detected error in the config file, the code would write a warning, but then just go ahead and use the bad data (or nothing perhaps) anyway - a failure of logic flow (unlikely to have ever happened, everyone seems to simply copy the sample config from the man page, and make minor adjustments as needed). If any of these changes make any difference to anyone (except me with my attempt to make longer queues - for no particularly well thought out reason), I'd be very surprised.
2022-06-14 11:06:13 +03:00
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dev/raidframe/raidframevar.h>
#include <dev/raidframe/raidframeio.h>
#include "rf_configure.h"
static char *rf_find_non_white(char *, int);
static char *rf_find_white(char *);
static int rf_search_file_for_start_of(const char *, char *, int, FILE *);
static int rf_get_next_nonblank_line(char *, int, FILE *, const char *);
#define RF_MIN(a,b) (((a) < (b)) ? (a) : (b))
static int distSpareYes = 1;
static int distSpareNo = 0;
/*
* The mapsw[] table below contains all the various RAID types that might
* be supported by the kernel. The actual supported types are found
* in sys/dev/raidframe/rf_layout.c.
*/
static const RF_LayoutSW_t mapsw[] = {
/* parity declustering */
{'T', "Parity declustering",
rf_MakeLayoutSpecificDeclustered, &distSpareNo},
/* parity declustering with distributed sparing */
{'D', "Distributed sparing parity declustering",
rf_MakeLayoutSpecificDeclustered, &distSpareYes},
/* declustered P+Q */
{'Q', "Declustered P+Q",
rf_MakeLayoutSpecificDeclustered, &distSpareNo},
/* RAID 5 with rotated sparing */
{'R', "RAID Level 5 rotated sparing", rf_MakeLayoutSpecificNULL, NULL},
/* Chained Declustering */
{'C', "Chained Declustering", rf_MakeLayoutSpecificNULL, NULL},
/* Interleaved Declustering */
{'I', "Interleaved Declustering", rf_MakeLayoutSpecificNULL, NULL},
/* RAID level 0 */
{'0', "RAID Level 0", rf_MakeLayoutSpecificNULL, NULL},
/* RAID level 1 */
{'1', "RAID Level 1", rf_MakeLayoutSpecificNULL, NULL},
/* RAID level 4 */
{'4', "RAID Level 4", rf_MakeLayoutSpecificNULL, NULL},
/* RAID level 5 */
{'5', "RAID Level 5", rf_MakeLayoutSpecificNULL, NULL},
/* Evenodd */
{'E', "EvenOdd", rf_MakeLayoutSpecificNULL, NULL},
/* Declustered Evenodd */
{'e', "Declustered EvenOdd",
rf_MakeLayoutSpecificDeclustered, &distSpareNo},
/* parity logging */
{'L', "Parity logging", rf_MakeLayoutSpecificNULL, NULL},
/* end-of-list marker */
{'\0', NULL, NULL, NULL}
};
static const RF_LayoutSW_t *
rf_GetLayout(RF_ParityConfig_t parityConfig)
{
const RF_LayoutSW_t *p;
/* look up the specific layout */
for (p = &mapsw[0]; p->parityConfig; p++)
if (p->parityConfig == parityConfig)
break;
if (!p->parityConfig)
return NULL;
return p;
}
2000-05-23 05:03:05 +04:00
/*
* called from user level to read the configuration file and create
* a configuration control structure. This is used in the user-level
* version of the driver, and in the user-level program that configures
* the system via ioctl.
*/
int
rf_MakeConfig(char *configname, RF_Config_t *cfgPtr)
{
implement 32-bit compat support for raidframe. convert several raidframe ioctls to be bitsize idempotent so that they work the same in 32 and 64 bit worlds, allowing netbsd32 to configure and query raid properly. remove useless 'row' in a few places. add COMPAT_80 and put the old ioctls there. raidframeio.h: RAIDFRAME_TEST_ACC - remove, unused RAIDFRAME_GET_COMPONENT_LABEL - convert to label not pointer to label RAIDFRAME_CHECK_RECON_STATUS_EXT RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT RAIDFRAME_CHECK_COPYBACK_STATUS_EXT - convert to progress info not pointer to info RAIDFRAME_GET_INFO - version entirely. raidframevar.h: - rf_recon_req{} has row, flags and raidPtr removed (they're not a useful part of this interface.) - RF_Config_s{} and RF_DeviceConfig_s{} have numRow/rows removed. - RF_RaidDisk_s{} is re-ordered slightly to fix alignment padding - the actual data was already OK. - InstallSpareTable() loses row argument rf_compat32.c has code for RF_Config_s{} in 32 bit mode, used by RAIDFRAME_CONFIGURE and RAIDFRAME_GET_INFO32. rf_compat80.c has code for rf_recon_req{}, RF_RaidDisk_s{} and RF_DeviceConfig_s{} to handle RAIDFRAME_FAIL_DISK, RAIDFRAME_GET_COMPONENT_LABEL, RAIDFRAME_CHECK_RECON_STATUS_EXT, RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT, RAIDFRAME_CHECK_COPYBACK_STATUS_EXT, RAIDFRAME_GET_INFO. move several of the per-ioctl code blocks into separate functions. add rf_recon_req_internal{} to replace old usage of global rf_recon_req{} that had unused void * in the structure, ruining it's 32/64 bit ABI. add missing case for RAIDFRAME_GET_INFO50. adjust raid tests to use the new .conf format, and add a case to test the old method as well. raidctl: deal with lack of 'row' members in a couple of places. fail request no longer takes row. handle "START array" sections with just "numCol numSpare", ie no "numRow" specified. for now, generate old-style configuration but update raidctl.8 to specify the new style (keeping reference to the old style.) note that: RF_ComponentLabel_s::{row,num_rows} and RF_SingleComponent_s::row are obsolete but not removed yet.
2018-01-18 03:32:48 +03:00
int numscanned, val, c, retcode, aa, bb, cc;
char buf[BUFSIZ], buf1[BUFSIZ], *cp;
const RF_LayoutSW_t *lp;
2000-05-23 05:03:05 +04:00
FILE *fp;
memset(cfgPtr, 0, sizeof(*cfgPtr));
2000-05-23 05:03:05 +04:00
fp = fopen(configname, "r");
if (!fp) {
warnx("Can't open config file %s", configname);
return -1;
2000-05-23 05:03:05 +04:00
}
rewind(fp);
if (rf_search_file_for_start_of("array", buf, sizeof(buf), fp)) {
warnx("Unable to find start of \"array\" params in config "
"file %s", configname);
2000-05-23 05:03:05 +04:00
retcode = -1;
goto out;
}
rf_get_next_nonblank_line(buf, sizeof(buf), fp,
"Config file error (\"array\" section): unable to get numRow "
"and numCol");
2000-05-23 05:03:05 +04:00
/*
* wackiness with aa, bb, cc to get around size problems on
* different platforms
*/
implement 32-bit compat support for raidframe. convert several raidframe ioctls to be bitsize idempotent so that they work the same in 32 and 64 bit worlds, allowing netbsd32 to configure and query raid properly. remove useless 'row' in a few places. add COMPAT_80 and put the old ioctls there. raidframeio.h: RAIDFRAME_TEST_ACC - remove, unused RAIDFRAME_GET_COMPONENT_LABEL - convert to label not pointer to label RAIDFRAME_CHECK_RECON_STATUS_EXT RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT RAIDFRAME_CHECK_COPYBACK_STATUS_EXT - convert to progress info not pointer to info RAIDFRAME_GET_INFO - version entirely. raidframevar.h: - rf_recon_req{} has row, flags and raidPtr removed (they're not a useful part of this interface.) - RF_Config_s{} and RF_DeviceConfig_s{} have numRow/rows removed. - RF_RaidDisk_s{} is re-ordered slightly to fix alignment padding - the actual data was already OK. - InstallSpareTable() loses row argument rf_compat32.c has code for RF_Config_s{} in 32 bit mode, used by RAIDFRAME_CONFIGURE and RAIDFRAME_GET_INFO32. rf_compat80.c has code for rf_recon_req{}, RF_RaidDisk_s{} and RF_DeviceConfig_s{} to handle RAIDFRAME_FAIL_DISK, RAIDFRAME_GET_COMPONENT_LABEL, RAIDFRAME_CHECK_RECON_STATUS_EXT, RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT, RAIDFRAME_CHECK_COPYBACK_STATUS_EXT, RAIDFRAME_GET_INFO. move several of the per-ioctl code blocks into separate functions. add rf_recon_req_internal{} to replace old usage of global rf_recon_req{} that had unused void * in the structure, ruining it's 32/64 bit ABI. add missing case for RAIDFRAME_GET_INFO50. adjust raid tests to use the new .conf format, and add a case to test the old method as well. raidctl: deal with lack of 'row' members in a couple of places. fail request no longer takes row. handle "START array" sections with just "numCol numSpare", ie no "numRow" specified. for now, generate old-style configuration but update raidctl.8 to specify the new style (keeping reference to the old style.) note that: RF_ComponentLabel_s::{row,num_rows} and RF_SingleComponent_s::row are obsolete but not removed yet.
2018-01-18 03:32:48 +03:00
/*
* Allow both "numCol numSpare" as well as old-style
* "numRow numCol numSpare".
* Note that numRow has always been ignored.
*/
2000-05-23 05:03:05 +04:00
numscanned = sscanf(buf, "%d %d %d", &aa, &bb, &cc);
if (numscanned != 3) {
implement 32-bit compat support for raidframe. convert several raidframe ioctls to be bitsize idempotent so that they work the same in 32 and 64 bit worlds, allowing netbsd32 to configure and query raid properly. remove useless 'row' in a few places. add COMPAT_80 and put the old ioctls there. raidframeio.h: RAIDFRAME_TEST_ACC - remove, unused RAIDFRAME_GET_COMPONENT_LABEL - convert to label not pointer to label RAIDFRAME_CHECK_RECON_STATUS_EXT RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT RAIDFRAME_CHECK_COPYBACK_STATUS_EXT - convert to progress info not pointer to info RAIDFRAME_GET_INFO - version entirely. raidframevar.h: - rf_recon_req{} has row, flags and raidPtr removed (they're not a useful part of this interface.) - RF_Config_s{} and RF_DeviceConfig_s{} have numRow/rows removed. - RF_RaidDisk_s{} is re-ordered slightly to fix alignment padding - the actual data was already OK. - InstallSpareTable() loses row argument rf_compat32.c has code for RF_Config_s{} in 32 bit mode, used by RAIDFRAME_CONFIGURE and RAIDFRAME_GET_INFO32. rf_compat80.c has code for rf_recon_req{}, RF_RaidDisk_s{} and RF_DeviceConfig_s{} to handle RAIDFRAME_FAIL_DISK, RAIDFRAME_GET_COMPONENT_LABEL, RAIDFRAME_CHECK_RECON_STATUS_EXT, RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT, RAIDFRAME_CHECK_COPYBACK_STATUS_EXT, RAIDFRAME_GET_INFO. move several of the per-ioctl code blocks into separate functions. add rf_recon_req_internal{} to replace old usage of global rf_recon_req{} that had unused void * in the structure, ruining it's 32/64 bit ABI. add missing case for RAIDFRAME_GET_INFO50. adjust raid tests to use the new .conf format, and add a case to test the old method as well. raidctl: deal with lack of 'row' members in a couple of places. fail request no longer takes row. handle "START array" sections with just "numCol numSpare", ie no "numRow" specified. for now, generate old-style configuration but update raidctl.8 to specify the new style (keeping reference to the old style.) note that: RF_ComponentLabel_s::{row,num_rows} and RF_SingleComponent_s::row are obsolete but not removed yet.
2018-01-18 03:32:48 +03:00
numscanned = sscanf(buf, "%d %d", &bb, &cc);
if (numscanned != 2) {
warnx("Config file error (\"array\" section): unable "
"to get numCol, numSpare");
retcode = -1;
goto out;
}
2000-05-23 05:03:05 +04:00
}
cfgPtr->numCol = (RF_RowCol_t) bb;
cfgPtr->numSpare = (RF_RowCol_t) cc;
/* debug section is optional */
for (c = 0; c < RF_MAXDBGV; c++)
cfgPtr->debugVars[c][0] = '\0';
rewind(fp);
if (!rf_search_file_for_start_of("debug", buf, sizeof(buf), fp)) {
2000-05-23 05:03:05 +04:00
for (c = 0; c < RF_MAXDBGV; c++) {
if (rf_get_next_nonblank_line(buf, sizeof(buf), fp,
NULL))
2000-05-23 05:03:05 +04:00
break;
cp = rf_find_non_white(buf, 0);
if (!strncmp(cp, "START", sizeof("START") - 1))
2000-05-23 05:03:05 +04:00
break;
(void) strlcpy(cfgPtr->debugVars[c], cp,
2003-07-13 11:37:02 +04:00
sizeof(cfgPtr->debugVars[c]));
2000-05-23 05:03:05 +04:00
}
}
rewind(fp);
2003-07-13 11:37:02 +04:00
strlcpy(cfgPtr->diskQueueType, "fifo", sizeof(cfgPtr->diskQueueType));
2000-05-23 05:03:05 +04:00
cfgPtr->maxOutstandingDiskReqs = 1;
2000-05-23 05:03:05 +04:00
/* scan the file for the block related to disk queues */
if (rf_search_file_for_start_of("queue", buf, sizeof(buf), fp) ||
rf_get_next_nonblank_line(buf, sizeof(buf), fp, NULL)) {
warnx("[No disk queue discipline specified in config file %s. "
"Using %s.]", configname, cfgPtr->diskQueueType);
2000-05-23 05:03:05 +04:00
}
Fix some config file parsing. First, and what got me started on this set of cleanups, the queue length in the "queue" section (START queue) is limited to what will fit in a char without losing accuracy (I tried setting it to 200, rather than the more common (universal?) 100 and found that the value configured into the array was -56 instead. Why the value needs to be passed through a char variable I have no idea (it is an int in the filesystem raidframe headers) - but that's the way it is done, and changing it would be an ABI change I believe (and so need versioning to alter) and that isn't worth it for this (or not now, IMO). Instead check that the value in the char is the same value as was read from the config file, and complain if not. Those of you with unsigned chars will be able to have queue lengths up to 255, the rest of us are limited to 127. While looking at that, I noticed some code that obviously fails to understand that scanf("%s") will never return a string containing spaces, and proceeded to attempt to remove trailing spaces from the result ... amusingly, after having used the result for its intended purpose (non existent trailing spaces unremoved), after which that buffer was never used again. That code is now gone (but for now, just #if 0'd rather than actually deleted - it should be cleaned up sometime). Then I saw some other issues with how the config was parsed - a simple (unbounded) scanf("%s") into a buffer, which hypothetically might not be large enough (not a security issue really, raidctl has no special privs, and it isn't likely that root could easily be tricked into running it on a bogus config file - or not without looking first anyway, and a huge long string would rather stand out). Bound the string length to something reasonable, and assert() that the buffer is big enough to contain it. Lastly, in the event of one particular detected error in the config file, the code would write a warning, but then just go ahead and use the bad data (or nothing perhaps) anyway - a failure of logic flow (unlikely to have ever happened, everyone seems to simply copy the sample config from the man page, and make minor adjustments as needed). If any of these changes make any difference to anyone (except me with my attempt to make longer queues - for no particularly well thought out reason), I'd be very surprised.
2022-06-14 11:06:13 +03:00
else {
2000-05-23 05:03:05 +04:00
/*
* the queue specifier line contains two entries: 1st char of first
2000-05-23 05:03:05 +04:00
* word specifies queue to be used 2nd word specifies max num reqs
* that can be outstanding on the disk itself (typically 1)
*/
Fix some config file parsing. First, and what got me started on this set of cleanups, the queue length in the "queue" section (START queue) is limited to what will fit in a char without losing accuracy (I tried setting it to 200, rather than the more common (universal?) 100 and found that the value configured into the array was -56 instead. Why the value needs to be passed through a char variable I have no idea (it is an int in the filesystem raidframe headers) - but that's the way it is done, and changing it would be an ABI change I believe (and so need versioning to alter) and that isn't worth it for this (or not now, IMO). Instead check that the value in the char is the same value as was read from the config file, and complain if not. Those of you with unsigned chars will be able to have queue lengths up to 255, the rest of us are limited to 127. While looking at that, I noticed some code that obviously fails to understand that scanf("%s") will never return a string containing spaces, and proceeded to attempt to remove trailing spaces from the result ... amusingly, after having used the result for its intended purpose (non existent trailing spaces unremoved), after which that buffer was never used again. That code is now gone (but for now, just #if 0'd rather than actually deleted - it should be cleaned up sometime). Then I saw some other issues with how the config was parsed - a simple (unbounded) scanf("%s") into a buffer, which hypothetically might not be large enough (not a security issue really, raidctl has no special privs, and it isn't likely that root could easily be tricked into running it on a bogus config file - or not without looking first anyway, and a huge long string would rather stand out). Bound the string length to something reasonable, and assert() that the buffer is big enough to contain it. Lastly, in the event of one particular detected error in the config file, the code would write a warning, but then just go ahead and use the bad data (or nothing perhaps) anyway - a failure of logic flow (unlikely to have ever happened, everyone seems to simply copy the sample config from the man page, and make minor adjustments as needed). If any of these changes make any difference to anyone (except me with my attempt to make longer queues - for no particularly well thought out reason), I'd be very surprised.
2022-06-14 11:06:13 +03:00
assert(64 < sizeof buf1);
if (sscanf(buf, "%64s %d", buf1, &val) != 2 || strlen(buf1) >= 60) {
warnx("Can't determine queue type and/or max outstanding "
Fix some config file parsing. First, and what got me started on this set of cleanups, the queue length in the "queue" section (START queue) is limited to what will fit in a char without losing accuracy (I tried setting it to 200, rather than the more common (universal?) 100 and found that the value configured into the array was -56 instead. Why the value needs to be passed through a char variable I have no idea (it is an int in the filesystem raidframe headers) - but that's the way it is done, and changing it would be an ABI change I believe (and so need versioning to alter) and that isn't worth it for this (or not now, IMO). Instead check that the value in the char is the same value as was read from the config file, and complain if not. Those of you with unsigned chars will be able to have queue lengths up to 255, the rest of us are limited to 127. While looking at that, I noticed some code that obviously fails to understand that scanf("%s") will never return a string containing spaces, and proceeded to attempt to remove trailing spaces from the result ... amusingly, after having used the result for its intended purpose (non existent trailing spaces unremoved), after which that buffer was never used again. That code is now gone (but for now, just #if 0'd rather than actually deleted - it should be cleaned up sometime). Then I saw some other issues with how the config was parsed - a simple (unbounded) scanf("%s") into a buffer, which hypothetically might not be large enough (not a security issue really, raidctl has no special privs, and it isn't likely that root could easily be tricked into running it on a bogus config file - or not without looking first anyway, and a huge long string would rather stand out). Bound the string length to something reasonable, and assert() that the buffer is big enough to contain it. Lastly, in the event of one particular detected error in the config file, the code would write a warning, but then just go ahead and use the bad data (or nothing perhaps) anyway - a failure of logic flow (unlikely to have ever happened, everyone seems to simply copy the sample config from the man page, and make minor adjustments as needed). If any of these changes make any difference to anyone (except me with my attempt to make longer queues - for no particularly well thought out reason), I'd be very surprised.
2022-06-14 11:06:13 +03:00
"reqs from line: %.*s", (int)(sizeof(buf) - 1), buf);
warnx("Using %s-%d", cfgPtr->diskQueueType,
cfgPtr->maxOutstandingDiskReqs);
2000-05-23 05:03:05 +04:00
} else {
Fix some config file parsing. First, and what got me started on this set of cleanups, the queue length in the "queue" section (START queue) is limited to what will fit in a char without losing accuracy (I tried setting it to 200, rather than the more common (universal?) 100 and found that the value configured into the array was -56 instead. Why the value needs to be passed through a char variable I have no idea (it is an int in the filesystem raidframe headers) - but that's the way it is done, and changing it would be an ABI change I believe (and so need versioning to alter) and that isn't worth it for this (or not now, IMO). Instead check that the value in the char is the same value as was read from the config file, and complain if not. Those of you with unsigned chars will be able to have queue lengths up to 255, the rest of us are limited to 127. While looking at that, I noticed some code that obviously fails to understand that scanf("%s") will never return a string containing spaces, and proceeded to attempt to remove trailing spaces from the result ... amusingly, after having used the result for its intended purpose (non existent trailing spaces unremoved), after which that buffer was never used again. That code is now gone (but for now, just #if 0'd rather than actually deleted - it should be cleaned up sometime). Then I saw some other issues with how the config was parsed - a simple (unbounded) scanf("%s") into a buffer, which hypothetically might not be large enough (not a security issue really, raidctl has no special privs, and it isn't likely that root could easily be tricked into running it on a bogus config file - or not without looking first anyway, and a huge long string would rather stand out). Bound the string length to something reasonable, and assert() that the buffer is big enough to contain it. Lastly, in the event of one particular detected error in the config file, the code would write a warning, but then just go ahead and use the bad data (or nothing perhaps) anyway - a failure of logic flow (unlikely to have ever happened, everyone seems to simply copy the sample config from the man page, and make minor adjustments as needed). If any of these changes make any difference to anyone (except me with my attempt to make longer queues - for no particularly well thought out reason), I'd be very surprised.
2022-06-14 11:06:13 +03:00
#if 0
2000-05-23 05:03:05 +04:00
char *ch;
Fix some config file parsing. First, and what got me started on this set of cleanups, the queue length in the "queue" section (START queue) is limited to what will fit in a char without losing accuracy (I tried setting it to 200, rather than the more common (universal?) 100 and found that the value configured into the array was -56 instead. Why the value needs to be passed through a char variable I have no idea (it is an int in the filesystem raidframe headers) - but that's the way it is done, and changing it would be an ABI change I believe (and so need versioning to alter) and that isn't worth it for this (or not now, IMO). Instead check that the value in the char is the same value as was read from the config file, and complain if not. Those of you with unsigned chars will be able to have queue lengths up to 255, the rest of us are limited to 127. While looking at that, I noticed some code that obviously fails to understand that scanf("%s") will never return a string containing spaces, and proceeded to attempt to remove trailing spaces from the result ... amusingly, after having used the result for its intended purpose (non existent trailing spaces unremoved), after which that buffer was never used again. That code is now gone (but for now, just #if 0'd rather than actually deleted - it should be cleaned up sometime). Then I saw some other issues with how the config was parsed - a simple (unbounded) scanf("%s") into a buffer, which hypothetically might not be large enough (not a security issue really, raidctl has no special privs, and it isn't likely that root could easily be tricked into running it on a bogus config file - or not without looking first anyway, and a huge long string would rather stand out). Bound the string length to something reasonable, and assert() that the buffer is big enough to contain it. Lastly, in the event of one particular detected error in the config file, the code would write a warning, but then just go ahead and use the bad data (or nothing perhaps) anyway - a failure of logic flow (unlikely to have ever happened, everyone seems to simply copy the sample config from the man page, and make minor adjustments as needed). If any of these changes make any difference to anyone (except me with my attempt to make longer queues - for no particularly well thought out reason), I'd be very surprised.
2022-06-14 11:06:13 +03:00
#endif
memcpy(cfgPtr->diskQueueType, buf1,
2000-05-23 05:03:05 +04:00
RF_MIN(sizeof(cfgPtr->diskQueueType), strlen(buf1) + 1));
Fix some config file parsing. First, and what got me started on this set of cleanups, the queue length in the "queue" section (START queue) is limited to what will fit in a char without losing accuracy (I tried setting it to 200, rather than the more common (universal?) 100 and found that the value configured into the array was -56 instead. Why the value needs to be passed through a char variable I have no idea (it is an int in the filesystem raidframe headers) - but that's the way it is done, and changing it would be an ABI change I believe (and so need versioning to alter) and that isn't worth it for this (or not now, IMO). Instead check that the value in the char is the same value as was read from the config file, and complain if not. Those of you with unsigned chars will be able to have queue lengths up to 255, the rest of us are limited to 127. While looking at that, I noticed some code that obviously fails to understand that scanf("%s") will never return a string containing spaces, and proceeded to attempt to remove trailing spaces from the result ... amusingly, after having used the result for its intended purpose (non existent trailing spaces unremoved), after which that buffer was never used again. That code is now gone (but for now, just #if 0'd rather than actually deleted - it should be cleaned up sometime). Then I saw some other issues with how the config was parsed - a simple (unbounded) scanf("%s") into a buffer, which hypothetically might not be large enough (not a security issue really, raidctl has no special privs, and it isn't likely that root could easily be tricked into running it on a bogus config file - or not without looking first anyway, and a huge long string would rather stand out). Bound the string length to something reasonable, and assert() that the buffer is big enough to contain it. Lastly, in the event of one particular detected error in the config file, the code would write a warning, but then just go ahead and use the bad data (or nothing perhaps) anyway - a failure of logic flow (unlikely to have ever happened, everyone seems to simply copy the sample config from the man page, and make minor adjustments as needed). If any of these changes make any difference to anyone (except me with my attempt to make longer queues - for no particularly well thought out reason), I'd be very surprised.
2022-06-14 11:06:13 +03:00
cfgPtr->diskQueueType[sizeof cfgPtr->diskQueueType - 1] = '\0';
#if 0 /* this indicates a lack of understanding of how scanf() works */
/* it was also pointless as buf1 data was (b4) never used again */
2000-05-23 05:03:05 +04:00
for (ch = buf1; *ch; ch++) {
if (*ch == ' ') {
*ch = '\0';
break;
}
}
Fix some config file parsing. First, and what got me started on this set of cleanups, the queue length in the "queue" section (START queue) is limited to what will fit in a char without losing accuracy (I tried setting it to 200, rather than the more common (universal?) 100 and found that the value configured into the array was -56 instead. Why the value needs to be passed through a char variable I have no idea (it is an int in the filesystem raidframe headers) - but that's the way it is done, and changing it would be an ABI change I believe (and so need versioning to alter) and that isn't worth it for this (or not now, IMO). Instead check that the value in the char is the same value as was read from the config file, and complain if not. Those of you with unsigned chars will be able to have queue lengths up to 255, the rest of us are limited to 127. While looking at that, I noticed some code that obviously fails to understand that scanf("%s") will never return a string containing spaces, and proceeded to attempt to remove trailing spaces from the result ... amusingly, after having used the result for its intended purpose (non existent trailing spaces unremoved), after which that buffer was never used again. That code is now gone (but for now, just #if 0'd rather than actually deleted - it should be cleaned up sometime). Then I saw some other issues with how the config was parsed - a simple (unbounded) scanf("%s") into a buffer, which hypothetically might not be large enough (not a security issue really, raidctl has no special privs, and it isn't likely that root could easily be tricked into running it on a bogus config file - or not without looking first anyway, and a huge long string would rather stand out). Bound the string length to something reasonable, and assert() that the buffer is big enough to contain it. Lastly, in the event of one particular detected error in the config file, the code would write a warning, but then just go ahead and use the bad data (or nothing perhaps) anyway - a failure of logic flow (unlikely to have ever happened, everyone seems to simply copy the sample config from the man page, and make minor adjustments as needed). If any of these changes make any difference to anyone (except me with my attempt to make longer queues - for no particularly well thought out reason), I'd be very surprised.
2022-06-14 11:06:13 +03:00
#endif
2000-05-23 05:03:05 +04:00
cfgPtr->maxOutstandingDiskReqs = val;
Fix some config file parsing. First, and what got me started on this set of cleanups, the queue length in the "queue" section (START queue) is limited to what will fit in a char without losing accuracy (I tried setting it to 200, rather than the more common (universal?) 100 and found that the value configured into the array was -56 instead. Why the value needs to be passed through a char variable I have no idea (it is an int in the filesystem raidframe headers) - but that's the way it is done, and changing it would be an ABI change I believe (and so need versioning to alter) and that isn't worth it for this (or not now, IMO). Instead check that the value in the char is the same value as was read from the config file, and complain if not. Those of you with unsigned chars will be able to have queue lengths up to 255, the rest of us are limited to 127. While looking at that, I noticed some code that obviously fails to understand that scanf("%s") will never return a string containing spaces, and proceeded to attempt to remove trailing spaces from the result ... amusingly, after having used the result for its intended purpose (non existent trailing spaces unremoved), after which that buffer was never used again. That code is now gone (but for now, just #if 0'd rather than actually deleted - it should be cleaned up sometime). Then I saw some other issues with how the config was parsed - a simple (unbounded) scanf("%s") into a buffer, which hypothetically might not be large enough (not a security issue really, raidctl has no special privs, and it isn't likely that root could easily be tricked into running it on a bogus config file - or not without looking first anyway, and a huge long string would rather stand out). Bound the string length to something reasonable, and assert() that the buffer is big enough to contain it. Lastly, in the event of one particular detected error in the config file, the code would write a warning, but then just go ahead and use the bad data (or nothing perhaps) anyway - a failure of logic flow (unlikely to have ever happened, everyone seems to simply copy the sample config from the man page, and make minor adjustments as needed). If any of these changes make any difference to anyone (except me with my attempt to make longer queues - for no particularly well thought out reason), I'd be very surprised.
2022-06-14 11:06:13 +03:00
if (cfgPtr->maxOutstandingDiskReqs != val) {
warnx("Queue length for %s out of range"
" [%d interp as %d], assuming 1",
buf1, val, cfgPtr->maxOutstandingDiskReqs);
cfgPtr->maxOutstandingDiskReqs = 1;
}
2000-05-23 05:03:05 +04:00
}
Fix some config file parsing. First, and what got me started on this set of cleanups, the queue length in the "queue" section (START queue) is limited to what will fit in a char without losing accuracy (I tried setting it to 200, rather than the more common (universal?) 100 and found that the value configured into the array was -56 instead. Why the value needs to be passed through a char variable I have no idea (it is an int in the filesystem raidframe headers) - but that's the way it is done, and changing it would be an ABI change I believe (and so need versioning to alter) and that isn't worth it for this (or not now, IMO). Instead check that the value in the char is the same value as was read from the config file, and complain if not. Those of you with unsigned chars will be able to have queue lengths up to 255, the rest of us are limited to 127. While looking at that, I noticed some code that obviously fails to understand that scanf("%s") will never return a string containing spaces, and proceeded to attempt to remove trailing spaces from the result ... amusingly, after having used the result for its intended purpose (non existent trailing spaces unremoved), after which that buffer was never used again. That code is now gone (but for now, just #if 0'd rather than actually deleted - it should be cleaned up sometime). Then I saw some other issues with how the config was parsed - a simple (unbounded) scanf("%s") into a buffer, which hypothetically might not be large enough (not a security issue really, raidctl has no special privs, and it isn't likely that root could easily be tricked into running it on a bogus config file - or not without looking first anyway, and a huge long string would rather stand out). Bound the string length to something reasonable, and assert() that the buffer is big enough to contain it. Lastly, in the event of one particular detected error in the config file, the code would write a warning, but then just go ahead and use the bad data (or nothing perhaps) anyway - a failure of logic flow (unlikely to have ever happened, everyone seems to simply copy the sample config from the man page, and make minor adjustments as needed). If any of these changes make any difference to anyone (except me with my attempt to make longer queues - for no particularly well thought out reason), I'd be very surprised.
2022-06-14 11:06:13 +03:00
}
2000-05-23 05:03:05 +04:00
rewind(fp);
if (rf_search_file_for_start_of("disks", buf, sizeof(buf), fp)) {
warnx("Can't find \"disks\" section in config file %s",
configname);
2000-05-23 05:03:05 +04:00
retcode = -1;
goto out;
}
implement 32-bit compat support for raidframe. convert several raidframe ioctls to be bitsize idempotent so that they work the same in 32 and 64 bit worlds, allowing netbsd32 to configure and query raid properly. remove useless 'row' in a few places. add COMPAT_80 and put the old ioctls there. raidframeio.h: RAIDFRAME_TEST_ACC - remove, unused RAIDFRAME_GET_COMPONENT_LABEL - convert to label not pointer to label RAIDFRAME_CHECK_RECON_STATUS_EXT RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT RAIDFRAME_CHECK_COPYBACK_STATUS_EXT - convert to progress info not pointer to info RAIDFRAME_GET_INFO - version entirely. raidframevar.h: - rf_recon_req{} has row, flags and raidPtr removed (they're not a useful part of this interface.) - RF_Config_s{} and RF_DeviceConfig_s{} have numRow/rows removed. - RF_RaidDisk_s{} is re-ordered slightly to fix alignment padding - the actual data was already OK. - InstallSpareTable() loses row argument rf_compat32.c has code for RF_Config_s{} in 32 bit mode, used by RAIDFRAME_CONFIGURE and RAIDFRAME_GET_INFO32. rf_compat80.c has code for rf_recon_req{}, RF_RaidDisk_s{} and RF_DeviceConfig_s{} to handle RAIDFRAME_FAIL_DISK, RAIDFRAME_GET_COMPONENT_LABEL, RAIDFRAME_CHECK_RECON_STATUS_EXT, RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT, RAIDFRAME_CHECK_COPYBACK_STATUS_EXT, RAIDFRAME_GET_INFO. move several of the per-ioctl code blocks into separate functions. add rf_recon_req_internal{} to replace old usage of global rf_recon_req{} that had unused void * in the structure, ruining it's 32/64 bit ABI. add missing case for RAIDFRAME_GET_INFO50. adjust raid tests to use the new .conf format, and add a case to test the old method as well. raidctl: deal with lack of 'row' members in a couple of places. fail request no longer takes row. handle "START array" sections with just "numCol numSpare", ie no "numRow" specified. for now, generate old-style configuration but update raidctl.8 to specify the new style (keeping reference to the old style.) note that: RF_ComponentLabel_s::{row,num_rows} and RF_SingleComponent_s::row are obsolete but not removed yet.
2018-01-18 03:32:48 +03:00
for (c = 0; c < cfgPtr->numCol; c++) {
char b1[MAXPATHLEN];
const char *b;
implement 32-bit compat support for raidframe. convert several raidframe ioctls to be bitsize idempotent so that they work the same in 32 and 64 bit worlds, allowing netbsd32 to configure and query raid properly. remove useless 'row' in a few places. add COMPAT_80 and put the old ioctls there. raidframeio.h: RAIDFRAME_TEST_ACC - remove, unused RAIDFRAME_GET_COMPONENT_LABEL - convert to label not pointer to label RAIDFRAME_CHECK_RECON_STATUS_EXT RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT RAIDFRAME_CHECK_COPYBACK_STATUS_EXT - convert to progress info not pointer to info RAIDFRAME_GET_INFO - version entirely. raidframevar.h: - rf_recon_req{} has row, flags and raidPtr removed (they're not a useful part of this interface.) - RF_Config_s{} and RF_DeviceConfig_s{} have numRow/rows removed. - RF_RaidDisk_s{} is re-ordered slightly to fix alignment padding - the actual data was already OK. - InstallSpareTable() loses row argument rf_compat32.c has code for RF_Config_s{} in 32 bit mode, used by RAIDFRAME_CONFIGURE and RAIDFRAME_GET_INFO32. rf_compat80.c has code for rf_recon_req{}, RF_RaidDisk_s{} and RF_DeviceConfig_s{} to handle RAIDFRAME_FAIL_DISK, RAIDFRAME_GET_COMPONENT_LABEL, RAIDFRAME_CHECK_RECON_STATUS_EXT, RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT, RAIDFRAME_CHECK_COPYBACK_STATUS_EXT, RAIDFRAME_GET_INFO. move several of the per-ioctl code blocks into separate functions. add rf_recon_req_internal{} to replace old usage of global rf_recon_req{} that had unused void * in the structure, ruining it's 32/64 bit ABI. add missing case for RAIDFRAME_GET_INFO50. adjust raid tests to use the new .conf format, and add a case to test the old method as well. raidctl: deal with lack of 'row' members in a couple of places. fail request no longer takes row. handle "START array" sections with just "numCol numSpare", ie no "numRow" specified. for now, generate old-style configuration but update raidctl.8 to specify the new style (keeping reference to the old style.) note that: RF_ComponentLabel_s::{row,num_rows} and RF_SingleComponent_s::row are obsolete but not removed yet.
2018-01-18 03:32:48 +03:00
if (rf_get_next_nonblank_line(
buf, sizeof(buf), fp, NULL)) {
warnx("Config file error: unable to find device "
"file name for disk at col %d", c);
implement 32-bit compat support for raidframe. convert several raidframe ioctls to be bitsize idempotent so that they work the same in 32 and 64 bit worlds, allowing netbsd32 to configure and query raid properly. remove useless 'row' in a few places. add COMPAT_80 and put the old ioctls there. raidframeio.h: RAIDFRAME_TEST_ACC - remove, unused RAIDFRAME_GET_COMPONENT_LABEL - convert to label not pointer to label RAIDFRAME_CHECK_RECON_STATUS_EXT RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT RAIDFRAME_CHECK_COPYBACK_STATUS_EXT - convert to progress info not pointer to info RAIDFRAME_GET_INFO - version entirely. raidframevar.h: - rf_recon_req{} has row, flags and raidPtr removed (they're not a useful part of this interface.) - RF_Config_s{} and RF_DeviceConfig_s{} have numRow/rows removed. - RF_RaidDisk_s{} is re-ordered slightly to fix alignment padding - the actual data was already OK. - InstallSpareTable() loses row argument rf_compat32.c has code for RF_Config_s{} in 32 bit mode, used by RAIDFRAME_CONFIGURE and RAIDFRAME_GET_INFO32. rf_compat80.c has code for rf_recon_req{}, RF_RaidDisk_s{} and RF_DeviceConfig_s{} to handle RAIDFRAME_FAIL_DISK, RAIDFRAME_GET_COMPONENT_LABEL, RAIDFRAME_CHECK_RECON_STATUS_EXT, RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT, RAIDFRAME_CHECK_COPYBACK_STATUS_EXT, RAIDFRAME_GET_INFO. move several of the per-ioctl code blocks into separate functions. add rf_recon_req_internal{} to replace old usage of global rf_recon_req{} that had unused void * in the structure, ruining it's 32/64 bit ABI. add missing case for RAIDFRAME_GET_INFO50. adjust raid tests to use the new .conf format, and add a case to test the old method as well. raidctl: deal with lack of 'row' members in a couple of places. fail request no longer takes row. handle "START array" sections with just "numCol numSpare", ie no "numRow" specified. for now, generate old-style configuration but update raidctl.8 to specify the new style (keeping reference to the old style.) note that: RF_ComponentLabel_s::{row,num_rows} and RF_SingleComponent_s::row are obsolete but not removed yet.
2018-01-18 03:32:48 +03:00
retcode = -1;
goto out;
}
implement 32-bit compat support for raidframe. convert several raidframe ioctls to be bitsize idempotent so that they work the same in 32 and 64 bit worlds, allowing netbsd32 to configure and query raid properly. remove useless 'row' in a few places. add COMPAT_80 and put the old ioctls there. raidframeio.h: RAIDFRAME_TEST_ACC - remove, unused RAIDFRAME_GET_COMPONENT_LABEL - convert to label not pointer to label RAIDFRAME_CHECK_RECON_STATUS_EXT RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT RAIDFRAME_CHECK_COPYBACK_STATUS_EXT - convert to progress info not pointer to info RAIDFRAME_GET_INFO - version entirely. raidframevar.h: - rf_recon_req{} has row, flags and raidPtr removed (they're not a useful part of this interface.) - RF_Config_s{} and RF_DeviceConfig_s{} have numRow/rows removed. - RF_RaidDisk_s{} is re-ordered slightly to fix alignment padding - the actual data was already OK. - InstallSpareTable() loses row argument rf_compat32.c has code for RF_Config_s{} in 32 bit mode, used by RAIDFRAME_CONFIGURE and RAIDFRAME_GET_INFO32. rf_compat80.c has code for rf_recon_req{}, RF_RaidDisk_s{} and RF_DeviceConfig_s{} to handle RAIDFRAME_FAIL_DISK, RAIDFRAME_GET_COMPONENT_LABEL, RAIDFRAME_CHECK_RECON_STATUS_EXT, RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT, RAIDFRAME_CHECK_COPYBACK_STATUS_EXT, RAIDFRAME_GET_INFO. move several of the per-ioctl code blocks into separate functions. add rf_recon_req_internal{} to replace old usage of global rf_recon_req{} that had unused void * in the structure, ruining it's 32/64 bit ABI. add missing case for RAIDFRAME_GET_INFO50. adjust raid tests to use the new .conf format, and add a case to test the old method as well. raidctl: deal with lack of 'row' members in a couple of places. fail request no longer takes row. handle "START array" sections with just "numCol numSpare", ie no "numRow" specified. for now, generate old-style configuration but update raidctl.8 to specify the new style (keeping reference to the old style.) note that: RF_ComponentLabel_s::{row,num_rows} and RF_SingleComponent_s::row are obsolete but not removed yet.
2018-01-18 03:32:48 +03:00
b = getfsspecname(b1, sizeof(b1), buf);
if (b == NULL) {
warnx("Config file error: warning: unable to "
"get device file for disk at col %d: %s",
c, b1);
b = "absent";
2000-05-23 05:03:05 +04:00
}
implement 32-bit compat support for raidframe. convert several raidframe ioctls to be bitsize idempotent so that they work the same in 32 and 64 bit worlds, allowing netbsd32 to configure and query raid properly. remove useless 'row' in a few places. add COMPAT_80 and put the old ioctls there. raidframeio.h: RAIDFRAME_TEST_ACC - remove, unused RAIDFRAME_GET_COMPONENT_LABEL - convert to label not pointer to label RAIDFRAME_CHECK_RECON_STATUS_EXT RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT RAIDFRAME_CHECK_COPYBACK_STATUS_EXT - convert to progress info not pointer to info RAIDFRAME_GET_INFO - version entirely. raidframevar.h: - rf_recon_req{} has row, flags and raidPtr removed (they're not a useful part of this interface.) - RF_Config_s{} and RF_DeviceConfig_s{} have numRow/rows removed. - RF_RaidDisk_s{} is re-ordered slightly to fix alignment padding - the actual data was already OK. - InstallSpareTable() loses row argument rf_compat32.c has code for RF_Config_s{} in 32 bit mode, used by RAIDFRAME_CONFIGURE and RAIDFRAME_GET_INFO32. rf_compat80.c has code for rf_recon_req{}, RF_RaidDisk_s{} and RF_DeviceConfig_s{} to handle RAIDFRAME_FAIL_DISK, RAIDFRAME_GET_COMPONENT_LABEL, RAIDFRAME_CHECK_RECON_STATUS_EXT, RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT, RAIDFRAME_CHECK_COPYBACK_STATUS_EXT, RAIDFRAME_GET_INFO. move several of the per-ioctl code blocks into separate functions. add rf_recon_req_internal{} to replace old usage of global rf_recon_req{} that had unused void * in the structure, ruining it's 32/64 bit ABI. add missing case for RAIDFRAME_GET_INFO50. adjust raid tests to use the new .conf format, and add a case to test the old method as well. raidctl: deal with lack of 'row' members in a couple of places. fail request no longer takes row. handle "START array" sections with just "numCol numSpare", ie no "numRow" specified. for now, generate old-style configuration but update raidctl.8 to specify the new style (keeping reference to the old style.) note that: RF_ComponentLabel_s::{row,num_rows} and RF_SingleComponent_s::row are obsolete but not removed yet.
2018-01-18 03:32:48 +03:00
strlcpy(cfgPtr->devnames[0][c], b,
sizeof(cfgPtr->devnames[0][c]));
2000-05-23 05:03:05 +04:00
}
/* "spare" section is optional */
rewind(fp);
if (rf_search_file_for_start_of("spare", buf, sizeof(buf), fp))
2000-05-23 05:03:05 +04:00
cfgPtr->numSpare = 0;
for (c = 0; c < cfgPtr->numSpare; c++) {
char b1[MAXPATHLEN];
const char *b;
if (rf_get_next_nonblank_line(buf, sizeof(buf), fp, NULL)) {
warnx("Config file error: unable to get device file "
"for spare disk %d", c);
2000-05-23 05:03:05 +04:00
retcode = -1;
goto out;
}
b = getfsspecname(b1, sizeof(b1), buf);
if (b == NULL) {
warnx("Config file error: warning: unable to get "
"device file for spare disk %d: %s", c, buf);
b = buf;
}
implement 32-bit compat support for raidframe. convert several raidframe ioctls to be bitsize idempotent so that they work the same in 32 and 64 bit worlds, allowing netbsd32 to configure and query raid properly. remove useless 'row' in a few places. add COMPAT_80 and put the old ioctls there. raidframeio.h: RAIDFRAME_TEST_ACC - remove, unused RAIDFRAME_GET_COMPONENT_LABEL - convert to label not pointer to label RAIDFRAME_CHECK_RECON_STATUS_EXT RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT RAIDFRAME_CHECK_COPYBACK_STATUS_EXT - convert to progress info not pointer to info RAIDFRAME_GET_INFO - version entirely. raidframevar.h: - rf_recon_req{} has row, flags and raidPtr removed (they're not a useful part of this interface.) - RF_Config_s{} and RF_DeviceConfig_s{} have numRow/rows removed. - RF_RaidDisk_s{} is re-ordered slightly to fix alignment padding - the actual data was already OK. - InstallSpareTable() loses row argument rf_compat32.c has code for RF_Config_s{} in 32 bit mode, used by RAIDFRAME_CONFIGURE and RAIDFRAME_GET_INFO32. rf_compat80.c has code for rf_recon_req{}, RF_RaidDisk_s{} and RF_DeviceConfig_s{} to handle RAIDFRAME_FAIL_DISK, RAIDFRAME_GET_COMPONENT_LABEL, RAIDFRAME_CHECK_RECON_STATUS_EXT, RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT, RAIDFRAME_CHECK_COPYBACK_STATUS_EXT, RAIDFRAME_GET_INFO. move several of the per-ioctl code blocks into separate functions. add rf_recon_req_internal{} to replace old usage of global rf_recon_req{} that had unused void * in the structure, ruining it's 32/64 bit ABI. add missing case for RAIDFRAME_GET_INFO50. adjust raid tests to use the new .conf format, and add a case to test the old method as well. raidctl: deal with lack of 'row' members in a couple of places. fail request no longer takes row. handle "START array" sections with just "numCol numSpare", ie no "numRow" specified. for now, generate old-style configuration but update raidctl.8 to specify the new style (keeping reference to the old style.) note that: RF_ComponentLabel_s::{row,num_rows} and RF_SingleComponent_s::row are obsolete but not removed yet.
2018-01-18 03:32:48 +03:00
strlcpy(cfgPtr->spare_names[c], b,
sizeof(cfgPtr->spare_names[c]));
2000-05-23 05:03:05 +04:00
}
/* scan the file for the block related to layout */
rewind(fp);
if (rf_search_file_for_start_of("layout", buf, sizeof(buf), fp)) {
warnx("Can't find \"layout\" section in configuration file %s",
configname);
2000-05-23 05:03:05 +04:00
retcode = -1;
goto out;
}
if (rf_get_next_nonblank_line(buf, sizeof(buf), fp, NULL)) {
warnx("Config file error (\"layout\" section): unable to find "
"common layout param line");
2000-05-23 05:03:05 +04:00
retcode = -1;
goto out;
}
c = sscanf(buf, "%d %d %d %c", &aa, &bb, &cc, &cfgPtr->parityConfig);
cfgPtr->sectPerSU = (RF_SectorNum_t) aa;
cfgPtr->SUsPerPU = (RF_StripeNum_t) bb;
cfgPtr->SUsPerRU = (RF_StripeNum_t) cc;
if (c != 4) {
warnx("Unable to scan common layout line");
2000-05-23 05:03:05 +04:00
retcode = -1;
goto out;
}
lp = rf_GetLayout(cfgPtr->parityConfig);
if (lp == NULL) {
warnx("Unknown parity config '%c'",
2000-05-23 05:03:05 +04:00
cfgPtr->parityConfig);
retcode = -1;
goto out;
}
retcode = lp->MakeLayoutSpecific(fp, cfgPtr,
lp->makeLayoutSpecificArg);
out:
2000-05-23 05:03:05 +04:00
fclose(fp);
if (retcode < 0)
retcode = errno = EINVAL;
else
errno = retcode;
return retcode;
}
/*
* used in architectures such as RAID0 where there is no layout-specific
* information to be passed into the configuration code.
*/
int
rf_MakeLayoutSpecificNULL(FILE *fp, RF_Config_t *cfgPtr, void *ignored)
{
2000-05-23 05:03:05 +04:00
cfgPtr->layoutSpecificSize = 0;
cfgPtr->layoutSpecific = NULL;
return 0;
}
int
rf_MakeLayoutSpecificDeclustered(FILE *configfp, RF_Config_t *cfgPtr, void *arg)
{
2000-05-23 05:03:05 +04:00
int b, v, k, r, lambda, norotate, i, val, distSpare;
char *cfgBuf, *bdfile, *p, *smname;
char buf[BUFSIZ], smbuf[BUFSIZ];
2000-05-23 05:03:05 +04:00
FILE *fp;
distSpare = *((int *) arg);
/* get the block design file name */
if (rf_get_next_nonblank_line(buf, sizeof(buf), configfp,
"Can't find block design file name in config file"))
return EINVAL;
bdfile = rf_find_non_white(buf, 1);
2000-05-23 05:03:05 +04:00
/* open bd file, check validity of configuration */
if ((fp = fopen(bdfile, "r")) == NULL) {
warn("RAID: config error: Can't open layout table file %s",
bdfile);
return EINVAL;
2000-05-23 05:03:05 +04:00
}
if (fgets(buf, sizeof(buf), fp) == NULL) {
warnx("RAID: config error: Can't read layout from layout "
"table file %s", bdfile);
fclose(fp);
return EINVAL;
}
i = sscanf(buf, "%u %u %u %u %u %u",
&b, &v, &k, &r, &lambda, &norotate);
2000-05-23 05:03:05 +04:00
if (i == 5)
norotate = 0; /* no-rotate flag is optional */
else if (i != 6) {
warnx("Unable to parse header line in block design file");
fclose(fp);
return EINVAL;
2000-05-23 05:03:05 +04:00
}
/*
* set the sparemap directory. In the in-kernel version, there's a
* daemon that's responsible for finding the sparemaps
*/
2000-05-23 05:03:05 +04:00
if (distSpare) {
if (rf_get_next_nonblank_line(smbuf, sizeof(smbuf), configfp,
"Can't find sparemap file name in config file")) {
fclose(fp);
return EINVAL;
2000-05-23 05:03:05 +04:00
}
smname = rf_find_non_white(smbuf, 1);
if (strlen(smname) >= RF_SPAREMAP_NAME_LEN) {
warnx("sparemap file name '%s' too long (max %d)",
smname, RF_SPAREMAP_NAME_LEN - 1);
fclose(fp);
return EINVAL;
}
2000-05-23 05:03:05 +04:00
} else {
smbuf[0] = '\0';
smname = smbuf;
}
/* allocate a buffer to hold the configuration info */
cfgPtr->layoutSpecificSize = RF_SPAREMAP_NAME_LEN +
6 * sizeof(int) + b * k;
2000-05-23 05:03:05 +04:00
cfgBuf = (char *) malloc(cfgPtr->layoutSpecificSize);
if (cfgBuf == NULL) {
fclose(fp);
return ENOMEM;
}
2000-05-23 05:03:05 +04:00
cfgPtr->layoutSpecific = (void *) cfgBuf;
p = cfgBuf;
/* install name of sparemap file */
for (i = 0; smname[i]; i++)
*p++ = smname[i];
/* pad with zeros */
while (i < RF_SPAREMAP_NAME_LEN) {
*p++ = '\0';
i++;
}
if ((i & (sizeof(int) - 1)) != 0) {
/* panic, unaligned data; RF_SPAREMAP_NAME_LEN invalid */
warnx("Program Bug: (RF_SPAREMAP_NAME_LEN(%d) %% %zd) != 0",
RF_SPAREMAP_NAME_LEN, sizeof(int));
fclose(fp);
return EINVAL;
}
2000-05-23 05:03:05 +04:00
/*
* fill in the buffer with the block design parameters
* and then the block design itself
*/
2000-05-23 05:03:05 +04:00
*((int *) p) = b;
p += sizeof(int);
*((int *) p) = v;
p += sizeof(int);
*((int *) p) = k;
p += sizeof(int);
*((int *) p) = r;
p += sizeof(int);
*((int *) p) = lambda;
p += sizeof(int);
*((int *) p) = norotate;
p += sizeof(int);
while (fscanf(fp, "%d", &val) == 1)
*p++ = (char) val;
fclose(fp);
2009-04-06 16:47:20 +04:00
if ((unsigned int)(p - cfgBuf) != cfgPtr->layoutSpecificSize) {
warnx("Size mismatch creating layout specific data: is %tu sb "
"%zu bytes", p - cfgBuf, 6 * sizeof(int) + b * k);
return EINVAL;
2000-05-23 05:03:05 +04:00
}
return 0;
}
/****************************************************************************
*
* utilities
*
***************************************************************************/
/* finds a non-white character in the line */
static char *
rf_find_non_white(char *p, int eatnl)
{
while (*p == ' ' || *p == '\t')
p++;
if (*p == '\n' && eatnl)
*p = '\0';
return p;
}
/* finds a white character in the line */
static char *
rf_find_white(char *p)
{
while (*p != '\0' && *p != ' ' && *p != '\t')
p++;
return p;
}
2000-05-23 05:03:05 +04:00
/*
* searches a file for a line that says "START string", where string is
* specified as a parameter
*/
static int
rf_search_file_for_start_of(const char *string, char *buf, int len, FILE *fp)
{
2000-05-23 05:03:05 +04:00
char *p;
while (1) {
if (fgets(buf, len, fp) == NULL)
return -1;
p = rf_find_non_white(buf, 0);
2000-05-23 05:03:05 +04:00
if (!strncmp(p, "START", strlen("START"))) {
p = rf_find_white(p);
p = rf_find_non_white(p, 0);
2000-05-23 05:03:05 +04:00
if (!strncmp(p, string, strlen(string)))
return 0;
2000-05-23 05:03:05 +04:00
}
}
}
/* reads from file fp into buf until it finds an interesting line */
static int
rf_get_next_nonblank_line(char *buf, int len, FILE *fp, const char *errmsg)
{
2000-05-23 05:03:05 +04:00
char *p;
size_t l;
2000-05-23 05:03:05 +04:00
while (fgets(buf, len, fp) != NULL) {
p = rf_find_non_white(buf, 0);
2000-05-23 05:03:05 +04:00
if (*p == '\n' || *p == '\0' || *p == '#')
continue;
l = strlen(buf);
while (l > 0 && (buf[--l] == ' ' || buf[l] == '\n'))
buf[l] = '\0';
return 0;
2000-05-23 05:03:05 +04:00
}
if (errmsg)
warnx("%s", errmsg);
return 1;
}
2000-05-23 05:03:05 +04:00
/*
* Allocates an array for the spare table, and initializes it from a file.
* In the user-level version, this is called when recon is initiated.
* When/if I move recon into the kernel, there'll be a daemon that does
* an ioctl into raidframe which will block until a spare table is needed.
* When it returns, it will read a spare table from the file system,
* pass it into the kernel via a different ioctl, and then block again
* on the original ioctl.
*
* This is specific to the declustered layout, but doesn't belong in
* rf_decluster.c because it uses stuff that can't be compiled into
* the kernel, and it needs to be compiled into the user-level sparemap daemon.
*/
2000-05-23 05:03:05 +04:00
void *
rf_ReadSpareTable(RF_SparetWait_t *req, char *fname)
{
2000-05-23 05:03:05 +04:00
int i, j, numFound, linecount, tableNum, tupleNum,
spareDisk, spareBlkOffset;
char buf[BUFSIZ], targString[BUFSIZ], errString[BUFSIZ];
2000-05-23 05:03:05 +04:00
RF_SpareTableEntry_t **table;
FILE *fp = NULL;
size_t len;
2000-05-23 05:03:05 +04:00
/* allocate and initialize the table */
table = calloc(req->TablesPerSpareRegion, sizeof(*table));
if (table == NULL) {
warn("%s: Unable to allocate table", __func__);
return NULL;
}
2000-05-23 05:03:05 +04:00
for (i = 0; i < req->TablesPerSpareRegion; i++) {
table[i] = calloc(req->BlocksPerTable, sizeof(**table));
if (table[i] == NULL) {
warn("%s: Unable to allocate table:%d", __func__, i);
goto out;
}
2000-05-23 05:03:05 +04:00
for (j = 0; j < req->BlocksPerTable; j++)
table[i][j].spareDisk =
table[i][j].spareBlockOffsetInSUs = -1;
}
/* 2. open sparemap file, sanity check */
if ((fp = fopen(fname, "r")) == NULL) {
warn("%s: Can't open sparemap file %s", __func__, fname);
goto out;
2000-05-23 05:03:05 +04:00
}
if (rf_get_next_nonblank_line(buf, 1024, fp,
"Invalid sparemap file: can't find header line"))
goto out;
len = strlen(buf);
if (len != 0 && buf[len - 1] == '\n')
buf[len - 1] = '\0';
2000-05-23 05:03:05 +04:00
2003-07-13 11:37:02 +04:00
snprintf(targString, sizeof(targString), "fdisk %d\n", req->fcol);
snprintf(errString, sizeof(errString),
"Invalid sparemap file: Can't find \"fdisk %d\" line", req->fcol);
for (;;) {
rf_get_next_nonblank_line(buf, sizeof(buf), fp, errString);
2000-05-23 05:03:05 +04:00
if (!strncmp(buf, targString, strlen(targString)))
break;
}
/* no more blank lines or comments allowed now */
linecount = req->TablesPerSpareRegion * req->TableDepthInPUs;
for (i = 0; i < linecount; i++) {
char linebuf[BUFSIZ];
if (fgets(linebuf, BUFSIZ, fp) == NULL) {
2010-01-27 21:34:02 +03:00
warnx("Sparemap file prematurely exhausted after %d "
"of %d lines", i, linecount);
goto out;
2000-05-23 05:03:05 +04:00
}
numFound = sscanf(linebuf, " %d %d %d %d", &tableNum, &tupleNum,
&spareDisk, &spareBlkOffset);
if (numFound != 4) {
warnx("Sparemap file format error - "
"line %d of %d lines",
i + 1, linecount);
goto out;
}
2000-05-23 05:03:05 +04:00
table[tableNum][tupleNum].spareDisk = spareDisk;
table[tableNum][tupleNum].spareBlockOffsetInSUs =
spareBlkOffset * req->SUsPerPU;
}
fclose(fp);
return (void *) table;
out:
if (fp)
fclose(fp);
for (i = 0; i < req->TablesPerSpareRegion; i++)
free(table[i]);
free(table);
return NULL;
}