/*
 *  Machtype: determine machine type & display type for the rios
 *
 * RCS Info
 *    $Id: machtype_rios.c,v 1.7 1996/06/02 07:38:50 ghudson Exp $
 */


#include <stdio.h>
#include <string.h>
#include <odmi.h>
#include <sys/cfgdb.h>
#include <sys/cfgodm.h>

typedef struct {
  unsigned update_database : 1;	/* update device in database 	*/
  unsigned found_in_list   : 1;	/* device found in master list  */
  unsigned defective_device: 1;	/* device is defective - no fru */
  unsigned defective_devfru: 1;   /* device is defective - w/fru  */
  unsigned delete_from_list: 1;	/* delete device from database  */
  unsigned do_not_disp_miss: 1;	/* do not display device in menu*/
  unsigned device_tested   : 1;	/* device has been tested       */
  unsigned device_driver_err:1; 	/* device driver open error     */
} diag_flag_t;

/* structure of key fields from PdDv  - Massive memory saver */
struct Pdv {
  short	led;
  short	detectable;
  short	fru;
  short	setno;
  short	msgno;
  char	catalog[NAMESIZE];
};

/* Structure containing all device information needed by the Diag */
/* Controller. Information is derived from the Customized Device  */
/* Object Class, PreDefined Diagnostic Object Class, and the      */
/* Customized Diagnostic Object Class. One entry is made for each */
/* device to be tested. 					  */
typedef struct diag_dev_info_s  {
	char	*Text;			/* describes device 	  */
	char	Asterisk;		/* display asterisk flag  */
	diag_flag_t	    flags;	/* misc device flags	  */
	struct  CuDv     *T_CuDv;    	/* customized device      */
	struct  Pdv	 *T_Pdv;	/* important PdDv items   */
	struct  CuVPD    *CuVPD_HW;	/* hardware vpd           */
	struct  CuVPD    *CuVPD_USER;	/* user entered vpd       */
	struct  CDiagDev *T_CDiagDev;	/* customized diag device */
	struct  PDiagDev *T_PDiagDev;	/* predefined diag device */
}diag_dev_info_t, *diag_dev_info_ptr_t;

typedef struct binding {
  char *name;
  char *title;
  char *attrib;
  char *value;
  short status;
} binding_t;

char *dev_status[] = { "defined", "available", "stopped" };

#define MAXRETURN 50

void handle_odm_error(char *what);
binding_t *find_value(char *name, char *attrib, int *nfound);
void usage(char *name);
void init_db();


diag_dev_info_t *stuff;
int num_in_db;
struct PdAt **at_stuff;
int *num_at;

main(argc,argv)
     int argc;
     char **argv;
{
  char *val;
  binding_t *found,*found1,*found2;
  int i,j,k;
  int c;
  int doall = 0;
  int docpu =0;
  int dodisp = 0;
  int dodisk = 0;
  int domem = 0;
  int doplat = 0;
  int doathenaV = 0;
  int dosyspV = 0;
  int dolocalV = 0;
  int dobosN = 0;
  int dobosV = 0;
  int dosysnam = 0;
  int verbose = 0;
  FILE *f;
  
  if (argc == 1) {
    printf("rsaix\n");
    exit(0);
  }

  while ((c = getopt(argc,argv,"AabcdLMpPrvVSkm")) != EOF)
    switch(c) {
    case 'a':
      doall = 1;
      break;
    case 'A':
      doathenaV = 1;
      break;
    case 'c':
      docpu = 1;
      break;
    case 'd':
      dodisp = 1;
      break;
    case 'L':
      dolocalV = 1;
      break;
    case 'M':
      domem = 1;
      break;
    case 'p':
      doplat = 1;
      break;
    case 'P':
      dosyspV = 1;
      break;
    case 'r':
      dodisk = 1;
      break;
    case 'v':
      verbose = 1;
      break;
    case 'N':
      dobosN = 1;
      break;
    case 'E':
      dobosV = 1;
      break;
    case 'S':
      dosysnam = 1;
      break;
    case 'V':
      verbose = 2;
      break;
    case 'k':
    case 'm':
      /* Ignore these, since we're getting the info from the ODM, not the */
      /* kernel or /dev/kmem */
      break;
    default:
      usage(argv[0]);
    }

  if (odm_initialize() == -1) {
    handle_odm_error("initializing ODM");
    exit(odmerrno);
  }

/* Print out entire config list if the -V option used */
  if (verbose == 2) {
    init_db();
    for (i=0;i<num_in_db;i++) {
      printf("%10s %9s %s\n",stuff[i].T_CuDv->name,stuff[i].T_CuDv->location,
	     stuff[i].Text);
      if (num_at[i] != 0) {
	for (j=0;j<num_at[i];j++)
	  printf("%20s %s\n",at_stuff[i][j].attribute,at_stuff[i][j].deflt);
      }
      printf("-----------------------------\n");
    }
    exit(0);
  }

  if (doplat || doall) {
      printf("rsaix\n");
  }

/* Print out version of Athena machtype compiled against */
  if (doathenaV || doall) {
    if (verbose)
	printf("Machtype version: %s.%s\n",ATHMAJV,ATHMINV);
      else
	printf("%s.%s\n",ATHMAJV,ATHMINV);
  }

/* Print out version of attached packs */
  if (dosyspV || doall) {
    char buf[256],rvd_version[256], *p;
    if ((f = fopen("/srvd/.rvdinfo","r")) == NULL ) {
      printf("Syspack information unavailable\n");
    } else {
      fgets(buf,256,f);
      fclose(f);

      /* If it is verbose, give the whole line, otherwise just the vers # */
      if (verbose) {
	printf(buf);
      } else {
	p = index(buf,' '); /* skip "Athena" */
	p = index(p+1,' '); /* skip "RVD" */
	p = index(p+1,' '); /* Skip "RSAIX" */
	p = index(p+1,' '); /* skip "version" */
	strncpy(rvd_version,p+1,256);
	p = index(rvd_version,' ');
	*p = '\0';
	printf("%s\n",rvd_version);
	}
    }
  }

/* Print out local version from /etc/athena/version */
  if (dolocalV || doall) {
    char buf[256],loc_version[256], *p;
    if ((f = fopen("/etc/athena/version","r")) == NULL) {
      printf("Local version information unavailable\n");
    } else {
      fseek(f,-100,2);
      while (fgets(buf,256,f) != NULL)
	;
      fclose(f);

      if (verbose) {
	printf(buf);
      } else {
	p = index(buf,' '); /* skip "Athena" */
	p = index(p+1,' '); /* skip "Workstation/Server" */
	p = index(p+1,' '); /* Skip "RSAIX" */
	p = index(p+1,' '); /* skip "version" */
	strncpy(loc_version,p+1,256);
	p = index(loc_version,' ');
	*p = '\0';
	printf("%s\n",loc_version);
      }
    }
  }
	
  /* Print out vendor OS name */
  if (dobosN) {
    if (verbose) {
	printf("AIX 3.1\n");
      } else {
	printf("AIX\n");
      }
    }

  /* Print out vendor OS version */
  if (dobosV) {
    printf("3.1\n");
  }

  /* Print out Athena System name */
  if (dosysnam) {
    printf("%s\n", ATHSYS);
  }

/* Print out cpu type */
  if (docpu || doall) {
    if (verbose) {
      init_db();
      found = find_value("sys0","modelcode",&i);
      printf("POWER %s\n",found[0].value);
    }
    else
      printf("POWER\n");
  }

/* Print out displays */
/* Get primary display name from hft; print out all displays */
  if (dodisp || doall) {
    init_db();
    found = find_value("hft","default_disp",&i);
    for(j=0;j<i;j++) {
      if (verbose == 1) {
	found1 = find_value(found[j].value,"dsp_name",&k);
	found2 = find_value(found[j].value,"dsp_desc",&k);
	printf("%s : %s (%s)\n",
	       found1[0].value, found2[0].value, dev_status[found1[j].status]);
      } else {
	found1 = find_value(found[j].value,"dsp_name",&k);
	if (found1[0].status != AVAILABLE) continue;
	printf("%s\n",found1[0].value);
      }
    }
  }

/* Print out disk types */
  if (dodisk || doall) {
    char *bootdisk;

    init_db();
    found = find_value("sys0","bootdisk",&i);
    bootdisk = found[0].value;

    found = find_value("hdisk","*",&i);
    for(j=0;j<i;j++) {
      char *size;
      found1 = find_value(found[j].name,"size",&k);
      if (k == 0)
	size = "unk";
      else
	size = found1[0].value;
      if (verbose == 1) {
	if (!strcmp(bootdisk,found[j].name)) {
	  printf("%6s %4s : %s (boot) (%s)\n",
		 found[j].name, size, found[j].title,
		 dev_status[found1[0].status]);
	} else {
	  printf("%6s %4s : %s (%s)\n",
		 found[j].name, size, found[j].title,
		 dev_status[found1[0].status]);
	}
      } else {
	if (found1[0].status != AVAILABLE) continue;
	if (!strcmp(bootdisk,found[j].name)) {
	  printf("%6s %4s boot\n",found[j].name,size);
	} else {
	  printf("%6s %4s\n",found[j].name,size);
	}
      }
    }

/* Print out floppy drives */
    found = find_value("fd","fdtype",&i);
    for (j=0;j<i;j++) {
      if (verbose == 1)
	printf("%6s  unk : %s %s (%s)\n",
	       found[j].name, found[j].value, found[j].title,
	       dev_status[found[j].status]);
      else {
	if (found[j].status != AVAILABLE) continue;
	printf("%6s  unk %s\n",found[j].name,found[j].value);
      }
    }
  }

/* Print out memory */
/* Note we get the total memory from the sys0 entry, but the individual */
/* cards are named mem?; use them to get individual information */

  if (domem || doall) {
    init_db();
    if (verbose == 1) {
      found = find_value("mem","size",&i);
      for(j=0;j<i;j++)
	printf("%s %3s MB : %s (%s)\n",
	       found[j].name, found[j].value, found[j].title,
	       dev_status[found[j].status]);
      found = find_value("sys0","realmem",&i);
      printf("Total : %s K\n",found[0].value);
    } else {
      found = find_value("sys0","realmem",&i);
      printf("%s K\n",found[0].value);
    }
  }
  exit(0);
}

void
init_db()
{
  static int filled = 0;
  int i,j,k;
  char crit[256];
  struct listinfo pdat_info,cuat_info;
  struct CuAt *CuAt_list;

  if (filled == 1)
    return;

  filled = 1;
/* Build initial DB */
  stuff = (diag_dev_info_t *) init_diag_db(&num_in_db);

/* Fill in attributes */
  at_stuff = (struct PdAt **)calloc(num_in_db,sizeof(struct PdAt *));
  num_at = (int *)calloc(num_in_db,sizeof(int));
  for(i=0;i<num_in_db;i++) {
    sprintf(crit,"uniquetype = %s",stuff[i].T_CuDv->PdDvLn_Lvalue);
    if ((at_stuff[i] = get_PdAt_list(PdAt_CLASS,crit,&pdat_info, MAXRETURN,1))
	== (struct PdAt *) -1) {
      handle_odm_error("Getting PdAt list");
      exit(odmerrno);
    }
    num_at[i] = pdat_info.num;
    sprintf(crit,"name = %s",stuff[i].T_CuDv->name);
    if ((CuAt_list = get_CuAt_list(CuAt_CLASS,crit,&cuat_info, MAXRETURN,1))
	== (struct CuAt *) -1) {
      handle_odm_error("Getting CuAt list");
      exit(odmerrno);
    }

/* Copy in customized attributed values in over default values */
    if (cuat_info.num != 0) {
      for (j=0;j<cuat_info.num;j++) {
	for (k=0;k<pdat_info.num;k++) {
	  if (!strcmp(at_stuff[i][k].attribute,CuAt_list[j].attribute)) {
	    strcpy(at_stuff[i][k].deflt,CuAt_list[j].value);
	    break;
	  }
	}
      }
    }
  }

}

binding_t *
find_value(char *name, char *attrib, int *nfound)
{
  int i,j;
  int namelen;
  binding_t *to_return;
  int n_alloc;
  
  *nfound = 0;
  n_alloc = 10;
  to_return = (binding_t *)calloc(n_alloc,sizeof(binding_t)*10);
  namelen = strlen(name);

  for(i=0;i<num_in_db;i++) {
    if (!strncmp(stuff[i].T_CuDv->name,name,namelen)) {
      if (attrib[0] == '*') {
	to_return[*nfound].name = stuff[i].T_CuDv->name;
	to_return[*nfound].status = stuff[i].T_CuDv->status;
	to_return[*nfound].title = stuff[i].Text;
	to_return[*nfound].attrib = "*";
	to_return[*nfound].value = "";
	(*nfound)++;
      } else {
	for(j=0;j<num_at[i];j++) {
	  if (!strcmp(at_stuff[i][j].attribute,attrib)) {
	    to_return[*nfound].name = stuff[i].T_CuDv->name;
	    to_return[*nfound].status = stuff[i].T_CuDv->status;
	    to_return[*nfound].title = stuff[i].Text;
	    to_return[*nfound].attrib = at_stuff[i][j].attribute;
	    to_return[*nfound].value = at_stuff[i][j].deflt;
	    (*nfound)++;
	    break;
	  }
	}
      }
    }
  }
  return(to_return);
}  

void handle_odm_error(char *what)
{
  char *err_msg;

  if (odm_err_msg(odmerrno,&err_msg) < 0)
    fprintf(stderr,"machtype: Unknown Error: %s\n",what);
  else
    fprintf(stderr,"machtype: Error %s : %s\n", what, err_msg);
  return;
}

void usage(char *name)
{
  fprintf(stderr,"usage:\n");
  fprintf(stderr,"  [-a]  All hw info\n");
  fprintf(stderr,"  [-c]  CPU type\n");
  fprintf(stderr,"  [-d]  Display type\n");
  fprintf(stderr,"  [-M]  Memory info\n");
  fprintf(stderr,"  [-p]  Platform name\n");
  fprintf(stderr,"  [-r]  Disk info\n");
  fprintf(stderr,"  [-v]  Verbose\n");
  fprintf(stderr,"  [-V]  Print out entire hw configuration\n");
  fprintf(stderr,"  [-A]  machtype version\n");
  fprintf(stderr,"  [-P]  system pack version\n");
  fprintf(stderr,"  [-L]  local disk version\n");
  fprintf(stderr,"  [-S]  athena System name\n");
  exit(1);
}
