/*
	Module contining general routines for BDM.
*/

#include <stdio.h>
#include <ctype.h>
#include <time.h>
#include "bdm.h"

extern struct sys_ident_node *sys_info; /* System information on idents */
extern struct pif_record record;
extern struct plist_type plist;
extern char my_account[ACCOUNTNAMESIZE];
extern int bd_master;
extern int bd_viewer;
extern int bd_cl_user_master;
extern int bd_cl_user_viewer;
extern char pname[PDESCSIZE];		/* Command parameter */
extern char username[USERNAMESIZE];
extern char ident[IDENTSIZE];
extern int  cl_size;
extern char owner[ACCOUNTNAMESIZE];
extern char partition[PNAMESIZE];	/* Command qualifier */
extern char expiration[EXPIRESIZE];
extern int  cl_user;
extern int  cl_administrator;
extern int  cl_full;
extern int  cl_brief;
extern int  cl_write;
extern int  cl_read;
extern int  cl_repair;
extern int  cl_confirm;
extern int  cl_type;
extern char description[PDESCSIZE];
extern int pif_eof;


/*  List of routines in this module. */
void dummy_routine();
void add_account();
void bdm_add();
void bdm_create();
void bdm_destroy();
void bdm_exit();
void bdm_expire();
void bdm_modify();
void bdm_remove();
void bdm_report();
void bdm_show();
void bdm_verify();
int check_expire();
void check_flags();
int check_priv();
void check_sys_info();
struct anode *find_account();
int find_partition();
struct sys_ident_node *find_sys_info();
struct sys_user_node *find_user_info();
void flush_partition();
int flush_pif();
int get_mv_rec();
int get_partition();
void move_account();
void pad_string();
void print_header();
void recreate_partition();
void remove_user();
void report_partition();
void truncate_string();
int verify_partition();
int verify_users();

/*
	Dummy routine for unimplemented functions.
*/
void dummy_routine()
{
  printf("Function is currently not implemented\n");
  return;
} /*** End of routine dummy_routine ***/



/*
	Add_account - Routine to add an account to the userlist or adminlist.
*/
void add_account(aptr,accountname)
  struct anode **aptr;
  char *accountname[];
{
  struct anode *save_ptr;
  struct anode *temp_ptr;
  char idname[IDENTSIZE+2];

  /* Save the beginning of the list. */
  save_ptr = *aptr;



  /* Add this node to the beginning of the list. */
  temp_ptr = (struct anode *)malloc(sizeof(struct anode));
  temp_ptr->prev = 0;
  temp_ptr->next = save_ptr;
  strncpy(temp_ptr->accountname,accountname,sizeof(temp_ptr->accountname));

  /* Now set the access mode */
  if(cl_write) {
    temp_ptr->access = 'W';
    if(plist.pid.plistidtype == '1') {
      sprintf(idname,"%s",plist.pid.plistident);
    } else {
#ifdef VMS
      sprintf(idname,"%s$W",plist.pid.plistident);
#else
      sprintf(idname,"%s_W",plist.pid.plistident);
#endif
    }
    if(!(grant_ident(idname,temp_ptr->accountname))) {
      printf("Could not grant identifier %s",idname);
      printf(" to account %s\n",temp_ptr->accountname);
    }
  } else {
    temp_ptr->access = 'R';
    /*   On VMS only one of the identifiers $R or $W is granted   */
    /*   but on Unix systems both of the identifiers could be     */
    /*   granted.                                                 */
    /* Grant the read identifier to the user */
    if(plist.pid.plistidtype == '1') {
      sprintf(idname,"%s",plist.pid.plistident);
    } else {
#ifdef VMS
      sprintf(idname,"%s$R",plist.pid.plistident);
#else
      sprintf(idname,"%s_R",plist.pid.plistident);
#endif /* VMS */
    }
    if(!(grant_ident(idname,temp_ptr->accountname))) {
      printf("Could not grant identifier %s",idname);
      printf(" to account %s\n",temp_ptr->accountname);
    }
  }

  *aptr = temp_ptr;
  return;
} /*** End of routine add_account ***/

/*
	BDM_ADD - Routine to add a user to a partition.
*/
void bdm_add()
{
  char new_account[ACCOUNTNAMESIZE];
  struct anode *uptr;
  struct anode *aptr;

  if(find_partition(partition)) {
    printf("Adding user %s to partition %s\n",username, plist.plistname);
    if(check_priv(TRUE)) {
      /* Found the correct partition and they have the correct priv's */
      /* Translate the username to an account name */
      if(!(trans_user(username,new_account))) {
	printf("No such username\n");
	bdm_exit(0);
      }
      /* Find out if the account is in the user or administrator lists */
      uptr = find_account(plist.userlist,new_account);
      aptr = find_account(plist.adminlist,new_account);
      if((uptr != 0) && (aptr != 0)) {
	printf("User is already a member of the partition\n");
	bdm_exit(0);
      }
      /* Now depending on if the user/administrator flag is set add the user */
      /* to the appropriate list */
      if(cl_administrator)
	add_account(&plist.adminlist,new_account);
      else
	add_account(&plist.userlist,new_account);
      flush_partition();	/* Once the partition has been modified flush */
    } else {
      printf("No administrator access to partition %s\n",plist.plistname);
      bdm_exit(0);
    }
  } else {
    printf("Partition not found or not unique\n");
    bdm_exit(0);
  }
  return;
} /*** End of routine bdm_add ***/

/*
	BDM_CREATE - Routine to create a partition.
*/
void bdm_create()
{
  int i;
  char idname[IDENTSIZE+2];

  printf("Creating partition %s\n",pname);

  if(bd_master) {
    if(find_partition(pname)) {
      printf("Partition already exists\n");
      bdm_exit(0);
    }
    flush_pif();	/* Copy the existing information */
    /* Make some fields blank for now... */
    plist.ploc.plistloc[0] = '\0';
    plist.ploc.plistvol[0] = '\0';
    plist.plisttype[0] = '\0';
    plist.plistexception[0] = '\0';
    plist.plistremote[0] = '\0';
    plist.plistexpire[0] = '\0';

    for(i=0;i<sizeof(pname);i++) plist.plistname[i] = pname[i];
    for(i=0;i<sizeof(description);i++) plist.plistdesc[i] = description[i];
    for(i=0;i<sizeof(ident);i++) plist.pid.plistident[i] = ident[i];
    for(i=0;i<sizeof(expiration);i++) plist.plistexpire[i] = expiration[i];
    plist.adminlist = (struct anode *)malloc(sizeof(struct anode));
    /* The owner is also an administrator */
    for(i=0;i<sizeof(owner);i++) {
      plist.plistowner[i] = owner[i];
      plist.adminlist->accountname[i] = owner[i];
    }
    plist.adminlist->access = 'W';	/* Owner has write access */
    plist.adminlist->next = 0;
    plist.plistsize = cl_size;
    plist.userlist = 0;
    flush_partition();	/* Now copy the new partition to the pif */
    /* Create the identifiers */
    if(!(create_ident(plist.pid.plistident,sizeof(plist.pid.plistident)))) {
      printf("Unable to create identifier\n");
      bdm_exit(0);
    }
    /* Now grant the owner identifier to the owner */
    for(i=0;(i<sizeof(plist.pid.plistident)) &&
		     (plist.pid.plistident[i] != ' ') &&
		     (plist.pid.plistident[i] != '\0');i++)
      idname[i] = plist.pid.plistident[i];
    if(!cl_type) {
#ifdef VMS
      idname[i++] = '$';
#else
      idname[i++] = '_';
#endif
      idname[i++] = 'W';
    }
    idname[i] = '\0';
    if(!(grant_ident(idname,plist.plistowner))) {
      printf("Could not grant identifier %s",idname);
      printf(" to account %s\n",plist.plistowner);
    }

#ifndef VMS
    /* If type 0 ident and Unix systems then grant _R to owner */
    if(!cl_type) {
      /* Grant the read ident to the owner */
      idname[i-1] = 'R';
      if(!(grant_ident(idname,plist.plistowner))) {
        printf("Could not grant identifier %s",idname);
        printf(" to account %s\n",plist.plistowner);
      }
    }
#endif

  } else {
    printf("No master priviledge\n");
    bdm_exit(0);
  }
  return;
} /*** End of routine bdm_create ***/

/*
	BDM_DESTROY - Routine to destroy a partition.
*/
void bdm_destroy()
{
  if(find_partition(pname)) {
    printf("Destroying partition %s\n",pname);
    if(check_priv(TRUE)) {
      destroy_ident(plist.pid.plistident);
    } else {
      printf("No administrator access to partition %s\n",pname);
      bdm_exit(0);
    }
  } else
    printf("Partition not found\n");

  return;
} /*** End of routine bdm_destroy ***/


/*
	Bdb_exit - Exit routine for bdm.

	Input: Flag - 0 to indicate an error in which case the PIF is closed
			and the scratch file is deleted.
		        OR to indicate that the scratch version of the PIF
			should not be copied to the PIF.
		      1 to indicate that the scratch PIF should be copied to
			the PIF.
*/
void bdm_exit(flag)
  int flag;
{
  close_pif();			/* Close the PIF and the scratch PIF. */
  if(flag) rename_pif();	/* Rename PIF.SCR to PIF.DAT */
  delete_scr();			/* Delete old PIF.SCR */
  exit(1);
} /*** End of bdm_exit ***/

/*
	BDM_EXPIRE - Routine to check expiration dates and remove partitions
			if they have expired.
*/
void bdm_expire()
{
  /* Check to see if the partition was specified on command line. If not then */
  /* check all partitions.                                                    */
  if(partition[0] == '\0') {
    while(get_partition()) {
      if(check_priv(TRUE)) {
	if(check_expire()) {
	  printf("Expiring partition %s\n",plist.plistname);
	  destroy_ident(plist.pid.plistident);
	} else
	  flush_partition();
      }
    }
  } else {
    if(find_partition(partition)) {
      if(check_priv(TRUE)) {
        if(check_expire()) {
	  printf("Expiring partition %s\n",plist.plistname);
	  destroy_ident(plist.pid.plistident);
	} else
	  flush_partition();
	flush_pif;
      } else
	printf("No access to partition %s\n",plist.plistname);
    } else
      printf("Partition not found\n");
  }

  return;
} /*** End of routine bdm_expire ***/

/*
	BDM_MODIFY - Routine to modify information about a user.
*/
void bdm_modify()
{
  char mod_account[ACCOUNTNAMESIZE];
  char idname[IDENTSIZE+2];	/* Identifier name with either $R or $W */
  struct anode *uptr;
  struct anode *aptr;
  struct anode *tmp_ptr;

  if(find_partition(partition)) {
    printf("Modifying user %s on partition %s\n",username, plist.plistname);
    if(check_priv(TRUE)) {
      if(!(trans_user(username,mod_account))) {
	printf("No such username\n");
	bdm_exit(0);
      }

      /* If the user being modified is the owner then print error and exit. */
      if(strncmp(plist.plistowner,mod_account,sizeof(mod_account)) == 0) {
	printf("Can't modify the owner of the partition.\n");
	bdm_exit(0);
      }

      /* Find the user on one of the lists. */
      uptr = find_account(plist.userlist,mod_account);
      aptr = find_account(plist.adminlist,mod_account);
      if((uptr == 0) && (aptr == 0)) {
        printf("User is not a member of this partition\n");
	bdm_exit(0);
      }

      /* If the write flag was specified on the command line then modify */
      /* the access. If the access was not set to write or was not write */
      /* then set it to read. This will fix records in the database that */
      /* where blank.							   */
      if(aptr == 0)
	tmp_ptr = uptr;
      else
	tmp_ptr = aptr;
      if(cl_write)
	tmp_ptr->access = 'W';
#ifdef VMS
      sprintf(idname,"%s$W",plist.pid.plistident);
#else
      sprintf(idname,"%s_W",plist.pid.plistident);
#endif
      if((tmp_ptr->access != 'W') || (cl_read)) {
        tmp_ptr->access = 'R';
        revoke_ident(idname,mod_account);
      }

      /* If user now has write access then grant the ident */
      if(tmp_ptr->access == 'W') {
	grant_ident(idname,mod_account);
      }


/* On VMS the user has either the read or write ident but not both. On Unix */
/* they can have both.                                                      */


#ifdef VMS
      sprintf(idname,"%s$R",plist.pid.plistident);
      /* If the user has write access then revoke the read identifier */
      if(tmp_ptr->access == 'W') {
        revoke_ident(idname,mod_account);
      }
#else
      sprintf(idname,"%s_R",plist.pid.plistident);
      grant_ident(idname,mod_account);
#endif
      if(tmp_ptr->access == 'R') {
	grant_ident(idname,mod_account);
      }


      /* If the user flag was specified then check to see which list they */
      /* where on. If on the admin list then move to the user list.       */
      if(cl_user) {
        /* Now if the user was on the adminlist then move them to the userlist*/
	/* The move_account routine update aptr and plist.userlist to point */
	/* to the beginning of the list.                                    */
        if(aptr != 0) {
	  move_account(&aptr,&plist.userlist);
  	  plist.adminlist = aptr;
	}
      }
      if(cl_administrator) {
        if(uptr != 0) {
          move_account(&uptr,&plist.adminlist);
	  plist.userlist = uptr;
	}
      }

      flush_partition();	/* Once the partition has been modified flush */
    } else {
      printf("No administrator access to partition %s\n",plist.plistname);
      bdm_exit(0);
    }
  } else {
    printf("Partition not found or not unique\n");
    bdm_exit(0);
  }
  return;

} /*** End of routine bdm_modify ***/

/*
	BDM_remove - Routine to remove a user from a partition.
*/
void bdm_remove()
{
  char account[ACCOUNTNAMESIZE];	/* Accountname to remove */
  char idname[IDENTSIZE+2];	/* Identifier name with either $R or $W */
  struct anode *uptr;
  struct anode *aptr;

  if(find_partition(partition)) {
    printf("Removing user %s from partition %s\n",username, plist.plistname);
    if(check_priv(TRUE)) {
      /* Found the correct partition and they have the correct priv's */
      /* Translate the username to an account name */
      if(!(trans_user(username,account))) {
	printf("No such username\n");
	bdm_exit(0);
      }
      /* Check to see if they are trying to remove the owner if so then error */
      if(strcmp(account,plist.plistowner) == 0) {
	printf("Can't remove the owner of the partition\n");
	bdm_exit(0);
      }
      /* Now find the user in the lists */
      /* The user should not be in both lists but if so remove from both lists*/
      uptr = find_account(plist.userlist,account);
      aptr = find_account(plist.adminlist,account);
      if((uptr == 0) && (aptr == 0)) {
	printf("No users found\n");
	bdm_exit(0);
      }
      if(uptr != 0) {
        remove_user(&uptr);
        plist.userlist = uptr;
      }
      if(aptr != 0) {
	remove_user(&aptr);
        plist.adminlist = aptr;
      }
      /* Now revoke the identifier from the user. */
      /* If this is a type 1 partition then the identifier does not end */
      /* with $x or _x (where x is either r or w).			*/
      if(plist.pid.plistidtype == '1') {
        sprintf(idname,"%s",plist.pid.plistident);
      } else {
#ifdef VMS
        sprintf(idname,"%s$R",plist.pid.plistident);
        revoke_ident(idname,account);
        sprintf(idname,"%s$W",plist.pid.plistident);
        revoke_ident(idname,account);
#else
        sprintf(idname,"%s_R",plist.pid.plistident);
        revoke_ident(idname,account);
        sprintf(idname,"%s_W",plist.pid.plistident);
        revoke_ident(idname,account);
#endif
      }
    } else {
      printf("No administrator access to partition %s\n",plist.plistname);
      bdm_exit(0);
    }
  } else {
    printf("Partition not found or not unique\n");
    bdm_exit(0);
  }

  flush_partition();		/* Once the partition has been modified flush */

  return;
}

/*
	BDM_report - Routine to generate a partition report. If no
	partition is specified then a report is generated for each
	partition this user has access.
*/
void bdm_report()
{
  /* Check to see if the partition was specified. If so then get the info */
  /* from the pif. */
  if(partition[0] == '\0') {
    print_header();
    while(get_partition())
      if(check_priv(FALSE)) report_partition();
  } else {
    if(find_partition(partition)) {
      if(check_priv(FALSE)) {
        print_header();
        report_partition();
      } else
        printf("No reporting access to partition %s\n",plist.plistname);
    } else
      printf("Partition not found\n");
  }

  return;
} /*** End of routine bdm_report ***/

/*
	BDM_SHOW - Routine to show information from the PIF by username.
*/
void bdm_show()
{
  char search_account[ACCOUNTNAMESIZE];
  struct anode *uptr;
  struct anode *aptr;
  int num_partitions;
  int username_specified;

  num_partitions = 0;
  username_specified = FALSE;

  /* If the username was specified on the command line then check to see    */
  /* if the username is the same as the calling user or if the calling user */
  /* has either master or viewer privs.                                     */
  if(strlen(username) != 0) {
    /* User specified a username on the command line, translate to account */
    trans_user(username,search_account);
    if(strncmp(search_account,my_account,ACCOUNTNAMESIZE) != 0) {
      if(!(bd_master) && !(bd_viewer)) {
	printf("No priviledge for viewing user information\n");
	bdm_exit(0);
      }
      username_specified = TRUE;
    }
  } else {
    strncpy(search_account,my_account,ACCOUNTNAMESIZE);
  }
  
  /* Loop thru each partition checking to see if the user has access to the */
  /* partition.                                                             */
  while(get_partition()) {
    /* Check to see if this person is the owner of the partition. */
    if(strncmp(search_account,plist.plistowner,ACCOUNTNAMESIZE) == 0) {
      if(num_partitions == 0) {
	printf("Partition name     Member type        Access\n");
	printf("--------------     -------------      ------\n");
      }
      printf("%-10.10s         Owner                 W\n",plist.plistname);
      num_partitions++;
    } else {
      /* Not the owner, check to see if they have access */
      uptr = find_account(plist.userlist,search_account);
      aptr = find_account(plist.adminlist,search_account);
      if(aptr != 0) {
        if(num_partitions == 0) {
    	  printf("Partition name     Member type        Access\n");
	  printf("--------------     -------------      ------\n");
        }
        printf("%-10.10s         Administrator         %c\n",plist.plistname,aptr->access);
        num_partitions++;
      } else {
        if(uptr != 0) {
          if(num_partitions == 0) {
	    printf("Partition name     Member type        Access\n");
	    printf("--------------     -------------      ------\n");
          }
  	  printf("%-10.10s         User                  %c\n",plist.plistname,uptr->access);
          num_partitions++;
        } else {
	  /* If the username the calling user is a master and the username */
	  /* was not specified or if the username was specified and the it */
	  /* is a master then print a status line. */
	  if((bd_master && !(username_specified)) ||
	     (bd_cl_user_master && username_specified)) {
            if(num_partitions == 0) {
	      printf("Partition name     Member type        Access\n");
	      printf("--------------     -------------      ------\n");
            }
	    printf("%-10.10s         Master\n",plist.plistname);
	    num_partitions++;
	  } else {
	    if((bd_viewer && !(username_specified)) ||
	       (bd_cl_user_viewer && username_specified)) {
              if(num_partitions == 0) {
	        printf("Partition name     Member type        Access\n");
	        printf("--------------     -------------      ------\n");
              }
	      printf("%-10.10s         Viewer\n",plist.plistname);
	      num_partitions++;
            }
          }
        }
      }
    }
  }

  if(num_partitions == 0)
    printf("User does not have access to any partitions\n");

  return;

} /*** End of routine BDM_SHOW ***/
    

/*
	BDM_VERIFY - Routine to check the information in the PIF against the
		     information in either the SYSUAF or the /etc/group files.
		     The routine must first go through the system files and
		     make a list of identifiers on the system. The routine
		     verify_partition will set the bit in the list entry
		     when it has completed verifying the partition. If all
		     partitions were chosen and the user is a master then
		     the verify_ident routine will go through all of the
		     entries in the ident list and flag those that have not
		     been verified. This results in the idents that are
		     in the system but not in the PIF being flagged.
*/
void bdm_verify()
{
  struct sys_ident_node *sys_info;
  int  i;

  /* Check to see if the partition was specified. If so then get the info */
  /* from the pif. Validate only the single partition if specified. */
  if(partition[0] == '\0') {
    printf("Verifying system information\n");
    get_sys_info();		/* Make list of partition info from sys info */
    printf("Done verifying system information\n");
    printf("Verifying partitions\n");
    i = 0;
    while(get_partition())
      if(check_priv(FALSE)) {
	printf("%12s  ",plist.plistname);
	if(!verify_partition()) i=0;
	if(++i > 4) {
	  i = 0;
	  printf("\n");
	}
      }
    printf("\n");
    check_sys_info();		/* Check info in sys lists  */
  } else {
    if(find_partition(partition)) {
      if(check_priv(FALSE)) {
        verify_partition();
        printf("\n");
      } else
	printf("No access to verify partition %s\n",plist.plistname);
    } else
      printf("Partition not found\n");
  }
  return;

} /*** End of routine BDM_VERIFY ***/
    
/*
	Check_expire - Routine to compare the date in the plist to today's
			date and return true if plist date is before today.
*/
int check_expire()
{
  long clock;
  struct tm *now;
  int month, day, year;		/* Month, day and year from PIF */


  if(strlen(plist.plistexpire)) {
    /* Partition has an expiration date, get current date and compare the */
    /* dates.								  */
    clock = time((long *)0);
    now = localtime(&clock);
    sscanf(plist.plistexpire,"%d%*c%d%*c%d",&month,&day,&year);
    /* Time routine returns month between 0-11 and years since 1900 */
    if( ((year-1900) < now->tm_year) || 
       (((year-1900) == now->tm_year) &&
            ( ((month-1) < now->tm_mon) ||
	     (((month-1) == now->tm_mon) && (day < now->tm_mday)))))
      return(TRUE);
  }
  return(FALSE);
} /*** End of routine CHECK_EXPIRE ***/

/*
	Check_flags - Routine to read the PIF and set the master_flag
			and viewer_flag.
*/
void check_flags()
{
  char user_account[ACCOUNTNAMESIZE];
  int  len;

  bd_master = FALSE;
  bd_viewer = FALSE;
  bd_cl_user_master = FALSE;
  bd_cl_user_viewer = FALSE;

  /* If the username parameter was specified on the command line then trans */
  /* to accountname.     						    */
  if((len = strlen(username)) != 0) {
    trans_user(username,user_account);
  }
  while(get_mv_rec()) {
    /* Check to see if calling user is a master or viewer */
    if(strncmp(record.pr_union.acc.accountname,my_account,
       strlen(record.pr_union.acc.accountname)) == 0) {
      if(record.rtype == 'M') bd_master = TRUE;
      if(record.rtype == 'V') bd_viewer = TRUE;
    }
    /* Check to see if username specified on the command line */
    if(len != 0) {
      if(strncmp(record.pr_union.acc.accountname,user_account,ACCOUNTNAMESIZE) == 0) {
	if(record.rtype == 'M') bd_cl_user_master = TRUE;
        if(record.rtype == 'V') bd_cl_user_viewer = TRUE;
      }
    }
  }
  return;
} /*** End of routine check_flags ***/


/*
	Check_priv - Routine to check to see if a user has access to a
	partition.

	Input: Update_flag - True if user is attempting to update the partition
			   - False if user is only viewing partition.
*/
int check_priv(update_flag)
  int update_flag;
{
  struct anode *aptr;

  if(bd_master) return(TRUE);	/* If they are a master then they can access */
  if(!(update_flag) && bd_viewer) return(TRUE);

  /* Check to see if this user is the owner of the partition */
  if(strncmp(plist.plistowner,my_account,sizeof(plist.plistowner)) == 0)
    return(TRUE);

  /* Check to see if this user is a valid administrator */
  aptr = plist.adminlist;
  while(aptr != 0) {
    if(strncmp(aptr->accountname,my_account,sizeof(aptr->accountname))==0)
      return(TRUE);
    aptr = aptr->next;
  }
  return(FALSE);
} /*** End of routine check_priv ***/

/*
        Check_sys_info - Routine to look through the system lists to see
                         if any ident is not in the PIF.
*/
void check_sys_info()
{
  struct sys_ident_node *sys_ptr;

  for(sys_ptr = sys_info;sys_ptr != 0; sys_ptr = sys_ptr->next) {
    if(!sys_ptr->in_pif) {
      printf("Identifier %s not in PIF\n",sys_ptr->ident_name);
    }
  }
  return;
} /*** End of routine check_sys_info ***/


/*
	find_account - Routine to find an account in the specified list.

	Return: anode - Pointer to matching node.

*/
struct anode *find_account(aptr,accountname)
struct anode *aptr;
char *accountname;
{

  char acnt[ACCOUNTNAMESIZE];

  /* String passed to this routine may contain characters after the account */
  /* name so move the data to a different location then truncate the string */
  /* then we can compare the two strings together.                          */
  strncpy(acnt,accountname,sizeof(acnt));
  truncate_string(acnt,sizeof(acnt));
  while(aptr != 0) {
    if(strncmp(aptr->accountname,acnt,sizeof(acnt)) == 0)
      return(aptr);
    aptr = aptr->next;
  }

  return(0);		/* Account not found in admin list. */
} /*** End of routine find_account ***/

/*
	Find_partition - Routine to read the PIF file and return the partition
	information for the desired partition.

	Input: Partition_name - Name of partition to fetch.
				If null then select the partition that the
				user has access.
	Output: 

	Return Value:	True if partition found and is unique.
			False if partition not found or if partition is not
			specified and the user has administrative priv's to
			more then one partition.
*/
int find_partition(partition_name)
char *partition_name;
{
  /* If the partition name was not specified look for a partition that this */
  /* user can access. If there is more then one then return false.          */
  if(strlen(partition_name) == 0) {
    /* Loop thru the partitions until we find a partition that this user */
    /* is either the owner or manager of...				 */
    while(get_partition()) {
      if(check_priv(TRUE)) {
	/* Can update this partition, now flush the remaining information in */
	/* the pif. While flushing check to see if the user can modify another*/
	/* partition and if so then return FALSE.			     */
        if(flush_pif()) return(FALSE);
	return(TRUE);
      } else {
	flush_partition();
      }
    }
  } else {
    while(get_partition()) {
      if(strncmp(partition_name,plist.plistname,sizeof(plist.plistname)) == 0) {
        flush_pif();
        return(TRUE);
      } else flush_partition();
    }
  }
  return(FALSE);	/* No partition found... */
} /*** End of routine find_partition ***/

/*
	Find_sys_info - Routine to search the system information for an ident.
			The routine will mark the bit that indicates the node
			has been accessed.
			
	Return - Pointer to the found ident_node
*/
struct sys_ident_node *find_sys_info(ident)
char *ident[IDENTSIZE+2];
{
  struct sys_ident_node *ident_node;

  for(ident_node=sys_info;ident_node != 0;ident_node = ident_node->next) {
    if(!strncmp(ident_node->ident_name,ident,sizeof(ident_node->ident_name))) {
      ident_node->in_pif = TRUE;
      return(ident_node);
    }
  }
  return(0);
} /*** End of routine find_sys_info ***/

/*
	Find_user_info - Routine to search the user list for the specified user.
			
	Return - Pointer to the found user_node
*/
struct sys_user_node *find_user_info(ident_node,accountname)
struct sys_ident_node *ident_node;
char *accountname[ACCOUNTNAMESIZE];
{
  struct sys_user_node *user_node;

  if(ident_node) {
    for(user_node = ident_node->u_node;user_node != 0;
        user_node = user_node->next) {
      if(!strcmp(user_node->accountname,accountname)) {
        user_node->in_pif = TRUE;
        return(user_node);
      }
    }
  }
  return(0);
} /*** End of routine find_user_info ***/

/*
	Flush_partition - Routine to flush the information in the plist area
			to the scratch file. The routine will release all of
			the space allocated to the structure.
*/
void flush_partition()
{
  char string[BUFSIZ];
  struct anode *aptr;
  int i, j;


  /* First write the partition record. */
  pad_string(plist.plistname,sizeof(plist.plistname));
  string[0] = 'P';
  string[1] = ' ';
  for(i=0, j=2;i<sizeof(plist.plistname);i++,j++)
    string[j] = plist.plistname[i];
  for(i=0;i<sizeof(plist.plistdesc);i++,j++)
    string[j] = plist.plistdesc[i];
  string[j] = '\0';
  put_pif(string);


  /* Write the identifier record. */
  string[0] = 'I';
  for(i=0, j=2;i<sizeof(plist.pid.plistident);i++,j++)
    if(plist.pid.plistident[i] == '\0') string[j] = ' ';
      else string[j] = plist.pid.plistident[i];
  string[j++] = plist.pid.plistidtype;
  string[j] = '\0';
  put_pif(string);

  /* Write the size record. */
  string[0] = 'S';
  sprintf(string,"S %10d",plist.plistsize);
  put_pif(string);

  /* Write the type record. */
  string[0] = 'T';
  for(i=0, j=2;i<sizeof(plist.plisttype);i++,j++)
    string[j] = plist.plisttype[i];
  string[j] = '\0';
  put_pif(string);

  /* Write the owner record. */
  string[0] = 'O';
  for(i=0, j=2;i<sizeof(plist.plistowner);i++,j++)
    string[j] = plist.plistowner[i];
  string[j] = '\0';
  put_pif(string);

  /* Write the location record */
  string[0] = 'L';
  pad_string(plist.ploc.plistloc,sizeof(plist.ploc.plistloc));
  for(i=0, j=2;i<sizeof(plist.ploc.plistloc);i++,j++)
    string[j] = plist.ploc.plistloc[i];
  for(i=0;i<sizeof(plist.ploc.plistvol);i++,j++)
    string[j] = plist.ploc.plistvol[i];
  string[j] = '\0';
  put_pif(string);

  /* Write the exception record. */
  string[0] = 'E';
  for(i=0, j=2;i<sizeof(plist.plistexception);i++,j++)
    string[j] = plist.plistexception[i];
  string[j] = '\0';
  put_pif(string);

  /* Write the expiration record. */
  string[0] = 'X';
  for(i=0, j=2;i<sizeof(plist.plistexpire);i++,j++)
    string[j]  = plist.plistexpire[i];
  string[j] = '\0';
  put_pif(string);

  /* Write the remote record. */
  string[0] = 'R';
  for(i=0, j=2;i<sizeof(plist.plistremote);i++,j++)
    string[j] = plist.plistremote[i];
  string[j] = '\0';
  put_pif(string);

  /* Write the expire record if not blank. */
  if(strlen(plist.plistexpire)) {
    string[0] = 'X';
    for(i=0, j=2;i<sizeof(plist.plistexpire);i++,j++)
      string[j] = plist.plistexpire[i];
    string[j] = '\0';
    put_pif(string);
  }

  /* Write the Administrator records. */
  string[0] = 'A';
  aptr = plist.adminlist;
  if(aptr != 0) {
    while(aptr->next != 0) {
      pad_string(aptr->accountname,sizeof(aptr->accountname));
      for(i=0, j=2;i<sizeof(aptr->accountname);i++,j++)
        string[j] = aptr->accountname[i];
      string[j++] = aptr->access;
      string[j] = '\0';
      put_pif(string);
      aptr = aptr->next;
    }
    if(aptr->accountname[0] != ' ') {
      pad_string(aptr->accountname,sizeof(aptr->accountname));
      for(i=0, j=2;i<sizeof(aptr->accountname);i++,j++)
        string[j] = aptr->accountname[i];

      string[j++] = aptr->access;
      string[j] = '\0';
      put_pif(string);
    }
  }

  /* Write the User records. */
  string[0] = 'U';
  aptr = plist.userlist;
  if(aptr != 0) {
    while(aptr->next != 0) {
      pad_string(aptr->accountname,sizeof(aptr->accountname));
      for(i=0, j=2;i<sizeof(aptr->accountname);i++,j++)
        string[j] = aptr->accountname[i];
      string[j++] = aptr->access;
      string[j] = '\0';
      put_pif(string);
      aptr = aptr->next;
    }
    if(aptr->accountname[0] != ' ') {
      pad_string(aptr->accountname,sizeof(aptr->accountname));
      for(i=0, j=2;i<sizeof(aptr->accountname);i++,j++)
        string[j] = aptr->accountname[i];
      string[j++] = aptr->access;
      string[j] = '\0';
      put_pif(string);
    }
  }

  return;
} /*** End of routine flush_partition ***/


/*
	Flush_pif - Routine to flush the remaining records from the pif file
	to the temporary pif.

	Return: TRUE - If user has administrative access to any partition and
			a partition exists (we have not hit the EOF).
*/
int flush_pif()
{
  int sts=FALSE;
  char string[BUFSIZ];
  int i, j;

  /* If no more partitions then return */
  if(pif_eof) return(FALSE);

  /* First write the partition record. */
  string[0] = 'P';
  string[1] = ' ';
  pad_string(record.pr_union.part.part_name,
             sizeof(record.pr_union.part.part_name));
  for(i=0, j=2;i<sizeof(record.pr_union.part.part_name);i++,j++)
    string[j] = record.pr_union.part.part_name[i];
  for(i=0;i<sizeof(record.pr_union.part.part_desc);i++,j++)
    string[j] = record.pr_union.part.part_desc[i];
  string[j] = '\0';
  put_pif(string);

  /* Now write the rest of the records. */
  while(read_pif(string,TRUE)) {
    /* If this user is an administrator or owner then they can update */
    if(((record.rtype == 'A') || (record.rtype == 'O'))
	&& (strncmp(&record.pr_union.acc.accountname[0],my_account,
		sizeof(record.pr_union.acc.accountname)) == 0)) sts = TRUE;
  }
  if(bd_master) sts = TRUE;	/* If a master then can update this partition */
  return(sts);
} /*** End of routine flush_pif ***/

/*
	Get_mv_rec - Routine to read the PIF and return a Master/Viewer
	record. Records are copied to the temporary PIF file while reading.

	Return - True if a record is found.
	       - False if end of the Master/Viewer list

	Implicit return - Record is set with the PIF record. The last
		read will set the record to the Partition record for
		later transactions.

*/
int get_mv_rec()
{
  char string[BUFSIZ];	/* Temporary string used to copy to the scratch pif */

  /* Check to see if we are already past the M & V records. */
  if((record.rtype != ' ') && (record.rtype != 'M') && (record.rtype != 'V'))
    return(FALSE);

  /* Now read the record. Cannot write the record until we find out if it is */
  /* not the start of a partition.                                           */
  if(read_pif(string,FALSE)) {
    if((record.rtype == 'M') || (record.rtype == 'V')) {
      put_pif(string);
      return(TRUE);
    }
  }
  return(FALSE);		/* Return FALSE if at EOF or record is not MV */
}


/*
	Get_partition - Routine to read all the information requarding a
		 	the next partition and load it into the p_lists.
	Return:	True if success
		False if no more partitions
*/
int get_partition()
{
  char string[BUFSIZ];		/* Actual record from the pif */
  struct anode *last_admin;
  struct anode *last_user;

  /* If we are at the EOF of the PIF then the Record is invalid */
  if(pif_eof) return(FALSE);

  /* The P record should be in the Record structure from the previous read */
  /* Start to fill in the Plist fields.					   */
  strncpy(plist.plistname,record.pr_union.part.part_name,
		sizeof(record.pr_union.part.part_name));
  strncpy(plist.plistdesc,record.pr_union.part.part_desc,
		sizeof(record.pr_union.part.part_desc));

  /* Make sure the name are terminated */
  truncate_string(plist.plistname,sizeof(plist.plistname));
  plist.plistname[sizeof(plist.plistname)] = '\0';

  /* Make sure previous contents are erased */
  plist.plistexpire[0] = 0;

  /* Make sure the admin and user list is blank */
  plist.adminlist = 0;
  plist.userlist = 0;
  last_admin = 0;
  last_user = 0;

  while(read_pif(string,FALSE)) {
    switch(record.rtype) {
      case 'P': return(TRUE);	/* Found another partition, exit routine */

      case 'A': /* Administrator record */
		/* First check to see if the user is already on a list  */
		/* If so then ignore this record.			*/
		if((find_account(plist.userlist,&record.pr_union.acc.accountname[0]) != 0)
                  || (find_account(plist.adminlist,&record.pr_union.acc.accountname[0]) != 0)) break;
		if(plist.adminlist == 0) {
		  plist.adminlist = (struct anode *)malloc(sizeof(struct anode));
		  last_admin = plist.adminlist;
		  last_admin->prev = 0;
		} else {
		  last_admin->next = (struct anode *)malloc(sizeof(struct anode));
		  last_admin->next->prev = last_admin;
		  last_admin = last_admin->next;
		}
		strncpy(last_admin->accountname,&record.pr_union.acc.accountname[0],
			sizeof(last_admin->accountname));
		truncate_string(last_admin->accountname,
				sizeof(last_admin->accountname));
		last_admin->access = record.pr_union.acc.access;
		if(last_admin->access != 'W') last_admin->access = 'R';
                last_admin->next = 0;
		break;

      case 'E': /* Exception record */
		strncpy(plist.plistexception,&record.pr_union.exception[0],
			sizeof(plist.plistexception));
		truncate_string(plist.plistexception,
			        sizeof(plist.plistexception));
		break;

      case 'I': /* Identifier record */
		strncpy(plist.pid.plistident,&record.pr_union.id.ident[0],
			sizeof(plist.pid.plistident));
		truncate_string(plist.pid.plistident,
			sizeof(plist.pid.plistident));
		plist.pid.plistidtype = record.pr_union.id.idtype;
		break;

      case 'L': /* Location record */
		strncpy(plist.ploc.plistloc,&record.pr_union.loc.location[0],
			sizeof(plist.ploc.plistloc));
		truncate_string(plist.ploc.plistloc,
				sizeof(plist.ploc.plistloc));
		strncpy(plist.ploc.plistvol,&record.pr_union.loc.vol_name[0],
			sizeof(plist.ploc.plistvol));
		truncate_string(plist.ploc.plistvol,
				sizeof(plist.ploc.plistvol));
		break;

      case 'O': /* Owner record */
		strncpy(plist.plistowner,&record.pr_union.acc.accountname[0],
			sizeof(plist.plistowner));
		truncate_string(plist.plistowner,sizeof(plist.plistowner));
		break;

      case 'R': /* Remote flag record */
		strncpy(plist.plistremote,&record.pr_union.remote[0],
			sizeof(plist.plistremote));
		truncate_string(plist.plistremote,sizeof(plist.plistremote));
		break;

      case 'S': /* Size record */
		plist.plistsize = atoi(&record.pr_union.psize[0]);
		break;

      case 'T': /* Partition type record */
		strncpy(plist.plisttype,&record.pr_union.type[0],
			sizeof(plist.plisttype));
		truncate_string(plist.plisttype,sizeof(plist.plisttype));
		break;

      case 'U': /* User record */
		/* First check to see if the user is already on a list  */
		/* If so then ignore this record.			*/
		if((find_account(plist.userlist,&record.pr_union.acc.accountname[0]) != 0)
                  || (find_account(plist.adminlist,&record.pr_union.acc.accountname[0]) != 0)) break;
		if(plist.userlist == 0) {
		  plist.userlist = (struct anode *)malloc(sizeof(struct anode));
		  last_user = plist.userlist;
		  last_user->prev = 0;
		} else {
		  last_user->next = (struct anode *)malloc(sizeof(struct anode));
		  last_user->next->prev = last_user;
		  last_user = last_user->next;
		}
		strncpy(last_user->accountname,&record.pr_union.acc.accountname[0],
			sizeof(last_user->accountname));
		truncate_string(last_user->accountname,
				sizeof(last_user->accountname));
		last_user->access = record.pr_union.acc.access;
		if(last_user->access != 'W') last_user->access = 'R';
                last_user->next = 0;
		break;

      case 'X':	/* Expiration record */
	        strncpy(plist.plistexpire,&record.pr_union.expire,
			sizeof(plist.plistexpire));
		truncate_string(plist.plistexpire,sizeof(plist.plistexpire));
		break;

      default:  printf("Unrecognized record in PIF, %s\n",&record);
		break;
    }
  }
  return(TRUE);
}


/*
	Routine to parse the gid in the li ack message.
*/
int li_parse_gid(line)
  char *line;
{
  char *s, *t;
  int  i;

  for(s=line;(*s != NULL);s++) {
    if(!strncmp(s,"gid",3)) {
      if((t = (char *)index(s,'=')) != NULL) {
	t++;    /* Point to the position after the = */
	i = atoi(t);
#ifdef VMS
	i = i + 0x80010000; /* Must be in correct VMS range */
#endif
	return(i);
      } else {
	return(0);
      }
    }
  }
}  /***** End of routine li_parse_gid *****/

/*
	Move_account - Routine to move an account from one list to the 
	front of another.
	Input:	From_ptr - pointer to the anode to move
		to_ptr   - pointer to the beginning of the list to move to
	Output: From_ptr - Pointer to the beginning of the list that the node
			   was originally in.
		To_ptr   - pointer to the beginning of the list node was moved
			   to. The first node is the node that was moved.
*/
void move_account(from_ptr,to_ptr)
  struct anode **from_ptr;
  struct anode **to_ptr;
{
  struct anode *aptr, *bptr, *tmp_ptr;

  aptr = *from_ptr;
  bptr = *to_ptr;

  if(aptr == 0) {
    printf("Call to move account with null first list\n");
    printf("Please call consulting office.\n");
    exit(1);
  }

  tmp_ptr = aptr;		/* Save the first pointer */

  remove_user(&aptr);

  /* Now add the node to the front of the second list */
  tmp_ptr->next = bptr;
  tmp_ptr->prev = 0;
  if(bptr != 0) bptr->prev = tmp_ptr;
  bptr = tmp_ptr;

  *from_ptr = aptr;
  *to_ptr = bptr;
  return;
} /*** End of routine move_account ***/

/*
	Pad_string - Routine to pad a string ( add space to the end ).
*/
void pad_string(sptr, size)
char *sptr;
int size;
{
  int i;
  int at_end;

  at_end = FALSE;

  for(i=0;i<size;i++,sptr++) {
    if(at_end)
      *sptr = ' ';
    else {
      if(*sptr == '\0') {
	*sptr = ' ';
	at_end = TRUE;
      }
    }
  }
  return;
} /*** End of routine pad_string ***/

/*
	Print_header - Routine to print a header on the report page.
*/
void print_header()
{
  if(cl_brief) {
    printf(" Partition        Size        Used      R-Users    W-Users\n");
    printf(" ----------      --------   ---------   -------    -------\n");
  }
  return;
} /*** End of routine print_header ***/


/*
	Recreate_partition - Routine to recreate the partition in the system
		tables when the data is in the PIF.
*/
void recreate_partition()
{
  char idname[IDENTSIZE+2];
  int i;

  printf("Recreating partition %s\n",plist.plistname);
  cl_type = plist.pid.plistidtype;
  if(!(create_ident(plist.pid.plistident,sizeof(plist.pid.plistident)))) {
    printf("Unable to create identifier\n");
    bdm_exit(0);
  }
  for(i=0;(i<sizeof(plist.pid.plistident)) &&
                   (plist.pid.plistident[i] != ' ') &&
                   (plist.pid.plistident[i] != '\0');i++)
    idname[i] = plist.pid.plistident[i];


  if(!cl_type) {

#ifdef VMS
    idname[i++] = '$';
#else
    idname[i++] = '_';
#endif
    idname[i++] = 'W';
  }
  idname[i] = '\0';
  if(!(grant_ident(idname,plist.plistowner))) {
    printf("Could not grant identifier %s",idname);
    printf(" to account %s\n",plist.plistowner);
  }

#ifndef VMS
  /* If type 0 ident and Unix systems then grant _R to owner */
  if(!cl_type) {
    /* Grant the read ident to the owner */
    idname[i-1] = 'R';
    if(!(grant_ident(idname,plist.plistowner))) {
      printf("Could not grant identifier %s",idname);
      printf(" to account %s\n",plist.plistowner);
    }
  }
#endif


  return;
} /*** End of routine recreate_partition ***/

/*
	Remove_user - Routine to remove a user from the specified list.
*/
void remove_user(aptr)
struct anode **aptr;
{
  struct anode *tmp_ptr, *bptr;

  tmp_ptr = *aptr;		/* Save the pointer */
  bptr = *aptr;

  if(bptr->next != 0) {
    bptr = bptr->next;
    bptr->prev = tmp_ptr->prev;
    if(bptr->prev != 0) bptr->prev->next = bptr;
  } else
    /* Must be at the end of the list */
    if(bptr->prev != 0) {
      bptr = bptr->prev;
      bptr->next = 0;   /* End of list */
    } else
      bptr = 0;

  /* Point to the beginning of the list. */
  if(bptr != 0) while(bptr->prev != 0) bptr = bptr->prev;

  /* Now update what is passed back... */
  *aptr = bptr;
  return;
}
/*
	Report_partition - Routine to generate a partition report using the
			   info from the plist area.
*/
void report_partition()
{
  struct anode *aptr;
  int used_space;
  int available_space;
  int num_administrators=0;
  int num_user_write=0;
  int num_user_read=0;
  char username[USERNAMESIZE];
  int sts;

  get_space(&available_space,&used_space); /* Get the partition space info */
  if(available_space > 0) plist.plistsize = available_space;
  
  if(cl_full) {
    printf("\n");
    printf("Partition: %s\n",plist.plistname);
    printf(" Description: %s\n",plist.plistdesc);
    if(trans_account(username,plist.plistowner))
      printf(" Owner: %12.12s                 ",username);
    else
      printf(" Owner: %12.12s                 ",plist.plistowner);
    printf(" Size: %8d",plist.plistsize);
    printf(" Used: %8d\n",used_space);
    printf(" Partition type: %-10.10s\n",plist.plisttype);
    printf(" Partition location: %s\n",plist.ploc.plistloc);
    if(strlen(plist.plistexpire))
      printf(" Partition expiration date: %s\n",plist.plistexpire);
    printf(" Identifier(s)/group(s): ");
    if(plist.pid.plistidtype == '1')
      printf("%s\n",plist.pid.plistident);
    else
#ifdef VMS
      printf("%s$W, %s$R\n",plist.pid.plistident,plist.pid.plistident);
#else
      printf("%s_W, %s_R\n",plist.pid.plistident,plist.pid.plistident);
#endif
    printf(" Administrators:\n");
    aptr = plist.adminlist;
    while(aptr != 0) {
      /* If partition type is 1 then all are write users */
      if(plist.pid.plistidtype == '1') aptr->access = 'W';
      if(trans_account(username,aptr->accountname))
        printf("     %12.12s, Access: %c\n",username,aptr->access);
      else
	/* Could not translate the accountname to a username, report account */
	printf("     %12.12s, Access: %c\n",aptr->accountname,aptr->access);
      aptr = aptr->next;
    }
    printf(" Users:\n");
    aptr = plist.userlist;
    while(aptr != 0) {
      /* If partition type is 1 then all are write users */
      if(plist.pid.plistidtype == '1') aptr->access = 'W';
      if(trans_account(username,aptr->accountname))
        printf("     %12.12s, Access: %c\n",username,aptr->access);
      else
        /* Could not translate the accountname to a username, report account */
        printf("     %12.12s, Access: %c\n",aptr->accountname,aptr->access);
      aptr = aptr->next;
    }
  } else {
    /* First count the number of administrators, number of users having write */
    /* access and the number of users having read access.                     */
    aptr = plist.adminlist;
    while(aptr != 0) {
      num_administrators++;
      aptr = aptr->next;
    }
    aptr = plist.userlist;
    while(aptr != 0) {
      if(aptr->access == 'W')
        num_user_write++;
      else
	num_user_read++;
      aptr = aptr->next;
    }
    /* If this is a type 1 partition ident then all users are the same type */
    if(plist.pid.plistidtype == '1') {
      num_user_write += num_user_read;
      num_user_read = 0;
    }
    printf("%-10.10s       %8d",plist.plistname,plist.plistsize);
    printf("    %8d",used_space);
    printf("     %5d",num_user_read);
    printf("      %5d\n",num_user_write+num_administrators);
  }

  return;
} /*** End of routine report_partition

/*
	Truncate_string - Routine to truncate a string ( remove white space
		from end of string ).
*/
void truncate_string(sptr, size)
char *sptr;
int size;
{
  int i;

  sptr = sptr + size - 1;
  for(i=size;i>0;sptr--) {
    if((*sptr == ' ') || (*sptr == '\0'))
      *sptr = '\0';
    else
      return;	/* Exit when we hit the first non white space */
  }
  return;

} /*** End of routine truncate_string ***/

/*
	Verify_partition - Routine to check a partition against the SYSUAF or
		the /etc/group files.

	Return:	status - set to TRUE if no errors occured in this partition
			 else set to FALSE.
*/
int verify_partition()
{
  char ident[IDENTSIZE+2], ident1[IDENTSIZE+2];
  struct sys_ident_node *ident_node, *ident_node1;
  char answer[BUFSIZ];
  int status = TRUE;

  if(plist.pid.plistidtype) {
    /* Type 1 partitions have only a single identifier */
    ident_node = find_sys_info(plist.pid.plistident);
    if(!ident_node) {
      printf("\n");
      printf("Partition %s does not exist in system tables\n",plist.plistname);
      status = FALSE;
      if(cl_repair) {
        answer[0] = 'Y';
        if(cl_confirm) {
          printf("Recreate partition? ");
          gets(answer);
        }
        if(toupper(answer[0]) == 'Y')
	  recreate_partition();
      }
    }
  } else {
    /* Type 0 partitions have 2 identifiers. They are ident$r and ident$w  */
    /* for VMS and ident_R and ident_W for Unix systems.                   */
#ifdef VMS
    sprintf(ident,"%s$W",plist.pid.plistident);
#else
    sprintf(ident,"%s_W",plist.pid.plistident);
#endif /* VMS */

    ident_node = find_sys_info(ident);

#ifdef VMS
    sprintf(ident1,"%s$R",plist.pid.plistident);
#else
    sprintf(ident1,"%s_R",plist.pid.plistident);
#endif /* VMS */

    ident_node1 = find_sys_info(ident1);

    if(!ident_node && !ident_node1) {
      printf("\n");
      printf("Partition %s does not exist in system tables\n",plist.plistname);
      status = FALSE;
      if(cl_repair) {
	answer[0] = 'Y';
	if(cl_confirm) {
	  printf("Recreate partition? ");
	  gets(answer);
	}
	if(toupper(answer[0]) == 'Y')
	  recreate_partition();
      }
    } else {
      if(!ident_node) {
	printf("\n");
#ifdef VMS
        printf("Identifier %s does not exist in system tables\n",ident);
#else
	printf("Group %s does not exist in system tables\n",ident);
#endif /* VMS */
	status = FALSE;
        if(cl_repair) {		/* Don't bother with confirm */
	  cl_type = 1;		/* Tell create_ident to not add $r or $w */
	  if(!(create_ident(ident),sizeof(ident))) {
	    printf("Unable to create identifier\n");
	  }
	}
      } else {
	if(!ident_node1) {
	  printf("\n");
#ifdef VMS
	  printf("Identifier %s does not exist in system tables\n",ident1);
#else
	  printf("Group %s does not exist in system tables\n",ident1);
#endif /* VMS */
	  status = FALSE;
	  if(cl_repair) {	/* Don't bother with confirm */
	    cl_type = 1;
	    if(!(create_ident(ident1),sizeof(ident1))) {
	      printf("Unable to create identifier\n");
	    }
	  }
	}
      }
    }
    /* Verify the user lists if the system info exists */
    if(ident_node && ident_node1)
      if(!verify_users(ident_node,ident_node1)) status = FALSE;
  }
  return(status);

} /*** End of routine verify_partition ***/

/*
	Verify_users - Routine to check to see if the users on the admin list
			and user lists are in the system lists.
		        The routine will also check the system and see if
			there are any users in the system list that are not
			in the user lists (admin and user lists).

		Inputs:	Write_ident - Pointer to write identifier node
			Read_ident  - Pointer to read identifier node
				      Nodes containing usernames/accounts
					are attached to the identifier nodes.

		Return: Status - Set to TRUE if no error occured.

*/
int verify_users(write_ident,read_ident)
struct sys_ident_node *write_ident, *read_ident;
{
  struct anode *uptr;
  char username[USERNAMESIZE];
  char answer[BUFSIZ];
  struct sys_user_node *user_node;
  int status = TRUE;

  /* Make sure the owner is in the admin list. */
  if(!find_user_info(write_ident,plist.plistowner)) {
    if(trans_account(username,plist.plistowner))
      printf("\nUser %s",username);
    else
      printf("\nAccount %s",plist.plistowner);
    printf(" is the owner of the partition but does not have admin access\n");
    status = FALSE;
  }
  /* Check the adminlist */
  for(uptr=plist.adminlist;uptr != 0;uptr = uptr->next) {
    if(!find_user_info(write_ident,uptr->accountname)) {
      if(trans_account(username,uptr->accountname))
	printf("\nUser %s",username);
      else
	printf("\nAccount %s",uptr->accountname);
      printf(" is in the PIF as an administrator but is not on the system\n");
      status = FALSE;
    }
#ifndef VMS
    /* Administrators on non VMS machines have both the read and write ident */
    if(!find_user_info(read_ident,uptr->accountname)) {
      if(trans_account(username,uptr->accountname))
        printf("\nUser %s",username);
      else
        printf("\nAccount %s",uptr->accountname);
      printf(" is in the PIF as an administrator but does not have read ident");
      printf(" on system\n");
      status = FALSE;
    }
#endif
  }

  /* Now check the user list and depending on which ident they have check */
  /* the appropriate list.                                                */
  for(uptr=plist.userlist;uptr != 0;uptr = uptr->next) {
    if(uptr->access == 'R') {
      if(!find_user_info(read_ident,uptr->accountname)) {
	if(trans_account(username,uptr->accountname))
	  printf("\nUser %s",username);
	else
	  printf("\nAccount %s",uptr->accountname);
	printf(" is in the PIF as a READ user but is not on the system\n");
	status = FALSE;
	if(cl_repair) {
	  answer[0] = 'Y';
	  if(cl_confirm) {
	    printf("Grant %s to %s? ",read_ident->ident_name,username);
	    gets(answer);
	  }
	  if(toupper(answer[0]) == 'Y') {
	    if(!(grant_ident(read_ident->ident_name,uptr->accountname))) {
	      printf("Could not grant identifier %s",read_ident->ident_name);
	      printf(" to user %s\n",username);
	    }
	  }
	}
      }
    } else {
#ifndef VMS
      /* Write users should have both the read and write identifiers on */
      /* non VMS hosts.                                                 */
      if(!find_user_info(read_ident,uptr->accountname)) {
        if(trans_account(username,uptr->accountname))
          printf("\nUser %s",username);
        else
          printf("\nAccount %s",uptr->accountname);
        printf(" is in the PIF as a WRITE user but does not have read ident");
	printf(" on system\n");
        status = FALSE;
        if(cl_repair) {
          answer[0] = 'Y';
          if(cl_confirm) {
            printf("Grant %s to %s? ",read_ident->ident_name,username);
            gets(answer);
          }
          if(toupper(answer[0]) == 'Y') {
            if(!(grant_ident(read_ident->ident_name,uptr->accountname))) {
              printf("Could not grant identifier %s",read_ident->ident_name);
              printf(" to user %s\n",username);
            }
          }
        }
      }
#endif
      /* Check write access identifier */
      if(!find_user_info(write_ident,uptr->accountname)) {
        if(trans_account(username,uptr->accountname))
          printf("\nUser %s",username);
        else
          printf("\nAccount %s",uptr->accountname);
        printf(" is in the PIF as a WRITE user but is not on the system\n");
        status = FALSE;
        if(cl_repair) {
	  answer[0] = 'Y';
	  if(cl_confirm) {
	    printf("Grant %s to %s? ",write_ident->ident_name,username);
	    gets(answer);
	  }
	  if(toupper(answer[0]) == 'Y') {
	    if(!(grant_ident(write_ident->ident_name,uptr->accountname))) {
	      printf("Could not grant identifier %s",write_ident->ident_name);
	      printf(" to user %s\n",username);
	    }
	  }
	}
      }
    }
  }
  /* Now that all users from the admin and user lists are on the system */
  /* verify that each user on the system lists is in the admin and user */
  /* list.                                                              */
  for(user_node = write_ident->u_node;user_node != 0;
      user_node = user_node->next) {
    if(!user_node->in_pif) {
      if(trans_account(username,user_node->accountname))
        printf("\nUser %s is not in the PIF ",username);
      else
	printf("\nAccount %s is not in the PIF ",user_node->accountname);
      printf("but has write access on the system\n");
      status = FALSE;
      if(cl_repair) {
        answer[0] = 'Y';
        if(cl_confirm) {
          printf("Revoke %s from %s? ",write_ident->ident_name,username);
	  gets(answer);
        }
        if(toupper(answer[0]) == 'Y') {
          if(!(revoke_ident(write_ident->ident_name,user_node->accountname))) {
            printf("Could not revoke identifier %s",write_ident->ident_name);
	    printf(" from user %s\n",username);
          }
        }
      }
    }
  }
  for(user_node = read_ident->u_node;user_node != 0;
      user_node = user_node->next) {
    if(!user_node->in_pif) {
      if(trans_account(username,user_node->accountname))
        printf("\nUser %s is not in the PIF ",username);
      printf("but has read access on the system\n");
      status = FALSE;
      if(cl_repair) {
        answer[0] = 'Y';
        if(cl_confirm) {
          printf("Revoke %s from %s? ",read_ident->ident_name,username);
          gets(answer);
        }
        if(toupper(answer[0]) == 'Y') {
          if(!(revoke_ident(read_ident->ident_name,user_node->accountname))) {
            printf("Could not revoke identifier %s",read_ident->ident_name);
            printf(" from user %s\n",username);
          }
        }
      }
    }
  }
  return(status);
} /*** End of routine verify_users ***/
