2816 lines
59 KiB
C
2816 lines
59 KiB
C
#ident "irix/cmd/mkplib.c: $Revision: 1.29 $"
|
|
|
|
/*
|
|
* mkplib.c
|
|
*
|
|
* partition config utility library.
|
|
*
|
|
*/
|
|
|
|
#define SN0 1
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
#include <unistd.h>
|
|
#include <sys/conf.h>
|
|
#include <sys/syssgi.h>
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/SN/router.h>
|
|
#include <sys/SN/klpart.h>
|
|
#include <sys/SN/SN0/sn0drv.h>
|
|
|
|
#include <sys/un.h>
|
|
#include <sys/socket.h>
|
|
#include <stdarg.h>
|
|
#include <syslog.h>
|
|
#include <netinet/in.h>
|
|
#include <netdb.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include "mkpart.h"
|
|
#include "mkpbe.h"
|
|
#include "mkprou.h"
|
|
#include "mkpd.h"
|
|
|
|
int debug ;
|
|
int force_option ;
|
|
extern int errno ;
|
|
static part_ipaddr_t part_ipaddr[MAX_PARTITION_PER_SYSTEM] ;
|
|
|
|
valid_config_t valid_config[MAX_TOTAL_MODULES] ;
|
|
valid_config_t *vc_hdr_p ;
|
|
|
|
extern void dump_sys_rmap(sys_rou_map_t *) ;
|
|
extern int check_numbers(partcfg_t *, partcfg_t *, char *) ;
|
|
extern int check_contiguous(sys_rou_map_t *, partcfg_t *, char *, int) ;
|
|
extern int check_interconn(sys_rou_map_t *, partcfg_t *, char *, int) ;
|
|
extern int is_metarouter(rou_map_t *) ;
|
|
|
|
static int lock_all_part(becmd_t *, char *) ;
|
|
static int unlock_all_part(becmd_t *, char *, int) ;
|
|
static int is_my_act_part(partcfg_t *, partcfg_t *, partid_t) ;
|
|
static int is_xpc_up(partid_t) ;
|
|
static int meta_routers_present(void) ;
|
|
static int count_partitions(partcfg_t *pc) ;
|
|
static int check_hub_version(void) ;
|
|
static void check_for_partid0(partcfg_t *) ;
|
|
|
|
/* separator string for parsing */
|
|
|
|
char *sep = " ,:=\n" ;
|
|
|
|
/* keywords in cfgfile */
|
|
|
|
char *file_keyw[] = {
|
|
#define FKEYW_PARTITION 0
|
|
"partition",
|
|
#define FKEYW_MODULE 1
|
|
"module",
|
|
NULL
|
|
} ;
|
|
|
|
char *shutdown_self_msg =
|
|
"Shutting down current partition to re-configure ...\n" ;
|
|
|
|
char *exit_now_msg =
|
|
"Exiting the command now.\n" ;
|
|
|
|
/*
|
|
* lib err msgs
|
|
*/
|
|
char *msglib[] = {
|
|
#define MSG_MEM_ALLOC 0
|
|
"Cannot allocate any more Memory\n",
|
|
#define MSG_MOD_EXCEED_LIMIT 1
|
|
"%d Modules on Partition %d exceeds limit."
|
|
" Check cfgfile or Command line.\n",
|
|
#define MSG_LIB_SYNTAX_ERROR 2
|
|
"Syntax error.\n",
|
|
#define MSG_PARTIAL_SYNTAX_ERROR 3
|
|
"Warning: Ignoring syntax error in part of command line.\n",
|
|
#define MSG_NO_PARTITIONS 4
|
|
"Machine not partitioned.\n",
|
|
#define MSG_INVALID_CONFIG 5
|
|
"Invalid Configuration specified.\n",
|
|
#define MSG_REMOTE_EADDR 6
|
|
"Unable to get remote addr. Check remote daemon.\n",
|
|
#define MSG_REXEC_FAILED 7
|
|
"Cannot run remote command on partition %d. Config unchanged.\n",
|
|
#define MSG_LOCK_ERR 8
|
|
"Cannot lock partition %d. Try later.\n",
|
|
#define MSG_UNLOCK_ERR 9
|
|
"Cannot unlock partition %d. Use -F option next time.\n",
|
|
#define MSG_ROUMAP_ERR 10
|
|
"Invalid router map on partition %d.\n"\
|
|
"Please do a manual check of craylink connectivity and use -F \n"\
|
|
"option to override sanity check.\n",
|
|
#define MSG_ALL_MODULE 11
|
|
"Module %d is in partition %d, which is also a new partition.\n",
|
|
#define MSG_ZERO_ROUTER 12
|
|
"Failed to obtain proper router map info from Partition %d.\n"\
|
|
"Please do a manual check of craylink connectivity and use -F \n"\
|
|
"option to override sanity check.\n",
|
|
NULL
|
|
} ;
|
|
|
|
/*
|
|
* partcfg data structure support routines.
|
|
*/
|
|
|
|
static partcfg_t *
|
|
partcfgInit(partcfg_t *pc, int nmods)
|
|
{
|
|
int i ;
|
|
|
|
if (pc) {
|
|
partcfgNext(pc) = NULL ;
|
|
partcfgId(pc) = INVALID_PARTID ;
|
|
for (i = 0; i < nmods; i++)
|
|
partcfgModuleId(pc, i) = 0 ;
|
|
partcfgNumMods(pc) = 0 ;
|
|
partcfgModsSize(pc) = nmods ;
|
|
}
|
|
return pc ;
|
|
}
|
|
|
|
partcfg_t *
|
|
partcfgCreate(int nmods)
|
|
{
|
|
partcfg_t *pc ;
|
|
|
|
if (pc = (partcfg_t *)malloc(sizeof(partcfg_t))) {
|
|
if (!(partcfgModules(pc) =
|
|
(moduleid_t *)malloc(nmods * sizeof(moduleid_t)))) {
|
|
free(pc) ;
|
|
return NULL ;
|
|
}
|
|
partcfgInit(pc, nmods) ;
|
|
}
|
|
|
|
return pc ;
|
|
}
|
|
|
|
/*
|
|
* Free the linked list recursively.
|
|
*/
|
|
|
|
void
|
|
partcfgFree(partcfg_t *pc)
|
|
{
|
|
if (partcfgModules(pc))
|
|
free(partcfgModules(pc)) ;
|
|
free(pc) ;
|
|
}
|
|
|
|
void
|
|
partcfgFreeList(partcfg_t *pc)
|
|
{
|
|
if (pc) {
|
|
if (partcfgNext(pc))
|
|
partcfgFreeList(partcfgNext(pc)) ;
|
|
partcfgFree(pc) ;
|
|
}
|
|
}
|
|
|
|
static void
|
|
partcfgInsertList(partcfg_t **pch, partcfg_t *pc)
|
|
{
|
|
if (pc)
|
|
partcfgNext(pc) = *pch ;
|
|
*pch = pc ;
|
|
}
|
|
|
|
void
|
|
partcfgDump(partcfg_t *pc)
|
|
{
|
|
int i ;
|
|
|
|
if (!pc)
|
|
return ;
|
|
|
|
printf(" partition: %d = module: ", partcfgId(pc)) ;
|
|
for (i = 0; i < partcfgNumMods(pc); i++)
|
|
printf("%d ", partcfgModuleId(pc, i)) ;
|
|
printf("\n") ;
|
|
}
|
|
|
|
void
|
|
partcfgDumpList(partcfg_t *pch)
|
|
{
|
|
partcfg_t *pc = pch ;
|
|
|
|
while (pc) {
|
|
partcfgDump(pc) ;
|
|
pc = partcfgNext(pc) ;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Parsing support.
|
|
*/
|
|
|
|
/* Is the given string, full of digits only? */
|
|
|
|
static int
|
|
isnumeric(char *s)
|
|
{
|
|
char *st = s ;
|
|
|
|
if (st == NULL)
|
|
return 0 ;
|
|
|
|
while (*st)
|
|
if (!isdigit(*st++))
|
|
return 0 ;
|
|
return 1 ;
|
|
}
|
|
|
|
/*
|
|
* get_part_from_string
|
|
*
|
|
* get partition number from arg string.
|
|
* It assumes that strtok pointer is initted.
|
|
* It is called in a loop in parse_string.
|
|
* Checks if the string is made up of digits only.
|
|
* Returns the integer value of the string.
|
|
*/
|
|
|
|
static int
|
|
get_part_from_string(void)
|
|
{
|
|
char *tmp;
|
|
|
|
tmp = strtok(NULL, sep) ;
|
|
if (isnumeric(tmp))
|
|
return(atoi(tmp)) ;
|
|
return -1 ;
|
|
}
|
|
|
|
/* Calculate offset of next string while parsing using strtok.
|
|
* This macro is local to parse_string.
|
|
*/
|
|
#define NXT_STR_PTR \
|
|
(str + ((__psunsigned_t)tok_ptr - (__psunsigned_t)tok_buf))
|
|
|
|
/*
|
|
* parse_string
|
|
*
|
|
* Parse a string of the form
|
|
* partition : <pno> = module : <modnum> <modnum> [,] <modnum>
|
|
* Assign partition and module values to partcfg struct.
|
|
*
|
|
* Input:
|
|
*
|
|
* One line of a config file, as given above or a concatenation
|
|
* of many such lines, built from the command line.
|
|
*
|
|
* Return :
|
|
*
|
|
* Pointer to the next character to be parsed. If the input
|
|
* string were from a file, this would be the \0 at the end
|
|
* of the line. If this is a concatenated string, the return
|
|
* value would be the pointer to next logical part of the
|
|
* string. A logical part is composed of partition and module
|
|
* keywords and a string of module numbers.
|
|
* This routine can be called in a loop to parse the concatenated
|
|
* string.
|
|
* status gets the SUCCESS of FAILURE of parsing.
|
|
*/
|
|
|
|
static char *
|
|
parse_string(char *str, partcfg_t *pc, int *status, char *errbuf)
|
|
{
|
|
int mod_indx = 0, tmp = 0,
|
|
keyw_indx = 0 ;
|
|
char tok_buf[MAX_CMDLINE_LEN], *tok_ptr = tok_buf ;
|
|
int mod_keyw_found = 0, mod_num_found = 0 ;
|
|
int par_keyw_found = 0, par_num_found = 0 ;
|
|
moduleid_t *m = partcfgModules(pc) ;
|
|
|
|
if ((!str) || (!pc) || (!status))
|
|
return NULL ;
|
|
*status = -1 ;
|
|
if (errbuf)
|
|
*errbuf = 0 ;
|
|
|
|
/* Make local copy and setup strtok buffer */
|
|
|
|
if (strlen(str) >= sizeof(tok_buf))
|
|
return NULL ;
|
|
strcpy(tok_ptr, str) ;
|
|
tok_ptr = strtok(tok_ptr, sep) ;
|
|
|
|
/* parse every token in a loop */
|
|
|
|
while (tok_ptr) {
|
|
db_printf("%s ", tok_ptr) ;
|
|
|
|
/* check if we got a keyword */
|
|
|
|
keyw_indx = get_string_index(file_keyw, tok_ptr) ;
|
|
|
|
switch (keyw_indx) {
|
|
case FKEYW_PARTITION:
|
|
|
|
/* If we already got a partition keyw
|
|
* we are ready to parse the next string
|
|
*/
|
|
if (par_keyw_found)
|
|
goto keyw_repeat ;
|
|
par_keyw_found = 1 ;
|
|
|
|
/* uses strtok to get next token */
|
|
if ((partcfgId(pc) =
|
|
get_part_from_string()) >= 0)
|
|
par_num_found = 1 ;
|
|
break ;
|
|
|
|
case FKEYW_MODULE:
|
|
|
|
/* If we already got a partition keyw
|
|
* we are ready to parse the next string
|
|
*/
|
|
if (mod_keyw_found)
|
|
goto keyw_repeat ;
|
|
mod_keyw_found = 1 ;
|
|
break ;
|
|
|
|
default:
|
|
|
|
/* These should be module numbers.
|
|
* check if it is gone beyond limit
|
|
* and if the value looks good.
|
|
*/
|
|
if (partcfgModLimit(pc, mod_indx)) {
|
|
if (!isnumeric(tok_ptr)) {
|
|
strcpy(errbuf,
|
|
msglib[MSG_LIB_SYNTAX_ERROR]) ;
|
|
return NULL ;
|
|
}
|
|
m[mod_indx] = tmp = atoi(tok_ptr) ;
|
|
} else {
|
|
sprintf(errbuf,
|
|
msglib[MSG_MOD_EXCEED_LIMIT],
|
|
mod_indx, partcfgId(pc)) ;
|
|
return NULL ;
|
|
}
|
|
|
|
if (!tmp) /* must be another string */
|
|
goto keyw_repeat ;
|
|
else
|
|
mod_num_found = 1 ;
|
|
|
|
partcfgNumMods(pc) = ++mod_indx ;
|
|
break ;
|
|
}
|
|
tok_ptr = strtok(NULL, sep) ; /* Get next token */
|
|
}
|
|
|
|
keyw_repeat:
|
|
/* Was the last sequence logically complete? */
|
|
if (par_keyw_found && par_num_found &&
|
|
mod_keyw_found && mod_num_found)
|
|
*status = 1 ;
|
|
else
|
|
strcpy(errbuf, msglib[MSG_LIB_SYNTAX_ERROR]) ;
|
|
|
|
db_printf("\n") ;
|
|
|
|
/* Still got a valid token? Return ptr to next logical string */
|
|
if (tok_ptr)
|
|
return(NXT_STR_PTR) ;
|
|
else /* Must be a single logical line, return ptr to the \0 */
|
|
return(str+strlen(str)) ;
|
|
}
|
|
|
|
/*
|
|
* parse_file
|
|
*
|
|
* parse the lines in the cfgfile
|
|
*
|
|
* Return:
|
|
*
|
|
* ptr to a linked list of partcfg_t which contains info
|
|
* about all lines.
|
|
* NULL, if file has no valid lines in it.
|
|
*/
|
|
|
|
partcfg_t *
|
|
parse_file(FILE *fp, char *errbuf)
|
|
{
|
|
char buf[MAX_CMDLINE_LEN] ;
|
|
char *bufp ;
|
|
partcfg_t *pc = NULL, *pch= NULL ;
|
|
int status ;
|
|
|
|
if (errbuf)
|
|
*errbuf = 0 ;
|
|
|
|
while (bufp = fgets(buf, MAX_CMDLINE_LEN, fp)) {
|
|
|
|
/* Skip comments */
|
|
|
|
if ((*bufp == '#') || (*bufp == '*'))
|
|
continue ;
|
|
|
|
pc = partcfgCreate(MAX_MODS_PER_PART) ;
|
|
if (pc == NULL) {
|
|
if (errbuf)
|
|
strcpy(errbuf, msglib[MSG_MEM_ALLOC]) ;
|
|
goto fail;
|
|
}
|
|
parse_string(bufp, pc, &status, errbuf) ;
|
|
if (status < 0) {
|
|
partcfgFree(pc) ;
|
|
pc = NULL ;
|
|
goto fail ;
|
|
}
|
|
partcfgInsertList(&pch, pc) ;
|
|
}
|
|
fail:
|
|
return pch;
|
|
}
|
|
|
|
/*
|
|
* parse_multi_string
|
|
*
|
|
* parse a string which is concactenated strings in a file.
|
|
*/
|
|
|
|
partcfg_t *
|
|
parse_multi_string(char *str, char *errbuf)
|
|
{
|
|
char *cp = str ;
|
|
partcfg_t *pc = NULL, *pch= NULL ;
|
|
int status ;
|
|
|
|
if (errbuf)
|
|
*errbuf = 0 ;
|
|
|
|
/* As long as cp does not point to a end of string \0 ... */
|
|
while ((cp) && *cp) {
|
|
pc = partcfgCreate(MAX_MODS_PER_PART) ;
|
|
if (pc == NULL) {
|
|
if (errbuf)
|
|
strcpy(errbuf, msglib[MSG_MEM_ALLOC]) ;
|
|
goto fail;
|
|
}
|
|
/* cp should point to the next logical part of the string. */
|
|
cp = parse_string(cp, pc, &status, errbuf) ;
|
|
if (status < 0) {
|
|
partcfgFree(pc) ;
|
|
pc = NULL ;
|
|
|
|
/* We have found atleast 1 logical element */
|
|
|
|
if (pch)
|
|
fprintf(stderr, msglib[MSG_PARTIAL_SYNTAX_ERROR]) ;
|
|
|
|
goto fail ;
|
|
}
|
|
partcfgInsertList(&pch, pc) ;
|
|
}
|
|
fail:
|
|
return pch;
|
|
}
|
|
|
|
/*
|
|
* cmd_to_file_string
|
|
*
|
|
* convert command line to a string
|
|
* that looks like a concatenation of
|
|
* strings from the cfgfile.
|
|
*/
|
|
|
|
char *
|
|
cmd_to_file_string(int argc, char **argv, int argi)
|
|
{
|
|
char *fsp ;
|
|
char local_buf[MAX_KEYW_LEN] ;
|
|
|
|
fsp = (char *)malloc(MAX_CMDLINE_LEN) ;
|
|
if (fsp == NULL) {
|
|
goto fail ;
|
|
}
|
|
*fsp = 0 ;
|
|
while (argi < argc) {
|
|
*local_buf = 0 ;
|
|
if (!strcmp(argv[argi], "-p")) {
|
|
strcat(local_buf, file_keyw[FKEYW_PARTITION]) ;
|
|
strcat(local_buf, " : ") ;
|
|
} else if (!strcmp(argv[argi], "-m")) {
|
|
strcat(local_buf, file_keyw[FKEYW_MODULE]) ;
|
|
strcat(local_buf, " : ") ;
|
|
} else {
|
|
strcat(local_buf, argv[argi]) ;
|
|
strcat(local_buf, " , ") ;
|
|
}
|
|
if ((strlen(fsp) + strlen(local_buf)) < MAX_CMDLINE_LEN)
|
|
strcat(fsp, local_buf) ;
|
|
else
|
|
return fsp ;
|
|
argi++ ;
|
|
}
|
|
db_printf("make_cline_string: %s\n", fsp) ;
|
|
fail:
|
|
return fsp ;
|
|
}
|
|
|
|
/*
|
|
* Search for a string str in the given table tab
|
|
* and return the index. tab should be an array of
|
|
* strings.
|
|
* Returns -1 if failure, index of string str in
|
|
* array tab if success.
|
|
*/
|
|
|
|
int
|
|
get_string_index(char **tab, char *str)
|
|
{
|
|
int i = 0 ;
|
|
char *cp ;
|
|
|
|
cp = tab[i] ;
|
|
while(cp) {
|
|
if (!strncmp(cp, str, strlen(cp)))
|
|
return i ;
|
|
cp = tab[++i] ;
|
|
}
|
|
return -1 ;
|
|
}
|
|
|
|
/*
|
|
* Support for mkpart -l option
|
|
*/
|
|
|
|
/* Search for a module in the given partcfg_t element. */
|
|
|
|
static int
|
|
partcfgLookupModule(partcfg_t *pc, moduleid_t m)
|
|
{
|
|
int i ;
|
|
for (i = 0; i < partcfgNumMods(pc) ; i++)
|
|
if (partcfgModuleId(pc, i) == m)
|
|
return 1 ;
|
|
return -1 ;
|
|
}
|
|
|
|
/*
|
|
* Search for partition p in the partcfg_t linked list.
|
|
* If moduleid < 0 search for partition only.
|
|
* If partid < 0 search for moduleid only.
|
|
*/
|
|
|
|
partcfg_t *
|
|
partcfgLookupPart(partcfg_t *pch, partid_t p, moduleid_t m)
|
|
{
|
|
partcfg_t *pc = pch;
|
|
|
|
while (pc) {
|
|
if ((m < 0) && (partcfgId(pc) == p))
|
|
return pc ;
|
|
if ((p < 0) && (partcfgLookupModule(pc, m) >= 0))
|
|
return pc ;
|
|
pc = partcfgNext(pc) ;
|
|
}
|
|
return NULL ;
|
|
}
|
|
|
|
/*
|
|
* addPnToPcList
|
|
* Add the new module m to partition p.
|
|
* If partition is new, create it first.
|
|
*/
|
|
|
|
partcfg_t *
|
|
addPnToPcList(partcfg_t **pch, partid_t p, moduleid_t m)
|
|
{
|
|
partcfg_t *pc ;
|
|
|
|
if ((pc = partcfgLookupPart(*pch, p, (moduleid_t) -1)) == NULL) {
|
|
pc = partcfgCreate(MAX_MODS_PER_PART) ;
|
|
partcfgId(pc) = p ;
|
|
partcfgInsertList(pch, pc) ;
|
|
}
|
|
|
|
if (partcfgLookupModule(pc, m) < 0) {
|
|
partcfgModuleId(pc, partcfgNumModsIncr(pc)) = m ;
|
|
}
|
|
|
|
return(*pch) ;
|
|
}
|
|
|
|
partcfg_t *
|
|
pnToPcList(pn_t *pnh, int cnt)
|
|
{
|
|
int i ;
|
|
pn_t *pn = pnh ;
|
|
partcfg_t *pch= NULL ;
|
|
int lcnt = (cnt > MAX_MODS_PER_PART) ?
|
|
MAX_MODS_PER_PART : cnt ;
|
|
|
|
for (i = 0; i < lcnt ; i++, pn++) {
|
|
if ( !IS_PARTID_VALID(pn->pn_partid) ||
|
|
(pn->pn_state != KLP_STATE_KERNEL) ||
|
|
/* There is no point in advertising a partition
|
|
* if its XPC is not up. The only way to do it
|
|
* now is to check if its admin file is created.
|
|
*/
|
|
(!is_xpc_up(pn->pn_partid)))
|
|
continue ;
|
|
addPnToPcList(&pch, pn->pn_partid, pn->pn_module) ;
|
|
}
|
|
return pch;
|
|
}
|
|
|
|
/*
|
|
* part_scan
|
|
*
|
|
* Build a list of all partitions discovered by the kernel
|
|
* and the modules that it consists of.
|
|
*/
|
|
|
|
partcfg_t *
|
|
part_scan(int dump_flag, char *errbuf)
|
|
{
|
|
partcfg_t *pc = NULL ;
|
|
pn_t *pn ;
|
|
int cnt = -1 ;
|
|
|
|
if (errbuf)
|
|
*errbuf = 0 ;
|
|
|
|
if (!(pn = (pn_t *)malloc(MAX_PN * sizeof(pn_t))))
|
|
return NULL ;
|
|
|
|
cnt = syssgi( SGI_PART_OPERATIONS,
|
|
SYSSGI_PARTOP_NODEMAP, MAX_PN, pn) ;
|
|
|
|
if (cnt < 0)
|
|
return NULL ;
|
|
|
|
pc = pnToPcList(pn, cnt) ;
|
|
|
|
if (debug || dump_flag) {
|
|
printf("Current partition config ... \n") ;
|
|
partcfgDumpList(pc) ;
|
|
printf("\n") ;
|
|
}
|
|
|
|
return(pc) ;
|
|
}
|
|
|
|
int
|
|
part_list(char *errbuf)
|
|
{
|
|
partcfg_t *pc ;
|
|
|
|
pc = part_scan(0, errbuf) ;
|
|
if (!pc) {
|
|
strcpy(errbuf, msglib[MSG_NO_PARTITIONS]) ;
|
|
return -1 ;
|
|
}
|
|
|
|
partcfgDumpList(pc) ;
|
|
|
|
partcfgFreeList(pc) ;
|
|
|
|
return 1 ;
|
|
}
|
|
|
|
int
|
|
part_reinit(char *errbuf)
|
|
{
|
|
partcfg_t *pc_act, *pc ;
|
|
int i ;
|
|
int mod_indx ;
|
|
moduleid_t *m ;
|
|
|
|
if (!yes_or_no("Reset all partition ids to 0? [y/n]: "))
|
|
return 1 ;
|
|
|
|
pc_act = part_scan(0, errbuf) ;
|
|
if (!pc_act) {
|
|
strcpy(errbuf, msglib[MSG_NO_PARTITIONS]) ;
|
|
return -1 ;
|
|
}
|
|
|
|
pc = partcfgCreate(MAX_MODS_PER_PART) ;
|
|
if (pc == NULL) {
|
|
if (errbuf)
|
|
strcpy(errbuf, msglib[MSG_MEM_ALLOC]) ;
|
|
return -1 ;
|
|
}
|
|
|
|
mod_indx = 0 ;
|
|
m = partcfgModules(pc) ;
|
|
partcfgId(pc) = 0 ;
|
|
while (pc_act) {
|
|
for (i=0; i < partcfgNumMods(pc_act); i++) {
|
|
m[mod_indx] = partcfgModuleId(pc_act, i) ;
|
|
partcfgNumMods(pc) = ++mod_indx ;
|
|
}
|
|
pc_act = partcfgNext(pc_act) ;
|
|
}
|
|
|
|
if (debug)
|
|
partcfgDump(pc) ;
|
|
|
|
part_make(pc, errbuf) ;
|
|
|
|
return 1 ;
|
|
|
|
}
|
|
|
|
/*
|
|
* mkpbe data structure becmd_t support.
|
|
*/
|
|
|
|
void
|
|
becmdDump(becmd_t *bec)
|
|
{
|
|
printf(" part %d:", bec->bec_partid) ;
|
|
printf(" %s\n", bec->bec_becl) ;
|
|
}
|
|
|
|
void
|
|
becmdDumpList(becmd_t *bech)
|
|
{
|
|
becmd_t *bec = bech ;
|
|
|
|
while (bec) {
|
|
becmdDump(bec) ;
|
|
bec = bec->bec_next ;
|
|
}
|
|
}
|
|
|
|
static becmd_t *
|
|
becmdInit(becmd_t *bec, int len, char *cmd)
|
|
{
|
|
if (bec) {
|
|
bec->bec_next = NULL ;
|
|
bec->bec_partid = INVALID_PARTID ;
|
|
bec->bec_becl[0] = 0 ;
|
|
if (cmd) ;
|
|
strcpy(bec->bec_becl, cmd) ;
|
|
bec->bec_becl_len = len ;
|
|
|
|
bec->bec_full_cl[0] = 0 ;
|
|
strcpy(bec->bec_full_cl, RSHCMD_NAME) ;
|
|
bec->bec_becl_len = len + 256 ;
|
|
}
|
|
|
|
return bec ;
|
|
}
|
|
|
|
becmd_t *
|
|
becmdCreate(int cl_len, char *cmd)
|
|
{
|
|
becmd_t *bec ;
|
|
|
|
if (cl_len < 0)
|
|
return NULL ;
|
|
|
|
if (bec = (becmd_t *)malloc(sizeof(becmd_t))) {
|
|
if (((bec->bec_becl = (char *)malloc(cl_len)) == NULL) ||
|
|
((bec->bec_full_cl = (char *)malloc(cl_len+256)) == NULL)) {
|
|
if (bec->bec_becl)
|
|
free(bec->bec_becl) ;
|
|
free(bec) ;
|
|
return NULL ;
|
|
}
|
|
becmdInit(bec, cl_len, cmd) ;
|
|
}
|
|
return bec ;
|
|
}
|
|
|
|
/* Free list recursively */
|
|
|
|
void
|
|
becmdFree(becmd_t *bec)
|
|
{
|
|
if (bec->bec_becl)
|
|
free(bec->bec_becl) ;
|
|
if (bec->bec_full_cl)
|
|
free(bec->bec_full_cl) ;
|
|
free(bec) ;
|
|
}
|
|
|
|
void
|
|
becmdFreeList(becmd_t *bec)
|
|
{
|
|
if (bec) {
|
|
if (bec->bec_next)
|
|
becmdFreeList(bec->bec_next) ;
|
|
becmdFree(bec) ;
|
|
}
|
|
}
|
|
|
|
static void
|
|
becmdInsertList(becmd_t **bech, becmd_t *bec)
|
|
{
|
|
if (bec)
|
|
bec->bec_next = *bech ;
|
|
*bech = bec ;
|
|
}
|
|
|
|
becmd_t *
|
|
becmdLookupList(becmd_t *bech, partid_t p)
|
|
{
|
|
becmd_t *bec = bech ;
|
|
|
|
while (bec) {
|
|
if (bec->bec_partid == p)
|
|
return bec ;
|
|
bec = bec->bec_next ;
|
|
}
|
|
|
|
return NULL ;
|
|
}
|
|
|
|
becmd_t *
|
|
becmdAllocate(becmd_t **bech, partid_t p, char *cmd)
|
|
{
|
|
becmd_t *bec ;
|
|
|
|
if (!(bec = becmdLookupList(*bech, p))) {
|
|
bec = becmdCreate(MAX_BECMD_LEN, cmd) ;
|
|
if (bec == NULL)
|
|
return NULL ;
|
|
becmdInsertList(bech, bec) ;
|
|
}
|
|
|
|
return bec ;
|
|
}
|
|
|
|
void
|
|
becmdAddModPart(becmd_t *bec, moduleid_t m, partid_t p)
|
|
{
|
|
char tmpbuf[MAX_MODPAR_LEN] ;
|
|
|
|
sprintf(tmpbuf, "%d %d ", m, p) ;
|
|
if ((strlen(tmpbuf) + strlen(bec->bec_becl)) > bec->bec_becl_len)
|
|
return ;
|
|
strcat(bec->bec_becl, tmpbuf) ;
|
|
}
|
|
|
|
/*
|
|
* Sanity checks support.
|
|
*/
|
|
|
|
int
|
|
checkModUnique(partcfg_t *pch, int m)
|
|
{
|
|
partcfg_t *pc = pch ;
|
|
int found = 0 ;
|
|
int i ;
|
|
|
|
while (pc) {
|
|
for (i=0; i < partcfgNumMods(pc) ; i++) {
|
|
if (m == partcfgModuleId(pc, i)) {
|
|
if (!found)
|
|
found = 1 ;
|
|
else
|
|
return -1 ;
|
|
}
|
|
}
|
|
pc = partcfgNext(pc) ;
|
|
}
|
|
|
|
return 1 ;
|
|
}
|
|
|
|
/*
|
|
* Check if all module numbers are unique.
|
|
*/
|
|
int
|
|
isModNumUnique(partcfg_t *pch)
|
|
{
|
|
partcfg_t *const_pch = pch ;
|
|
partcfg_t *pc = pch ;
|
|
int i ;
|
|
|
|
while (pc) {
|
|
for (i=0; i < partcfgNumMods(pc) ; i++)
|
|
if (checkModUnique(const_pch,
|
|
partcfgModuleId(pc, i)) < 0)
|
|
return -1 ;
|
|
pc = partcfgNext(pc) ;
|
|
}
|
|
return 1 ;
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
|
|
int
|
|
partcfgValid(partcfg_t *pc, char *errbuf)
|
|
{
|
|
/* Is the partid valid? Does it have atleast 1 module */
|
|
|
|
if (!IS_PARTID_VALID(partcfgId(pc))) {
|
|
sprintf(errbuf, "Partition id %d is invalid.\n",
|
|
partcfgId(pc)) ;
|
|
return -1 ;
|
|
}
|
|
if (partcfgNumMods(pc) == 0) {
|
|
sprintf(errbuf, "Partition %d has no modules in it.\n",
|
|
partcfgId(pc)) ;
|
|
return -1 ;
|
|
}
|
|
return 1 ;
|
|
}
|
|
|
|
/*
|
|
* Check if each of the required partition and module config
|
|
* is OK. The per partition tests are yet to be determined.
|
|
*/
|
|
int
|
|
partcfgValidList(partcfg_t *pc, char *errbuf)
|
|
{
|
|
if (isModNumUnique(pc) < 0)
|
|
return -1 ;
|
|
|
|
while (pc) {
|
|
if (partcfgValid(pc, errbuf) < 0)
|
|
return -1 ;
|
|
pc = partcfgNext(pc) ;
|
|
}
|
|
return 1 ;
|
|
}
|
|
|
|
/*
|
|
* mkpd_read_req
|
|
*
|
|
* Read a request packet from fd, check for sanity.
|
|
*
|
|
* Return
|
|
*
|
|
* count of bytes needed or opcode if success.
|
|
* A -ve code indicating the place of failure.
|
|
*/
|
|
int
|
|
mkpd_read_req(int fd, mkpd_packet_t *packet, char type)
|
|
{
|
|
mkpd_cnt_t cnt ;
|
|
char *buf = (char *)packet ;
|
|
|
|
if (packet == NULL)
|
|
return -1 ;
|
|
|
|
cnt = read(fd, buf, PACKET_REQ_LEN) ;
|
|
if ((cnt != PACKET_REQ_LEN) || (packet->version != VERSION)) {
|
|
if (debug)
|
|
perror("mkpd_read_req") ;
|
|
return -2 ;
|
|
}
|
|
|
|
if (packet->ptype != type)
|
|
return -3 ;
|
|
|
|
if (packet->ptype == PACKET_TYPE_OPCODE)
|
|
return(packet->op) ;
|
|
|
|
return (packet->cnt) ;
|
|
}
|
|
|
|
/*
|
|
* get_raw_path
|
|
*
|
|
* Get the path of the raw device file to be opened for
|
|
* partid p. /hw/xplink/admin/01/partition
|
|
* Check if length of the partid field like 01 exceeds
|
|
* 2 digits. This is needed for padding the partid's ascii
|
|
* version to the number of digits used in the hwgraph path
|
|
* name of the file. The kernel just creates a 2 digit value
|
|
* for each number. This scheme breaks if we are going to
|
|
* have mixed field widths.
|
|
*/
|
|
int
|
|
get_raw_path(char *path, partid_t p)
|
|
{
|
|
char tmp[MKPD_MAX_XRAW_FNAME_LEN] ;
|
|
int len ;
|
|
int i ;
|
|
|
|
*path = 0 ;
|
|
*tmp = 0 ;
|
|
|
|
sprintf(path, "%x\000", p) ;
|
|
len = (MKPD_PART_FNAME_LEN-strlen(path)) ;
|
|
if (len < 0)
|
|
return -1 ;
|
|
|
|
for (i=0;i<len;i++)
|
|
tmp[i] = '0';
|
|
tmp[i] = 0 ;
|
|
|
|
strcat(tmp, path) ;
|
|
|
|
strcpy(path, MKPD_XPLINK_RAW_PATH) ;
|
|
strcat(path, tmp) ;
|
|
strcat(path, MKPD_XPLINK_RAW_PATH_1) ;
|
|
|
|
return 1 ;
|
|
}
|
|
|
|
/*
|
|
* get_connect_socket
|
|
*
|
|
* create a socket and try to connect to it. This is for the
|
|
* client mkpart.
|
|
*/
|
|
int
|
|
get_connect_socket(void)
|
|
{
|
|
int sock = -1 ;
|
|
struct sockaddr_un sname ;
|
|
|
|
sock = socket(PF_UNIX, SOCK_STREAM, 0) ;
|
|
if (sock < 0) {
|
|
if (debug) perror("socket") ;
|
|
goto get_conn_done ;
|
|
}
|
|
|
|
sname.sun_family = AF_UNIX ;
|
|
strcpy(sname.sun_path, MKPD_SOCKET_NAME) ;
|
|
|
|
if (connect(sock, (caddr_t)&sname, sizeof(sname)) < 0) {
|
|
if (debug) perror("connect") ;
|
|
close(sock) ;
|
|
sock = -1 ;
|
|
}
|
|
get_conn_done:
|
|
return sock ;
|
|
}
|
|
|
|
/*
|
|
* get_data_from_local
|
|
*
|
|
* The mkpart client uses this routine to contact the
|
|
* local mkpd daemon and get its work done.
|
|
*
|
|
* Parameters
|
|
*
|
|
* op opcode
|
|
* p Partition id of the target partition.
|
|
* buf buffer to receive data
|
|
* buflen length of this buffer
|
|
*/
|
|
int
|
|
get_data_from_local(char op, partid_t p, char *buf, int buflen)
|
|
{
|
|
int sock ;
|
|
mkpd_reqbuf_t req ;
|
|
mkpd_packet_t packet ;
|
|
mkpd_cnt_t cnt ;
|
|
char *tmpbuf ;
|
|
int rv = 1 ;
|
|
|
|
/* Let's go to our daemon. */
|
|
/* XXX Try to get in errbuf and print the actual reason of failure. */
|
|
|
|
if ((sock = get_connect_socket()) < 0)
|
|
return -1 ;
|
|
|
|
/*
|
|
* Prepare a request buf to the local daemon. This is different
|
|
* from the request packet that goes between daemons.
|
|
*/
|
|
|
|
req.version = VERSION ;
|
|
req.op = op ;
|
|
req.part = p ;
|
|
req.cnt = buflen ;
|
|
req.flag = force_option ;
|
|
|
|
/* Write it to the socket */
|
|
|
|
if (write(sock, &req, sizeof(mkpd_reqbuf_t)) != sizeof(mkpd_reqbuf_t)) {
|
|
rv = -2 ;
|
|
goto close_n_ret ;
|
|
}
|
|
|
|
/*
|
|
* Read back from the socket, a packet of type COUNT. This
|
|
* gives the length of the data the daemon is having for us.
|
|
*/
|
|
if ((cnt = mkpd_read_req(sock, &packet, PACKET_TYPE_COUNT)) < 0) {
|
|
db_printf("get_data_from_local: mkpd_read_req fail %d\n", cnt) ;
|
|
rv = -3 ;
|
|
goto close_n_ret ;
|
|
}
|
|
|
|
/*
|
|
* We need to pull out all the data from the daemon.
|
|
* Try to alloc a bigger buf if needed.
|
|
*/
|
|
if (cnt > buflen) {
|
|
tmpbuf = (char *)malloc(cnt) ;
|
|
if (!tmpbuf) { /* too bad, read what we can */
|
|
tmpbuf = buf ;
|
|
cnt = buflen ;
|
|
}
|
|
}
|
|
else
|
|
tmpbuf = buf ;
|
|
|
|
if (read(sock, tmpbuf, cnt) != cnt) {
|
|
db_printf("get_data_from_local: read data fail %d\n", errno) ;
|
|
rv = -4 ;
|
|
goto close_n_ret;
|
|
}
|
|
|
|
/* If we had allocated new buffer, copy data back. */
|
|
|
|
if (cnt > buflen) {
|
|
bcopy(tmpbuf, buf, buflen) ;
|
|
free(tmpbuf) ;
|
|
}
|
|
|
|
close_n_ret:
|
|
close(sock) ;
|
|
|
|
return rv ;
|
|
}
|
|
|
|
/*
|
|
* mkpbe support
|
|
*/
|
|
|
|
/*
|
|
* Convert the 4 number ipaddr to an ascii string. This is used
|
|
* to build the rexec command. rexec 192.XXXX ...
|
|
*/
|
|
|
|
void
|
|
make_ipaddr(char *ipaddr)
|
|
{
|
|
char tmp[MKPD_MAX_IPADDR_ASCII_LEN] ;
|
|
|
|
sprintf(tmp, "%d.%d.%d.%d",
|
|
ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]) ;
|
|
strcpy(ipaddr, tmp) ;
|
|
|
|
if (debug)
|
|
printf("ipaddr : %s\n", ipaddr) ;
|
|
}
|
|
|
|
/*
|
|
* Execute the mkpbe command locally. This does not need rexec.
|
|
* System will do.
|
|
*/
|
|
int
|
|
becmdExecuteLocal(becmd_t *bec)
|
|
{
|
|
if (bec) {
|
|
if (debug)
|
|
printf("system %s\n", bec->bec_becl) ;
|
|
system(bec->bec_becl) ;
|
|
}
|
|
return 1 ;
|
|
}
|
|
|
|
/*
|
|
* Execute a mkpbe command remotely.
|
|
*/
|
|
int
|
|
becmdExecute(becmd_t *bec, char *errbuf)
|
|
{
|
|
char ipaddr[MKPD_MAX_IPADDR_ASCII_LEN] ;
|
|
|
|
/* check if it is a command for the local partition. */
|
|
|
|
if (bec->bec_partid == get_my_partid()) {
|
|
becmdExecuteLocal(bec);
|
|
return 1 ;
|
|
}
|
|
|
|
/* Get the IPADDR of the remote partition. */
|
|
|
|
if ((get_data_from_local(OPCODE_GET_IPADDR,
|
|
bec->bec_partid, ipaddr, sizeof(ipaddr)) < 0)
|
|
|| (*ipaddr == 0)) {
|
|
strcpy(errbuf, msglib[MSG_REMOTE_EADDR]) ;
|
|
return -1 ;
|
|
}
|
|
|
|
/* Convert ipaddr to ascii string. */
|
|
|
|
make_ipaddr(ipaddr) ;
|
|
|
|
strncpy( part_ipaddr[bec->bec_partid].ipaddr, ipaddr,
|
|
MKPD_MAX_IPADDR_ASCII_LEN) ;
|
|
|
|
/*
|
|
* rexec the command. If rexec fails due to any reason,
|
|
* rexec itself will print an err msg. If the command
|
|
* fails at the remote end, it will send back a msg
|
|
* which is printed out by the printf below.
|
|
*/
|
|
if (rexec_mkpbe(ipaddr, bec->bec_becl, errbuf, 1) < 0) {
|
|
fprintf(stderr, "%s\n", errbuf) ;
|
|
return -1 ;
|
|
}
|
|
|
|
return 1 ;
|
|
}
|
|
|
|
void
|
|
mk_scan_mkpbe(becmd_t *bec, char *cmd)
|
|
{
|
|
strcpy(cmd, bec->bec_becl) ;
|
|
/* Insert the -s option as the becl is already setup correctly. */
|
|
cmd[17] = '-' ;
|
|
cmd[18] = 's' ;
|
|
}
|
|
|
|
/*
|
|
* becmdRexecScanLocal
|
|
*
|
|
* Run the mkpbe scan command locally.
|
|
*/
|
|
becmdRexecScanLocal(becmd_t *bec)
|
|
{
|
|
char cmd[MAX_BECMD_LEN] ;
|
|
FILE *fh ;
|
|
char buf[BUFSIZ] ;
|
|
|
|
*buf = 0 ;
|
|
if (bec) {
|
|
mk_scan_mkpbe(bec, cmd) ;
|
|
if (debug)
|
|
printf("popen %s\n", cmd) ;
|
|
if ((fh = popen(cmd, "r")) != NULL) {
|
|
fgets(buf, BUFSIZ, fh) ;
|
|
if (*buf) {
|
|
fprintf(stdout, "%s\n", (buf+1)) ;
|
|
return -1 ;
|
|
}
|
|
}
|
|
}
|
|
return 1 ;
|
|
}
|
|
|
|
/*
|
|
* becmdRexecScan
|
|
*
|
|
* Run a dummy rexec command on all partitions first.
|
|
* If one of them fails we know that the next rexec
|
|
* to the same partition is bound to fail. We will
|
|
* not be able to completely change the config. Abort
|
|
* the command, keeping the system config intact.
|
|
*/
|
|
int
|
|
becmdRexecScan(becmd_t *bec, char *errbuf, int local_flag)
|
|
{
|
|
char ipaddr[MKPD_MAX_IPADDR_ASCII_LEN] ;
|
|
char cmd[MAX_BECMD_LEN] ;
|
|
|
|
/* check if it is a command for the local partition. */
|
|
|
|
if ((bec->bec_partid == get_my_partid()) || (local_flag))
|
|
return(becmdRexecScanLocal(bec)) ;
|
|
|
|
if ((get_data_from_local(OPCODE_GET_IPADDR,
|
|
bec->bec_partid, ipaddr, sizeof(ipaddr)) < 0)
|
|
|| (*ipaddr == 0)) {
|
|
strcpy(errbuf, msglib[MSG_REMOTE_EADDR]) ;
|
|
return -1 ;
|
|
}
|
|
|
|
make_ipaddr(ipaddr) ;
|
|
|
|
/*
|
|
* Remote exec the mkpbe cmd, with the -s arg. -s will
|
|
* just scan all the modules and try to read the NVRAM
|
|
* on them. If any one of them fails, the scan is deemed
|
|
* to be a failure.
|
|
*/
|
|
|
|
mk_scan_mkpbe(bec, cmd) ;
|
|
|
|
if (rexec_mkpbe(ipaddr, cmd, errbuf, 1) < 0) {
|
|
fprintf(stderr, "%s\n", errbuf) ;
|
|
return -1 ;
|
|
}
|
|
|
|
return 1 ;
|
|
}
|
|
|
|
/*
|
|
* becmdExecuteList
|
|
*
|
|
* Execute the given commands on the respective partitions
|
|
* as specified in the becmd_t list.
|
|
*/
|
|
int
|
|
becmdExecuteList(becmd_t *bech, char *errbuf, int local_flag)
|
|
{
|
|
becmd_t *bec = bech ;
|
|
int rv = 1 ;
|
|
int errmsg_flag = 1 ; /* Yes on error reporting */
|
|
|
|
/*
|
|
* Try to lock all partitions. If any one of them fail,
|
|
* unlock all of them. Supress error reporting in unlock.
|
|
* We are bound to encounter some errors that have to be
|
|
* ignored.
|
|
*/
|
|
|
|
if ((!force_option) && (!local_flag) &&
|
|
(lock_all_part(bech, errbuf) < 0)) {
|
|
rv = -1 ;
|
|
errmsg_flag = 0 ; /* supress unlock err msg */
|
|
goto unlock_ret ;
|
|
}
|
|
|
|
/*
|
|
* Scan all the partitions to see if rexec works
|
|
* successfully before running the actual command.
|
|
* If rexec fails now, we retain the old state of
|
|
* the partitions.
|
|
*/
|
|
while (bec) {
|
|
if (becmdRexecScan(bec, errbuf, local_flag) < 0) {
|
|
if (!*errbuf)
|
|
sprintf(errbuf, msglib[MSG_REXEC_FAILED],
|
|
bec->bec_partid) ;
|
|
rv = -1 ;
|
|
goto unlock_ret ;
|
|
}
|
|
bec = bec->bec_next ;
|
|
}
|
|
|
|
if (debug)
|
|
printf("Rexec scan done\n") ;
|
|
|
|
/* Execute the given mkpbe command on the respective partitions. */
|
|
|
|
bec = bech ;
|
|
while (bec) {
|
|
if (local_flag) {
|
|
if (becmdExecuteLocal(bec) < 0) {
|
|
rv = -1 ;
|
|
goto unlock_ret ;
|
|
}
|
|
} else {
|
|
if (becmdExecute(bec, errbuf) < 0) {
|
|
rv = -1 ;
|
|
goto unlock_ret ;
|
|
}
|
|
}
|
|
bec = bec->bec_next ;
|
|
}
|
|
|
|
unlock_ret:
|
|
if ((!force_option) && (!local_flag)
|
|
&& (unlock_all_part(bech, errbuf, errmsg_flag)) < 0)
|
|
rv = -1 ;
|
|
|
|
return rv ;
|
|
}
|
|
|
|
/*
|
|
* mkpart -p X -m Y Z support.
|
|
*/
|
|
|
|
int
|
|
part_make(partcfg_t *pc_req, char *errbuf)
|
|
{
|
|
partcfg_t *pc_act ;
|
|
partcfg_t *pc = pc_req ;
|
|
partid_t part ;
|
|
partcfg_t *pc_tmp ;
|
|
becmd_t *bech = NULL, *bec ;
|
|
int i ;
|
|
int local_flag = 0 ;
|
|
int rv = PART_MAKE_NORMAL ;
|
|
|
|
/* Get a list of partitions found and their constituent modules. */
|
|
|
|
pc_act = part_scan(0, errbuf) ;
|
|
if (!pc_act) {
|
|
/*
|
|
* No partitions found. Assigning partids to modules will
|
|
* not involve any remote partitions.
|
|
*/
|
|
fprintf(stderr, "WARNING: Assigning Partition ids now.\n") ;
|
|
local_flag = 1 ;
|
|
part = INVALID_PARTID ;
|
|
rv = PART_MAKE_UNPARTITIONED ;
|
|
}
|
|
|
|
/*
|
|
* For all the partitions/modules in the required config
|
|
* lookup the module in the actual config. Build a mkpbe
|
|
* command line for the existing partition. Add the required
|
|
* module number and its new partition number to this
|
|
* command line. This will be ultimately remotely executed.
|
|
*/
|
|
while (pc) {
|
|
for (i=0; i < partcfgNumMods(pc); i++) {
|
|
if (!local_flag) {
|
|
pc_tmp = partcfgLookupPart(pc_act,
|
|
(partid_t) -1,
|
|
partcfgModuleId(pc, i)) ;
|
|
if (pc_tmp)
|
|
part = partcfgId(pc_tmp) ;
|
|
else { /* Module not found. */
|
|
strcpy( errbuf,
|
|
msglib[MSG_INVALID_CONFIG]) ;
|
|
rv = -1 ;
|
|
goto free_n_ret ;
|
|
}
|
|
}
|
|
|
|
/* Alloc a becmd_t for the partition part */
|
|
/* On a non-partitioned system, only one
|
|
* list is created which can be execed on
|
|
* the local machine.
|
|
*/
|
|
bec = becmdAllocate(&bech, part, BECMD_NAME) ;
|
|
if (bec == NULL) {
|
|
rv = -1 ;
|
|
goto free_n_ret ;
|
|
}
|
|
|
|
/* Add new partition and mod id to command line */
|
|
|
|
bec->bec_partid = part ;
|
|
becmdAddModPart(bec, partcfgModuleId(pc, i),
|
|
partcfgId(pc)) ;
|
|
}
|
|
pc = partcfgNext(pc) ;
|
|
}
|
|
|
|
if (debug) {
|
|
printf("Remote commands to be executed ... \n") ;
|
|
becmdDumpList(bech) ;
|
|
}
|
|
|
|
bzero(part_ipaddr, sizeof(part_ipaddr)) ;
|
|
|
|
/* Execute the commands built up for each existing partition. */
|
|
|
|
if (becmdExecuteList(bech, errbuf, local_flag) < 0) {
|
|
rv = -1 ;
|
|
}
|
|
|
|
free_n_ret:
|
|
becmdFreeList(bech) ;
|
|
return rv ;
|
|
}
|
|
|
|
/*
|
|
* part_activate
|
|
*
|
|
* Re-discover all partitions now.
|
|
*/
|
|
|
|
/* ARGSUSED */
|
|
|
|
int
|
|
part_activate(char *errbuf)
|
|
{
|
|
if (0 > syssgi( SGI_PART_OPERATIONS,
|
|
SYSSGI_PARTOP_ACTIVATE, 0, 0)) {
|
|
sprintf(errbuf, "Partition activate: %s", strerror(errno)) ;
|
|
return -1 ;
|
|
}
|
|
|
|
return 1 ;
|
|
}
|
|
|
|
/*
|
|
* part_kill
|
|
*
|
|
* Dissociate from a specific partition.
|
|
*
|
|
* TBD using sys call XXX
|
|
*/
|
|
/* ARGSUSED */
|
|
|
|
int
|
|
part_kill(partcfg_t *pc, char *errbuf)
|
|
{
|
|
if (0 > syssgi( SGI_PART_OPERATIONS,
|
|
SYSSGI_PARTOP_DEACTIVATE, partcfgId(pc), 0)) {
|
|
sprintf(errbuf, "Partition kill: %s", strerror(errno)) ;
|
|
return -1 ;
|
|
}
|
|
|
|
return 1 ;
|
|
}
|
|
|
|
/*
|
|
* get_my_partid
|
|
* Gets own partition id.
|
|
*/
|
|
partid_t
|
|
get_my_partid(void)
|
|
{
|
|
partid_t mypid ;
|
|
|
|
mypid = syssgi( SGI_PART_OPERATIONS,
|
|
SYSSGI_PARTOP_GETPARTID, 0, 0);
|
|
if (mypid < 0) {
|
|
return INVALID_PARTID ;
|
|
}
|
|
return mypid ;
|
|
}
|
|
|
|
/*
|
|
* check_all_modules
|
|
*
|
|
* Check if all modules are accounted for.
|
|
*
|
|
* Return:
|
|
*
|
|
* -1 if error
|
|
* NULL if all mods are accounted for
|
|
* valid ptr to partcfg list if some mods are left out.
|
|
*/
|
|
partcfg_t *
|
|
check_all_modules(partcfg_t *pc_req, partcfg_t *pc_act, char *errbuf, int *stat)
|
|
{
|
|
partcfg_t *pc = pc_act ;
|
|
partcfg_t *pc_new = NULL ;
|
|
int i ;
|
|
|
|
*stat = 0 ;
|
|
|
|
/* for all modules in pc_act */
|
|
|
|
while (pc) {
|
|
for (i = 0; i < partcfgNumMods(pc); i++) {
|
|
/* if it is in pc_req, go on to the next */
|
|
if ( partcfgLookupPart(pc_req, (partid_t)-1,
|
|
partcfgModuleId(pc,i)))
|
|
continue ;
|
|
|
|
/* We found a module not accounted for, but has
|
|
* the same partition id as in pc_req. The user
|
|
* is breaking an existing partition, but has
|
|
* used a existing partition number.
|
|
* For ex, part 3 had modules 4,5,6,7.
|
|
* User wants 4 and 5 in part 3 but has not
|
|
* specified what to do with 6 and 7
|
|
*/
|
|
if ( partcfgLookupPart(pc_req, partcfgId(pc),
|
|
(moduleid_t) -1)) {
|
|
sprintf(errbuf, msglib[MSG_ALL_MODULE],
|
|
partcfgModuleId(pc,i), partcfgId(pc)) ;
|
|
*stat = -1 ;
|
|
return NULL ;
|
|
}
|
|
|
|
addPnToPcList(&pc_new, partcfgId(pc),
|
|
partcfgModuleId(pc,i)) ;
|
|
}
|
|
pc = partcfgNext(pc) ;
|
|
}
|
|
|
|
if (pc_new) {
|
|
fprintf(stderr, "Some modules were left out. ") ;
|
|
fprintf(stderr, "The complete partition config looks like ...\n") ;
|
|
partcfgDumpList(pc_new) ;
|
|
partcfgDumpList(pc_req) ;
|
|
if (yes_or_no("Is this OK? [y/n]: "))
|
|
return pc_new ;
|
|
else {
|
|
strcpy(errbuf, exit_now_msg) ;
|
|
*stat = -1 ;
|
|
return NULL ;
|
|
}
|
|
}
|
|
|
|
return pc_new ;
|
|
}
|
|
|
|
/*
|
|
* Check if the given command input satisfies some basic checks.
|
|
* Build a complete map of the routers in the system.
|
|
*/
|
|
int
|
|
check_sanity(partcfg_t *pch, char *errbuf)
|
|
{
|
|
part_rou_map_t *pmap ;
|
|
sys_rou_map_t sys_rmap ;
|
|
partcfg_t *pc_act, *pc ;
|
|
partcfg_t *pc_req = pch ;
|
|
partcfg_t *pc_new = NULL ;
|
|
int i = 0 ;
|
|
int status ;
|
|
int mr_flag = 0 ;
|
|
|
|
if (pch == NULL)
|
|
return -1 ;
|
|
|
|
if (debug)
|
|
printf("Checking sanity ... \n") ;
|
|
|
|
if (check_hub_version() < 0)
|
|
return -1 ;
|
|
|
|
pc_act = part_scan(0, NULL) ;
|
|
if (!pc_act) {
|
|
fprintf(stderr, "WARNING: This is a unpartitioned system.\n"
|
|
"Perform manual sanity check of required config\n") ;
|
|
return 1 ;
|
|
}
|
|
|
|
/* Basic checks. */
|
|
|
|
*errbuf = 0 ;
|
|
if (partcfgValidList(pch, errbuf) < 0) {
|
|
if (!(*errbuf))
|
|
strcpy(errbuf, msglib[MSG_INVALID_CONFIG]) ;
|
|
return -1 ;
|
|
}
|
|
|
|
if (debug)
|
|
printf(" List is valid.\n") ;
|
|
|
|
/*
|
|
* pc_req may be a subset of pc_act.
|
|
* Find the diff and add it to pc_req.
|
|
* pc req must include all modules found in pc_act.
|
|
*/
|
|
|
|
pc_new = check_all_modules(pc_req, pc_act, errbuf, &status) ;
|
|
if (status < 0)
|
|
return -1 ;
|
|
|
|
if (debug)
|
|
printf(" All modules included now.\n") ;
|
|
|
|
/*
|
|
* Check if a partition if of 0 has sneaked in.
|
|
* We cannot allow a partition id of 0 on partitioned
|
|
* systems. The router workaround is not performed
|
|
* on unpartitioned systems which is now assumed to be
|
|
* indicated by a partition id of 0.
|
|
*/
|
|
|
|
check_for_partid0(pc_req) ;
|
|
check_for_partid0(pc_new) ;
|
|
|
|
/*
|
|
* Sanity checks for meta routers are different.
|
|
*/
|
|
|
|
if (meta_routers_present()) {
|
|
|
|
/* If all modules are in 1 partition it is OK. */
|
|
|
|
if ((!pc_new) && (count_partitions(pc_req) == 1))
|
|
return 1 ;
|
|
|
|
mr_flag = 1 ;
|
|
} else if (debug)
|
|
printf(" Meta routers not present.\n") ;
|
|
|
|
/*
|
|
* Check if total Number of modules and number of
|
|
* modules look like a mktg/array permitted
|
|
* config.
|
|
* For now we know that array permits only 4 module
|
|
* and 8 and 16 module configs??
|
|
* Also, we know that due to router table distribution
|
|
* methods, the number of mods in a part should be a
|
|
* power of 2.
|
|
*/
|
|
|
|
if (check_numbers(pc_act, pc_req, errbuf) < 0)
|
|
return -1 ;
|
|
|
|
/* Check if the required config matches any of the
|
|
* marketing support valid configs. If not, warn the
|
|
* user for now.
|
|
*/
|
|
if (check_valid_config(pc_act, pc_req, pc_new, vc_hdr_p) < 0) {
|
|
printf("WARNING: The desired partition config is not "
|
|
"one of the standard\n"
|
|
" supported configs. "
|
|
"Continuing to check if other requirements are met.\n"); }
|
|
|
|
if (debug)
|
|
printf(" Mktg permitted config.\n") ;
|
|
|
|
/* Build the router map of the whole system. */
|
|
/* Get router map info from all partitions. */
|
|
|
|
if (debug)
|
|
printf(" Building complete router map\n") ;
|
|
|
|
pc = pc_act ;
|
|
sys_rmap.sze = MAX_PARTITION_PER_SYSTEM ;
|
|
|
|
while (pc) {
|
|
|
|
/* Allocate partition router map */
|
|
|
|
pmap = (part_rou_map_t *)malloc(sizeof(part_rou_map_t)) ;
|
|
if (pmap == NULL)
|
|
return -1 ;
|
|
part_rou_map_init(pmap) ; /* Init it to 0s */
|
|
|
|
sys_rmap.pr_map[i] = pmap ; /* Install in sys rou map */
|
|
|
|
if (partcfgId(pc) == get_my_partid()) { /* Local */
|
|
create_my_rou_map(partcfgId(pc),
|
|
pmap, sizeof(part_rou_map_t)) ;
|
|
if (debug)
|
|
printf(" local rou map created\n") ;
|
|
} else {
|
|
if (debug)
|
|
printf(" Getting router map of "
|
|
"partition %d\n", partcfgId(pc)) ;
|
|
get_data_from_local(OPCODE_GET_ROUCFG, /* Remote */
|
|
partcfgId(pc),
|
|
(char *)pmap, sizeof(part_rou_map_t)) ;
|
|
}
|
|
|
|
if (pmap->cnt == 0) {
|
|
sprintf(errbuf, msglib[MSG_ZERO_ROUTER], partcfgId(pc));
|
|
return -1 ;
|
|
}
|
|
|
|
/*
|
|
* Update the partition index i into all router structs
|
|
* in pmap. This is used to xref a router struct
|
|
* from the port info of another router struct.
|
|
*/
|
|
if (update_pmap(pmap, i) < 0) {
|
|
sprintf(errbuf, msglib[MSG_ROUMAP_ERR], partcfgId(pc)) ;
|
|
return -1 ;
|
|
}
|
|
|
|
pc = partcfgNext(pc) ;
|
|
i++ ;
|
|
}
|
|
sys_rmap.pr_map[i] = NULL ;
|
|
sys_rmap.cnt = i ;
|
|
|
|
/* Interlink the ports of each router to the respective
|
|
router map structure. */
|
|
|
|
if (link_all_roumap(&sys_rmap, errbuf) < 0)
|
|
return -1 ;
|
|
|
|
if (debug)
|
|
dump_sys_rmap(&sys_rmap) ;
|
|
|
|
/*
|
|
* check if the route between any 2 routers in the
|
|
* proposed system is contained within a proposed
|
|
* partition.
|
|
*/
|
|
|
|
if (check_contiguous(&sys_rmap, pch, errbuf, mr_flag) < 0)
|
|
return -1 ;
|
|
|
|
if (pc_new)
|
|
if (check_contiguous(&sys_rmap, pc_new, errbuf, mr_flag) < 0)
|
|
return -1 ;
|
|
|
|
/*
|
|
* Check if there exists atleast 1 route between
|
|
* any 2 partitions, that does not go through a
|
|
* 3 rd partition.
|
|
*/
|
|
if (check_interconn(&sys_rmap, pch, errbuf, mr_flag) < 0)
|
|
return -1 ;
|
|
|
|
if (pc_new)
|
|
if (check_interconn(&sys_rmap, pc_new, errbuf, mr_flag) < 0)
|
|
return -1 ;
|
|
|
|
return(1) ;
|
|
}
|
|
|
|
|
|
/*
|
|
* rexec_mkpbe
|
|
*
|
|
* Run the mkpart back end command remotely using rexec.
|
|
*/
|
|
int
|
|
rexec_mkpbe(char *host, char *cmd, char *errbuf, int flag)
|
|
{
|
|
struct servent *se ;
|
|
int rstm ;
|
|
char buf[1024] ;
|
|
|
|
se = getservbyname("exec", "tcp") ;
|
|
/* XXX change user name ?? */
|
|
|
|
/* rexec prints an err msg in case of problems. */
|
|
|
|
if ((rstm = rexec(&host, se->s_port, "root", "\n", cmd, NULL)) < 0)
|
|
return -1 ;
|
|
|
|
if (debug)
|
|
printf("%s, %d\n", cmd, rstm) ;
|
|
|
|
*buf = 0 ;
|
|
read(rstm, buf, 1024) ;
|
|
|
|
/* In this case, a non-zero value in the first byte
|
|
* means error. It is also an error code.
|
|
*/
|
|
if ((flag) && (*buf)) {
|
|
if (debug) {
|
|
printf("%d: ", *buf) ;
|
|
printf("%s\n", ((char *)buf)+1) ;
|
|
}
|
|
strcpy(errbuf, ((char *)buf)+1) ;
|
|
return -1 ;
|
|
}
|
|
|
|
return 1 ;
|
|
}
|
|
|
|
/*
|
|
* lock_all_part
|
|
*
|
|
* set the lock variable to the locking part id.
|
|
* Return -1 if we fail on the first partid.
|
|
*/
|
|
static int
|
|
lock_all_part(becmd_t *bech, char *errbuf)
|
|
{
|
|
becmd_t *bec = bech ;
|
|
char status_buf[16] ;
|
|
int rc ;
|
|
|
|
while (bec) {
|
|
rc = get_data_from_local(OPCODE_LOCK_PART,
|
|
bec->bec_partid, status_buf, 16) ;
|
|
if (rc < 0) {
|
|
if (rc == -1)
|
|
sprintf(errbuf, "Cannot contact local mkpd daemon."
|
|
" Please check if mkpd is on.\n") ;
|
|
else
|
|
sprintf(errbuf, msglib[MSG_LOCK_ERR],
|
|
((bec->bec_partid == INVALID_PARTID)?
|
|
0:bec->bec_partid)) ;
|
|
return -1 ;
|
|
}
|
|
bec = bec->bec_next ;
|
|
}
|
|
return 1 ;
|
|
}
|
|
|
|
/*
|
|
* unlock_all_part
|
|
*
|
|
* tries to unlock all partitions, even if some of them fail
|
|
* reports err if flag is set.
|
|
*/
|
|
static int
|
|
unlock_all_part(becmd_t *bech, char *errbuf, int errmsg_flag)
|
|
{
|
|
becmd_t *bec = bech ;
|
|
int rv = 1 ;
|
|
char status_buf[16] ;
|
|
|
|
while (bec) {
|
|
if (get_data_from_local(OPCODE_UNLOCK_PART,
|
|
bec->bec_partid, status_buf, 16) < 0) {
|
|
if ((rv >= 0) && (errmsg_flag)) {
|
|
sprintf(errbuf, msglib[MSG_UNLOCK_ERR],
|
|
bec->bec_partid) ;
|
|
rv = -1 ;
|
|
}
|
|
}
|
|
bec = bec->bec_next ;
|
|
}
|
|
return rv ;
|
|
}
|
|
|
|
#include <signal.h>
|
|
|
|
static void
|
|
sigint_handler(void)
|
|
{
|
|
/* fprintf(stderr, "Ignoring interrupt.\n") ; */
|
|
}
|
|
|
|
void
|
|
ignore_signal(int signal, int flags)
|
|
{
|
|
struct sigaction act ;
|
|
|
|
act.sa_flags = flags ;
|
|
act.sa_handler = sigint_handler ;
|
|
sigemptyset(&act.sa_mask) ;
|
|
sigaction(signal, &act, NULL) ;
|
|
}
|
|
|
|
void
|
|
logmsg(char *msg, ...)
|
|
{
|
|
va_list args ;
|
|
|
|
va_start(args, msg) ;
|
|
vsyslog(LOG_ERR, msg, args) ;
|
|
}
|
|
|
|
int
|
|
isModuleRebooted(moduleid_t m, moduleid_t *mlist)
|
|
{
|
|
int i = 0 ;
|
|
|
|
while (mlist[i])
|
|
if (mlist[i++] == m)
|
|
return 1 ;
|
|
return 0 ;
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
|
|
int
|
|
check_part_reboot_state(pn_t *pn, int cnt, moduleid_t *mlist, char *errbuf)
|
|
{
|
|
int i ;
|
|
int found = 0 ;
|
|
|
|
for (i = 0; i < cnt; i++) {
|
|
if (isModuleRebooted(pn[i].pn_module, mlist)) {
|
|
found = 1 ;
|
|
if (pn[i].pn_state != KLP_STATE_PROM)
|
|
return 0 ;
|
|
}
|
|
}
|
|
if (found)
|
|
return 1 ;
|
|
else
|
|
return 0 ;
|
|
}
|
|
|
|
void
|
|
dump_mlist(moduleid_t *mlist)
|
|
{
|
|
int i = 0 ;
|
|
|
|
printf("Module List >-> ") ;
|
|
while (mlist[i])
|
|
printf("%d ", mlist[i++]) ;
|
|
printf("\n") ;
|
|
}
|
|
|
|
void
|
|
fill_mlist(partid_t p, partcfg_t *pc_act, moduleid_t *mlist, int *new)
|
|
{
|
|
int i, j ;
|
|
partcfg_t *pc_tmp ;
|
|
|
|
pc_tmp = partcfgLookupPart(pc_act, p, (moduleid_t)-1) ;
|
|
if (pc_tmp) {
|
|
for(i = 0, j = *new ; i < partcfgNumMods(pc_tmp) ; i++)
|
|
mlist[j+i] = partcfgModuleId(pc_tmp, i) ;
|
|
*new = j+i ;
|
|
}
|
|
}
|
|
|
|
void
|
|
shutdown_self(void)
|
|
{
|
|
fprintf(stderr, "%s", shutdown_self_msg) ;
|
|
system("echo 1|init 0") ;
|
|
}
|
|
|
|
void
|
|
shutdown_self_query(char *errbuf)
|
|
{
|
|
if (yes_or_no("Want to reboot now? [y/n]: ")) {
|
|
shutdown_self() ;
|
|
} else {
|
|
strcpy(errbuf, exit_now_msg) ;
|
|
return ;
|
|
}
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
|
|
#define TOTAL_WAIT_MINS 3
|
|
#define TOTAL_WAIT_SECS 60*TOTAL_WAIT_MINS
|
|
#define WAIT_INTERVAL_SECS 10
|
|
|
|
int
|
|
wait_reboot_self( partcfg_t *pc,
|
|
partcfg_t *pc_act,
|
|
moduleid_t *mlist,
|
|
char *errbuf,
|
|
int mr_flag)
|
|
{
|
|
int done = 0 ;
|
|
int wait_time = 0 ;
|
|
pn_t *pn ;
|
|
int cnt ;
|
|
|
|
/* On meta router systems we do not do sync reboot. If
|
|
* partitions are combined, they have to be combined to
|
|
* a single partition. Just shutdown self, dont wait.
|
|
|
|
if (mr_flag)
|
|
goto shut_self ;
|
|
*/
|
|
|
|
pn = (pn_t *)malloc(MAX_PN * sizeof(pn_t)) ;
|
|
|
|
while (!done) {
|
|
if (0 > syssgi( SGI_PART_OPERATIONS,
|
|
SYSSGI_PARTOP_ACTIVATE, 0, 0, 0)) {
|
|
continue ;
|
|
}
|
|
|
|
sleep(WAIT_INTERVAL_SECS) ;
|
|
|
|
cnt = syssgi( SGI_PART_OPERATIONS,
|
|
SYSSGI_PARTOP_NODEMAP, MAX_PN, pn, NULL) ;
|
|
{
|
|
int i ;
|
|
printf("cnt = %d >-> ", cnt) ;
|
|
for(i=0;i<cnt;i++)
|
|
printf("%d:%d,",
|
|
pn[i].pn_state, pn[i].pn_module) ;
|
|
printf("\n") ;
|
|
}
|
|
#if 0 /* DEBUG */
|
|
#endif
|
|
|
|
if (cnt < 0)
|
|
continue ;
|
|
|
|
if (check_part_reboot_state(pn, cnt, mlist, errbuf))
|
|
break ;
|
|
|
|
#ifdef MANUAL_WAIT
|
|
if (yes_or_no("Are other parts done yet? [y/n]: "))
|
|
done = 1 ;
|
|
else
|
|
exit(1) ;
|
|
#endif
|
|
|
|
wait_time += WAIT_INTERVAL_SECS ;
|
|
if (wait_time >= TOTAL_WAIT_SECS)
|
|
return -1 ;
|
|
}
|
|
|
|
/* shutdown self */
|
|
|
|
shutdown_self() ;
|
|
|
|
return 1 ;
|
|
}
|
|
|
|
void
|
|
part_reboot( partcfg_t *pc,
|
|
partcfg_t *pc_act,
|
|
moduleid_t *mlist,
|
|
int flag,
|
|
char *errbuf)
|
|
{
|
|
int i ;
|
|
partcfg_t *pc_tmp ;
|
|
int index = 0 ;
|
|
|
|
/* Flag all partitions to be rebooted */
|
|
|
|
for (i=0; i < partcfgNumMods(pc); i++) {
|
|
pc_tmp = partcfgLookupPart(pc_act, (partid_t) -1,
|
|
partcfgModuleId(pc, i)) ;
|
|
if (pc_tmp)
|
|
part_ipaddr[partcfgId(pc_tmp)].flags = PART_REBOOT ;
|
|
}
|
|
|
|
/* shutdown all affected partitions */
|
|
|
|
for (i=0; i<MAX_PARTITION_PER_SYSTEM; i++) {
|
|
if (i == get_my_partid())
|
|
continue ;
|
|
if (part_ipaddr[i].flags == PART_REBOOT) {
|
|
fill_mlist(i, pc_act, mlist, &index) ;
|
|
fprintf(stderr, "Rebooting partition %d\n", i) ;
|
|
if (flag)
|
|
rexec_mkpbe(part_ipaddr[i].ipaddr,
|
|
PART_REBOOT_CMD, errbuf, 0) ;
|
|
else {
|
|
rexec_mkpbe(part_ipaddr[i].ipaddr,
|
|
PART_REBOOT_SHUTDOWN_CMD, errbuf, 0) ;
|
|
}
|
|
part_ipaddr[i].flags = PART_REBOOT_DONE ;
|
|
}
|
|
}
|
|
dump_mlist(mlist) ;
|
|
#if 0
|
|
#endif
|
|
}
|
|
|
|
void
|
|
inquire_and_reboot(partcfg_t *pc_req, char *errbuf)
|
|
{
|
|
partcfg_t *pc_act, *pc_tmp ;
|
|
partcfg_t *pc = pc_req, *mypc = NULL ;
|
|
partid_t partid ;
|
|
int i, found ;
|
|
int combine = 0 ;
|
|
moduleid_t mlist[MAX_MODS_PER_PART] , mymlist[MAX_MODS_PER_PART] ;
|
|
int mr_flag ;
|
|
int reboot_flag = 0 ;
|
|
char *reboot_other_msg =
|
|
"NOTE: Rebooting partitions that do not affect current partition.\n\
|
|
They have to be checked manually.\n" ;
|
|
|
|
bzero(mlist, sizeof(mlist)) ;
|
|
|
|
pc_act = part_scan(0, errbuf) ;
|
|
if (!pc_act)
|
|
return ;
|
|
|
|
/* If we have meta routers on this system,
|
|
* do not do this synchronized reboot.
|
|
*/
|
|
|
|
mr_flag = meta_routers_present() ;
|
|
|
|
/* Find all NEW partitions that will be combined. */
|
|
|
|
while (pc) {
|
|
pc_tmp = partcfgLookupPart(pc_act, (partid_t) -1,
|
|
partcfgModuleId(pc, 0)) ;
|
|
if (pc_tmp)
|
|
partid = partcfgId(pc_tmp) ;
|
|
|
|
for (i=0; i < partcfgNumMods(pc); i++) {
|
|
pc_tmp = partcfgLookupPart(pc_act, (partid_t) -1,
|
|
partcfgModuleId(pc, i)) ;
|
|
if ((pc_tmp) && (partcfgId(pc_tmp) != partid)) {
|
|
pc->flags |= PART_COMBINE ;
|
|
combine = 1 ;
|
|
}
|
|
}
|
|
pc = partcfgNext(pc) ;
|
|
}
|
|
|
|
if (!combine) {
|
|
shutdown_self_query(errbuf) ;
|
|
return ;
|
|
#if 0
|
|
if (yes_or_no("Want to reboot now? [y/n]: ")) {
|
|
printf(shutdown_self_msg) ;
|
|
system("echo 1|init 0") ;
|
|
} else {
|
|
strcpy(errbuf, exit_now_msg) ;
|
|
return ;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* Ask the user for a reboot */
|
|
|
|
pc = pc_req ;
|
|
while(pc) {
|
|
if (pc->flags & PART_COMBINE) {
|
|
fprintf(stderr, "Partition %d combines 2 or more "
|
|
"existing partitions\n", partcfgId(pc)) ;
|
|
|
|
if (reboot_flag =
|
|
yes_or_no( "Reboot them now? [y/n]: ")) {
|
|
if (is_my_act_part(pc, pc_act, get_my_partid()))
|
|
{
|
|
mypc = pc ;
|
|
found = 1 ;
|
|
} else {
|
|
found = 0 ;
|
|
fprintf(stderr, reboot_other_msg) ;
|
|
}
|
|
|
|
/* If this is a meta router system, do not
|
|
* do the nvram command. The IOprom need not
|
|
* wait, for a reboot.
|
|
|
|
if (mr_flag)
|
|
found = 0 ;
|
|
*/
|
|
|
|
part_reboot(pc, pc_act, mlist, found, errbuf) ;
|
|
if (mypc && found) {
|
|
bcopy(mlist, mymlist, sizeof(mlist)) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* XXX re-init globals if any */
|
|
|
|
pc = partcfgNext(pc) ;
|
|
}
|
|
|
|
if (mypc && reboot_flag) {
|
|
dump_mlist(mymlist) ;
|
|
#if 0
|
|
#endif
|
|
wait_reboot_self(mypc, pc_act, mymlist, errbuf, mr_flag) ;
|
|
}
|
|
}
|
|
|
|
int
|
|
yes_or_no(char *msg)
|
|
{
|
|
char buf[256] ;
|
|
|
|
*buf = 0 ;
|
|
while ((*buf != 'y') && (*buf != 'n')) {
|
|
fprintf(stderr, "%s", msg) ;
|
|
gets(buf) ;
|
|
}
|
|
|
|
if (*buf == 'y')
|
|
return 1 ;
|
|
else
|
|
return 0 ;
|
|
}
|
|
|
|
#if 0
|
|
|
|
void
|
|
dump_kldir_state(void)
|
|
{
|
|
pn_t *pn ;
|
|
int i ;
|
|
int cnt ;
|
|
|
|
pn = (pn_t *)malloc(MAX_PN * sizeof(pn_t)) ;
|
|
|
|
if (0 > syssgi(SGI_PART_OPERATIONS,
|
|
SYSSGI_PARTOP_ACTIVATE, 0, 0, 0)) {
|
|
return ;
|
|
}
|
|
|
|
sleep(5) ;
|
|
|
|
cnt = syssgi(SGI_PART_OPERATIONS,
|
|
SYSSGI_PARTOP_NODEMAP, MAX_PN, pn, NULL) ;
|
|
|
|
{
|
|
printf("cnt = %d >-> \n", cnt) ;
|
|
for(i=0;i<cnt;i++) printf("s.%d:m.%d:p.%d:n:%d\n",
|
|
pn[i].pn_state, pn[i].pn_module,
|
|
pn[i].pn_partid, pn[i].pn_nasid) ;
|
|
printf("\n") ;
|
|
}
|
|
|
|
free(pn) ;
|
|
}
|
|
#endif
|
|
|
|
static int
|
|
is_my_act_part(partcfg_t *pc, partcfg_t *pc_act, partid_t partid)
|
|
{
|
|
int i ;
|
|
partcfg_t *pc_tmp = NULL ;
|
|
|
|
for (i=0; i < partcfgNumMods(pc); i++) {
|
|
pc_tmp = partcfgLookupPart(pc_act, (partid_t) -1,
|
|
partcfgModuleId(pc, i)) ;
|
|
if ((pc_tmp) && (partcfgId(pc_tmp) == partid)) {
|
|
return 1 ;
|
|
}
|
|
}
|
|
return 0 ;
|
|
}
|
|
|
|
static int
|
|
is_xpc_up(partid_t p)
|
|
{
|
|
int fd ;
|
|
char name[MKPD_MAX_XRAW_FNAME_LEN] ;
|
|
struct stat buf ;
|
|
|
|
if (get_raw_path(name, p) < 0)
|
|
return 0 ;
|
|
|
|
fd = stat(name, &buf) ;
|
|
if (fd < 0) {
|
|
if (debug) {
|
|
perror("stat") ;
|
|
}
|
|
return 0 ;
|
|
}
|
|
return 1 ;
|
|
}
|
|
|
|
static int
|
|
meta_routers_present(void)
|
|
{
|
|
part_rou_map_t *pmap ;
|
|
int i ;
|
|
rou_map_t *rm ;
|
|
|
|
pmap = (part_rou_map_t *)malloc(sizeof(part_rou_map_t)) ;
|
|
if (pmap == NULL)
|
|
return 0 ;
|
|
|
|
part_rou_map_init(pmap) ; /* Init it to 0s */
|
|
|
|
create_my_rou_map(get_my_partid(),
|
|
pmap, sizeof(part_rou_map_t)) ;
|
|
|
|
for (i=0; i< pmap->cnt; i++) {
|
|
rm = &pmap->roumap[i] ;
|
|
|
|
if (is_metarouter(rm)) {
|
|
if (pmap)
|
|
free(pmap) ;
|
|
if (debug)
|
|
printf(" Meta routers present.\n") ;
|
|
return 1 ;
|
|
}
|
|
}
|
|
|
|
if (pmap)
|
|
free(pmap) ;
|
|
if (debug)
|
|
printf(" Meta routers not present.\n") ;
|
|
|
|
return 0 ;
|
|
}
|
|
|
|
int
|
|
count_partitions(partcfg_t *pc)
|
|
{
|
|
int count = 0 ;
|
|
partcfg_t *pc_tmp = pc ;
|
|
|
|
while (pc_tmp) {
|
|
count ++ ;
|
|
pc_tmp = partcfgNext(pc_tmp) ;
|
|
}
|
|
return count ;
|
|
}
|
|
|
|
void
|
|
inquire_and_reboot_init(char *errbuf)
|
|
{
|
|
partcfg_t *pc ;
|
|
partcfg_t *pc_req ;
|
|
int i ;
|
|
|
|
if (pc_req = partcfgCreate(MAX_MODS_PER_PART)) {
|
|
partcfgId(pc_req) = 0 ;
|
|
} else
|
|
return ;
|
|
|
|
pc = part_scan(0, errbuf) ;
|
|
if (!pc)
|
|
return ;
|
|
|
|
while (pc) {
|
|
for (i=0;i<partcfgNumMods(pc);i++)
|
|
addPnToPcList(&pc_req, 0, partcfgModuleId(pc, i)) ;
|
|
pc = partcfgNext(pc) ;
|
|
}
|
|
|
|
if (debug) {
|
|
printf("Required config looks like ...\n") ;
|
|
partcfgDump(pc_req) ;
|
|
}
|
|
|
|
inquire_and_reboot(pc_req, errbuf) ;
|
|
|
|
}
|
|
|
|
#include <invent.h>
|
|
#include <ftw.h>
|
|
#include <sys/attributes.h>
|
|
#include <sys/iograph.h>
|
|
#include <paths.h>
|
|
|
|
#define MAX_WALK_DEPTH 32
|
|
|
|
/* ARGSUSED */
|
|
|
|
int
|
|
check_hub_version_cb(const char *p, const struct stat *s, int i, struct FTW *f)
|
|
{
|
|
struct stat buf;
|
|
char info[256], node_name[256] ;
|
|
int len = sizeof(info);
|
|
int rc;
|
|
invent_miscinfo_t *minvent ;
|
|
invent_generic_t *ginvent ;
|
|
|
|
|
|
if (lstat(p,&buf)) /* Make sure lstat succeeds */
|
|
return 0;
|
|
if (S_ISLNK(buf.st_mode)) /* Check if we are looking at a link*/
|
|
return 0;
|
|
rc = attr_get((char *)p, INFO_LBL_DETAIL_INVENT, info, &len, 0);
|
|
if (rc == 0) {
|
|
minvent = (invent_miscinfo_t *) info ;
|
|
ginvent = (invent_generic_t *)info ;
|
|
if ( (ginvent->ig_invclass == INV_MISC) &&
|
|
(minvent->im_type == INV_HUB) &&
|
|
(minvent->im_rev < 5)) {
|
|
strcpy(node_name, p) ;
|
|
node_name[strlen(node_name)-strlen("/node/hub")] = 0 ;
|
|
fprintf(stderr, "The node board %s is not at the "
|
|
"required \n"
|
|
"revision level for partitioning."
|
|
" Use -F option to override this.\n",
|
|
node_name) ;
|
|
return 2 ;
|
|
}
|
|
}
|
|
return 0 ;
|
|
}
|
|
|
|
int
|
|
check_hub_version(void)
|
|
{
|
|
if (nftw(_PATH_HWGFS, check_hub_version_cb, MAX_WALK_DEPTH, FTW_PHYS)
|
|
== 2)
|
|
return -1 ;
|
|
else
|
|
return 1 ;
|
|
}
|
|
|
|
/* Valid Config Support */
|
|
|
|
/* This section contains support to check for certain
|
|
* specific partition configs and alert the user about
|
|
* them. For example, on a 8 module machine, we can
|
|
* allow the user to do a 2 X 4 module partition only.
|
|
* Any other partitioning is not supported and is the
|
|
* responsibility of the user.
|
|
*/
|
|
|
|
/* The list of supported configs is read from the file
|
|
* /etc/config/mkpart.config. This is not user modifiable.
|
|
* It has a weird fixed format that can be understood by
|
|
* the mkpart only. In case the info cannot be obtained from
|
|
* the file, the data struct below provides it.
|
|
*/
|
|
|
|
/* The interpretation of various fields are:
|
|
* NMods NCfgs <NCombos, (NPartTypes X NModsPerPart) + > ...
|
|
* For a NMods number of modules system, eg: 4
|
|
* There are NCfgs number of configs supported eg: 3
|
|
* (other than the default of all mods in 1 partition)
|
|
* There are 3 sets of info that follow NCfgs. NCombos is
|
|
* the different combinations that follow eg: 2
|
|
* NPartTypes X NModsPerPart is the number of partitions
|
|
* allowed and the modules per partition eg 2 X 1
|
|
* So for a 4 module system we can have 3 combinations of
|
|
* partitioning, 4 partitions with 1 mod per partition OR
|
|
* 2 partitions with 2 modules per partition OR 2 partitions
|
|
* 1 partition with 2 modules and 2 partitions with 1 module each.
|
|
*/
|
|
|
|
char *valid_config_default[] = {
|
|
"2 2 1 1 2 1 2 1",
|
|
"4 4 1 1 4 1 4 1 1 2 2 2 1 2 2 1",
|
|
"8 2 1 1 8 1 2 4",
|
|
"16 2 1 1 16 1 4 4",
|
|
NULL
|
|
} ;
|
|
|
|
/*
|
|
* Parse a line and store its info in valid_config_t
|
|
* element given. Return -1 if something is wrong.
|
|
* Does not clean the element on failure.
|
|
*/
|
|
|
|
int
|
|
read_valid_config_line(char *line, valid_config_t *vcp)
|
|
{
|
|
int j,k ;
|
|
char tok_buf[MAX_CMDLINE_LEN], *tok_ptr = tok_buf ;
|
|
char *tmp ;
|
|
|
|
if (!line || !vcp)
|
|
return -1 ;
|
|
|
|
/* Line too big. */
|
|
|
|
if (strlen(line) >= sizeof(tok_buf))
|
|
return -1 ;
|
|
strcpy(tok_ptr, line) ;
|
|
tok_ptr = strtok(tok_ptr, sep) ;
|
|
|
|
/* Get next integer from the line */
|
|
|
|
if (!(tmp = tok_ptr)) return -1 ;
|
|
if (sscanf(tmp, "%d", &vcTotalModules(vcp)) != 1)
|
|
return -1 ;
|
|
|
|
if (!(tmp = strtok(NULL, sep))) return -1 ;
|
|
if (sscanf(tmp, "%d", &vcNConfigs(vcp)) != 1)
|
|
return -1 ;
|
|
|
|
for (j=0;j<vcNConfigs(vcp);j++) {
|
|
|
|
if (!(tmp = strtok(NULL, sep))) return -1 ;
|
|
if (sscanf(tmp, "%d", &vcComboNCombos(vcp,j)) != 1)
|
|
return -1 ;
|
|
|
|
for (k=0;k<vcComboNCombos(vcp,j);k++) {
|
|
|
|
if (!(tmp = strtok(NULL, sep))) return -1 ;
|
|
if (sscanf(tmp, "%d", &vcComboPartition(vcp,j,k)) != 1)
|
|
return -1 ;
|
|
|
|
if (!(tmp = strtok(NULL, sep))) return -1 ;
|
|
if (sscanf(tmp, "%d", &vcComboModule(vcp,j,k)) != 1)
|
|
return -1 ;
|
|
|
|
}
|
|
}
|
|
|
|
return 1 ;
|
|
}
|
|
|
|
/* Parse file for the permitted configs info. */
|
|
|
|
int
|
|
read_valid_config_file(char *vc_fname, valid_config_t *vchp)
|
|
{
|
|
FILE *fp ;
|
|
char buf[MAX_CMDLINE_LEN] ; /* max len of line in file */
|
|
char *bufp ;
|
|
int i = 0 ;
|
|
|
|
fp = fopen(vc_fname, "r");
|
|
if (fp == NULL) {
|
|
return -1 ;
|
|
}
|
|
|
|
bufp = fgets(buf, MAX_CMDLINE_LEN, fp) ;
|
|
if (bufp) {
|
|
if (strncmp( bufp, VALID_CONFIG_FILE_MAGIC,
|
|
strlen(VALID_CONFIG_FILE_MAGIC)))
|
|
return -1 ;
|
|
}
|
|
else
|
|
return -1 ;
|
|
|
|
i = 0 ;
|
|
while (bufp = fgets(buf, MAX_CMDLINE_LEN, fp)) {
|
|
|
|
if (!bufp || (i >= MAX_TOTAL_MODULES))
|
|
return -1 ;
|
|
|
|
/* Skip comments, empty lines */
|
|
|
|
if ( (*bufp == '#') || (*bufp == '*') ||
|
|
(*bufp == '\n') || (*bufp == '\0'))
|
|
continue ;
|
|
|
|
if (read_valid_config_line(bufp, &vchp[i]) < 0)
|
|
return -1 ;
|
|
|
|
i++ ;
|
|
}
|
|
|
|
return 1 ;
|
|
}
|
|
|
|
/* Parse local data structure if file does not contain valid info. */
|
|
|
|
int
|
|
read_valid_config_default(valid_config_t *vchp)
|
|
{
|
|
int i = 0 ;
|
|
|
|
while (valid_config_default[i]) {
|
|
|
|
if (i >= MAX_TOTAL_MODULES)
|
|
return -1 ;
|
|
|
|
if (read_valid_config_line( valid_config_default[i],
|
|
&vchp[i]) < 0)
|
|
return -1 ;
|
|
|
|
i++ ;
|
|
}
|
|
return 1 ;
|
|
}
|
|
|
|
/* Read valid configuration info, either from file or the
|
|
* local data struct. If everything fails, clean the config struct.
|
|
*/
|
|
|
|
void
|
|
read_valid_config(valid_config_t *vchp)
|
|
{
|
|
if (read_valid_config_file(VALID_CONFIG_FILE, vchp) < 0) {
|
|
bzero(vchp, sizeof(valid_config_t) * MAX_TOTAL_MODULES) ;
|
|
if (read_valid_config_default(vchp) < 0)
|
|
bzero(vchp, sizeof(valid_config_t)*MAX_TOTAL_MODULES) ;
|
|
|
|
}
|
|
|
|
if (debug)
|
|
dump_valid_config_all(vchp) ;
|
|
}
|
|
|
|
char *vc_file_hdr =
|
|
"NMods NCfgs <NCombos, (NPartTypes X NModsPerPart) + > ... \n" ;
|
|
|
|
void
|
|
dump_valid_config(valid_config_t *vcp)
|
|
{
|
|
int nc ;
|
|
int j,k ;
|
|
|
|
printf("%d %d", vcTotalModules(vcp), vcNConfigs(vcp)) ;
|
|
for (j=0;j<vcNConfigs(vcp);j++) {
|
|
printf(" <%d,", vcComboNCombos(vcp,j)) ;
|
|
nc = vcComboNCombos(vcp,j) ;
|
|
for (k=0;k<nc;k++) {
|
|
printf(" (%d X %d) ",
|
|
vcComboPartition(vcp,j,k),
|
|
vcComboModule(vcp,j,k)) ;
|
|
if (nc>1)
|
|
printf(" + ") ;
|
|
}
|
|
printf(">") ;
|
|
}
|
|
printf("\n") ;
|
|
}
|
|
|
|
void
|
|
dump_valid_config_all(valid_config_t *vchp)
|
|
{
|
|
int i;
|
|
valid_config_t *vcp = &vchp[0] ;
|
|
|
|
printf("%s", vc_file_hdr) ;
|
|
|
|
for (i=0;i<MAX_TOTAL_MODULES;i++) {
|
|
vcp = &vchp[i] ;
|
|
if (!vcValid(vcp))
|
|
continue ;
|
|
dump_valid_config(vcp) ;
|
|
}
|
|
}
|
|
|
|
int
|
|
count_total_modules(partcfg_t *pch)
|
|
{
|
|
int count = 0 ;
|
|
partcfg_t *pc_tmp = pch ;
|
|
|
|
while (pc_tmp) {
|
|
count += partcfgNumMods(pc_tmp) ;
|
|
pc_tmp = partcfgNext(pc_tmp) ;
|
|
}
|
|
return count ;
|
|
}
|
|
|
|
/*
|
|
* check_valid_config
|
|
*
|
|
* Checks if a required config matches one of the permitted
|
|
* configurations. Returns -1 if it does not match.
|
|
* The required config may be a combination of pc_req and
|
|
* pc_new = left out modules.
|
|
*/
|
|
int
|
|
check_valid_config( partcfg_t *pc_act,
|
|
partcfg_t *pc_req,
|
|
partcfg_t *pc_new,
|
|
valid_config_t *vchp)
|
|
{
|
|
int total_modules = count_total_modules(pc_act) ;
|
|
int i = 0, j ;
|
|
valid_config_t *vcp = &vchp[0] ;
|
|
int found = 0 ;
|
|
partcfg_t *pc ;
|
|
int tmp[MAX_CONFIG][MAX_COMBOS];
|
|
int fail ;
|
|
|
|
/* Find if we have an entry for our total_modules in the
|
|
* valid config table.
|
|
*/
|
|
while (vcValid(vcp)) {
|
|
if (vcTotalModules(vcp) == total_modules) {
|
|
found = 1 ;
|
|
break ;
|
|
}
|
|
i++ ;
|
|
vcp = &vchp[i] ;
|
|
}
|
|
|
|
if (!found) {
|
|
return -1 ;
|
|
}
|
|
|
|
if (debug)
|
|
dump_valid_config(vcp) ;
|
|
|
|
/* For all required partitions, check if there is a match
|
|
* on number of modules anywhere in valid config list. If
|
|
* we find a match, put 1 in the tmp array.
|
|
*/
|
|
pc = pc_req ;
|
|
bzero(tmp, sizeof(tmp)) ;
|
|
while (pc) {
|
|
for (i=0;i<vcNConfigs(vcp); i++) {
|
|
for (j=0;j<vcComboNCombos(vcp,i);j++) {
|
|
if ( vcComboModule(vcp,i,j) ==
|
|
partcfgNumMods(pc)) {
|
|
tmp[i][j] += 1 ;
|
|
}
|
|
}
|
|
}
|
|
pc = partcfgNext(pc) ;
|
|
}
|
|
|
|
pc = pc_new ;
|
|
while (pc) {
|
|
for (i=0;i<vcNConfigs(vcp); i++) {
|
|
for (j=0;j<vcComboNCombos(vcp,i);j++) {
|
|
if ( vcComboModule(vcp,i,j) ==
|
|
partcfgNumMods(pc)) {
|
|
tmp[i][j] += 1 ;
|
|
}
|
|
}
|
|
}
|
|
pc = partcfgNext(pc) ;
|
|
}
|
|
|
|
/* For all config X combos, check if we have a perfect
|
|
* match on number of partitions in tmp.
|
|
*/
|
|
for (i=0;i<vcNConfigs(vcp); i++) {
|
|
fail = 0 ;
|
|
for (j=0;j<vcComboNCombos(vcp,i);j++) {
|
|
if (tmp[i][j] != vcComboPartition(vcp,i,j)) {
|
|
fail = 1 ;
|
|
break ;
|
|
}
|
|
}
|
|
if (!fail) break ;
|
|
}
|
|
|
|
if (fail) {
|
|
return -1 ;
|
|
}
|
|
|
|
return 1 ;
|
|
}
|
|
|
|
static void
|
|
check_for_partid0(partcfg_t *pc_req)
|
|
{
|
|
partcfg_t *pc = pc_req ;
|
|
|
|
while (pc) {
|
|
if (partcfgId(pc) == 0) {
|
|
printf("WARNING: Partition id 0 should be avoided "
|
|
"on a partitioned system.\n") ;
|
|
if (!yes_or_no("Do you want to continue? [y/n] ")) {
|
|
printf("Exiting the command now.\n") ;
|
|
exit(0) ;
|
|
} else
|
|
return ;
|
|
}
|
|
pc = partcfgNext(pc) ;
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG_VALID_CONFIG
|
|
|
|
partcfg_t *
|
|
generate_pc_from_user(void)
|
|
{
|
|
char buf[MAX_CMDLINE_LEN] ;
|
|
char *bufp ;
|
|
partcfg_t *pc = NULL , *pch = NULL ;
|
|
int status ;
|
|
|
|
printf("Enter partition:p=module:m1 m2 ...\n") ;
|
|
while (bufp = gets(buf)) {
|
|
pc = partcfgCreate(MAX_MODS_PER_PART) ;
|
|
parse_string(bufp, pc, &status, NULL) ;
|
|
partcfgInsertList(&pch, pc) ;
|
|
}
|
|
|
|
partcfgDumpList(pch) ;
|
|
|
|
return pch ;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|