/*
 * "$Id: setld.c,v 1.16 2003/12/22 12:37:25 mike Exp $"
 *
 *   Tru64 package gateway for the ESP Package Manager (EPM)
 *
 *   Copyright 2001-2003 by Easy Software Products
 *   Copyright 2001 by Aneesh Kumar (aneesh.kumar@digital.com) at Digital India.
 *
 *   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.
 *
 * Contents:
 *
 *   make_setld() - Make a Tru64 setld package.
 */

/*
 * Include necessary headers...
 */

#include "epm.h"


/*
 * 'make_setld()' - Make a Tru64 setld package.
 */

int					/* O - 0 = success, 1 = fail */
make_setld(const char     *prodname,	/* I - Product short name */
           const char     *directory,	/* I - Directory for distribution files */
           const char     *platname,	/* I - Platform name */
           dist_t         *dist,	/* I - Distribution information */
           struct utsname *platform)	/* I - Platform information */
{
  int		i;			/* Looping var */
  FILE		*fp;			/* Spec file */
  tarf_t	*tarfile;		/* .tardist file */
  char		name[1024];		/* Full product name */
  char		scpname[1024];		/* XXXVVV control program filename */
  char		miname[1024];		/* XXXVVV.mi filename */
  char		keyname[1024];		/* XXXVVV.key filename */
  char		filename[1024];		/* Destination filename */
  char		subset[1024];		/* Subset name */
  file_t	*file;			/* Current distribution file */
  command_t	*c;			/* Current command */
  char		current[1024];		/* Current directory */
  struct passwd	*pwd;			/* Pointer to user record */
  struct group	*grp;			/* Pointer to group record */
  const char	*runlevels;		/* Run levels */


  (void)platform;

 /*
  * Check the package information to make sure it complies with the
  * extremely limited Tru64 packager requirements.
  */

  if (dist->vernumber < 100 || dist->vernumber > 999)
  {
    fprintf(stderr, "epm: Need a version number between 100 and 999 inclusive.\n"
                    "     The current version number (%d) is out of range.\n",
            dist->vernumber);
    return (1);
  }

  if (strlen(prodname) < 3)
  {
    fprintf(stderr, "epm: Need a product name of at least 3 characters.\n"
                    "     The current product name (%s) is not acceptable.\n",
            prodname);
    return (1);
  }

  for (i = 0; prodname[i]; i ++)
    if (!isupper(prodname[i]))
    {
      fprintf(stderr, "epm: Need a product name containing uppercase letters.\n"
                      "     The current product name (%s) is not acceptable.\n",
              prodname);
      return (1);
    }

 /*
  * Prepare for packaging...
  */

  if (dist->relnumber)
  {
    if (platname[0])
      snprintf(name, sizeof(name), "%s-%s-%d-%s", prodname, dist->version,
               dist->relnumber, platname);
    else
      snprintf(name, sizeof(name), "%s-%s-%d", prodname, dist->version,
               dist->relnumber);
  }
  else if (platname[0])
    snprintf(name, sizeof(name), "%s-%s-%s", prodname, dist->version, platname);
  else
    snprintf(name, sizeof(name), "%s-%s", prodname, dist->version);

  getcwd(current, sizeof(current));

  snprintf(subset, sizeof(subset), "%sALL%03d", prodname, dist->vernumber);

 /*
  * Add symlinks for init scripts...
  */

  for (i = 0; i < dist->num_files; i ++)
    if (tolower(dist->files[i].type) == 'i')
    {
     /*
      * Make symlinks for all of the selected run levels...
      */

      for (runlevels = get_runlevels(dist->files + i, "023");
           isdigit(*runlevels);
	   runlevels ++)
      {
	file = add_file(dist);
	file->type = 'l';
	file->mode = 0;
	strcpy(file->user, "root");
	strcpy(file->group, "sys");
	snprintf(file->src, sizeof(file->src), "../init.d/%s",
        	 dist->files[i].dst);

        if (*runlevels == '0')
	  snprintf(file->dst, sizeof(file->dst), "/sbin/rc0.d/K%02d%s",
        	   get_stop(dist->files + i, 0), dist->files[i].dst);
        else
	  snprintf(file->dst, sizeof(file->dst), "/sbin/rc%c.d/S%02d%s",
        	   *runlevels, get_start(dist->files + i, 99),
		   dist->files[i].dst);
      }

     /*
      * Then send the original file to /sbin/init.d...
      */

      file = dist->files + i;

      snprintf(filename, sizeof(filename), "/sbin/init.d/%s", file->dst);
      strcpy(file->dst, filename);
    }

 /*
  * Build package directories...
  *
  * Note: The src/scps directory and the key, inventory, and
  *       subset control programs below should actually go in
  *       a data subdirectory according to the Tru64
  *       documentation, but (at least under 4.0d) the invcutter
  *       program will not be able to find the distribution files
  *       if they are not colocated with these data files.
  */

  if (Verbosity)
    puts("Creating Tru64 (setld) distribution...");

  run_command(NULL, "/bin/rm -rf %s/output", directory);

  run_command(NULL, "/bin/rm -rf %s/src", directory);

  snprintf(filename, sizeof(filename), "%s/output", directory);
  mkdir(filename, 0777);

  snprintf(filename, sizeof(filename), "%s/src", directory);
  mkdir(filename, 0777);

  snprintf(filename, sizeof(filename), "%s/src/scps", directory);
  mkdir(filename, 0777);

 /*
  * Write the subset control program...
  */

  if (Verbosity)
    puts("Creating subset control program...");

  snprintf(scpname, sizeof(scpname), "%s/src/scps/%s.scp", directory, subset);

  if ((fp = fopen(scpname, "w")) == NULL)
  {
    fprintf(stderr, "epm: Unable to create subset control program \"%s\" - %s\n",
            scpname, strerror(errno));
    return (1);
  }

  fputs("#!/bin/sh\n", fp);
  fputs("case $ACT in\n", fp);

  fputs("PRE_L)\n", fp);
  for (i = dist->num_files, file = dist->files; i > 0; i --, file ++)
    if (tolower(file->type) == 'i')
      qprintf(fp, "%s stop\n", file->dst);
  for (i = dist->num_commands, c = dist->commands; i > 0; i --, c ++)
    if (c->type == COMMAND_PRE_INSTALL)
      fprintf(fp, "%s\n", c->command);
  fputs(";;\n", fp);

  fputs("POST_L)\n", fp);
  for (i = dist->num_commands, c = dist->commands; i > 0; i --, c ++)
    if (c->type == COMMAND_POST_INSTALL)
      fprintf(fp, "%s\n", c->command);
  for (i = dist->num_files, file = dist->files; i > 0; i --, file ++)
    if (tolower(file->type) == 'c')
    {
      qprintf(fp, "if test ! -f %s; then\n", file->dst);
      qprintf(fp, "	/bin/cp %s.N %s\n", file->dst, file->dst);
      fputs("fi\n", fp);
    }
  for (i = dist->num_files, file = dist->files; i > 0; i --, file ++)
    if (tolower(file->type) == 'i')
      qprintf(fp, "%s start\n", file->dst);
  fputs(";;\n", fp);

  fputs("PRE_D)\n", fp);
  for (i = dist->num_files, file = dist->files; i > 0; i --, file ++)
    if (tolower(file->type) == 'i')
      qprintf(fp, "%s stop\n", file->dst);
  for (i = dist->num_commands, c = dist->commands; i > 0; i --, c ++)
    if (c->type == COMMAND_PRE_REMOVE)
      fprintf(fp, "%s\n", c->command);
  for (i = dist->num_files, file = dist->files; i > 0; i --, file ++)
    if (tolower(file->type) == 'c')
    {
      qprintf(fp, "if cmp -s %s.N %s; then\n", file->dst, file->dst);
      qprintf(fp, "	/bin/rm -f %s\n", file->dst);
      fputs("fi\n", fp);
    }
  fputs(";;\n", fp);

  fputs("POST_D)\n", fp);
  for (i = dist->num_commands, c = dist->commands; i > 0; i --, c ++)
    if (c->type == COMMAND_POST_REMOVE)
      fprintf(fp, "%s\n", c->command);
  fputs(";;\n", fp);

  fputs("esac\n", fp);

  fclose(fp);

 /*
  * Sort the file list by the destination name, since kits need a sorted
  * list...
  */

  sort_dist_files(dist);

 /*
  * Now do the inventory file...
  */

  if (Verbosity)
    puts("Creating master inventory file...");

  snprintf(miname, sizeof(miname), "%s/src/%s%03d.mi", directory, prodname, dist->vernumber);

  if ((fp = fopen(miname, "w")) == NULL)
  {
    fprintf(stderr, "epm: Unable to create master inventory file \"%s\" - %s\n",
            miname, strerror(errno));
    return (1);
  }

  for (i = dist->num_files, file = dist->files; i > 0; i --, file ++)
    switch (tolower(file->type))
    {
      case 'c' :
          fprintf(fp, "2\t.%s.N\t%s\n", file->dst, subset);
	  break;
      case 'd' :
      case 'i' :
      case 'f' :
      case 'l' :
          fprintf(fp, "0\t.%s\t%s\n", file->dst, subset);
	  break;
    }

  fclose(fp);

 /*
  * Create the key file...
  */

  if (Verbosity)
    puts("Creating key file...");

  snprintf(keyname, sizeof(keyname), "%s/src/%s%03d.k", directory, prodname, dist->vernumber);

  if ((fp = fopen(keyname, "w")) == NULL)
  {
    fprintf(stderr, "epm: Unable to create key file \"%s\" - %s\n",
            keyname, strerror(errno));
    return (1);
  }

  qprintf(fp, "NAME='%s, %s'\n", dist->product, dist->version);
  fprintf(fp, "CODE=%s\n", prodname);
  fprintf(fp, "VER=%03d\n", dist->vernumber);
  fprintf(fp, "MI=%s%03d.mi\n", prodname, dist->vernumber);
  fputs("COMPRESS=0\n", fp);
  fputs("%%\n", fp);
  qprintf(fp, "%s\t.\t0\t'%s, %s'\n", subset, dist->product, dist->version);
  fclose(fp);

 /*
  * Copy the files over...
  */

  if (Verbosity)
    puts("Copying temporary distribution files...");

  for (i = dist->num_files, file = dist->files; i > 0; i --, file ++)
  {
   /*
    * Find the username and groupname IDs...
    */

    pwd = getpwnam(file->user);
    grp = getgrnam(file->group);

    endpwent();
    endgrent();

   /*
    * Copy the file or make the directory or make the symlink as needed...
    */

    switch (tolower(file->type))
    {
      case 'c' :
      case 'f' :
      case 'i' :
          snprintf(filename, sizeof(filename), "%s/src%s", directory, file->dst);

	  if (Verbosity > 1)
	    printf("%s -> %s...\n", file->src, filename);

	  if (copy_file(filename, file->src, file->mode, pwd ? pwd->pw_uid : 0,
			grp ? grp->gr_gid : 0))
	    return (1);
          break;

      case 'd' :
          snprintf(filename, sizeof(filename), "%s/src%s", directory, file->dst);

	  if (Verbosity > 1)
	    printf("Directory %s...\n", filename);

          make_directory(filename, file->mode, pwd ? pwd->pw_uid : 0,
			 grp ? grp->gr_gid : 0);
          break;

      case 'l' :
          snprintf(filename, sizeof(filename), "%s/src%s", directory, file->dst);

	  if (Verbosity > 1)
	    printf("%s -> %s...\n", file->src, filename);

          make_link(filename, file->src);
          break;
    }
  }

 /*
  * Build the distribution from the inventory and control files...
  */

  if (Verbosity)
    puts("Building Tru64 (setld) distribution...");

  snprintf(filename, sizeof(filename), "%s/src", directory);
  chdir(filename);

  if (run_command(NULL, "kits %s%03d.k . ../output", prodname, dist->vernumber))
    return (1);

  chdir(current);

 /*
  * Tar and compress the distribution...
  */

  if (Verbosity)
    puts("Creating tar.gz file for distribution...");

  snprintf(filename, sizeof(filename), "%s/%s.tar.gz", directory, name);

  if ((tarfile = tar_open(filename, 1)) == NULL)
    return (1);

  snprintf(filename, sizeof(filename), "%s/output", directory);

  if (tar_directory(tarfile, filename, prodname))
  {
    tar_close(tarfile);
    return (1);
  }

  tar_close(tarfile);

 /*
  * Remove temporary files...
  */

  if (!KeepFiles)
  {
    if (Verbosity)
      puts("Removing temporary distribution files...");

    run_command(NULL, "/bin/rm -rf %s/output", directory);

    run_command(NULL, "/bin/rm -rf %s/src", directory);
  }

  return (0);
}


/*
 * End of "$Id: setld.c,v 1.16 2003/12/22 12:37:25 mike Exp $".
 */
