/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* bos720 src/bos/usr/sbin/drmgr/sample_scripts/sysadmin_mv_rsets.c.S 1.1 */
/*                                                                        */
/* Licensed Materials - Property of IBM                                   */
/*                                                                        */
/* Restricted Materials of IBM                                            */
/*                                                                        */
/* COPYRIGHT International Business Machines Corp. 2000,2002              */
/* All Rights Reserved                                                    */
/*                                                                        */
/* US Government Users Restricted Rights - Use, duplication or            */
/* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.      */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */


static char sccsid[] = "@(#)09	1.1  src/bos/usr/sbin/drmgr/sample_scripts/sysadmin_mv_rsets.c.S, cmdcfg, bos720 8/22/02 11:46:49";

 /*
 * FILE NAME : sysadmin_mv_rsets.c
 *
 * ORIGINS: 27
 *
 * This file is a DLPAR application framework
 * related C source file. This file can
 * be compiled to obtain a binary, and this
 * can be registered with DLPAR subsystem for callouts
 * during DLPAR operations.
 *
 * NOTE : This file can be compiled on AIX 5.2/+ OS. 
 *
 * This file provides the source to move the
 * rset attachments from the cpu being removed
 * to another cpu if available.
 * In this particular example the rsets are being
 * moved in checkrelease phase itself.
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <usersec.h>
#include <errno.h>
#include <string.h>
#include <sys/rset.h>
#include <sys/wlm.h>
#include <sys/systemcfg.h>

#define NCLASSES	32
#define NUMSUB		12

#define SCRIPTINFO		0
#define REGISTER		1
#define USAGE			2
#define CHECKRELEASE		3
#define PRERELEASE		4
#define POSTRELEASE		5
#define UNOPRERELEASE		6
#define CHECKACQUIRE		7
#define PREACQUIRE		8
#define POSTACQUIRE		9
#define UNDOPREACQUIRE		10

char * DR_script_commands[] = { "scriptinfo", "register", "usage",
				"checkrelease", "prerelease", "postrelease",
				"undoprerelease", "checkacquire", "preacquire",
				"undopreacquire" };
typedef struct{
	char rs_name[1024];		/* name of rset */
	rsethandle_t	rset_hand;	/* handle of rset */
} rset_info;

struct class_definition clinfo[NCLASSES];    /* array to hold superclasses */
struct class_definition subclinfo[NUMSUB];   /* array to hold subclasses */
rset_info rset_arr[NCLASSES*NUMSUB];	     /* array to hold rsets */
int r_count = 0, count, count2;

int str_to_cmd(char *cmd_str);
int process_scriptinfo(void);
int process_register(void);
int process_usage(char *resource);
int process_checkrelease(char *resource);
int process_prerelease(char *resource);
int process_undoprerelease(char *resource);
int process_postrelease(char *resource);
void find_rsets();
void save_rset(struct class_definition *cldef);
void change_rset(rsethandle_t rs1, char *rs_name);

int
main(int argc, char * argv[])
{

	char	*command_str = "dummy";
	char 	*resource_name = "dummy";
	int	command;
	int	ret_code = 0;
	int	i;

	switch(argc) {
		case 0:
		case 1:
			/* error. we expect command atleast */
			return(1);
		case 2:
			command_str = argv[1];
			break;
		case 3:
			command_str = argv[1];
			resource_name = argv[2];
			break;
		default:
			return(2);

	}       /* end of switch */
	command = str_to_cmd(command_str);

	switch(command) {
		case    SCRIPTINFO:
			ret_code = process_scriptinfo();
			break;
		case    REGISTER:
			ret_code = process_register();
			break;
		case    USAGE:
			ret_code = process_usage(resource_name);
			break;
		case    CHECKRELEASE:
			ret_code = process_checkrelease(resource_name);
			break;
		case    PRERELEASE:
			ret_code = process_prerelease(resource_name);
			break;
		case    POSTRELEASE:
			ret_code = process_postrelease(resource_name);
			break;
		case    UNOPRERELEASE:
			ret_code = process_undoprerelease(resource_name);
			break;
		case    CHECKACQUIRE:
			ret_code = 10;
			break;
		case    PREACQUIRE:
			ret_code = 10;
			break;
		case    POSTACQUIRE:
			ret_code = 10;
			break;
		case    UNDOPREACQUIRE:
			ret_code = 10;
			break;
	}       /* end of switch */
	exit(ret_code);
}	/* end of main */

int
str_to_cmd(char * cmd_str)
{
	int     i;
	for(i=0;i<sizeof(DR_script_commands); i++) {
		if(!strcmp(DR_script_commands[i], cmd_str)) {
			/* found a match */
			return(i);
		}
	}
	return(1);
}       /* end of str_to_cmd */

#define SCRIPT_INFO     "WLM program to handle preprocessing of DLPAR"
#define SCRIPT_VERSION  "1"
#define SCRIPT_VENDOR   "IBM Corp."
#define SCRIPT_TIMEOUT  7

/*
 * Used to create info displayed in drmgr -l command
 */
int
process_scriptinfo(void)
{
	fprintf(stdout, "DR_SCRIPTINFO=%s\n", SCRIPT_INFO);
	fprintf(stdout, "DR_VERSION=%s\n", SCRIPT_VERSION);
	fprintf(stdout, "DR_DATE=%s\n", "24052002");
	fprintf(stdout, "DR_VENDOR=%s\n", SCRIPT_VENDOR);
	fprintf(stdout, "DR_TIMEOUT=%d\n", SCRIPT_TIMEOUT);
	return(0);
}       /* end of process_scriptinfo */


#define CPU_RESOURCE		"cpu"
#define CPU_RESOURCE_USE	"RSET Management Control"

/*
 * Registers this script with drmgr for all cpu operations
 */
int
process_register(void)
{
	fprintf(stdout, "DR_RESOURCE=%s\n",CPU_RESOURCE);
	return(0);
}


int
process_usage(char * resource)
{
	if(!strcmp(resource, CPU_RESOURCE)) {
		fprintf(stdout, "DR_USAGE=%s\n", CPU_RESOURCE_USE);
		return(0);
	}
	else{
		return(1);
	}
}

int
process_checkrelease(char *resource)
{
	char *cpu_to_remove;	/* string to hold which cpu will be removed */
	int rc, 		/* return code */
	    cpu_id,		/* integer value of cpu to remove */
	    i,
	    done, 		/* flag to signify done searching */
	    try_cpu, 		/* cpu to try and add to rset */
	    ind_cpu;		/* loop index */
	rsethandle_t rs1;	/* rset to test */

	fprintf(stdout, "DR_LOG_DEBUG=process_checkrelease entry\n");

	/*
		* Retrieve env variable set by drmgr which specifies which
		* LCPUID is going to be removed
		*/
	cpu_to_remove=getenv("DR_LCPUID");

	fprintf(stdout, "DR_LOG_DEBUG=Removing LCPUID %s\n", cpu_to_remove);
	cpu_id = atoi(cpu_to_remove);

	/* Create an array of all the rsets on the system */
	find_rsets();

	fprintf(stdout, "DR_LOG_DEBUG=Search rsets for LCPUID\n");

	/*
		* For each of the rsets found
		*/
	for (i=0; i < r_count; i++){	
		rs1 = rset_arr[i].rset_hand;

		/*
		 * Check to see if DR_LCPUID is in rset
		 */
		rc = rs_op(RS_TESTRESOURCE, rs1, NULL, R_PROCS, cpu_id);
		if (rc == 0 || rc == EINVAL){
			if (rc == 0){ /* LCPUID not found in rset rs1 */
				fprintf(stdout, "DR_LOG_DEBUG=LCPUID %d not in rset %d\n", cpu_id, i);
			}
			else{ /* Error with rs_op call, exit program*/
				return(1);
			}
		}
		else{ /* LCPUID was found in rs1 */
			fprintf(stdout, "DR_LOG_DEBUG=LCPUID %s found in rset %d\n", cpu_to_remove, i);
			
			/*
			 * Remove DR_LCPUID from rset
			 */
			if (rs_op(RS_DELRESOURCE, rs1, NULL, R_PROCS, cpu_id) != 0){
				fprintf(stdout, "DR_LOG_DEBUG=LCPUID %s could not be removed from rset %d\n", cpu_to_remove, i);
				return(1);	/* Error removing cpu */	
			}
			else{ /* LCPUID was successfully removed from rs1 */
				fprintf(stdout, "DR_LOG_DEBUG=LCPUID %s removed from rset %d\n", cpu_to_remove, i);

				/*
				 * Save changes to rset
				 */
				change_rset(rs1, rset_arr[i].rs_name);
			}
		}
	}
	fprintf(stdout, "DR_LOG_DEBUG=PASS\n");
	fprintf(stdout, "DR_LOG_DEBUG=process_checkrelease exit\n");
	return(0);
}

int
process_prerelease(char *resource)
{

	fprintf(stdout, "DR_LOG_DEBUG=process_prerelease entry\n");
	fprintf(stdout, "DR_LOG_DEBUG=process_prerelease exit\n");
	return(0);
}

int
process_postrelease(char *resource)
{
	
	fprintf(stdout, "DR_LOG_DEBUG=process_postrelease entry\n");
	fprintf(stdout, "DR_LOG_DEBUG=process_postrelease exit\n");
	return(0);
}

int
process_undoprerelease(char *resource)
{

	fprintf(stdout, "DR_LOG_DEBUG=process_undoprerelease entry\n");
	fprintf(stdout, "DR_LOG_DEBUG=process_undoprerelease exit\n");
	return(0);
}
	
/*
 * Function Name : find_rsets
 *
 * Description : Find all classes and subclasses in the current
 *		 wlm configuration and the rsets associated with
 *		 those classes and subclasses.
 *
 * Parameters : NONE
 *
 * Return : NOTHING
 */
void
find_rsets(){

	int flags = WLM_VERSION;
	int i, j, rc;
	struct wlm_args args;

	fprintf(stdout, "DR_LOG_DEBUG=find_rsets entry\n");

	/*
	 * call to make wlm apis available for this process
	 */
	rc = wlm_initialize(flags);
	if (rc){ /* Error in wlm_initialize call */
		fprintf(stdout, "DR_LOG_DEBUG=Error with wlm_initialize\n");
		exit(1);
	}

	memset(&args, 0, sizeof(args));
	memset(clinfo, 0, sizeof(clinfo));
	memset(subclinfo, 0, sizeof(clinfo));

	/*
	 * Initialize args struct for call to wlm_read_classes.
	 * Need to gather all rsets from current wlm configuration
	 */
	args.versflags = flags;
	args.confdir[0] = '\0';
	args.cl_def.data.descr.name[0] = '\0';

	count = NCLASSES;
	fprintf(stdout, "DR_LOG_DEBUG=Read wlm classes\n");

	/* Read class info from current configuration */
	rc = wlm_read_classes(&args, clinfo, &count);
	if (rc){
		fprintf(stdout, "DR_LOG_DEBUG=Error reading classes\n");
		exit(3);
	}

	/* For each class gathered from wlm_read_classes */
	for (i=0; i < count; i++){

		/* Call to save rset in array */
		save_rset(&clinfo[i]);

		/*
		 * Set up args struct to query for any subclasses
		 * that may be related to the super class in question
		 */
		strcpy(args.cl_def.data.descr.name, clinfo[i].data.descr.name);
		args.confdir[0] = '\0';
		args.versflags  = flags;
		count2 = NUMSUB;

		/* Get subclasses for current class */
		rc = wlm_read_classes(&args, subclinfo, &count2);
		if (rc){
			continue;
		}

		/* For each subclass */
		for (j=0; j < count2; j++){
			save_rset(&subclinfo[j]);
		}
	}
}

/*
 * Function Name : save_rset
 *
 * Description : Will take a class definition and save the rset
 * 		 associated with it, only if it is not already in the
 * 		 rset array.
 *
 * Parameters : struct class_definition *cldef - class struct which holds all
 *				properties of the class, especially the
 *				rset information
 *
 * Return : NOTHING
 */
void
save_rset(struct class_definition *cldef){

	int rc, i;
	char *rsetname, *namespace, *div;
	char temprset[255];
	rsethandle_t rs_temp;

	/* Make space for new rset */
	rs_temp = rs_alloc(RS_EMPTY);

	/* Save the rset name */
	strcpy(temprset, cldef->data.rset_name);
	strcpy(rset_arr[r_count].rs_name, cldef->data.rset_name);

	fprintf(stdout, "DR_LOG_DEBUG=Searching %s\n", cldef->data.descr.name);

	/* If there is an rset associated with the current class */
	if (temprset[0] != '\377' && strlen(temprset)){
		fprintf(stdout, "DR_LOG_DEBUG=temprset = %s\n", temprset);

		/* Divide rset name into namespace and rset name */
		namespace = temprset;
		div = strchr(temprset, '/');
		rsetname = div + 1;
		*div = '\0';
		fprintf(stdout, "Looking for %s/%s\n", namespace, rsetname);

		/* Get rset info and place in rs_temp */
		rc = rs_getnamedrset(namespace, rsetname, rs_temp);
		if (rc){
			fprintf(stdout, "DR_LOG_DEBUG=Error with rset %s/%s\n",
						namespace, rsetname);
			exit(4);
		}

		/* Check to make sure this rset is not already in array */
		for (i=0; i < r_count; i++){
			if ((strcmp(rset_arr[i].rs_name, cldef->data.rset_name) == 0)){
				/* rset has already been found and placed
				 * in the rset array, therefore we do not
				 * need to save it again
				 */
				break;
			}
		}

		/* If the rset is not found is not found in the array,
		 * add the rset
		 */
		if (i == r_count){
			fprintf(stdout, "Added %s/%s\n", namespace, rsetname);
			rset_arr[r_count++].rset_hand = rs_temp;
		}
	}
}

/*
 * Function Name : change_rset
 *
 * Description : Take an rset handle and the name of the rset.  It will
 * 		 make a copy of the rset and replace the original rset in
 * 		 both the kernel and in the configuration file.
 *
 * Parameters : rsethandle_t rs1 - handle of the rset to change and then add
 *			to both wlm configurations
 *		char * rs_name - Name of the rset in which to change.
 *
 * Return : NOTHING
 */
void
change_rset(rsethandle_t rs1, char *rs_name){
	struct wlm_args args;
	int i, rc, j;
	rsethandle_t    rs2;
	char t_rset[255];
	char *n_space, *div, *r_name;

	/* Create space for rset */
	rs2 = rs_alloc(RS_EMPTY);

	/*
	 * Copy current rset, rs1,  into newly created one, rs2.
	 * This copy will only copy the processors that are in
	 * rs1 into rs2.
	 */
	rs_op(RS_COPY, rs1, rs2, R_PROCS, 0);

	/* Gather rset name and name space from argument rs_name */
	strcpy(t_rset, rs_name);
	n_space = t_rset;
	div = strchr(t_rset, '/');
	r_name = div + 1;
	*div = '\0';

	/* Register new rset with same name as original rset */
	rs_registername(rs2, n_space, r_name,
		RS_IRUSR | RS_IWUSR | RS_IRGRP | RS_IROTH, RS_REDEFINE);
	fprintf(stdout, "DR_LOG_DEBUG=Entered change_rset for %s\n", rs_name);

	/*
	 * For each class in the wlm configurations, check to see if
	 * the class uses the newly created rset.  If so, re-connect
	 * the class to the new rset.
	 */
	for(i=0; i < count; i++){
		/* Check to see if class has rset associated with it */
		if (strlen(clinfo[i].data.rset_name) &&
			(clinfo[i].data.rset_name[0] != '\377') &&
			(strcmp(clinfo[i].data.rset_name, rs_name)) == 0){
			fprintf(stdout, "DR_LOG_DEBUG=Changing class %s\n",
				clinfo[i].data.descr.name);

			/* Initialize args argument */
			wlm_init_class_definition(&args);
			args.versflags = WLM_VERSION;
			args.cl_def = clinfo[i];
			args.confdir[0] = '\0';
			strcpy(args.cl_def.data.rset_name, rs_name);

			/* Re-associate class with new rset in kernel only */
			if ((rc = wlm_change_class(&args)) != 0){
				fprintf(stdout, "DR_LOG_DEBUG=Error changing class, rc = %d, errno = %d\n", rc, errno);
			}
			else{
				fprintf(stdout, "DR_LOG_DEBUG=Changed class\n");
			}

			/*
			 * Now re-associate class with the wlm configuration
			 * in /etc/wlm.  Use current since the current
			 * directory will point to the wlm configuration in
			 * use.
			 */
			strcpy(args.confdir, "current");

			if ((rc = wlm_change_class(&args)) != 0){
				fprintf(stdout, "DR_LOG_DEBUG=Error changing class, rc = %d, errno = %d\n", rc, errno);
			}
			else{
				fprintf(stdout, "DR_LOG_DEBUG=Changed class\n");
			}
		}
	}

	/* Do same thing as above for subclasses if need be */
	for(j=0; j < count2; j++){
		if ((strcmp(subclinfo[i].data.rset_name, rs_name)) == 0){
			fprintf(stdout, "DR_LOG_DEBUG=comparing to %s\n",
				subclinfo[i].data.rset_name);
			fprintf(stdout, "DR_LOG_DEBUG=Changing class %s\n",
				subclinfo[j].data.descr.name);

			/* Initialize wlm args */
			wlm_init_class_definition(&args);
			args.versflags = WLM_VERSION;
			args.cl_def = subclinfo[j];
			args.confdir[0] = '\0';
			strcpy(args.cl_def.data.rset_name, rs_name);

			/* Change kernel configuration of wlm */
			if ((rc = wlm_change_class(&args)) != 0){
				fprintf(stdout, "DR_LOG_DEBUG=Error changing class, rc = %d, errno = %d\n", rc, errno);
			}
			else{
				fprintf(stdout, "DR_LOG_DEBUG=Changed class\n");
			}

			/* Change /etc/wlm configuration */
			strcpy(args.confdir, "current");
			if ((rc = wlm_change_class(&args)) != 0){
				fprintf(stdout, "DR_LOG_DEBUG=Error changing class, rc = %d, errno = %d\n", rc, errno);
			}
			else{
				fprintf(stdout, "DR_LOG_DEBUG=Changed class\n");
			}
		}

	}
}

