]> andersk Git - moira.git/blobdiff - clients/moira/cluster.c
Support setting/displaying publicflg for containers, and displaying
[moira.git] / clients / moira / cluster.c
index 4f8b77cf259946c6ebf08246187bcab5deb30778..88aeed65f3c461a79627f175f978ecf8b3e8522c 100644 (file)
-#if (!defined(lint) && !defined(SABER))
-  static char rcsid_module_c[] = "$Header$";
-#endif lint
-
-/*     This is the file cluster.c for the MOIRA Client, which allows a nieve
- *      user to quickly and easily maintain most parts of the MOIRA database.
- *     It Contains: 
- *     
+/* $Id$
+ *
+ *     This is the file cluster.c for the Moira Client, which allows users
+ *      to quickly and easily maintain most parts of the Moira database.
+ *     It Contains:
+ *
  *     Created:        4/22/88
  *     By:             Chris D. Peterson
  *
- *      $Source$
- *      $Author$
- *      $Header$
- *     
- *     Copyright 1988 by the Massachusetts Institute of Technology.
- *
- *     For further information on copyright and distribution 
- *     see the file mit-copyright.h
+ * Copyright (C) 1988-1998 by the Massachusetts Institute of Technology.
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
  */
 
 /* BTW: for anyone who cares MCD is short for Machine, Cluster, Data. */
 
-#include <stdio.h>
-#include <strings.h>
+#include <mit-copyright.h>
 #include <moira.h>
 #include <moira_site.h>
-#include <menu.h>
+#include <mrclient.h>
 
-#include "mit-copyright.h"
 #include "defs.h"
 #include "f_defs.h"
 #include "globals.h"
 
-#define MACHINE  0
-#define CLUSTER  1
-#define DATA     2
-#define MAP      3
+#include <sys/types.h>
+
+#ifdef HAVE_UNAME
+#include <sys/utsname.h>
+#endif
+
+#ifndef _WIN32
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#endif /* _WIN32 */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void PrintAliases(char **info);
+static void PrintMachine(char **info);
+struct mqelem *GetMCInfo(int type, char *name1, char *name2);
+struct mqelem *GetMachineByOwner(char *type, char *name);
+char **AskMCDInfo(char **info, int type, Bool name);
+int CheckAndRemoveFromCluster(char *name, Bool ask_user);
+int CheckAndRemoveCnames(char *name, Bool ask_user);
+int CheckAndRemoveMachines(char *name, Bool ask_first);
+
+static char *PrintContainerInfo(char **info);
+static void RealUpdateContainer(char **info, Bool junk);
+static void RealDeleteContainer(char **info, Bool one_container);
+static void RealRemoveMachineFromContainer(char **info, Bool one_contmap);
+
+#define MACHINE   0
+#define CLUSTER   1
+#define DATA      2
+#define MAP       3
+#define SUBNET   4
+#define CNAME    5
+#define CONTAINER 6
+#define CONTMAP   7
 
 #define M_DEFAULT_TYPE     DEFAULT_NONE
 
 #define C_DEFAULT_DESCRIPT DEFAULT_NONE
 #define C_DEFAULT_LOCATION DEFAULT_NONE
 
+#define CON_DEFAULT_TYPE   DEFAULT_NONE
+
 #define CD_DEFAULT_LABEL   DEFAULT_NONE
 #define CD_DEFAULT_DATA    DEFAULT_NONE
 
+#define S_DEFAULT_LOW  "18.0.0.20"
+#define S_DEFAULT_HIGH "18.0.2.249"
+
+static char *states[] = {
+  "Reserved (0)",
+  "Active (1)",
+  "None (2)",
+  "Deleted (3)"
+};
+
+static char *subnet_states[] = {
+  "Reserved (0)",
+  "Billable (1)",
+  "Private, 10 Mbps (2)",
+  "Private, 100 Mbps (3)",
+  "Private, Other (4)",
+  "Resnet, Dorm (5)",
+  "Infrastructure (6)",
+  "Private, 1000 Mbps (7)",
+  "Resnet, FSILG (8)"
+};
+
+static char *MacState(int state)
+{
+  static char buf[BUFSIZ];
+
+  if (state < 0 || state > 3)
+    {
+      sprintf(buf, "Unknown (%d)", state);
+      return buf;
+    }
+  return states[state];
+}
+
+static char *SubnetState(int state)
+{
+  static char buf[BUFSIZ];
+
+  if (state < 0 || state > 8)
+    {
+      sprintf(buf, "Unknown (%d)", state);
+      return buf;
+    }
+  return subnet_states[state];
+}
+
 /* -------------------- Set Defaults -------------------- */
 
 /*     Function Name: SetMachineDefaults
  *     Returns: info - the array.
  */
 
-static char **
-SetMachineDefaults(info, name)
-char ** info, *name;
+static char **SetMachineDefaults(char **info, char *name)
 {
-    info[M_NAME] = Strsave(name);
-    info[M_TYPE] = Strsave(M_DEFAULT_TYPE);
-    info[M_MODBY] = info[M_MODTIME] = info[M_MODWITH] = info[M_END] = NULL;
-    return(info);
+  info[M_NAME] = strdup(name);
+  info[M_VENDOR] = strdup(M_DEFAULT_TYPE);
+  info[M_MODEL] = strdup(M_DEFAULT_TYPE);
+  info[M_OS] = strdup(M_DEFAULT_TYPE);
+  info[M_LOC] = strdup(M_DEFAULT_TYPE);
+  info[M_CONTACT] = strdup(M_DEFAULT_TYPE);
+  info[M_BILL_CONTACT] = strdup(M_DEFAULT_TYPE);
+  info[M_ACCT_NUMBER] = strdup("");
+  info[M_USE] = strdup("0");
+  info[M_STAT] = strdup("1");
+  info[M_SUBNET] = strdup("NONE");
+  info[M_ADDR] = strdup("unique");
+  info[M_OWNER_TYPE] = strdup("NONE");
+  info[M_OWNER_NAME] = strdup("NONE");
+  info[M_ACOMMENT] = strdup("");
+  info[M_OCOMMENT] = strdup("");
+  info[17] = info[18] = NULL;
+  return info;
 }
 
 /*     Function Name: SetClusterDefaults
@@ -71,63 +157,214 @@ char ** info, *name;
  *     Returns: info - the array.
  */
 
-static char **
-SetClusterDefaults(info, name)
-char ** info, *name;
+static char **SetClusterDefaults(char **info, char *name)
+{
+  info[C_NAME] = strdup(name);
+  info[C_DESCRIPT] = strdup(C_DEFAULT_DESCRIPT);
+  info[C_LOCATION] = strdup(C_DEFAULT_LOCATION);
+  info[C_MODBY] = info[C_MODTIME] = info[C_MODWITH] = info[C_END] = NULL;
+  return info;
+}
+
+static char **SetContainerDefaults(char **info, char *name)
+{
+  info[CON_NAME] = strdup(name);
+  info[CON_PUBLIC] = strdup(DEFAULT_NO);
+  info[CON_DESCRIPT] = strdup(CON_DEFAULT_TYPE);
+  info[CON_LOCATION] = strdup(CON_DEFAULT_TYPE);
+  info[CON_CONTACT] = strdup(CON_DEFAULT_TYPE);
+  info[CON_OWNER_TYPE] = strdup("NONE");
+  info[CON_OWNER_NAME] = strdup("NONE");
+  info[CON_MEMACE_TYPE] = strdup("NONE");
+  info[CON_MEMACE_NAME] = strdup("NONE");
+  info[CON_MODBY] = info[CON_MODTIME] = info[CON_MODWITH] = NULL;
+  info[CON_END] = NULL;
+  return info;
+}
+
+/*     Function Name: SetSubnetDefaults
+ *     Description: sets Subnet defaults.
+ *     Arguments: info - an array to put the defaults into.
+ *                 name - name of the Subnet.
+ *     Returns: info - the array.
+ */
+
+static char **SetSubnetDefaults(char **info, char *name)
 {
-    info[C_NAME] = Strsave(name);
-    info[C_DESCRIPT] = Strsave(C_DEFAULT_DESCRIPT);
-    info[C_LOCATION] = Strsave(C_DEFAULT_LOCATION);
-    info[C_MODBY] = info[C_MODTIME] = info[C_MODWITH] = info[C_END] = NULL;
-    return(info);
+  char buf[256];
+
+  info[SN_NAME] = strdup(name);
+  info[SN_DESC] = strdup("");
+  info[SN_STATUS] = strdup("1");
+  info[SN_CONTACT] = strdup(DEFAULT_NONE);
+  info[SN_ACCT_NUMBER] = strdup("");
+  sprintf(buf, "%ld", ntohl(inet_addr("18.255.0.0")));
+  info[SN_ADDRESS] = strdup(buf);
+  sprintf(buf, "%ld", ntohl(inet_addr("255.255.0.0")));
+  info[SN_MASK] = strdup(buf);
+  sprintf(buf, "%ld", ntohl(inet_addr(S_DEFAULT_LOW)));
+  info[SN_LOW] = strdup(buf);
+  sprintf(buf, "%ld", ntohl(inet_addr(S_DEFAULT_HIGH)));
+  info[SN_HIGH] = strdup(buf);
+  info[SN_PREFIX] = strdup("");
+  info[SN_ACE_TYPE] = strdup("LIST");
+  info[SN_ACE_NAME] = strdup("network");
+  info[SN_MODBY] = info[SN_MODTIME] = info[SN_MODWITH] = info[SN_END] = NULL;
+  return info;
 }
 
 /* -------------------- General Functions -------------------- */
 
+static char aliasbuf[256];
+
+void PrintAliases(char **info)
+{
+  if (strlen(aliasbuf) == 0)
+    sprintf(aliasbuf, "Aliases:  %s", info[0]);
+  else
+    {
+      strcat(aliasbuf, ", ");
+      strcat(aliasbuf, info[0]);
+    }
+}
+
+
 /*     Function Name: PrintMachInfo
- *     Description: This function Prints out the Machine info in 
+ *     Description: This function Prints out the Machine info in
  *                   a coherent form.
  *     Arguments: info - array of information about a machine.
  *     Returns: The name of the Machine
  */
 
-static char *
-PrintMachInfo(info)
-char ** info;
+static char *PrintMachInfo(char **info)
+{
+  char buf[BUFSIZ], tbuf[256];
+  char *args[3];
+  struct mqelem *elem = NULL, *elem2 = NULL;
+  int stat;
+
+  Put_message("");
+  sprintf(buf, "Machine:  %s", info[M_NAME]);
+  Put_message(buf);
+  args[0] = "*";
+  args[1] = info[M_NAME];
+  if ((stat = do_mr_query("get_hostalias", 2, args, StoreInfo, &elem)))
+    {
+      if (stat != MR_NO_MATCH)
+       com_err(program_name, stat, " looking up aliases");
+    }
+  else
+    {
+      aliasbuf[0] = 0;
+      Loop(QueueTop(elem), (void (*)(char **)) PrintAliases);
+      FreeQueue(elem);
+      Put_message(aliasbuf);
+    }
+  sprintf(tbuf, "%s %s", info[M_OWNER_TYPE],
+         strcmp(info[M_OWNER_TYPE], "NONE") ? info[M_OWNER_NAME] : "");
+  sprintf(buf, "Address:  %-16s    Network:    %-16s",
+         info[M_ADDR], info[M_SUBNET]);
+  Put_message(buf);
+  sprintf(buf, "Owner:    %-16s    Use data:   %s", tbuf, info[M_INUSE]);
+  Put_message(buf);
+  sprintf(buf, "Status:   %-16s    Changed:    %s",
+         MacState(atoi(info[M_STAT])), info[M_STAT_CHNG]);
+  Put_message(buf);
+  Put_message("");
+  sprintf(buf, "Vendor:   %-16s    Location:        %s", info[M_VENDOR], 
+         info[M_LOC]);
+  Put_message(buf);
+  sprintf(buf, "Model:    %-16s    Contact:         %s", info[M_MODEL], 
+         info[M_CONTACT]);
+  Put_message(buf);
+  sprintf(buf, "OS:       %-16s    Billing Contact: %s", info[M_OS],
+         info[M_BILL_CONTACT]);
+  Put_message(buf);
+  sprintf(buf, "Opt:      %-16s    Account Number:  %s", info[M_USE],
+         info[M_ACCT_NUMBER]);
+  Put_message(buf);
+  Put_message("");
+  sprintf(buf, "Adm cmt: %s", info[M_ACOMMENT]);
+  Put_message(buf);
+  sprintf(buf, "Op cmt:  %s", info[M_OCOMMENT]);
+  Put_message(buf);
+  Put_message("");
+  sprintf(buf, "Created  by %s on %s", info[M_CREATOR], info[M_CREATED]);
+  Put_message(buf);
+  sprintf(buf, MOD_FORMAT, info[M_MODBY], info[M_MODTIME], info[M_MODWITH]);
+  Put_message(buf);
+  /* Do a get_subnet for the machine's subnet.  We need to know if it's
+   *  Private.
+   */
+  args[0] = info[M_SUBNET];
+  stat = do_mr_query("get_subnet", 1, args, StoreInfo, &elem2);
+  if (stat)
+    com_err(program_name, stat, " looking up subnet info");
+  else if (atoi(((char **)elem2->q_data)[2]) == SNET_STATUS_PRIVATE_10MBPS ||
+          atoi(((char **)elem2->q_data)[2]) == SNET_STATUS_PRIVATE_100MBPS ||
+          atoi(((char **)elem2->q_data)[2]) == SNET_STATUS_PRIVATE_1000MBPS)
+    {
+      Put_message("");
+      sprintf(buf, "Warning:  This host is on a private subnet.");
+      Put_message(buf);
+      sprintf(buf, "Billing information shown is superseded by billing information for the subnet.");
+      Put_message(buf);
+      FreeQueue(elem2);
+    }
+
+  return info[M_NAME];
+}
+
+/*      Function Name: PrintMachine
+ *      Description: Prints the name of a machine record
+ *      Arguments: info - array of information about the machine.
+ *      Returns: nothing.
+ */
+
+static void PrintMachine(char **info)
 {
-    char buf[BUFSIZ];
+     char buf[BUFSIZ];
 
-    Put_message("");
-    sprintf(buf, "Machine: %-30s Type: %s", info[M_NAME], info[M_TYPE]);
-    Put_message(buf);
-    sprintf(buf, MOD_FORMAT, info[M_MODBY], info[M_MODTIME], info[M_MODWITH]);
-    Put_message(buf);
-    return(info[M_NAME]);
+     sprintf(buf, "Machine: %s", info[M_NAME]);
+     Put_message(buf);
+}
+
+/*     Function Name: PrintCname
+ *     Description: Prints the Data on a host alias
+ *     Arguments: info a pointer to the data array.
+ *     Returns: The name of the alias.
+ */
+
+static char *PrintCname(char **info)
+{
+  char buf[BUFSIZ];
+
+  sprintf(buf, "Alias: %-32s Canonical Name: %s", info[0], info[1]);
+  Put_message(buf);
+  return info[0];
 }
 
 /*     Function Name: PrintClusterInfo
- *     Description: This function Prints out the cluster info 
+ *     Description: This function Prints out the cluster info
  *                   in a coherent form.
  *     Arguments: info - array of information about a cluster.
  *     Returns: The name of the cluster.
  */
 
-static char *
-PrintClusterInfo(info)
-char ** info;
+static char *PrintClusterInfo(char **info)
 {
-    char buf[BUFSIZ];
-
-    Put_message("");
-    sprintf(buf, "Cluster:     %s", info[C_NAME]);
-    Put_message(buf);
-    sprintf(buf, "Description: %s", info[C_DESCRIPT]);
-    Put_message(buf);
-    sprintf(buf, "Location:    %s", info[C_LOCATION]);
-    Put_message(buf);
-    sprintf(buf, MOD_FORMAT, info[C_MODBY], info[C_MODTIME], info[C_MODWITH]);
-    Put_message(buf);
-    return(info[C_NAME]);
+  char buf[BUFSIZ];
+
+  Put_message("");
+  sprintf(buf, "Cluster:     %s", info[C_NAME]);
+  Put_message(buf);
+  sprintf(buf, "Description: %s", info[C_DESCRIPT]);
+  Put_message(buf);
+  sprintf(buf, "Location:    %s", info[C_LOCATION]);
+  Put_message(buf);
+  sprintf(buf, MOD_FORMAT, info[C_MODBY], info[C_MODTIME], info[C_MODWITH]);
+  Put_message(buf);
+  return info[C_NAME];
 }
 
 /*     Function Name: PrintClusterData
@@ -136,17 +373,15 @@ char ** info;
  *     Returns: The name of the cluster.
  */
 
-static char *
-PrintClusterData(info)
-char ** info;
+static char *PrintClusterData(char **info)
 {
-    char buf[BUFSIZ];
+  char buf[BUFSIZ];
 
-    Put_message("");
-    sprintf(buf, "Cluster: %-20s Label: %-15s Data: %s",
-           info[CD_NAME], info[CD_LABEL], info[CD_DATA]);
-    Put_message(buf);
-    return(info[CD_NAME]);
+  Put_message("");
+  sprintf(buf, "Cluster: %-20s Label: %-15s Data: %s",
+         info[CD_NAME], info[CD_LABEL], info[CD_DATA]);
+  Put_message(buf);
+  return info[CD_NAME];
 }
 
 /*     Function Name: PrintMCMap
@@ -155,15 +390,60 @@ char ** info;
  *     Returns: none
  */
 
-static char *
-PrintMCMap(info)
-char ** info;
+static char *PrintMCMap(char **info)
+{
+  char buf[BUFSIZ];
+  sprintf(buf, "Cluster: %-30s Machine: %-20s",
+         info[MAP_CLUSTER], info[MAP_MACHINE]);
+  Put_message(buf);
+  return "";                   /* Used by QueryLoop(). */
+}
+
+/*     Function Name: PrintSubnetInfo
+ *     Description: This function Prints out the subnet info
+ *                   in a coherent form.
+ *     Arguments: info - array of information about a subnet.
+ *     Returns: The name of the subnet.
+ */
+
+static char *PrintSubnetInfo(char **info)
 {
-    char buf[BUFSIZ];
-    sprintf(buf, "Cluster: %-30s Machine: %-20s",
-           info[MAP_CLUSTER], info[MAP_MACHINE]);
-    Put_message(buf);
-    return("");                        /* Used by QueryLoop(). */
+  char buf[BUFSIZ];
+  struct in_addr addr, mask, low, high;
+
+  Put_message("");
+  sprintf(buf, "        Network:  %s", info[SN_NAME]);
+  Put_message(buf);
+  sprintf(buf, "    Description:  %s", info[SN_DESC]);
+  Put_message(buf);
+  sprintf(buf, "         Status:  %s", SubnetState(atoi(info[SN_STATUS])));
+  Put_message(buf);
+  sprintf(buf, "        Contact:  %s", info[SN_CONTACT]);
+  Put_message(buf);
+  sprintf(buf, " Account Number:  %s", info[SN_ACCT_NUMBER]);
+  Put_message(buf);
+  addr.s_addr = htonl(atoi(info[SN_ADDRESS]));
+  mask.s_addr = htonl(atoi(info[SN_MASK]));
+  low.s_addr = htonl(atoi(info[SN_LOW]));
+  high.s_addr = htonl(atoi(info[SN_HIGH]));
+  /* screwy sequence is here because inet_ntoa returns a pointer to
+     a static buf.  If it were all one sprintf, the last value would
+     appear 4 times. */
+  sprintf(buf, "        Address:  %s        Mask:  ", inet_ntoa(addr));
+  strcat(buf, inet_ntoa(mask));
+  strcat(buf, "\n           High:  ");
+  strcat(buf, inet_ntoa(high));
+  strcat(buf, "       Low:  ");
+  strcat(buf, inet_ntoa(low));
+  Put_message(buf);
+  sprintf(buf, "Hostname prefix:  %s", info[SN_PREFIX]);
+  Put_message(buf);
+  sprintf(buf, "          Owner:  %s %s\n", info[SN_ACE_TYPE],
+         strcmp(info[SN_ACE_TYPE], "NONE") ? info[SN_ACE_NAME] : "");
+  Put_message(buf);
+  sprintf(buf, MOD_FORMAT, info[SN_MODBY], info[SN_MODTIME], info[SN_MODWITH]);
+  Put_message(buf);
+  return info[SN_NAME];
 }
 
 /*     Function Name: GetMCInfo.
@@ -174,133 +454,434 @@ char ** info;
  *     Returns: the top element of a queue containing the data or NULL.
  */
 
-struct qelem *
-GetMCInfo(type, name1, name2)
-int type;
-char * name1, *name2;
+struct mqelem *GetMCInfo(int type, char *name1, char *name2)
 {
+  int stat;
+  struct mqelem *elem = NULL;
+  char *args[5];
 
-    int stat;
-    struct qelem * elem = NULL;
-    char * args[2];
-
-    switch (type) {
+  switch (type)
+    {
     case MACHINE:
-       if ( (stat = do_mr_query("get_machine", 1, &name1,
-                                 StoreInfo, (char *)&elem)) != 0) {
+      args[0] = name1;
+      args[1] = args[2] = args[3] = "*";
+      if ((stat = do_mr_query("get_host", 4, args, StoreInfo, &elem)))
+       {
+         if (stat == MR_NO_MATCH)
+           {
+             char buf[128];
+             sprintf(buf, "Machine '%s' is not in the database.", name1);
+             Put_message(buf);
+           }
+         else
            com_err(program_name, stat, " in get_machine.");
-           return(NULL);
+         return NULL;
+       }
+      break;
+    case CNAME:
+      args[0] = name1;
+      args[1] = name2;
+      if ((stat = do_mr_query("get_hostalias", 2, args, StoreInfo, &elem)))
+       {
+         com_err(program_name, stat, " in get_hostalias.");
+         return NULL;
        }
-       break;
+      break;
+    case SUBNET:
+      if ((stat = do_mr_query("get_subnet", 1, &name1, StoreInfo, &elem)))
+       {
+         if (stat == MR_NO_MATCH)
+           {
+             char buf[128];
+             sprintf(buf, "Network '%s' is not in the database.", name1);
+             Put_message(buf);
+           }
+         else
+           com_err(program_name, stat, " in get_subnet.");
+         return NULL;
+       }
+      break;
     case CLUSTER:
-       if ( (stat = do_mr_query("get_cluster",  1, &name1,
-                                 StoreInfo, (char *)&elem)) != 0) {
-           com_err(program_name, stat, " in get_cluster.");
-           return(NULL);
+      if ((stat = do_mr_query("get_cluster", 1, &name1, StoreInfo, &elem)))
+       {
+         com_err(program_name, stat, " in get_cluster.");
+         return NULL;
        }
-       break;
+      break;
     case MAP:
-       args[MAP_MACHINE] = name1;
-       args[MAP_CLUSTER] = name2;
-       if ( (stat = do_mr_query("get_machine_to_cluster_map", 2, args,
-                                 StoreInfo, (char *)&elem)) != 0) {
-           com_err(program_name, stat, " in get_machine_to_cluster_map.");
-           return(NULL);
+      args[MAP_MACHINE] = name1;
+      args[MAP_CLUSTER] = name2;
+      if ((stat = do_mr_query("get_machine_to_cluster_map", 2, args,
+                             StoreInfo, &elem)))
+       {
+         com_err(program_name, stat, " in get_machine_to_cluster_map.");
+         return NULL;
        }
-       break;
+      break;
     case DATA:
-       args[CD_NAME] = name1;
-       args[CD_LABEL] = name2;
-       if ( (stat = do_mr_query("get_cluster_data", 2, args,
-                                 StoreInfo, (char *)&elem)) != 0) {
-           com_err(program_name, stat, " in get_cluster_data.");
-           return(NULL);
+      args[CD_NAME] = name1;
+      args[CD_LABEL] = name2;
+      if ((stat = do_mr_query("get_cluster_data", 2, args, StoreInfo, &elem)))
+       {
+         com_err(program_name, stat, " in get_cluster_data.");
+         return NULL;
+       }
+      break;
+    case CONTAINER:
+      args[CON_NAME] = name1;
+      if ((stat = do_mr_query("get_container", 1, &name1, StoreInfo, &elem)))
+       {
+         com_err(program_name, stat, " in get_container.");
+         return NULL;
+       }
+      break;
+    case CONTMAP:
+      args[0] = name1;
+      if ((stat = do_mr_query("get_machine_to_container_map", 1, &name1,
+                             StoreInfo, &elem)))
+       {
+         com_err(program_name, stat, " in get_machine_to_container_map.");
+         return NULL;
        }
     }
-    return(QueueTop(elem));
+  return QueueTop(elem);
 }
 
 /*     Function Name: AskMCDInfo.
- *     Description: This function askes the user for information about a 
+ *     Description: This function askes the user for information about a
  *                   machine and saves it into a structure.
  *     Arguments: info - a pointer the information to ask about
  *                 type - type of information - MACHINE
  *                                              CLUSTER
  *                                              DATA
+ *                                              CONTAINER
  *                 name - T/F : change the name of this type.
  *     Returns: none.
  */
 
-char **
-AskMCDInfo(info, type, name)
-char ** info;
-int type;
-Bool name;
+char **AskMCDInfo(char **info, int type, Bool name)
 {
-    char temp_buf[BUFSIZ], *newname;
+  char temp_buf[BUFSIZ], *newname, *oldnewname;
 
-    switch (type) {
+  switch (type)
+    {
     case MACHINE:
-       sprintf(temp_buf, "Setting the information for the Machine %s.",
-               info[M_NAME]);
-       break;
+      sprintf(temp_buf, "\nSetting the information for the Machine %s...",
+             info[M_NAME]);
+      break;
+    case SUBNET:
+      sprintf(temp_buf, "Setting the information for the Network %s...",
+             info[SN_NAME]);
+      break;
     case CLUSTER:
-       sprintf(temp_buf, "Setting the information for the Cluster %s.",
-               info[C_NAME]);
-       break;
+      sprintf(temp_buf, "Setting the information for the Cluster %s...",
+             info[C_NAME]);
+      break;
     case DATA:
-       sprintf(temp_buf, "Setting the Data for the Cluster %s.",
-               info[CD_NAME]);
-       break;
+      sprintf(temp_buf, "Setting the Data for the Cluster %s...",
+             info[CD_NAME]);
+      break;
+    case CONTAINER:
+      sprintf(temp_buf, "Setting the Data for the Container %s...",
+             info[CON_NAME]);
+      break;
     }
-    Put_message(temp_buf);
+  Put_message(temp_buf);
 
-    if (name) {
-       switch (type) {
+  if (name)
+    {
+      switch (type)
+       {
        case MACHINE:
-           newname = Strsave(info[M_NAME]);
-           GetValueFromUser("The new name for this machine? ", &newname);
-           newname = canonicalize_hostname(newname);
-           break;
+         newname = strdup(info[M_NAME]);
+         if (GetValueFromUser("The new name for this machine? ", &newname) ==
+             SUB_ERROR)
+           return NULL;
+         oldnewname = strdup(newname);
+         newname = canonicalize_hostname(newname);
+         if (strcasecmp(newname, oldnewname) && *oldnewname != '"')
+           {
+             sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'\n",
+                     oldnewname, newname);
+             Put_message(temp_buf);
+           }
+         free(oldnewname);
+         break;
+       case SUBNET:
+         newname = strdup(info[SN_NAME]);
+         if (GetValueFromUser("The new name for this network? ", &newname) ==
+             SUB_ERROR)
+           return NULL;
+         break;
        case CLUSTER:
-           newname = Strsave(info[C_NAME]);
-           GetValueFromUser("The new name for this cluster? ",
-                            &newname);
-           break;
+         newname = strdup(info[C_NAME]);
+         if (GetValueFromUser("The new name for this cluster? ", &newname) ==
+             SUB_ERROR)
+           return NULL;
+         break;
+       case CONTAINER:
+         newname = strdup(info[CON_NAME]);
+         if (GetValueFromUser("The new name for this container? ", &newname)
+             == SUB_ERROR)
+           return NULL;
+         break;
        default:
-           Put_message("Unknown type in AskMCDInfo, programmer botch");
-           return(NULL);
+         Put_message("Unknown type in AskMCDInfo, programmer botch");
+         return NULL;
        }
     }
 
-    switch(type) {
+  switch (type)
+    {
     case MACHINE:
-       GetTypeFromUser("Machine's Type", "mac_type", &info[M_TYPE]);
-       FreeAndClear(&info[M_MODTIME], TRUE);
-       FreeAndClear(&info[M_MODBY], TRUE);
-       FreeAndClear(&info[M_MODWITH], TRUE);
-       break;
+      if (GetValueFromUser("Machine's vendor", &info[M_VENDOR]) == SUB_ERROR)
+       return NULL;
+      if (GetValueFromUser("Machine's model", &info[M_MODEL]) == SUB_ERROR)
+       return NULL;
+      if (GetValueFromUser("Machine's operating system", &info[M_OS]) ==
+         SUB_ERROR)
+       return NULL;
+      if (GetValueFromUser("Machine's location", &info[M_LOC]) == SUB_ERROR)
+       return NULL;
+      if (GetValueFromUser("Machine's contact", &info[M_CONTACT]) ==
+         SUB_ERROR)
+       return NULL;
+      if (GetValueFromUser("Machine's billing contact", 
+                          &info[M_BILL_CONTACT]) == SUB_ERROR)
+       return NULL;
+      if (GetValueFromUser("Machine's billing account number",
+                          &info[M_ACCT_NUMBER]) == SUB_ERROR)
+       return NULL;
+      while (1)
+       {
+         int i;
+         if (GetValueFromUser("Machine's status (? for help)",
+                                &info[M_STAT]) == SUB_ERROR)
+           return NULL;
+         if (isdigit(info[M_STAT][0]))
+           break;
+         Put_message("Valid status numbers:");
+         for (i = 0; i < 4; i++)
+           Put_message(states[i]);
+       }
+
+      /* there appears to be some argument mismatch between the client
+       * and the server.. so here is this argument shuffler.
+       * I have since modified this to always shuffle the arguments..
+       * not just do so when performing a modify all fields request.
+       * The SetMachinedefaults() has been changed to reflect this.
+       * pray for us and may we attain enlightenment through structures.
+       */
+
+      if (name)
+       {
+         /* info did not come from SetMachineDefaults(), which does not
+          * initialize entry 10 (M_STAT_CHNG), therefore we can
+          * free it.
+          */
+         /* This is an update of an existing machine and the structure
+          * was filled in thru a query to the db which does fill in this
+          * field.
+          */
+         free(info[10]);
+       }
+
+      info[10] = info[M_SUBNET];
+      info[11] = info[M_ADDR];
+      info[12] = info[M_OWNER_TYPE];
+      info[13] = info[M_OWNER_NAME];
+      info[14] = info[M_ACOMMENT];
+      info[15] = info[M_OCOMMENT];
+
+      if (name)
+       {
+         if (GetValueFromUser("Machine's network (or 'none')", &info[10])
+             == SUB_ERROR)
+           return NULL;
+       }
+      if (GetValueFromUser("Machine's address (or 'unassigned' or 'unique')",
+                          &info[11]) == SUB_ERROR)
+       return NULL;
+      if (GetTypeFromUser("Machine's owner type", "ace_type", &info[12]) ==
+         SUB_ERROR)
+       return NULL;
+      if (strcmp(info[12], "NONE") &&
+         GetValueFromUser("Owner's Name", &info[13]) == SUB_ERROR)
+       return NULL;
+      if (!strcmp(info[12], "KERBEROS"))
+         {
+           char *canon;
+
+           mrcl_validate_kerberos_member(info[13], &canon);
+           if (mrcl_get_message())
+             Put_message(mrcl_get_message());
+           free(info[13]);
+           info[13] = canon;
+         }
+      if (GetValueFromUser("Administrative comment", &info[14]) == SUB_ERROR)
+       return NULL;
+      if (GetValueFromUser("Operational comment", &info[15]) == SUB_ERROR)
+       return NULL;
+      info[16] = NULL;
+      FreeAndClear(&info[17], TRUE);
+      FreeAndClear(&info[18], TRUE);
+      break;
+    case SUBNET:
+      if (GetValueFromUser("Network description", &info[SN_DESC]) == SUB_ERROR)
+       return NULL;
+      while (1)
+       {
+         int i;
+         if (GetValueFromUser("Network's status (? for help)",
+                              &info[SN_STATUS]) == SUB_ERROR)
+           return NULL;
+         if (isdigit(info[SN_STATUS][0]))
+           break;
+         Put_message("Valid status numbers:");
+         for (i = 0; i < 9; i++)
+           Put_message(subnet_states[i]);
+       }
+      if (GetValueFromUser("Network's contact", &info[SN_CONTACT]) == SUB_ERROR)
+       return NULL;
+      if (GetValueFromUser("Network's billing account number", 
+                          &info[SN_ACCT_NUMBER]) == SUB_ERROR)
+       return NULL;
+      if (GetAddressFromUser("Network address", &info[SN_ADDRESS]) == SUB_ERROR)
+       return NULL;
+      if (GetAddressFromUser("Network mask", &info[SN_MASK]) == SUB_ERROR)
+       return NULL;
+      if (atoi(info[SN_LOW]) == (int)ntohl(inet_addr(S_DEFAULT_LOW)))
+       {
+         struct in_addr low;
+         unsigned long mask, addr;
+
+         addr = atoi(info[SN_ADDRESS]);
+         mask = atoi(info[SN_MASK]);
+         low.s_addr = atoi(info[SN_LOW]);
+         low.s_addr = (low.s_addr & ~mask) | (addr & mask);
+         free(info[SN_LOW]);
+         sprintf(temp_buf, "%ld", low.s_addr);
+         info[SN_LOW] = strdup(temp_buf);
+       }
+      if (GetAddressFromUser("Lowest assignable address", &info[SN_LOW]) ==
+         SUB_ERROR)
+       return NULL;
+      if (atoi(info[SN_HIGH]) == (int)ntohl(inet_addr(S_DEFAULT_HIGH)))
+       {
+         struct in_addr high;
+         unsigned long mask, addr;
+
+         addr = atoi(info[SN_ADDRESS]);
+         mask = atoi(info[SN_MASK]);
+         high.s_addr = atoi(info[SN_HIGH]);
+         high.s_addr = (high.s_addr & ~mask) | (addr & mask);
+         free(info[SN_HIGH]);
+         sprintf(temp_buf, "%ld", high.s_addr);
+         info[SN_HIGH] = strdup(temp_buf);
+       }
+      if (GetAddressFromUser("Highest assignable address", &info[SN_HIGH]) ==
+         SUB_ERROR)
+       return NULL;
+      if (GetValueFromUser("Hostname prefix", &info[SN_PREFIX]) == SUB_ERROR)
+       return NULL;
+      if (GetTypeFromUser("Owner type", "ace_type", &info[SN_ACE_TYPE]) ==
+         SUB_ERROR)
+       return NULL;
+      if (strcmp(info[SN_ACE_TYPE], "NONE") &&
+         GetValueFromUser("Owner name", &info[SN_ACE_NAME]) == SUB_ERROR)
+       return NULL;
+      if (!strcmp(info[SN_ACE_TYPE], "KERBEROS"))
+         {
+           char *canon;
+
+           mrcl_validate_kerberos_member(info[SN_ACE_NAME], &canon);
+           if (mrcl_get_message())
+             Put_message(mrcl_get_message());
+           free(info[SN_ACE_NAME]);
+           info[SN_ACE_NAME] = canon;
+         }
+      FreeAndClear(&info[SN_MODTIME], TRUE);
+      FreeAndClear(&info[SN_MODBY], TRUE);
+      FreeAndClear(&info[SN_MODWITH], TRUE);
+      break;
     case CLUSTER:
-       GetValueFromUser("Cluster's Description:", &info[C_DESCRIPT]);
-       GetValueFromUser("Cluster's Location:", &info[C_LOCATION]);
-       FreeAndClear(&info[C_MODTIME], TRUE);
-       FreeAndClear(&info[C_MODBY], TRUE);
-       FreeAndClear(&info[C_MODWITH], TRUE);
-       break;
+      if (GetValueFromUser("Cluster's Description:", &info[C_DESCRIPT]) ==
+         SUB_ERROR)
+       return NULL;
+      if (GetValueFromUser("Cluster's Location:", &info[C_LOCATION]) ==
+         SUB_ERROR)
+       return NULL;
+      FreeAndClear(&info[C_MODTIME], TRUE);
+      FreeAndClear(&info[C_MODBY], TRUE);
+      FreeAndClear(&info[C_MODWITH], TRUE);
+      break;
     case DATA:
-       GetValueFromUser("Label defining this data?", &info[CD_LABEL]);
-       GetValueFromUser("The data itself ? ", &info[CD_DATA]);
-       break;
+      if (GetValueFromUser("Label defining this data?", &info[CD_LABEL]) ==
+         SUB_ERROR)
+       return NULL;
+      if (GetValueFromUser("The data itself ? ", &info[CD_DATA]) == SUB_ERROR)
+       return NULL;
+      break;
+    case CONTAINER:
+      if (GetYesNoValueFromUser("Is this a public container", 
+                               &info[CON_PUBLIC]) == SUB_ERROR)
+       return NULL;
+      if (GetValueFromUser("Container's Description:", &info[CON_DESCRIPT]) ==
+         SUB_ERROR)
+       return NULL;
+      if (GetValueFromUser("Container's Location:", &info[CON_LOCATION]) ==
+         SUB_ERROR)
+       return NULL;
+      if (GetValueFromUser("Container's Contact:", &info[CON_CONTACT]) == 
+         SUB_ERROR)
+       return NULL;
+      if (GetTypeFromUser("Container's owner type", "ace_type", 
+                         &info[CON_OWNER_TYPE]) == SUB_ERROR)
+       return NULL;
+      if (strcmp(info[CON_OWNER_TYPE], "NONE") &&
+         GetValueFromUser("Owner's Name", &info[CON_OWNER_NAME]) == SUB_ERROR)
+       return NULL;
+      if (!strcmp(info[CON_OWNER_TYPE], "KERBEROS"))
+       {
+         char *canon;
+
+         mrcl_validate_kerberos_member(info[CON_OWNER_NAME], &canon);
+         if (mrcl_get_message())
+           Put_message(mrcl_get_message());
+         free(info[CON_OWNER_NAME]);
+         info[CON_OWNER_NAME] = canon;
+       }
+      if (GetTypeFromUser("Container's Membership ACL", "ace_type",
+                         &info[CON_MEMACE_TYPE]) == SUB_ERROR)
+       return NULL;
+      if (strcmp(info[CON_MEMACE_TYPE], "NONE") &&
+         GetValueFromUser("Membership ACL", &info[CON_MEMACE_NAME])
+         == SUB_ERROR)
+       return NULL;
+      if (!strcmp(info[CON_MEMACE_TYPE], "KERBEROS"))
+       {
+         char *canon;
+
+         mrcl_validate_kerberos_member(info[CON_MEMACE_NAME], &canon);
+         if (mrcl_get_message())
+           Put_message(mrcl_get_message());
+         free(info[CON_MEMACE_NAME]);
+         info[CON_MEMACE_NAME] = canon;
+       }
+      FreeAndClear(&info[CON_MODTIME], TRUE);
+      FreeAndClear(&info[CON_MODBY], TRUE);
+      FreeAndClear(&info[CON_MODWITH], TRUE);
+      break;
     }
 
-/* 
- * Slide the newname into the #2 slot, this screws up all future references 
- * to this list.
- */
-    if (name)                  
-       SlipInNewName(info, newname);
+  /*
+   * Slide the newname into the #2 slot, this screws up all future references
  * to this list.
  */
+  if (name)
+    SlipInNewName(info, newname);
 
-    return(info);
+  return info;
 }
 
 /* -----------  Machine Menu ----------- */
@@ -311,68 +892,151 @@ Bool name;
  *     Returns: DM_NORMAL.
  */
 
-/* ARGSUSED */
-int
-ShowMachineInfo(argc, argv)
-int argc;
-char **argv;
+int ShowMachineInfo(int argc, char **argv)
+{
+  struct mqelem *top;
+  char *tmpname;
+
+  tmpname = canonicalize_hostname(strdup(argv[1]));
+  top = GetMCInfo(MACHINE, tmpname, NULL);
+  Loop(top, ((void (*)(char **)) PrintMachInfo));
+  FreeQueue(top);
+  return DM_NORMAL;
+}
+
+/*     Function Name: ShowMachineQuery
+ *     Description: This function shows the information about a machine.
+ *             or group of machines, which may be selected through a
+ *             number of criteria.
+ *     Arguments: argc, argv - the name of the machine in argv[1],
+ *             the address of the machine in argv[2],
+ *             the location of the machine in argv[3],
+ *             and the contact name in argv[4].
+ *          any of these may be wildcards.
+ *     Returns: DM_NORMAL.
+ */
+
+int ShowMachineQuery(int argc, char **argv)
 {
-    struct qelem *top;
-    char *tmpname;
+  int stat;
+  struct mqelem *top, *elem = NULL;
+  char *args[5];
+
+  if (!strcmp(argv[1], "") && !strcmp(argv[2], "") &&
+      !strcmp(argv[3], "") && !strcmp(argv[4], ""))
+    {
+      Put_message("You must specify at least one parameter of the query.");
+      return DM_NORMAL;
+    }
 
-    tmpname = canonicalize_hostname(strsave(argv[1]));
-    top = GetMCInfo(MACHINE, tmpname, (char *) NULL);
-    Loop(top, ( (void *) PrintMachInfo) );
-    FreeQueue(top);
-    return(DM_NORMAL);
+  if (*argv[1])
+    args[0] = canonicalize_hostname(strdup(argv[1]));
+  else
+    args[0] = "*";
+  if (*argv[2])
+    args[1] = argv[2];
+  else
+    args[1] = "*";
+  if (*argv[3])
+    args[2] = argv[3];
+  else
+    args[2] = "*";
+  if (*argv[4])
+    args[3] = argv[4];
+  else
+    args[3] = "*";
+
+  if ((stat = do_mr_query("get_host", 4, args, StoreInfo, &elem)))
+    {
+      if (stat == MR_NO_MATCH)
+       Put_message("No machine(s) found matching query in the database.");
+      else
+       com_err(program_name, stat, " in get_machine.");
+      return DM_NORMAL;
+    }
+  top = QueueTop(elem);
+  Loop(top, ((void (*)(char **)) PrintMachInfo));
+  FreeQueue(top);
+  return DM_NORMAL;
 }
 
 /*     Function Name: AddMachine
  *     Description: This function adds a new machine to the database.
- *     Arguments: argc, argv - the name of the machine in argv[1].
+ *     Arguments: argc, argv - the name of the network in argv[1].
  *     Returns: DM_NORMAL.
  */
 
-/* ARGSUSED */
-int
-AddMachine(argc, argv)
-int argc;
-char **argv;
+int AddMachine(int argc, char **argv)
 {
-    char **args, *info[MAX_ARGS_SIZE], *name;
-    int stat;
+  char **args, *info[MAX_ARGS_SIZE], *name, buf[256], *xargs[5];
+  char **rinfo;
+  struct mqelem *elem = NULL;
+  int stat;
+
+  if (!ValidName(argv[1]))     /* Checks for wildcards. */
+    return DM_NORMAL;
+
+  /*
+   * get the network record
+   */
+
+  if (strcasecmp(argv[1], "none") &&
+      (stat = do_mr_query("get_subnet", 1, &argv[1], StoreInfo, &elem)))
+    {
+      if (stat == MR_NO_MATCH)
+       {
+         char buf[128];
+         sprintf(buf, "Network '%s' is not in the database.", argv[1]);
+         Put_message(buf);
+       } else
+         com_err(program_name, stat, " in get_subnet.");
+      return DM_NORMAL;
+    }
 
-    if (!ValidName(argv[1]))   /* Checks for wildcards. */
-       return(DM_NORMAL);
-/* 
- * Check to see if this machine already exists. 
- */
-    name =  canonicalize_hostname(strsave(argv[1]));
+  /*
+   * Check to see if this machine already exists.
+   */
 
-    if ( (stat = do_mr_query("get_machine", 1, &name, NullFunc, NULL)) == 0) {
-       Put_message("This machine already exists.");
-       free(name);
-       return(DM_NORMAL);
+  name = strdup(""); /* want to put prefix here */
+  if (GetValueFromUser("Machine name", &name) == SUB_ERROR)
+    return 0;
+
+  name = canonicalize_hostname(strdup(name));
+
+  xargs[0] = name;
+  xargs[1] = xargs[2] = xargs[3] = "*";
+  if (!(stat = do_mr_query("get_host", 4, xargs, NULL, NULL)))
+    {
+      sprintf(buf, "The machine '%s' already exists.", name);
+      Put_message(buf);
+      free(name);
+      return DM_NORMAL;
+    }
+  else if (stat != MR_NO_MATCH)
+    {
+      com_err(program_name, stat,
+             " while checking machine '%s' in AddMachine.", name);
+      free(name);
+      return DM_NORMAL;
     }
-    else if (stat != MR_NO_MATCH) {
-       com_err(program_name, stat, " in AddMachine.");
-       free(name);
-       return(DM_NORMAL);
+  rinfo = SetMachineDefaults(info, name);
+  rinfo[M_SUBNET] = strdup(argv[1]);
+  if (!(args = AskMCDInfo(rinfo, MACHINE, FALSE)))
+    {
+      Put_message("Aborted.");
+      return DM_NORMAL;
     }
 
-    args = AskMCDInfo(SetMachineDefaults(info, name), MACHINE, FALSE);
+  /*
+   * Actually create the new Machine.
+   */
 
-/*
- * Actually create the new Machine.
- */
-    
-    if ( (stat = do_mr_query("add_machine", CountArgs(args), 
-                             args, Scream, NULL)) != 0)
-       com_err(program_name, stat, " in AddMachine.");
+  if ((stat = do_mr_query("add_host", CountArgs(args), args, NULL, NULL)))
+    com_err(program_name, stat, " in AddMachine.");
 
-    FreeInfo(info);
-    free(name);
-    return(DM_NORMAL);
+  FreeInfo(info);
+  free(name);
+  return DM_NORMAL;
 }
 
 /*     Function Name: RealUpdateMachine
@@ -382,19 +1046,19 @@ char **argv;
  *     Returns: none.
  */
 
-/* ARGSUSED */
-static void
-RealUpdateMachine(info, junk)
-char ** info;
-Bool junk;
+static void RealUpdateMachine(char **info, Bool junk)
 {
-    register int stat;
-    char ** args = AskMCDInfo(info, MACHINE, TRUE);
-    if ( (stat = do_mr_query("update_machine", CountArgs(args), 
-                             args, Scream, NULL)) != 0)
-       com_err(program_name, stat, " in UpdateMachine.");
-    else
-       Put_message("Machine sucessfully updated.");
+  int stat;
+  char **args = AskMCDInfo(info, MACHINE, TRUE);
+  if (!args)
+    {
+      Put_message("Aborted.");
+      return;
+    }
+  if ((stat = do_mr_query("update_host", CountArgs(args), args, NULL, NULL)))
+    com_err(program_name, stat, " in UpdateMachine.");
+  else
+    Put_message("Machine successfully updated.");
 }
 
 /*     Function Name: UpdateMachine
@@ -403,88 +1067,153 @@ Bool junk;
  *     Returns: DM_NORMAL.
  */
 
-/* ARGSUSED */
-int
-UpdateMachine(argc, argv)
-int argc;
-char **argv;
+int UpdateMachine(int argc, char **argv)
 {
-    struct qelem *top;
-    char *tmpname;
+  struct mqelem *top;
+  char *tmpname;
 
-    tmpname = canonicalize_hostname(strsave(argv[1]));
-    top = GetMCInfo( MACHINE,  tmpname, (char *) NULL);
-    QueryLoop(top, NullPrint, RealUpdateMachine, "Update the machine");
+  tmpname = canonicalize_hostname(strdup(argv[1]));
+  top = GetMCInfo(MACHINE, tmpname, NULL);
+  QueryLoop(top, NullPrint, RealUpdateMachine, "Update the machine");
 
-    FreeQueue(top);
-    free(tmpname);
-    return(DM_NORMAL);
+  FreeQueue(top);
+  free(tmpname);
+  return DM_NORMAL;
 }
 
 /*     Function Name: CheckAndRemoveFromCluster
  *     Description: This func tests to see if a machine is in a cluster.
  *                   and if so then removes it
- *     Arguments: name - name of the machine (already Canonocalized).
+ *     Arguments: name - name of the machine (already Canonicalized).
  *                 ask_user- query the user before removing if from clusters?
  *     Returns: MR_ERROR if machine left in a cluster, or mr_error.
  */
 
-int 
-CheckAndRemoveFromCluster(name, ask_user)
-char * name;
-Bool ask_user;
-{
-    register int stat, ret_value;
-    Bool delete_it;
-    char *args[10], temp_buf[BUFSIZ], *ptr;
-    struct qelem *top, *elem = NULL;
-    
-    ret_value = SUB_NORMAL;    /* initialize ret_value. */
-    args[0] = name;
-    args[1] = "*";
-    stat = do_mr_query("get_machine_to_cluster_map", 2, args, 
-                       StoreInfo, (char *)&elem);
-    if (stat && stat != MR_NO_MATCH) {
-       com_err(program_name, stat, " in get_machine_to_cluster_map.");
-       return(DM_NORMAL);
-    }
-    if (stat == MR_SUCCESS) {
-       elem = top = QueueTop(elem);
-       if (ask_user) {
-           sprintf(temp_buf, "%s is assigned to the following clusters.",
-                   name);
-           Put_message(temp_buf);
-           Loop(top, (void *) PrintMCMap);
-           ptr = "Remove this machine from ** ALL ** these clusters?";
-           if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
-               delete_it = TRUE;
-           else {
-               Put_message("Aborting...");
-               FreeQueue(top);
-               return(SUB_ERROR);
+int CheckAndRemoveFromCluster(char *name, Bool ask_user)
+{
+  int stat, ret_value;
+  Bool delete_it;
+  char *args[10], temp_buf[BUFSIZ], *ptr;
+  struct mqelem *top, *elem = NULL;
+
+  ret_value = SUB_NORMAL;      /* initialize ret_value. */
+  args[0] = name;
+  args[1] = "*";
+  stat = do_mr_query("get_machine_to_cluster_map", 2, args, StoreInfo, &elem);
+  if (stat && stat != MR_NO_MATCH)
+    {
+      com_err(program_name, stat, " in get_machine_to_cluster_map.");
+      return DM_NORMAL;
+    }
+  if (stat == MR_SUCCESS)
+    {
+      elem = top = QueueTop(elem);
+      if (ask_user)
+       {
+         sprintf(temp_buf, "%s is assigned to the following clusters.", name);
+         Put_message(temp_buf);
+         Loop(top, (void (*)(char **)) PrintMCMap);
+         ptr = "Remove this machine from ** ALL ** these clusters?";
+         if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
+           delete_it = TRUE;
+         else
+           {
+             Put_message("Aborting...");
+             FreeQueue(top);
+             return SUB_ERROR;
            }
        }
-       else
-           delete_it = TRUE;
+      else
+       delete_it = TRUE;
+
+      if (delete_it)
+       {
+         while (elem)
+           {
+             char **info = elem->q_data;
+             if ((stat = do_mr_query("delete_machine_from_cluster",
+                                      2, info, NULL, NULL)))
+               {
+                 ret_value = SUB_ERROR;
+                 com_err(program_name, stat,
+                         " in delete_machine_from_cluster.");
+                 sprintf(temp_buf,
+                         "Machine %s ** NOT ** removed from cluster %s.",
+                         info[MAP_MACHINE], info[MAP_CLUSTER]);
+                 Put_message(temp_buf);
+               }
+             elem = elem->q_forw;
+           }
+       }
+    }
+  return ret_value;
+}
+
+/*     Function Name: CheckAndRemoveCnames
+ *     Description: This func tests to see if a machine has cnames, 
+ *                   and if so then removes them.
+ *     Arguments: name - name of the machine (already Canonicalized).
+ *                 ask_user- query the user before removing cnames?
+ *     Returns: MR_ERROR if machine left with a cname, or mr_error.
+ */
 
-       if (delete_it) {
-           while (elem != NULL) {
-               char **info = (char **) elem->q_data;
-               if ( (stat = do_mr_query( "delete_machine_from_cluster",
-                                         2, info, Scream, NULL)) != 0) {
-                   ret_value = SUB_ERROR;
-                   com_err(program_name, stat, 
-                           " in delete_machine_from_cluster.");
-                   sprintf(temp_buf, 
-                           "Machine %s ** NOT ** removed from cluster %s.",
-                           info[MAP_MACHINE], info[MAP_CLUSTER]);
-                   Put_message(temp_buf);
+int CheckAndRemoveCnames(char *name, Bool ask_user)
+{
+  int stat, ret_value;
+  Bool delete_it;
+  char *args[10], temp_buf[BUFSIZ], *ptr;
+  struct mqelem *top, *elem = NULL;
+
+  ret_value = SUB_NORMAL;
+  args[0] = "*";
+  args[1] = name;
+  stat = do_mr_query("get_hostalias", 2, args, StoreInfo, &elem);
+  if (stat && stat != MR_NO_MATCH)
+    {
+      com_err(program_name, stat, " in get_hostalias.");
+      return DM_NORMAL;
+    }
+  if (stat == MR_SUCCESS)
+    {
+      elem = top = QueueTop(elem);
+      if (ask_user)
+       {
+         sprintf(temp_buf, "%s has the following cnames.", name);
+         Put_message(temp_buf);
+         Loop(top, (void (*)(char **)) PrintCname);
+         ptr = "Remove ** ALL ** these cnames?";
+         if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
+           delete_it = TRUE;
+         else
+           {
+             Put_message("Aborting...");
+             FreeQueue(top);
+             return SUB_ERROR;
+           }
+       }
+      else
+       delete_it = TRUE;
+
+      if (delete_it)
+       {
+         while (elem)
+           {
+             char **info = elem->q_data;
+             if ((stat = do_mr_query("delete_hostalias", 2, info, 
+                                     NULL, NULL)))
+               {
+                 ret_value = SUB_ERROR;
+                 com_err(program_name, stat, " in delete_hostalias.");
+                 sprintf(temp_buf, 
+                         "Cname %s ** NOT ** removed from host %s.",
+                         info[0], info[1]);
+                 Put_message(temp_buf);
                }
-               elem = elem->q_forw;
+             elem = elem->q_forw;
            }
        }
     }
-    return(ret_value);
+  return ret_value;
 }
 
 /*     Function Name: RealDeleteMachine
@@ -495,28 +1224,32 @@ Bool ask_user;
  *     Returns: none.
  */
 
-static void
-RealDeleteMachine(info, one_machine)
-char ** info;
-Bool one_machine;
-{
-    register int stat;
-    char temp_buf[BUFSIZ];
-
-    sprintf(temp_buf, "Are you sure you want to delete the machine %s (y/n)? ",
-           info[M_NAME]);
-    if(!one_machine || Confirm(temp_buf)) {
-       if (CheckAndRemoveFromCluster(info[M_NAME], TRUE) != SUB_ERROR) {
-           if ( (stat = do_mr_query("delete_machine", 1,
-                                     &info[M_NAME], Scream, NULL)) != 0) {
-               com_err(program_name, stat, " in DeleteMachine.");
-               sprintf(temp_buf, "%s ** NOT ** deleted.", 
-                       info[M_NAME]);
-               Put_message(temp_buf);
-           }
-           else {
-               sprintf(temp_buf, "%s successfully Deleted.", info[M_NAME]);
-               Put_message(temp_buf);
+static void RealDeleteMachine(char **info, Bool one_machine)
+{
+  int stat;
+  char temp_buf[BUFSIZ];
+
+  sprintf(temp_buf, "Are you sure you want to delete the machine %s (y/n)? ",
+         info[M_NAME]);
+  if (!one_machine || Confirm(temp_buf))
+    {
+      if (CheckAndRemoveFromCluster(info[M_NAME], TRUE) != SUB_ERROR)
+       {
+         if (CheckAndRemoveCnames(info[M_NAME], TRUE) != SUB_ERROR)
+           {
+             if ((stat = do_mr_query("delete_host", 1,
+                                     &info[M_NAME], NULL, NULL)))
+               {
+                 com_err(program_name, stat, " in DeleteMachine.");
+                 sprintf(temp_buf, "%s ** NOT ** deleted.",
+                         info[M_NAME]);
+                 Put_message(temp_buf);
+               }
+             else
+               {
+                 sprintf(temp_buf, "%s successfully Deleted.", info[M_NAME]);
+                 Put_message(temp_buf);
+               }
            }
        }
     }
@@ -530,23 +1263,81 @@ Bool one_machine;
 
 /* Perhaps we should remove the cluster if it has no machine now. */
 
-/* ARGSUSED */
-int
-DeleteMachine(argc, argv)
-int argc;
-char **argv;
+int DeleteMachine(int argc, char **argv)
+{
+  struct mqelem *top;
+  char *tmpname;
+
+  tmpname = canonicalize_hostname(strdup(argv[1]));
+  top = GetMCInfo(MACHINE, tmpname, (char *) NULL);
+  QueryLoop(top, PrintMachInfo, RealDeleteMachine, "Delete the machine");
+  FreeQueue(top);
+  free(tmpname);
+  return DM_NORMAL;
+}
+
+
+/*     Function Name: ShowCname
+ *     Description: This function shows machine aliases
+ *     Arguments: argc, argv - the alias argv[1], the real name in argv[2]
+ *     Returns: DM_NORMAL.
+ */
+
+int ShowCname(int argc, char **argv)
 {
-    struct qelem *top;
-    char *tmpname;
+  struct mqelem *top;
+  char *tmpalias, *tmpname;
+
+  tmpalias = partial_canonicalize_hostname(strdup(argv[1]));
+  tmpname = canonicalize_hostname(strdup(argv[2]));
+  top = GetMCInfo(CNAME, tmpalias, tmpname);
+  Put_message("");             /* blank line on screen */
+  Loop(top, ((void (*)(char **)) PrintCname));
+  FreeQueue(top);
+  return DM_NORMAL;
+}
+
+
+int AddCname(int argc, char **argv)
+{
+  int stat;
+  char *args[10];
+
+  args[0] = partial_canonicalize_hostname(strdup(argv[1]));
+  args[1] = canonicalize_hostname(strdup(argv[2]));
+  stat = do_mr_query("add_hostalias", 2, args, NULL, NULL);
+  switch (stat)
+    {
+    case MR_SUCCESS:
+      break;
+    case MR_EXISTS:
+      Put_message("That alias name is already in use.");
+      break;
+    case MR_PERM:
+      Put_message("Permission denied.  "
+                 "(Regular users can only add two aliases to a host.");
+      break;
+    default:
+      com_err(program_name, stat, " in add_hostalias");
+    }
+  return DM_NORMAL;
+}
+
 
-    tmpname = canonicalize_hostname(strsave(argv[1]));
-    top = GetMCInfo(MACHINE, tmpname, (char *) NULL);
-    QueryLoop(top, PrintMachInfo, RealDeleteMachine, "Delete the machine");
-    FreeQueue(top);
-    free(tmpname);
-    return(DM_NORMAL);
+int DeleteCname(int argc, char **argv)
+{
+  int stat;
+  char *args[10];
+
+  args[0] = partial_canonicalize_hostname(strdup(argv[1]));
+  args[1] = canonicalize_hostname(strdup(argv[2]));
+  stat = do_mr_query("delete_hostalias", 2, args, NULL, NULL);
+  if (stat)
+    com_err(program_name, stat, " in delete_hostalias");
+  return DM_NORMAL;
 }
 
+
 /*     Function Name: AddMachineToCluster
  *     Description: This function adds a machine to a cluster
  *     Arguments: argc, argv - The machine name is argv[1].
@@ -554,82 +1345,90 @@ char **argv;
  *     Returns: DM_NORMAL.
  */
 
-/* ARGSUSED */
-int 
-AddMachineToCluster(argc, argv)
-int argc;
-char ** argv;
-{
-    int stat;
-    char *machine, *cluster, temp_buf[BUFSIZ], *args[10];
-    Bool add_it, one_machine, one_cluster;
-    struct qelem * melem, *mtop, *celem, *ctop;
-
-    machine = canonicalize_hostname(strsave(argv[1]));
-    cluster = argv[2];
-
-    celem = ctop = GetMCInfo(CLUSTER,  cluster, (char *) NULL);
-    melem = mtop = GetMCInfo(MACHINE,  machine, (char *) NULL);
-    free(machine);
-
-    one_machine = (QueueCount(mtop) == 1);
-    one_cluster = (QueueCount(ctop) == 1);
-
-    /* No good way to use QueryLoop() here, sigh */
-
-    while (melem != NULL) {
-       char ** minfo = (char **) melem->q_data;
-       while (celem != NULL) {
-           char ** cinfo = (char **) celem->q_data;
-           if (one_machine && one_cluster) 
-               add_it = TRUE;
-           else {
-               sprintf(temp_buf,"Add machine %s to cluster %s (y/n/q) ?",
-                       minfo[M_NAME], cinfo[C_NAME]);
-               switch (YesNoQuitQuestion(temp_buf, FALSE)) {
+int AddMachineToCluster(int argc, char **argv)
+{
+  int stat;
+  char *machine, *cluster, temp_buf[BUFSIZ], *args[10];
+  Bool add_it, one_machine, one_cluster;
+  struct mqelem *melem, *mtop, *celem, *ctop;
+
+  machine = canonicalize_hostname(strdup(argv[1]));
+  if (strcasecmp(machine, argv[1]) && *argv[1] != '"')
+    {
+      sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
+             argv[1], machine);
+      Put_message(temp_buf);
+    }
+  cluster = argv[2];
+
+  celem = ctop = GetMCInfo(CLUSTER, cluster, NULL);
+  melem = mtop = GetMCInfo(MACHINE, machine, NULL);
+  free(machine);
+
+  one_machine = (QueueCount(mtop) == 1);
+  one_cluster = (QueueCount(ctop) == 1);
+
+  /* No good way to use QueryLoop() here, sigh */
+
+  while (melem)
+    {
+      char **minfo = melem->q_data;
+      while (celem)
+       {
+         char **cinfo = celem->q_data;
+         if (one_machine && one_cluster)
+           add_it = TRUE;
+         else
+           {
+             sprintf(temp_buf, "Add machine %s to cluster %s (y/n/q) ?",
+                     minfo[M_NAME], cinfo[C_NAME]);
+             switch (YesNoQuitQuestion(temp_buf, FALSE))
+               {
                case TRUE:
-                   add_it = TRUE;
-                   break;
+                 add_it = TRUE;
+                 break;
                case FALSE:
-                   add_it = FALSE;
-                   break;
+                 add_it = FALSE;
+                 break;
                default:
-                   Put_message("Aborting...");
-                   FreeQueue(ctop);
-                   FreeQueue(mtop);
-                   return(DM_NORMAL);
+                 Put_message("Aborting...");
+                 FreeQueue(ctop);
+                 FreeQueue(mtop);
+                 return DM_NORMAL;
                }
            }
-           if (add_it) {
-               args[0] = minfo[M_NAME];
-               args[1] = cinfo[C_NAME];
-               stat = do_mr_query("add_machine_to_cluster", 2, args,
-                                   Scream, NULL);
-               switch (stat) {
+         if (add_it)
+           {
+             args[0] = minfo[M_NAME];
+             args[1] = cinfo[C_NAME];
+             stat = do_mr_query("add_machine_to_cluster", 2, args,
+                                NULL, NULL);
+             switch (stat)
+               {
                case MR_SUCCESS:
-                   break;
+                 break;
                case MR_EXISTS:
-                   sprintf(temp_buf, "%s is already in cluster %s",
-                           minfo[M_NAME], cinfo[C_NAME]);
-                   Put_message(temp_buf);
-                   break;
+                 sprintf(temp_buf, "%s is already in cluster %s",
+                         minfo[M_NAME], cinfo[C_NAME]);
+                 Put_message(temp_buf);
+                 break;
                default:
-                   com_err(program_name, stat, " in AddMachineToCluster.");
-                   break;
+                 com_err(program_name, stat, " in AddMachineToCluster.");
+                 break;
                }
            }
-           celem = celem->q_forw;
+         celem = celem->q_forw;
        }
-       celem = ctop;           /* reset cluster element. */
-       melem = melem->q_forw;
+      celem = ctop;            /* reset cluster element. */
+      melem = melem->q_forw;
     }
-    FreeQueue(ctop);
-    FreeQueue(mtop);               
-    return(DM_NORMAL);
+  FreeQueue(ctop);
+  FreeQueue(mtop);
+  return DM_NORMAL;
 }
 
 /*     Function Name: RealRemoveMachineFromCluster
- *     Description: This function actually removes the machine from its 
+ *     Description: This function actually removes the machine from its
  *                   cluster.
  *     Arguments: info - all information nescessary to perform the removal.
  *                 one_map - True if there is only one case, and we should
@@ -637,28 +1436,27 @@ char ** argv;
  *     Returns: none.
  */
 
-static void
-RealRemoveMachineFromCluster(info, one_map)
-char ** info;
-Bool one_map;
-{
-    char temp_buf[BUFSIZ];
-    register int stat;
-
-    sprintf(temp_buf, "Remove %s from the cluster %s", 
-           info[MAP_MACHINE], info[MAP_CLUSTER]);
-    if (!one_map || Confirm(temp_buf)) {
-       if ( (stat = do_mr_query("delete_machine_from_cluster", 2, 
-                                 info, Scream, NULL)) != 0 )
-           com_err(program_name, stat, " in delete_machine_from_cluster");
-       else {
-           sprintf(temp_buf, "%s has been removed from the cluster %s.",
-                   info[MAP_MACHINE], info[MAP_CLUSTER]);
-           Put_message(temp_buf);
+static void RealRemoveMachineFromCluster(char **info, Bool one_map)
+{
+  char temp_buf[BUFSIZ];
+  int stat;
+
+  sprintf(temp_buf, "Remove %s from the cluster %s",
+         info[MAP_MACHINE], info[MAP_CLUSTER]);
+  if (!one_map || Confirm(temp_buf))
+    {
+      if ((stat = do_mr_query("delete_machine_from_cluster", 2,
+                             info, NULL, NULL)))
+       com_err(program_name, stat, " in delete_machine_from_cluster");
+      else
+       {
+         sprintf(temp_buf, "%s has been removed from the cluster %s.",
+                 info[MAP_MACHINE], info[MAP_CLUSTER]);
+         Put_message(temp_buf);
        }
     }
-    else
-       Put_message("Machine not removed.");
+  else
+    Put_message("Machine not removed.");
 }
 
 /*     Function Name: RemoveMachineFromCluster
@@ -668,39 +1466,192 @@ Bool one_map;
  *     Returns: none.
  */
 
-/* ARGSUSED */
-int
-RemoveMachineFromCluster(argc, argv)
-int argc;
-char ** argv;
-{
-    struct qelem *elem = NULL;
-    char buf[BUFSIZ], * args[10];
-    register int stat;
-
-    args[MAP_MACHINE] = canonicalize_hostname(strsave(argv[1]));
-    args[MAP_CLUSTER] = argv[2];
-    args[MAP_END] = NULL;
-
-    stat = do_mr_query("get_machine_to_cluster_map", CountArgs(args), args,
-                       StoreInfo, (char *)&elem);
-    if (stat == MR_NO_MATCH) {
-       sprintf(buf, "The machine %s is not is the cluster %s.",
-               args[MAP_MACHINE], args[MAP_CLUSTER]);
-       Put_message(buf);
-       free(args[MAP_MACHINE]);
-       return(DM_NORMAL);
-    }
-    if (stat != MR_SUCCESS)
-       com_err(program_name, stat, " in delete_machine_from_cluster");
+int RemoveMachineFromCluster(int argc, char **argv)
+{
+  struct mqelem *elem = NULL;
+  char buf[BUFSIZ], *args[10];
+  int stat;
+
+  args[MAP_MACHINE] = canonicalize_hostname(strdup(argv[1]));
+  if (strcasecmp(args[MAP_MACHINE], argv[1]) && *argv[1] != '"')
+    {
+      sprintf(buf, "Warning: '%s' canonicalized to '%s'.",
+             argv[1], args[MAP_MACHINE]);
+      Put_message(buf);
+    }
+  args[MAP_CLUSTER] = argv[2];
+  args[MAP_END] = NULL;
+
+  stat = do_mr_query("get_machine_to_cluster_map", CountArgs(args), args,
+                    StoreInfo, &elem);
+  if (stat == MR_NO_MATCH)
+    {
+      sprintf(buf, "The machine %s is not in the cluster %s.",
+             args[MAP_MACHINE], args[MAP_CLUSTER]);
+      Put_message(buf);
+      free(args[MAP_MACHINE]);
+      return DM_NORMAL;
+    }
+  if (stat != MR_SUCCESS)
+    com_err(program_name, stat, " in delete_machine_from_cluster");
+
+  elem = QueueTop(elem);
+  QueryLoop(elem, PrintMCMap, RealRemoveMachineFromCluster,
+           "Remove this machine from this cluster");
+
+  FreeQueue(elem);
+  free(args[MAP_MACHINE]);
+  return DM_NORMAL;
+}
+
+/* ---------- Subnet Menu -------- */
+
+/*     Function Name: ShowSubnetInfo
+ *     Description: Gets information about a subnet given its name.
+ *     Arguments: argc, argc - the name of the subnet in in argv[1].
+ *     Returns: DM_NORMAL.
+ */
+
+int ShowSubnetInfo(int argc, char **argv)
+{
+  struct mqelem *top;
+
+  top = GetMCInfo(SUBNET, argv[1], (char *) NULL);
+  Loop(top, (void (*)(char **)) PrintSubnetInfo);
+  FreeQueue(top);
+  return DM_NORMAL;
+}
+
+/*     Function Name: AddSubnet
+ *     Description: Creates a new subnet.
+ *     Arguments: argc, argv - the name of the new subnet is argv[1].
+ *     Returns: DM_NORMAL.
+ */
+
+int AddSubnet(int argc, char **argv)
+{
+  char **args, *info[MAX_ARGS_SIZE], *name = argv[1];
+  int stat;
+
+  /*
+   * Check to see if this subnet already exists.
+   */
+  if (!ValidName(name))
+    return DM_NORMAL;
+
+  if ((stat = do_mr_query("get_subnet", 1, &name, NULL, NULL)) == MR_SUCCESS)
+    {
+      Put_message("This subnet already exists.");
+      return DM_NORMAL;
+    }
+  else if (stat != MR_NO_MATCH)
+    {
+      com_err(program_name, stat, " in AddSubnet.");
+      return DM_NORMAL;
+    }
+  if (!(args = AskMCDInfo(SetSubnetDefaults(info, name), SUBNET, FALSE)))
+    {
+      Put_message("Aborted.");
+      FreeInfo(info);
+      return DM_NORMAL;
+    }
+
+  /*
+   * Actually create the new Subnet.
+   */
+  if ((stat = do_mr_query("add_subnet", CountArgs(args), args, NULL, NULL)))
+    com_err(program_name, stat, " in AddSubnet.");
+
+  FreeInfo(info);
+  return DM_NORMAL;
+}
 
-    elem = QueueTop(elem);
-    QueryLoop(elem, PrintMCMap, RealRemoveMachineFromCluster,
-             "Remove this machine from this cluster");
+/*     Function Name: RealUpdateSubnet
+ *     Description: This function actually performs the subnet update.
+ *     Arguments: info - all information nesc. for updating the subnet.
+ *                 junk - an UNUSED boolean.
+ *     Returns: none.
+ */
 
-    FreeQueue(elem);
-    free(args[MAP_MACHINE]);
-    return(DM_NORMAL);
+static void RealUpdateSubnet(char **info, Bool junk)
+{
+  int stat;
+  char **args = AskMCDInfo(info, SUBNET, TRUE);
+  if (!args)
+    {
+      Put_message("Aborted.");
+      return;
+    }
+  if ((stat = do_mr_query("update_subnet", CountArgs(args), args, NULL, NULL)))
+    com_err(program_name, stat, " in UpdateSubnet.");
+  else
+    Put_message("Subnet successfully updated.");
+}
+
+/*     Function Name: UpdateSubnet
+ *     Description: This Function Updates a subnet
+ *     Arguments: name of the subnet in argv[1].
+ *     Returns: DM_NORMAL.
+ */
+
+int UpdateSubnet(int argc, char **argv)
+{
+  struct mqelem *top;
+  top = GetMCInfo(SUBNET, argv[1], NULL);
+  QueryLoop(top, NullPrint, RealUpdateSubnet, "Update the subnet");
+
+  FreeQueue(top);
+  return DM_NORMAL;
+}
+
+/*     Function Name: RealDeleteSubnet
+ *     Description: Actually performs the subnet deletion.
+ *     Arguments: info - all information about this subnet.
+ *                 one_subnet - If true then there was only one subnet in
+ *                               the queue, and we should confirm.
+ *     Returns: none.
+ */
+
+static void RealDeleteSubnet(char **info, Bool one_subnet)
+{
+  int stat;
+  char temp_buf[BUFSIZ];
+
+  sprintf(temp_buf,
+         "Are you sure the you want to delete the subnet %s (y/n) ?",
+         info[C_NAME]);
+  if (!one_subnet || Confirm(temp_buf))
+    {
+      if ((stat = do_mr_query("delete_subnet", 1, &info[C_NAME], NULL, NULL)))
+       {
+         com_err(program_name, stat, " in delete_subnet.");
+         sprintf(temp_buf, "Subnet %s ** NOT ** deleted.", info[C_NAME]);
+         Put_message(temp_buf);
+       }
+      else
+       {
+         sprintf(temp_buf, "subnet %s successfully deleted.",
+                 info[C_NAME]);
+         Put_message(temp_buf);
+       }
+    }
+}
+
+/*     Function Name: DeleteSubnet
+ *     Description: This function removes a subnet from the database.
+ *     Arguments: argc, argv - the name of the subnet is stored in argv[1].
+ *     Returns: DM_NORMAL.
+ */
+
+int DeleteSubnet(int argc, char **argv)
+{
+  struct mqelem *top;
+
+  top = GetMCInfo(SUBNET, argv[1], NULL);
+  QueryLoop(top, PrintSubnetInfo, RealDeleteSubnet, "Delete the subnet");
+
+  FreeQueue(top);
+  return DM_NORMAL;
 }
 
 /* ---------- Cluster Menu -------- */
@@ -711,18 +1662,14 @@ char ** argv;
  *     Returns: DM_NORMAL.
  */
 
-/* ARGSUSED */
-int
-ShowClusterInfo(argc, argv)
-int argc;
-char ** argv;
+int ShowClusterInfo(int argc, char **argv)
 {
-    struct qelem *top;
+  struct mqelem *top;
 
-    top = GetMCInfo(CLUSTER, argv[1], (char *) NULL);
-    Loop(top, (void *) PrintClusterInfo);
-    FreeQueue(top);
-    return(DM_NORMAL);
+  top = GetMCInfo(CLUSTER, argv[1], NULL);
+  Loop(top, (void (*)(char **)) PrintClusterInfo);
+  FreeQueue(top);
+  return DM_NORMAL;
 }
 
 /*     Function Name: AddCluster
@@ -731,39 +1678,42 @@ char ** argv;
  *     Returns: DM_NORMAL.
  */
 
-/* ARGSUSED */
-int
-AddCluster(argc, argv)
-int argc;
-char ** argv;
+int AddCluster(int argc, char **argv)
 {
-    char **args, *info[MAX_ARGS_SIZE], *name = argv[1];
-    int stat;
-/* 
- * Check to see if this cluster already exists. 
- */
-    if (!ValidName(name))
-       return(DM_NORMAL);
-
-    if ( (stat = do_mr_query("get_cluster", 1, &name, 
-                             NullFunc, NULL)) == MR_SUCCESS) {
-       Put_message("This cluster already exists.");
-       return(DM_NORMAL);
+  char **args, *info[MAX_ARGS_SIZE], *name = argv[1];
+  int stat;
+
+  /*
+   * Check to see if this cluster already exists.
+   */
+  if (!ValidName(name))
+    return DM_NORMAL;
+
+  if ((stat = do_mr_query("get_cluster", 1, &name, NULL, NULL)) == MR_SUCCESS)
+    {
+      Put_message("This cluster already exists.");
+      return DM_NORMAL;
     }
-    else if (stat != MR_NO_MATCH) {
-       com_err(program_name, stat, " in AddCluster.");
-       return(DM_NORMAL);
+  else if (stat != MR_NO_MATCH)
+    {
+      com_err(program_name, stat, " in AddCluster.");
+      return DM_NORMAL;
     }
-    args = AskMCDInfo(SetClusterDefaults(info, name), CLUSTER, FALSE);
-/*
- * Actually create the new Cluster.
- */
-    if ( (stat = do_mr_query("add_cluster", CountArgs(args), 
-                             args, Scream, NULL)) != 0)
-       com_err(program_name, stat, " in AddCluster.");
+  if (!(args = AskMCDInfo(SetClusterDefaults(info, name), CLUSTER, FALSE)))
+    {
+      Put_message("Aborted.");
+      FreeInfo(info);
+      return DM_NORMAL;
+    }
+
+  /*
+   * Actually create the new Cluster.
+   */
+  if ((stat = do_mr_query("add_cluster", CountArgs(args), args, NULL, NULL)))
+    com_err(program_name, stat, " in AddCluster.");
 
-    FreeInfo(info);
-    return(DM_NORMAL);
+  FreeInfo(info);
+  return DM_NORMAL;
 }
 
 /*     Function Name: RealUpdateCluster
@@ -773,19 +1723,21 @@ char ** argv;
  *     Returns: none.
  */
 
-/* ARGSUSED */
-static void
-RealUpdateCluster(info, junk)
-char ** info;
-Bool junk;
+static void RealUpdateCluster(char **info, Bool junk)
 {
-    register int stat;
-    char ** args = AskMCDInfo(info, CLUSTER, TRUE);
-    if ( (stat = do_mr_query("update_cluster", CountArgs(args), 
-                             args, Scream, NULL)) != 0)
-       com_err(program_name, stat, " in UpdateCluster.");
-    else
-       Put_message("Cluster successfully updated.");
+  int stat;
+  char **args = AskMCDInfo(info, CLUSTER, TRUE);
+
+  if (!args)
+    {
+      Put_message("Aborted.");
+      return;
+    }
+  if ((stat = do_mr_query("update_cluster", CountArgs(args),
+                         args, NULL, NULL)))
+    com_err(program_name, stat, " in UpdateCluster.");
+  else
+    Put_message("Cluster successfully updated.");
 }
 
 /*     Function Name: UpdateCluster
@@ -794,18 +1746,14 @@ Bool junk;
  *     Returns: DM_NORMAL.
  */
 
-/* ARGSUSED */
-int 
-UpdateCluster(argc, argv)
-int argc;
-char ** argv;
+int UpdateCluster(int argc, char **argv)
 {
-    struct qelem *top;    
-    top = GetMCInfo( CLUSTER, argv[1], (char *) NULL );
-    QueryLoop(top, NullPrint, RealUpdateCluster, "Update the cluster");
+  struct mqelem *top;
+  top = GetMCInfo(CLUSTER, argv[1], NULL);
+  QueryLoop(top, NullPrint, RealUpdateCluster, "Update the cluster");
 
-    FreeQueue(top);
-    return(DM_NORMAL);
+  FreeQueue(top);
+  return DM_NORMAL;
 }
 
 /*     Function Name: CheckAndRemoveMachine
@@ -817,69 +1765,72 @@ char ** argv;
  *     Returns: SUB_ERROR if all machines not removed.
  */
 
-int
-CheckAndRemoveMachines(name, ask_first)
-char * name;
-Bool ask_first;
-{
-    register int stat, ret_value;
-    Bool delete_it;
-    char *args[10], temp_buf[BUFSIZ], *ptr;
-    struct qelem *top, *elem = NULL;
-    
-    ret_value = SUB_NORMAL;
-    args[MAP_MACHINE] = "*";
-    args[MAP_CLUSTER] = name;
-    stat = do_mr_query("get_machine_to_cluster_map", 2, args, 
-                       StoreInfo, (char *)&elem);
-    if (stat && stat != MR_NO_MATCH) {
-       com_err(program_name, stat, " in get_machine_to_cluster_map.");
-       return(DM_NORMAL);
-    }
-    if (stat == 0) {
-       elem = top = QueueTop(elem);
-       if (ask_first) {
-           sprintf(temp_buf,
-                   "The cluster %s has the following machines in it:",
-                   name);
-           Put_message(temp_buf);
-           while (elem != NULL) {
-               char **info = (char **) elem->q_data;
-               Print(1, &info[MAP_MACHINE], (char *) NULL);
-               elem = elem->q_forw;
+int CheckAndRemoveMachines(char *name, Bool ask_first)
+{
+  int stat, ret_value;
+  Bool delete_it;
+  char *args[10], temp_buf[BUFSIZ], *ptr;
+  struct mqelem *top, *elem = NULL;
+
+  ret_value = SUB_NORMAL;
+  args[MAP_MACHINE] = "*";
+  args[MAP_CLUSTER] = name;
+  stat = do_mr_query("get_machine_to_cluster_map", 2, args, StoreInfo, &elem);
+  if (stat && stat != MR_NO_MATCH)
+    {
+      com_err(program_name, stat, " in get_machine_to_cluster_map.");
+      return DM_NORMAL;
+    }
+  if (stat == MR_SUCCESS)
+    {
+      elem = top = QueueTop(elem);
+      if (ask_first)
+       {
+         sprintf(temp_buf, "The cluster %s has the following machines in it:",
+                 name);
+         Put_message(temp_buf);
+         while (elem)
+           {
+             char **info = elem->q_data;
+             Print(1, &info[MAP_MACHINE], (char *) NULL);
+             elem = elem->q_forw;
            }
-           ptr = "Remove ** ALL ** these machines from this cluster?";
-
-           if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
-               delete_it = TRUE;
-           else {
-               Put_message("Aborting...");
-               FreeQueue(top);
-               return(SUB_ERROR);
+         ptr = "Remove ** ALL ** these machines from this cluster?";
+
+         if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
+           delete_it = TRUE;
+         else
+           {
+             Put_message("Aborting...");
+             FreeQueue(top);
+             return SUB_ERROR;
            }
        }
-       else
-           delete_it = TRUE;
-
-       if (delete_it) {
-           elem = top;
-           while (elem != 0) {
-               char **info = (char **) elem->q_data;
-               if ( (stat = do_mr_query("delete_machine_from_cluster",
-                                         2, info, Scream, NULL)) != 0) {
-                   ret_value = SUB_ERROR;
-                   com_err(program_name, stat, 
-                           " in delete_machine_from_cluster.");
-                   sprintf(temp_buf, 
-                           "Machine %s ** NOT ** removed from cluster %s.",
-                           info[MAP_MACHINE], info[MAP_CLUSTER]);
-                   Put_message(temp_buf);
+      else
+       delete_it = TRUE;
+
+      if (delete_it)
+       {
+         elem = top;
+         while (elem)
+           {
+             char **info = elem->q_data;
+             if ((stat = do_mr_query("delete_machine_from_cluster",
+                                     2, info, NULL, NULL)))
+               {
+                 ret_value = SUB_ERROR;
+                 com_err(program_name, stat,
+                         " in delete_machine_from_cluster.");
+                 sprintf(temp_buf,
+                         "Machine %s ** NOT ** removed from cluster %s.",
+                         info[MAP_MACHINE], info[MAP_CLUSTER]);
+                 Put_message(temp_buf);
                }
-               elem = elem->q_forw;
+             elem = elem->q_forw;
            }
        }
     }
-    return(ret_value);
+  return ret_value;
 }
 
 /*     Function Name: RealDeleteCluster
@@ -890,30 +1841,30 @@ Bool ask_first;
  *     Returns: none.
  */
 
-static void
-RealDeleteCluster(info, one_cluster)
-char ** info;
-Bool one_cluster;
-{
-    register int stat;
-    char temp_buf[BUFSIZ];
-    
-    sprintf(temp_buf, 
-           "Are you sure the you want to delete the cluster %s (y/n) ?", 
-           info[C_NAME]);
-    if (!one_cluster || Confirm(temp_buf)) {
-       if (CheckAndRemoveMachines(info[C_NAME], TRUE) != SUB_ERROR) {
-           if ( (stat = do_mr_query("delete_cluster", 1,
-                                     &info[C_NAME], Scream, NULL)) != 0) {
-               com_err(program_name, stat, " in delete_cluster.");
-               sprintf(temp_buf, "Cluster %s ** NOT ** deleted.", 
-                       info[C_NAME]);
-               Put_message(temp_buf);
+static void RealDeleteCluster(char **info, Bool one_cluster)
+{
+  int stat;
+  char temp_buf[BUFSIZ];
+
+  sprintf(temp_buf,
+         "Are you sure the you want to delete the cluster %s (y/n) ?",
+         info[C_NAME]);
+  if (!one_cluster || Confirm(temp_buf))
+    {
+      if (CheckAndRemoveMachines(info[C_NAME], TRUE) != SUB_ERROR)
+       {
+         if ((stat = do_mr_query("delete_cluster", 1,
+                                 &info[C_NAME], NULL, NULL)))
+           {
+             com_err(program_name, stat, " in delete_cluster.");
+             sprintf(temp_buf, "Cluster %s ** NOT ** deleted.", info[C_NAME]);
+             Put_message(temp_buf);
            }
-           else {
-               sprintf(temp_buf, "cluster %s sucesfully deleted.", 
-                       info[C_NAME]);
-               Put_message(temp_buf);
+         else
+           {
+             sprintf(temp_buf, "cluster %s successfully deleted.",
+                     info[C_NAME]);
+             Put_message(temp_buf);
            }
        }
     }
@@ -925,21 +1876,17 @@ Bool one_cluster;
  *     Returns: DM_NORMAL.
  */
 
-/* ARGSUSED */
-int
-DeleteCluster(argc, argv)
-int argc;
-char ** argv;
+int DeleteCluster(int argc, char **argv)
 {
-    struct qelem *top;
+  struct mqelem *top;
 
-    top = GetMCInfo( CLUSTER, argv[1], (char *) NULL );
-    QueryLoop(top, PrintClusterInfo, RealDeleteCluster, "Delete the cluster");
+  top = GetMCInfo(CLUSTER, argv[1], NULL);
+  QueryLoop(top, PrintClusterInfo, RealDeleteCluster, "Delete the cluster");
 
-    FreeQueue(top);
-    return(DM_NORMAL);
+  FreeQueue(top);
+  return DM_NORMAL;
 }
-    
+
 /* ----------- Cluster Data Menu -------------- */
 
 /*     Function Name: ShowClusterData
@@ -949,23 +1896,20 @@ char ** argv;
  *     Returns: DM_NORMAL.
  */
 
-/* ARGSUSED */
-int
-ShowClusterData(argc, argv)
-int argc; 
-char ** argv; 
-{ 
-    struct qelem *elem, *top;
-    char **info;
-
-    top = elem = GetMCInfo(DATA, argv[1], argv[2]);
-    while (elem != NULL) {
-       info = (char **) elem->q_data;
-       PrintClusterData(info);
-       elem = elem->q_forw;
+int ShowClusterData(int argc, char **argv)
+{
+  struct mqelem *elem, *top;
+  char **info;
+
+  top = elem = GetMCInfo(DATA, argv[1], argv[2]);
+  while (elem)
+    {
+      info = elem->q_data;
+      PrintClusterData(info);
+      elem = elem->q_forw;
     }
-    FreeQueue(top);
-    return(DM_NORMAL);
+  FreeQueue(top);
+  return DM_NORMAL;
 }
 
 /*     Function Name: AddClusterData
@@ -976,18 +1920,21 @@ char ** argv;
  *     Returns: DM_NORMAL.
  */
 
-/* ARGSUSED */
-int
-AddClusterData(argc, argv)
-int argc; 
-char ** argv; 
-{ 
-    int stat;
-
-    if( (stat = do_mr_query("add_cluster_data", 3, argv + 1,
-                            Scream, (char *) NULL)) != 0)
-       com_err(program_name, stat, " in AddClusterData.");
-
+int AddClusterData(int argc, char **argv)
+{
+  int stat, i;
+
+  for (i = 1; i < 4; i++)
+    {
+      if (IS_EMPTY(argv[i]))
+       {
+         Put_message("Cluster data cannot be an empty string.");
+         return DM_NORMAL;
+       }
+    }
+  if ((stat = do_mr_query("add_cluster_data", 3, argv + 1, NULL, NULL)))
+    com_err(program_name, stat, " in AddClusterData.");
+  return DM_NORMAL;
 }
 
 /*     Function Name: RealRemoveClusterData
@@ -999,25 +1946,23 @@ char ** argv;
  *     Returns: none.
  */
 
-static void
-RealRemoveClusterData(info, one_item)
-char ** info;
-Bool one_item;
-{
-    register int stat;
-    char * temp_ptr;
-
-    Put_message(" ");
-    temp_ptr = "Are you sure that you want to remove this cluster data (y/n) ?";
-    PrintClusterData(info);
-    if (!one_item || Confirm(temp_ptr)) {
-       if( (stat = do_mr_query("delete_cluster_data", 3, info,
-                                Scream, (char *) NULL)) != 0) {
-           com_err(program_name, stat, " in DeleteClusterData.");
-           Put_message("Data not removed.");
+static void RealRemoveClusterData(char **info, Bool one_item)
+{
+  int stat;
+  char *temp_ptr;
+
+  Put_message(" ");
+  temp_ptr = "Are you sure that you want to remove this cluster data (y/n) ?";
+  PrintClusterData(info);
+  if (!one_item || Confirm(temp_ptr))
+    {
+      if ((stat = do_mr_query("delete_cluster_data", 3, info, NULL, NULL)))
+       {
+         com_err(program_name, stat, " in DeleteClusterData.");
+         Put_message("Data not removed.");
        }
-       else
-           Put_message("Removal sucessful.");
+      else
+       Put_message("Removal successful.");
     }
 }
 
@@ -1029,20 +1974,16 @@ Bool one_item;
  *     Returns: DM_NORMAL.
  */
 
-/* ARGSUSED */
-int 
-RemoveClusterData(argc, argv)
-int argc; 
-char ** argv; 
+int RemoveClusterData(int argc, char **argv)
 {
-    struct qelem *top;
+  struct mqelem *top;
 
-    top = GetMCInfo(DATA, argv[1], argv[2]);
-    QueryLoop(top, PrintClusterData, RealRemoveClusterData, 
-             "Remove data from cluster");
+  top = GetMCInfo(DATA, argv[1], argv[2]);
+  QueryLoop(top, PrintClusterData, RealRemoveClusterData,
+           "Remove data from cluster");
 
-    FreeQueue(top);
-    return(DM_NORMAL);
+  FreeQueue(top);
+  return DM_NORMAL;
 }
 
 /*     Function Name: MachineToClusterMap
@@ -1052,26 +1993,603 @@ char ** argv;
  *     Returns: none.
  */
 
-/* ARGSUSED */
-int 
-MachineToClusterMap(argc,argv)
-int argc;
-char **argv;
+int MachineToClusterMap(int argc, char **argv)
+{
+  struct mqelem *elem, *top;
+  char *tmpname, temp_buf[256];
+
+  tmpname = canonicalize_hostname(strdup(argv[1]));
+  if (strcasecmp(tmpname, argv[1]) && *argv[1] != '"')
+    {
+      sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
+             argv[1], tmpname);
+      Put_message(temp_buf);
+    }
+  top = elem = GetMCInfo(MAP, tmpname, argv[2]);
+
+  Put_message("");             /* blank line on screen */
+  while (elem)
+    {
+      char **info = elem->q_data;
+      PrintMCMap(info);
+      elem = elem->q_forw;
+    }
+
+  FreeQueue(top);
+  free(tmpname);
+  return DM_NORMAL;
+}
+
+/*        Function Name: MachineByOwner
+ *        Description: This function prints all machines which are owned by 
+ *                     a given user or group.
+ *        Arguments: none.
+ *        Returns: DM_NORMAL.
+ */
+
+int MachineByOwner(int argc, char **argv)
+{
+  char buf[BUFSIZ], temp_buf[BUFSIZ], *type, *name;
+  struct mqelem *top;
+
+  type = strdup("USER");
+  if (GetTypeFromUser("Type of owner", "ace_type", &type) == SUB_ERROR)
+    return DM_NORMAL;
+
+  sprintf(buf, "Name of %s", type);
+  name = strdup(user);
+  if (GetValueFromUser(buf, &name) == SUB_ERROR)
+    return DM_NORMAL;
+
+  switch (YesNoQuestion("Do you want a recursive search (y/n)", FALSE))
+    {
+    case TRUE:
+      sprintf(temp_buf, "R%s", type);     /* "USER to "RUSER", etc. */
+      free(type);
+      type = strdup(temp_buf);
+      break;
+    case FALSE:
+      break;
+    default:
+      return DM_NORMAL;
+    }
+
+  top = GetMachineByOwner(type, name);
+  Loop(top, PrintMachine);
+
+  FreeQueue(top);
+  return DM_NORMAL;
+}
+
+/*         Function Name: GetMachineByOwner
+ *         Description: This function stores information retrieved by 
+ *                      the get_host_by_owner query
+ *         Arguments: type - an ace_type, argv[0] for the query
+ *                    name - name of machine, argv[1] for the query
+ *         Returns: the top element of a queue returning the data, or NULL.
+ */
+
+struct mqelem *GetMachineByOwner(char *type, char *name)
+{
+  char *args[2];
+  struct mqelem *elem = NULL;
+  int status;
+
+  args[0] = type;
+  args[1] = name;
+  if ((status = do_mr_query("get_host_by_owner", 2, args, StoreInfo, &elem)))
+    {
+      com_err(program_name, status, " in get_host_by_owner");
+      return NULL;
+    }
+  return QueueTop(elem);
+}
+
+int MachineByAcctNumber(int argc, char **argv)
+{
+  char *args[1], *account_number;
+  int status;
+  struct mqelem *elem = NULL;
+
+  account_number = strdup("");
+  if (GetValueFromUser("Account Number", &account_number) == SUB_ERROR)
+    return DM_NORMAL;
+
+  args[0] = account_number;
+  if (status = do_mr_query("get_host_by_account_number", 1, args, StoreInfo, 
+                          &elem))
+    {
+      com_err(program_name, status, " in get_host_by_account_number");
+      return DM_NORMAL;
+    }
+  Loop(QueueTop(elem), (void (*)(char **)) PrintMachInfo);
+  FreeQueue(elem);
+
+  return DM_NORMAL;
+}
+
+int ShowContainerInfo(int argc, char **argv)
+{
+  struct mqelem *top;
+
+  top = GetMCInfo(CONTAINER, argv[1], NULL);
+  Loop(top, (void (*)(char **)) PrintContainerInfo);
+  FreeQueue(top);
+  return DM_NORMAL;
+}
+
+static char *PrintContainerInfo(char **info)
+{
+  char buf[BUFSIZ], tbuf[256];
+  char *args[2];
+  struct mqelem *elem = NULL;
+  int stat;
+
+  Put_message("");
+  sprintf(buf, "Container:      %-16s    Public:      %s", info[CON_NAME],
+         atoi(info[CON_PUBLIC]) ? "Yes" : "No");
+  Put_message(buf);
+  /* Do a get_container_list to see what the associated list is. */
+  args[0] = info[CON_NAME];
+  if (stat = do_mr_query("get_container_list", 1, args, StoreInfo, &elem))
+    {
+      if (stat != MR_NO_MATCH)
+       com_err(program_name, stat, " looking up container list");
+    }
+  else 
+    {
+      sprintf(buf, "Container's associated list is: LIST %s",
+             ((char **)elem->q_data)[1]);
+      Put_message(buf);
+      FreeQueue(elem);
+    }
+  sprintf(buf, "Description:    %-16s", info[CON_DESCRIPT]);
+  Put_message(buf);
+  sprintf(buf, "Location:       %-16s    Contact:     %s", info[CON_LOCATION],
+         info[CON_CONTACT]);
+  Put_message(buf);
+  sprintf(tbuf, "%s %s", info[CON_OWNER_TYPE],
+         strcmp(info[CON_OWNER_TYPE], "NONE") ? info[CON_OWNER_NAME] : "");
+  sprintf(buf, "Owner:          %-16s", tbuf);
+  Put_message(buf);
+  sprintf(tbuf, "%s %s", info[CON_MEMACE_TYPE],
+         strcmp(info[CON_MEMACE_TYPE], "NONE") ? info[CON_MEMACE_NAME] : "");
+  sprintf(buf, "Membership ACL: %-16s", tbuf);
+  Put_message(buf);
+  Put_message("");
+  sprintf(buf, MOD_FORMAT, info[CON_MODBY], info[CON_MODTIME], 
+         info[CON_MODWITH]);
+  Put_message(buf);
+  return(info[CON_NAME]);
+}
+
+static char *PrintContainer(char **info)
 {
-    struct qelem *elem, *top;
-    char *tmpname;
+  char buf[BUFSIZ];
 
-    tmpname = canonicalize_hostname(strsave(argv[1]));
-    top = elem = GetMCInfo(MAP, tmpname, argv[2]);
+  sprintf(buf, "Container: %s", info[CON_NAME]);
+  Put_message(buf);
+  return "";
+}
+
+static char *PrintMContMap(char **info)
+{
+  char buf[BUFSIZ];
+  sprintf(buf, "Container: %-30s Machine: %-20s",
+         info[1], info[0]);
+  Put_message(buf);
+  return "";
+}
+
+int AddContainer(int argc, char **argv)
+{
+  char **args, *info[MAX_ARGS_SIZE], *name = argv[1];
+  int stat;
+
+  /* Can't use ValidName() because spaces are allowed in container names */
+  if (IS_EMPTY(name))
+    {
+      Put_message("Please use a non-empty name.");
+      return DM_NORMAL;
+    }
+
+  if (strchr(name, '*') || strchr(name, '?'))
+    {
+      Put_message("Wildcards not accepted here.");
+      return DM_NORMAL;
+    }
+
+  /* Check if this cluster already exists. */
+  if ((stat = do_mr_query("get_container", 1, &name, NULL, NULL))
+      == MR_SUCCESS)
+    {
+      Put_message("This container already exists.");
+      return DM_NORMAL;
+    }
+  else if (stat != MR_NO_MATCH)
+    {
+      com_err(program_name, stat, " in AddContainer.");
+      return DM_NORMAL;
+    }
+  if (!(args = AskMCDInfo(SetContainerDefaults(info, name), CONTAINER, FALSE)))
+    {
+      Put_message("Aborted.");
+      FreeInfo(info);
+      return DM_NORMAL;
+    }
+
+  /* Create the new container. */
+  if ((stat = do_mr_query("add_container", CountArgs(args), args, NULL, NULL)))
+    com_err(program_name, stat, " in AddContainer.");
+
+  FreeInfo(info);
+  return DM_NORMAL;
+}
+
+int UpdateContainer(int argc, char **argv)
+{
+  struct mqelem *top;
+  top = GetMCInfo(CONTAINER, argv[1], NULL);
+  QueryLoop(top, NullPrint, RealUpdateContainer, "Update the container");
+
+  FreeQueue(top);
+  return DM_NORMAL;
+}
+
+static void RealUpdateContainer(char **info, Bool junk)
+{
+  int stat;
+  char **args = AskMCDInfo(info, CONTAINER, TRUE);
+
+  if (!args)
+    {
+      Put_message("Aborted.");
+      return;
+    }
+  if ((stat = do_mr_query("update_container", CountArgs(args), args,
+                         NULL, NULL)))
+    com_err(program_name, stat, " in UpdateContainer.");
+  else
+    Put_message("Container successfully updated.");
+}
+
+int DeleteContainer(int argc, char **argv)
+{
+  struct mqelem *top;
+
+  top = GetMCInfo(CONTAINER, argv[1], NULL);
+  QueryLoop(top, PrintClusterInfo, RealDeleteContainer, 
+           "Delete the container");
+
+  FreeQueue(top);
+  return DM_NORMAL;
+}
+
+static void RealDeleteContainer(char **info, Bool one_container)
+{
+  int stat;
+  char temp_buf[BUFSIZ];
+
+  sprintf(temp_buf,
+         "Are you sure you want to delete the container %s (y/n) ?",
+         info[CON_NAME]);
+  if (!one_container || Confirm(temp_buf))
+    {
+      if (CheckAndRemoveMachinesFromContainer(info[CON_NAME], TRUE) 
+         != SUB_ERROR)
+       {
+         if ((stat = do_mr_query("delete_container", 1, &info[CON_NAME],
+                                 NULL, NULL)))
+           {
+             com_err(program_name, stat, " in delete_container.");
+             sprintf(temp_buf, "Container %s ** NOT ** deleted.", 
+                     info[CON_NAME]);
+             Put_message(temp_buf);
+           }
+         else
+           {
+             sprintf(temp_buf, "Container %s successfully deleted.",
+                     info[CON_NAME]);
+             Put_message(temp_buf);
+           }
+       }
+    }
+}
+
+int CheckAndRemoveMachinesFromContainer(char *name, Bool ask_first)
+{
+  int stat, ret_value;
+  Bool delete_it;
+  char *args[10], temp_buf[BUFSIZ], *ptr;
+  struct mqelem *top, *elem = NULL;
   
-    Put_message("");           /* blank line on screen */
-    while (elem != NULL) {
-       char ** info = (char **) elem->q_data;
-       PrintMCMap(info);
-       elem = elem->q_forw;
+  ret_value = SUB_NORMAL;
+  args[0] = name;
+  args[1] = "0";
+  stat = do_mr_query("get_machines_of_container", 2, args, StoreInfo, 
+                    &elem);
+  if (stat && stat != MR_NO_MATCH)
+    {
+      com_err(program_name, stat, " in get_machines_of_container");
+      return DM_NORMAL;
+    }
+  if (stat == MR_SUCCESS)
+    {
+      elem = top = QueueTop(elem);
+      if (ask_first)
+       {
+         sprintf(temp_buf,
+                 "The container %s has the following machines in it:", name);
+         Put_message(temp_buf);
+         while (elem)
+           {
+             char **info = elem->q_data;
+             Print(1, &info[0], (char *) NULL);
+             elem = elem->q_forw;
+           }
+         ptr = "Remove ** ALL ** these machines from this container?";
+
+         if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
+           delete_it = TRUE;
+         else
+           {
+             Put_message("Aborting...");
+             FreeQueue(top);
+             return SUB_ERROR;
+           }
+       }
+      else
+       delete_it = TRUE;
+
+      if (delete_it)
+       {
+         elem = top;
+         while (elem)
+           {
+             char **info = elem->q_data;
+             if ((stat = do_mr_query("delete_machine_from_container",
+                                     2, info, NULL, NULL)))
+               {
+                 ret_value = SUB_ERROR;
+                 com_err(program_name, stat, 
+                         " in delete_machine_from_container.");
+                 sprintf(temp_buf, 
+                         "Machine %s ** NOT ** removed from container %s.",
+                         info[0], info[1]);
+                 Put_message(temp_buf);
+               }
+             elem = elem->q_forw;
+           }
+       }
     }
+  return ret_value;
+}
 
-    FreeQueue(top);
-    free(tmpname);
-    return(DM_NORMAL);
+int GetSubContainers(int argc, char **argv)
+{
+  char *args[2];
+  struct mqelem *elem = NULL, *top = NULL;
+  int stat;
+
+  args[0] = argv[1];
+
+  if (YesNoQuestion("Do you want a recursive search?", TRUE) == TRUE)
+    args[1] = "1";
+  else
+    args[1] = "0";
+
+  if (stat = do_mr_query("get_subcontainers_of_container", 2, args,
+                        StoreInfo, &elem))
+    com_err(program_name, stat, " in get_subcontainers_of_container");
+
+  top = QueueTop(elem);
+  Loop(top, ((void (*)(char **)) PrintContainer));
+  FreeQueue(top);
+  return DM_NORMAL;
+}
+
+int MachineToContainerMap(int argc, char **argv)
+{
+  struct mqelem *elem, *top;
+  char *tmpname, temp_buf[256];
+
+  tmpname = canonicalize_hostname(strdup(argv[1]));
+  if (strcasecmp(tmpname, argv[1]) && *argv[1] != '"')
+    {
+      sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
+             argv[1], tmpname);
+      Put_message(temp_buf);
+    }
+  top = elem = GetMCInfo(CONTMAP, tmpname, NULL);
+
+  Put_message("");
+  while (elem)
+    {
+      char **info = elem->q_data;
+      PrintMContMap(info);
+      elem = elem->q_forw;
+    }
+
+  FreeQueue(top);
+  free(tmpname);
+  return DM_NORMAL;
+}
+
+int AddMachineToContainer(int argc, char **argv)
+{
+  int stat;
+  char *machine, *container, temp_buf[BUFSIZ], *args[10];
+  Bool add_it, one_machine, one_container;
+  struct mqelem *melem, *mtop, *celem, *ctop;
+
+  machine = canonicalize_hostname(strdup(argv[1]));
+  if (strcasecmp(machine, argv[1]) && *argv[1] != '"')
+    {
+      sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
+             argv[1], machine);
+      Put_message(temp_buf);
+    }
+  container = argv[2];
+
+  celem = ctop = GetMCInfo(CONTAINER, container, NULL);
+  melem = mtop = GetMCInfo(MACHINE, machine, NULL);
+  free(machine);
+
+  one_machine = (QueueCount(mtop) == 1);
+  one_container = (QueueCount(ctop) == 1);
+
+  while (melem)
+    {
+      char **minfo = melem->q_data;
+      while (celem)
+       {
+         char **cinfo = celem->q_data;
+         if (one_machine && one_container)
+           add_it = TRUE;
+         else
+           {
+             sprintf(temp_buf, "Add machine %s to container %s (y/n/q) ?",
+                     minfo[M_NAME], cinfo[CON_NAME]);
+             switch (YesNoQuestion(temp_buf, FALSE))
+               {
+               case TRUE:
+                 add_it = TRUE;
+                 break;
+               case FALSE:
+                 add_it = FALSE;
+                 break;
+           default:
+             Put_message("Aborting...");
+             FreeQueue(ctop);
+             FreeQueue(mtop);
+             return DM_NORMAL;
+               }
+           }
+         if (add_it)
+           {
+             args[0] = minfo[M_NAME];
+             args[1] = cinfo[CON_NAME];
+             stat = do_mr_query("add_machine_to_container", 2, args, NULL, 
+                                NULL);
+             switch (stat)
+               {
+               case MR_SUCCESS:
+                 break;
+               case MR_EXISTS:
+                 sprintf(temp_buf, "%s is already in container %s",
+                         minfo[M_NAME], cinfo[CON_NAME]);
+                 Put_message(temp_buf);
+                 break;
+               default:
+                 com_err(program_name, stat, " in AddMachineToContainer.");
+                 break;
+               }
+           }
+         celem = celem->q_forw;
+       }
+      celem = ctop;
+      melem = melem->q_forw;
+    }
+  FreeQueue(ctop);
+  FreeQueue(mtop);
+  return DM_NORMAL;
+}
+
+int RemoveMachineFromContainer(int argc, char **argv)
+{
+  struct mqelem *elem = NULL;
+  char buf[BUFSIZ], *args[10];
+  int stat;
+
+  args[0] = canonicalize_hostname(strdup(argv[1]));
+  if (strcasecmp(args[0], argv[1]) && *argv[1] != '"')
+    {
+      sprintf(buf, "Warning: '%s' canonicalized to '%s'.",
+             argv[1], args[0]);
+      Put_message(buf);
+    }
+  args[1] = argv[2];
+  args[2] = NULL;
+
+  stat = do_mr_query("get_machine_to_container_map", 1, args, StoreInfo, 
+                    &elem);
+  if (stat == MR_NO_MATCH)
+    {
+      sprintf(buf, "The machine %s is not in the container %s.",
+             args[0], args[1]);
+      Put_message(buf);
+      free(args[0]);
+      return DM_NORMAL;
+    }
+  if (stat != MR_SUCCESS)
+    com_err(program_name, stat, " in deleter_machine_from_container");
+
+  elem = QueueTop(elem);
+  QueryLoop(elem, PrintMContMap, RealRemoveMachineFromContainer, 
+           "Remove this machine from this container");
+  
+  FreeQueue(elem);
+  free(args[0]);
+  return DM_NORMAL;
+}
+
+static void RealRemoveMachineFromContainer(char **info, Bool one_contmap)
+{
+  char temp_buf[BUFSIZ];
+  int stat;
+
+  sprintf(temp_buf, "Remove %s from the container %s",
+         info[0], info[1]);
+  if (!one_contmap || Confirm(temp_buf))
+    {
+      if ((stat = do_mr_query("delete_machine_from_container", 2,
+                             info, NULL, NULL)))
+       com_err(program_name, stat, " in delete_machine_from_container");
+      else
+       {
+         sprintf(temp_buf, "%s has been removed from the container %s.",
+                 info[0], info[1]);
+         Put_message(temp_buf);
+       }
+    }
+  else
+    Put_message("Machine not removed.");
+}
+
+int GetMachinesOfContainer(int argc, char **argv)
+{
+  char *args[2];
+  struct mqelem *elem = NULL, *top = NULL;
+  int stat;
+
+  args[0] = argv[1];
+
+  if (YesNoQuestion("Do you want a recursive search?", TRUE) == TRUE)
+    args[1] = "1";
+  else
+    args[1] = "0";
+
+  if (stat = do_mr_query("get_machines_of_container", 2, args,
+                        StoreInfo, &elem))
+    com_err(program_name, stat, " in get_machines_of_container");
+
+  top = QueueTop(elem);
+  Loop(top, ((void (*)(char **)) PrintMContMap));
+  FreeQueue(top);
+  return DM_NORMAL;
+}
+
+int GetTopLevelCont(int argc, char **argv)
+{
+  int status;
+  struct mqelem *elem = NULL;
+  if (status = do_mr_query("get_toplevel_containers", 0, NULL, StoreInfo, 
+                          &elem))
+    {
+      com_err(program_name, status, " in get_toplevel_containers");
+      return DM_NORMAL;
+    }
+  Loop(QueueTop(elem), (void(*)(char **)) PrintContainer);
+  FreeQueue(elem);
+  return DM_NORMAL;
 }
This page took 0.828092 seconds and 4 git commands to generate.