/* Copyright (c) 1996, 1997, 1998 Thorsten Kukuk
   Author: Thorsten Kukuk <kukuk@vt.uni-paderborn.de>

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software Foundation,
   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#define _GNU_SOURCE

#ifdef HAVE_GETOPT_H
#include <getopt.h>
#else
#include "lib/compat/getopt.h"
#endif
#include <stdio.h>
#include <string.h>
#include <locale.h>
#include <libintl.h>
#include <rpcsvc/nis.h>

#ifndef _
#define _(String) gettext (String)
#endif

#define ENTRY_FLAG(obj, col) (obj)->EN_data.en_cols.en_cols_val[col].ec_flags

static int add_tbl (int argc, char *argv[], int uppercase, char *defaults);
static int create_tbl (int argc, char *argv[], char *path, char *sep,
		       char *defaults);
static int destroy_tbl (int argc, char *tablename);
static int modify (int argc, char *argv[], int uppercase);
static int remove_entr (int argc, char *argv[], int uppercase);
static int update_table (int argc, char *argv[], char *path, char *sep,
			 char *type);

/* Name and version of program.  */
/* Print the version information.  */
static inline void
print_version (void)
{
  fprintf (stdout, "nistbladm (%s) %s\n", PACKAGE, VERSION);
  fprintf (stdout, gettext ("\
Copyright (C) %s Thorsten Kukuk.\n\
This is free software; see the source for copying conditions.  There is NO\n\
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
"), "1998");
  /* fprintf (stdout, _("Written by %s.\n"), "Thorsten Kukuk"); */
}

static inline void
print_usage (void)
{
  fputs (_("Usage: nistbladm -a|-A [ -D defaults ] colname=value ... tablename\n"),
	 stdout);
  fputs (_("       nistbladm -a|-A [ -D defaults ] indexedname\n"), stdout);
  fputs (_("       nistbladm -c [-D defaults] [-p path] [-s sep] type\n"),
	 stdout);
  fputs (_("                       colname=[flags][,access] ...  tablename\n"),
	 stdout);
  fputs (_("       nistbladm -d tablename\n"), stdout);
  fputs (_("       nistbladm -e|-E colname=value ...  indexedname\n"), stdout);
  fputs (_("       nistbladm -m colname=value ...  indexedname\n"), stdout);
  fputs (_("       nistbladm -r|-R [colname=value ...] tablename\n"), stdout);
  fputs (_("       nistbladm -r|-R indexedname\n"), stdout);
  fputs (_("       nistbladm -u [-p path] [-s sep] [-t type]\n"), stdout);
  fputs (_("                               [colname=access ... ] tablename\n"),
	 stdout);
}

static void
print_help (void)
{
  fputs (_("Usage: nistbladm [OPTIONS]\n"), stdout);
  fputs (_("nistbladm - NIS+ table administration tool\n\n"), stdout);

  fputs (_("  -a, -A         Add entries to a NIS+ table\n"), stdout);
  fputs (_("  -c             Create a table in the NIS+ namespace\n"), stdout);
  fputs (_("  -d tablename   Detroy the table 'tablename'\n"), stdout);
  fputs (_("  -e, -E         Edit entry in a table\n"), stdout);
  fputs (_("  -r, -R         Remove entries from a table\n"), stdout);
  fputs (_("  -u             Update attributes of a table\n"), stdout);
  fputs (_("  --help         Give this help list\n"), stdout);
  fputs (_("  --usage        Give a short usage message\n"), stdout);
  fputs (_("  --version      Print program version\n"), stdout);
}

static inline void
print_error (void)
{
  const char *program = "nistbladm";

  fprintf (stderr,
           _("Try `%s --help' or `%s --usage' for more information.\n"),
           program, program);
}

int
main (int argc, char *argv[])
{
  int uppercase = 0;
  int add_table = 0;
  int create_table = 0;
  int destroy_table = 0;
  int modify_entry = 0;
  int remove_entry = 0;
  int update_attr = 0;
  char *tablename = NULL;
  char *path = NULL;
  char *sep = NULL;
  char *type = NULL;
  char *defaults = NULL;

  setlocale (LC_MESSAGES, "");
  bindtextdomain (PACKAGE, LOCALEDIR);
  textdomain (PACKAGE);

  while (1)
    {
      int c;
      int option_index = 0;
      static struct option long_options[] =
      {
	{"version", no_argument, NULL, '\255'},
	{"usage", no_argument, NULL, '\254'},
	{"help", no_argument, NULL, '\253'},
	{NULL, 0, NULL, '\0'}
      };

      c = getopt_long (argc, argv, "aAcd:D:eEmp:rRs:t:u",
		       long_options, &option_index);
      if (c == (-1))
	break;
      switch (c)
	{
	case 'A':
	  uppercase = 1;
	case 'a':
	  if ((destroy_table + modify_entry + remove_entry + update_attr) > 1)
	    goto error;
	  add_table = 1;
	  break;
	case 'c':
	  if ((add_table + destroy_table + modify_entry + remove_entry +
	       update_attr) > 1)
	    goto error;
	  create_table = 1;
	  break;
	case 'D':
	  defaults = optarg;
	  break;
	case 'd':
	  if ((add_table + create_table + modify_entry + remove_entry +
	       update_attr) > 1)
	    goto error;
	  destroy_table = 1;
	  tablename = optarg;
	  break;
	case 'E':
	case 'm':
	  uppercase = 1;
	case 'e':
	  if ((add_table + create_table + destroy_table + modify_entry +
	       update_attr) > 1)
	    goto error;
	  modify_entry = 1;
	  break;
	case 'p':
	  if (!update_attr && !create_table)
	    goto error;
	  path = optarg;
	  break;
	case 'R':
	  uppercase = 1;
	case 'r':
	  if ((add_table + create_table + destroy_table + modify_entry +
	       update_attr) > 1)
	    goto error;
	  remove_entry = 1;
	  break;
	case 's':
	  if (!update_attr && !create_table)
	    goto error;
	  sep = optarg;
	  break;
	case 't':
	  if (!update_attr && !create_table)
	    goto error;
	  type = optarg;
	  break;
	case 'u':
	  if ((add_table + create_table + destroy_table + modify_entry +
	       remove_entry) > 1)
	    goto error;
	  update_attr = 1;
	  break;
	case '\255':
	  print_version ();
	  return 0;
	case '\254':
	  print_usage ();
	  return 0;
	case '\253':
	  print_help ();
	default:
	error:
	  print_error ();
	  return 1;
	}
    }

  argc -= optind;
  argv += optind;

  if ((defaults != NULL) && !(add_table || create_table))
      {
	print_error ();
	return 1;
      }


  if (add_table) /* nistbladm called with -a|-A */
    return add_tbl (argc, argv, uppercase, defaults);

  if (create_table) /* nistbladm called with -c */
    return create_tbl (argc, argv, path, sep, defaults);

  if (destroy_table) /* nistbladm called with -d */
    return destroy_tbl (argc, tablename);

  if (modify_entry) /* nistbladm called with -e|-E|-m */
    return modify (argc, argv, uppercase);

  if (remove_entry) /* nistbladm called with -r|-R */
    return remove_entr (argc, argv, uppercase);

  if (update_attr) /* nistbladm called with -u */
    return update_table (argc, argv, path, sep, type);

  print_error ();
  return 1;
}

static int
add_tbl (int argc, char *argv[], int uppercase, char *defaults)
{
  int i;
  nis_result *res;
  nis_object *obj = calloc (1, sizeof (nis_object));
  char *buf, *tbl = NULL;

  if (argc < 1)
    {
      fprintf (stderr, _("%s: To few arguments\n"), "nistbladm");
      print_error ();
      return 1;
    }

  if (argv[argc-1][0] == '[') /* Shit, who has allowed indexed names here ? */
    {
      if (argc != 1)
	{
	  fprintf (stderr, _("%s: Wrong number of arguments\n"), "nistbladm");
	  print_error ();
	  return 1;
	}
      tbl = strchr (argv[0], ']');
      ++tbl; ++tbl;
      res = nis_lookup (tbl, FOLLOW_LINKS|EXPAND_NAME);
    }
  else
    res = nis_lookup (argv[argc-1], FOLLOW_LINKS|EXPAND_NAME);
  if (res == NULL || res->status != NIS_SUCCESS)
    {
      if (res == NULL)
	fputs (_("Out of memory!\n"), stderr);
      else
	nis_perror (res->status, _("can't add entry"));
      nis_freeresult (res);
      return 1;
    }
  obj->zo_name = strdup (NIS_RES_OBJECT (res)->zo_name);
  obj->zo_domain = strdup (NIS_RES_OBJECT (res)->zo_domain);
  obj->zo_owner = __nis_default_owner (defaults);
  obj->zo_group = __nis_default_group (defaults);
  obj->zo_access = __nis_default_access (defaults, 0);
  obj->zo_ttl = __nis_default_ttl (defaults);
  obj->zo_data.zo_type = NIS_ENTRY_OBJ;
  obj->EN_data.en_type = strdup (NIS_RES_OBJECT (res)->TA_data.ta_type);
  obj->EN_data.en_cols.en_cols_len =
    NIS_RES_OBJECT (res)->TA_data.ta_maxcol;
  obj->EN_data.en_cols.en_cols_val =
    calloc (obj->EN_data.en_cols.en_cols_len, sizeof (entry_col));
  if (tbl) /* We have indexed names, so'n shit */
    {
      unsigned int j;
      char *name, *val, *p;
      p = argv[0];
      ++p;

      do {
	bool_t found = FALSE;

	name = p;
	val = strchr (p, '=');
	if (val == NULL)
	  {
	    print_error ();
	    return 1;
	  }
	p = strchr (val, ',');
	*val = '\0';
	++val;
	if (p != NULL)
	  {
	    if (p[-1] == ']')
	      p[-1] = '\0';
	    else
	      {
		*p ='\0';
		++p;
	      }
	  }

	for (j = 0; j < obj->EN_data.en_cols.en_cols_len; ++j)
	  {
	    if (strcmp (NIS_RES_OBJECT (res)->TA_data.ta_cols.ta_cols_val[j].tc_name,
			name) == 0)
	      {
		found = TRUE;
		obj->EN_data.en_cols.en_cols_val[j].ec_value.ec_value_val =
		  strdup (val);
		obj->EN_data.en_cols.en_cols_val[j].ec_value.ec_value_len =
		  strlen (val) + 1;
	      }
	  }
	if (!found)
	  {
	    fprintf (stderr, "%s: no such column\n", name);
	    nis_freeresult (res);
	    return 1;
	  }
      } while (p != NULL && *p != ',');
    }
  else
    {
      for (i = 0; i < argc -1; ++i)
	{
	  unsigned int j;
	  bool_t found = FALSE;
	  char *p = strchr (argv[i], '=');
	  if (p == NULL)
	    {
	      print_error ();
	      return 1;
	    }
	  *p = '\0'; ++p;
	  for (j = 0; j < obj->EN_data.en_cols.en_cols_len; ++j)
	    {
	      if (strcmp (NIS_RES_OBJECT (res)->TA_data.ta_cols.ta_cols_val[j].tc_name,
			  argv[i]) == 0)
		{
		  found = TRUE;
		  obj->EN_data.en_cols.en_cols_val[j].ec_value.ec_value_val =
		    strdup (p);
		  obj->EN_data.en_cols.en_cols_val[j].ec_value.ec_value_len =
		    strlen (p) + 1;
		}
	    }
	  if (!found)
	    {
	      fprintf (stderr, "%s: no such column\n", argv[i]);
	      nis_freeresult (res);
	      return 1;
	    }
	}
    }
  buf = malloc (strlen (obj->zo_name) + strlen (obj->zo_domain) + 10);
  sprintf (buf, "%s.%s", obj->zo_name, obj->zo_domain);
  nis_freeresult (res);
  if (uppercase)
    res = nis_add_entry (buf, obj, ADD_OVERWRITE);
  else
    res = nis_add_entry (buf, obj, 0);
  nis_free_object (obj);
  if (res == NULL || res->status != NIS_SUCCESS)
    {
      if (res == NULL)
	fputs (_("Out of memory!\n"), stderr);
      else
	nis_perror (res->status, _("can't add entry"));
      nis_freeresult (res);
      return 1;
    }
  return 0;
}

static int
create_tbl (int argc, char *argv[], char *path, char *sep, char *defaults)
{
  nis_result *res;
  nis_object *obj = calloc (1, sizeof (nis_object));
  int i;

  if (argc < 2)
    {
      fprintf (stderr, _("%s: Wrong number of arguments\n"), "nistbladm");
      print_error ();
      return 1;
    }

  if (argv[argc-1][strlen (argv[argc-1])-1] != '.')
    {
      fputs ("tablename must be fully qualified.\n", stderr);
      return 1;
    }

  obj->zo_name = strdup ("");
  obj->zo_domain = strdup ("");
  obj->zo_owner = __nis_default_owner (defaults);
  obj->zo_group = __nis_default_group (defaults);
  obj->zo_access = __nis_default_access (defaults, 0);
  obj->zo_ttl = __nis_default_ttl (defaults);
  obj->zo_data.zo_type = NIS_TABLE_OBJ;
  obj->TA_data.ta_type = strdup (argv[0]);
  obj->TA_data.ta_maxcol = argc - 2;
  if (sep)
    obj->TA_data.ta_sep = sep[0];
  else
    obj->TA_data.ta_sep = ' ';
  if (path)
    obj->TA_data.ta_path = strdup (path);
  else
    obj->TA_data.ta_path = strdup ("");
  obj->TA_data.ta_cols.ta_cols_len = argc - 2;
  obj->TA_data.ta_cols.ta_cols_val = calloc (argc - 2, sizeof (table_col));
  for (i = 1; i < argc - 1; ++i)
    {
      char *name, *flags, *access;
      unsigned int j;

      name = argv[i];
      flags = strchr (name, '=');
      if (flags != NULL)
	{
	  *flags = '\0';
	  ++flags;
	  access = strchr (flags, ',');
	  if (access != NULL)
	    {
	      *access = '\0';
	      ++access;
	    }
	}
      else
	access = NULL;
      obj->TA_data.ta_cols.ta_cols_val[i-1].tc_name = strdup (name);
      obj->TA_data.ta_cols.ta_cols_val[i-1].tc_flags = 0;
      if (flags != NULL && strlen (flags) > 0)
	{
	  for (j = 0; j < strlen (flags); ++j)
	    {
	      switch (flags[j])
		{
		case 'S':
		case 's':
		  obj->TA_data.ta_cols.ta_cols_val[i-1].tc_flags |=
		    TA_SEARCHABLE;
		  break;
		case 'I':
		case 'i':
		  obj->TA_data.ta_cols.ta_cols_val[i-1].tc_flags |=
		    TA_CASE;
		  break;
		case 'C':
		case 'c':
		  obj->TA_data.ta_cols.ta_cols_val[i-1].tc_flags |=
		    TA_CRYPT;
		  break;
		case 'B':
		case 'b':
		  obj->TA_data.ta_cols.ta_cols_val[i-1].tc_flags |=
		    TA_BINARY;
		  break;
		case 'X':
		case 'x':
		  obj->TA_data.ta_cols.ta_cols_val[i-1].tc_flags |= TA_XDR;
		  break;
		default:
		  print_error ();
		  return 1;
		}
	    }
	}
      if (access != NULL && strlen (access) > 0)
	{
	  char *cp, *buf = alloca (10 + strlen (access));

	  if (buf == NULL)
	    {
	      fputs (_("Out of memory!\n"), stderr);
	      return 1;
	    }

	  cp = stpcpy (buf, "access=");
	  strcpy (cp, access);
	  obj->TA_data.ta_cols.ta_cols_val[i-1].tc_rights =
	    __nis_default_access (buf, 0);
	}
      else
	obj->TA_data.ta_cols.ta_cols_val[i-1].tc_rights =
	  __nis_default_access (NULL, 0);
    }
  res = nis_add (argv[argc -1], obj);
  nis_free_object (obj);
  if (res == NULL || res->status != NIS_SUCCESS)
    {
      if (res == NULL)
	fputs (_("Out of memory!\n"), stderr);
      else
	nis_perror (res->status, _("can't create table"));
      nis_freeresult (res);
      return 1;
    }
  nis_freeresult (res);
  return 0;
}

static int
destroy_tbl (int argc, char *tablename)
{
  char buf[NIS_MAXNAMELEN + 1];
  nis_result *res, *res2;

  if (argc != 0)
    {
      fprintf (stderr, _("%s: To many arguments\n"), "nistbladm");
      print_error ();
      return 1;
    }

  res = nis_lookup (tablename, MASTER_ONLY|FOLLOW_LINKS|EXPAND_NAME);

  if (res == NULL || res->status != NIS_SUCCESS)
    {
      if (res == NULL)
	fprintf (stderr, _("Out of memory!\n"));
      else
	nis_perror (res->status, "nistbladm");
      nis_freeresult (res);
      return 1;
    }
  if (__type_of (NIS_RES_OBJECT(res)) != NIS_TABLE_OBJ)
    {
      fprintf (stderr, _("%s is not a table!\n"), tablename);
      nis_freeresult (res);
      return 1;
    }
  if (NIS_RES_NUMOBJ(res) > 1)
    {
      fprintf (stderr, _("lookup of %s gives more then one object!\n"),
	       tablename);
      nis_freeresult (res);
      return 1;
    }

  snprintf (buf, NIS_MAXNAMELEN, "%s.%s", NIS_RES_OBJECT(res)->zo_name,
	    NIS_RES_OBJECT(res)->zo_domain);
  res2 = nis_remove (buf, NIS_RES_OBJECT(res));
  nis_freeresult (res);
  if (res2 == NULL || res2->status != NIS_SUCCESS)
    {
      if (res2 == NULL)
	fputs (_("Out of memory!\n"), stderr);
      else
	nis_perror (res2->status, _("can't remove table"));
      nis_freeresult (res2);
      return 1;
    }
  return 0;
}

static int
modify (int argc, char *argv[], int uppercase)
{
  nis_object *obj;
  nis_result *res;
  char *buf, *p;
  int i;

  if (argc < 2)
    {
      fprintf (stderr, _("%s: To few arguments\n"), "nistbladm");
      print_error ();
      return 1;
    }

  if (argv[argc-1][0] != '[') /* No indexed name ?*/
    {
      print_error ();
      return 1;
    }

  res = nis_list (argv[argc-1], MASTER_ONLY|EXPAND_NAME|FOLLOW_LINKS, NULL,
		  NULL);
  if (res == NULL || NIS_RES_STATUS (res) != NIS_SUCCESS)
    {
      if (res == NULL)
	fputs (_("Out of memory!\n"), stderr);
      else
	nis_perror (res->status, _("can't find entry"));
      nis_freeresult (res);
      return 1;
    }
  if (NIS_RES_NUMOBJ (res) > 1)
    {
      nis_freeresult (res);
      fputs (_("Indexed name is not unique!\n"), stderr);
      return 1;
    }
  buf = calloc (1, strlen (argv[argc-1]) + 5 +
		strlen (NIS_RES_OBJECT (res)->zo_name) +
		strlen (NIS_RES_OBJECT (res)->zo_domain));
  strcpy (buf, argv[argc-1]);
  p = strchr (buf, ']');
  ++p; ++p;
  p = stpcpy (p, NIS_RES_OBJECT (res)->zo_name);
  p = stpcpy (p, ".");
  p = stpcpy (p, NIS_RES_OBJECT (res)->zo_domain);
  obj = nis_clone_object (NIS_RES_OBJECT(res), NULL);
  nis_freeresult (res);
  p = strchr (buf, ']');
  ++p; ++p;
  res = nis_lookup (p, MASTER_ONLY|FOLLOW_LINKS);
  if (res == NULL || NIS_RES_STATUS (res) != NIS_SUCCESS)
    {
      if (res == NULL)
	fputs (_("Out of memory!\n"), stderr);
      else
	nis_perror (res->status, _("can't find table"));
      nis_freeresult (res);
      return 1;
    }
  /* OK, we have the fully qualified name, now lets us modify
     the object */
  for (i = 0; i < argc-1; ++i)
    {
      unsigned int j;
      bool_t found = FALSE;
      char *cp = strchr (argv[i], '=');

      if (cp == NULL)
	{
	  print_error ();
	  return 1;
	}
      *cp = 0; ++cp;
      for (j = 0; j < obj->EN_data.en_cols.en_cols_len; ++j)
	{
	  if (strcmp (NIS_RES_OBJECT (res)->TA_data.ta_cols.ta_cols_val[j].tc_name,
		      argv[i]) == 0)
	    {
	      found = TRUE;
	      free (ENTRY_VAL (obj, j));
	      ENTRY_VAL (obj, j) = strdup (cp);
	      ENTRY_LEN (obj, j) = strlen (cp) + 1;
	      ENTRY_FLAG (obj, j) = ENTRY_FLAG (obj, j) | EN_MODIFIED;
	    }
	}
      if (!found)
	{
	  fprintf (stderr, "%s: no such column\n", argv[i]);
	  nis_freeresult (res);
	  nis_free_object (obj);
	  return 1;
	}
    }
  nis_freeresult (res);
  if (uppercase)
    res = nis_modify_entry (buf, obj, MOD_SAMEOBJ);
  else
    res = nis_modify_entry (buf, obj, MOD_EXCLUSIVE|MOD_SAMEOBJ);
  nis_free_object (obj);
  free (buf);
  if (res == NULL || res->status != NIS_SUCCESS)
    {
      if (res == NULL)
	fputs (_("Out of memory!\n"), stderr);
      else
	nis_perror (res->status, _("can't modify entry"));
      nis_freeresult (res);
      return 1;
    }
  nis_freeresult (res);
  return 0;
}

static int
remove_entr (int argc, char *argv[], int uppercase)
{
  nis_result *res, *res2;
  char *buf, *p;

  if (argc == 0)
    {
      fprintf (stderr, _("%s: Wrong number of arguments\n"), "nistbladm");
      print_error ();
      return 1;
    }
  if (argv[0][0] == '[') /* indexed name */
    buf = strdup (argv[0]);
  else
    {
      /* We have to create our own indexed name */
      u_long buflen;

      if (argc == 1)
	buflen = 5 + strlen (argv[0]);
      else
	{
	  int i;

	  buflen = argc + 5;
	  for (i = 0; i < argc; ++i)
	    buflen += strlen (argv[i]);
	}
      buf = calloc (1, buflen);
      if (buf == NULL)
	{
	  fputs (_("Out of memory!\n"), stderr);
	  return 1;
	}
      if (argc == 1)
	sprintf (buf, "[],%s", argv[0]);
      else
	{
	  int i;

	  p = stpcpy (buf, "[");
	  for (i = 0; i < argc - 1; ++i)
	    {
	      p = stpcpy (p, argv[i]);
	      p = stpcpy (p, ",");
	    }
	  --p;
	  p = stpcpy (p, "],");
	  p = stpcpy (p, argv[argc-1]);
	}
    }
  p = strchr (buf, ']');
  ++p; ++p;
  res = nis_lookup (p, MASTER_ONLY|EXPAND_NAME|FOLLOW_LINKS);
  if (res == NULL || NIS_RES_STATUS (res) != NIS_SUCCESS)
    {
      if (res == NULL)
	fputs (_("Out of memory!\n"), stderr);
      else
	nis_perror (res->status, _("can't find entry"));
      nis_freeresult (res);
      return 1;
    }
  buf = realloc (buf, strlen (buf) + 5 +
		 strlen (NIS_RES_OBJECT (res)->zo_name) +
		 strlen (NIS_RES_OBJECT (res)->zo_domain));
  p = strchr (buf, ']');
  ++p; ++p;
  p = stpcpy (p, NIS_RES_OBJECT (res)->zo_name);
  p = stpcpy (p, ".");
  p = stpcpy (p, NIS_RES_OBJECT (res)->zo_domain);
  if (uppercase)
    res2 = nis_remove_entry (buf, NULL, REM_MULTIPLE);
  else
    res2 = nis_remove_entry (buf, NULL, 0);
  nis_freeresult (res);
  free (buf);
  if (res2 == NULL || res2->status != NIS_SUCCESS)
    {
      if (res2 == NULL)
	fputs (_("Out of memory!\n"), stderr);
      else
	nis_perror (res2->status, _("can't remove entry"));
      nis_freeresult (res2);
      return 1;
    }
  nis_freeresult (res2);
  return 0;
}

static int
update_table (int argc, char *argv[], char *path, char *sep, char *type)
{
  nis_object *obj;
  nis_result *res;
  char *buf;

  res = nis_lookup (argv[argc -1], MASTER_ONLY|FOLLOW_LINKS|EXPAND_NAME);
  if (res == NULL || res->status != NIS_SUCCESS)
    {
      if (res == NULL)
	fputs (_("Out of memory!\n"), stderr);
      else
	nis_perror (res->status, _("can't update entry"));
      nis_freeresult (res);
      return 1;
    }
  if (__type_of (NIS_RES_OBJECT (res)) != NIS_TABLE_OBJ)
    {
      fprintf (stderr, "%s is not a table!\n", argv[argc-1]);
      nis_freeresult (res);
      return 1;
    }
  obj = nis_clone_object (NIS_RES_OBJECT (res), NULL);
  nis_freeresult (res);
  if (path != NULL)
    {
      free (obj->TA_data.ta_path);
      obj->TA_data.ta_path = strdup (path);
    }
  if (sep != NULL)
    obj->TA_data.ta_sep = *sep;
  if (type != NULL)
    {
      free (obj->TA_data.ta_type);
      obj->TA_data.ta_type = strdup (type);
    }
  /* Now do the access stuff here ! */
  if (argc > 1)
    {
      int i;

      for (i = 0; i < argc - 1; ++i)
	{
	  unsigned int j;
	  bool_t found = FALSE;
	  char *p = strchr (argv[i], '=');
	  if (p == NULL)
	    {
	      print_error ();
	      return 1;
	    }
	  *p = 0; ++p;
	  for (j = 0; j < obj->TA_data.ta_cols.ta_cols_len; ++j)
	    {
	      if (strcmp (obj->TA_data.ta_cols.ta_cols_val[j].tc_name,
			  argv[i])
		  == 0)
		{
		  char *buf2 = malloc (10 + strlen (p));
		  sprintf (buf2, "access=%s", p);
		  obj->TA_data.ta_cols.ta_cols_val[j].tc_rights =
		    __nis_default_access (buf2,
			   obj->TA_data.ta_cols.ta_cols_val[j].tc_rights);
		  obj->TA_data.ta_cols.ta_cols_val[j].tc_flags |= TA_MODIFIED;
		  found = TRUE;
		}
	    }
	  if (!found)
	    {
	      fprintf (stderr, "%s: no such column\n", argv[i]);
	      nis_freeresult (res);
	      nis_free_object (obj);
	      return 1;
	    }
	}
    }
  buf = malloc (strlen (obj->zo_name) + strlen (obj->zo_domain) + 5);
  sprintf (buf, "%s.%s", obj->zo_name, obj->zo_domain);
  res = nis_modify (buf, obj);
  free (buf);
  if (res == NULL || res->status != NIS_SUCCESS)
    {
      if (res == NULL)
	fputs (_("Out of memory!\n"), stderr);
      else
	nis_perror (res->status, _("can't update entry"));
      nis_freeresult (res);
      return 1;
    }
  return 0;
}
