/*
 * tools/vgdisplay.c
 *
 * Copyright (C) 1997 - 2000  Heinz Mauelshagen, Sistina Software
 *
 * March-July,November 1997
 * January,May,June,September 1998
 * February,May,October,November 1999
 * February,March 2000
 *
 * LVM 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.
 * 
 * LVM 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 LVM; see the file COPYING.  If not, write to
 * the Free Software Foundation, 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA. 
 *
 */

/*
 * Changelog
 *
 *    07/10/1997 - option s implemented
 *    09/11/1997 - added use /etc/lvmtab in addition direct disk access (opt_D)
 *               - added -a option
 *    16/05/1998 - added lvmtab check
 *    18/01/1998 - added output of free volume group size to option s output
 *    27/06/1998 - changed lvm_tab_* calling convention
 *    08/07/1998 - use vg_red() instead of lvm_tab_vg_read() with -D
 *    02/09/1998 - corrected some messages
 *    21/02/1999 - removed LVM_LOCK and LVM_UNLOCK
 *    27/05/1999 - reformated -s output
 *    06/10/1999 - implemented support for long options
 *    03/11/1999 - implemented option -c for colon seperated output
 *    15/02/2000 - use lvm_error()
 *    08/03/2000 - check for mutual exclusive -c/-s
 *    23/01/2001 - added call to lvm_init (JT)
 *    09/04/2001 - Tidy usage message and command-line options.
 *
 */

#include <lvm_user.h>

char *cmd = NULL;

#ifdef DEBUG
int opt_d = 0;
#endif

void usage ( int ret)
{
   FILE *stream = stderr;

   if ( ret == 0) {
      stream = stdout;
      printf ( "%s (IOP %d)\n\n", lvm_version, LVM_LIB_IOP_VERSION);
      printf ( "%s -- display volume group information\n", cmd);
   }

   fprintf ( stream, "\n%s "
             "[-c|--colon | -s|--short | -v[v]|--verbose [--verbose]]\n\t"
             DEBUG_HELP_2
             "[-h|--help] "
             "[--version]\n\t"
             "[-A|--activevolumegroups | [-D|--disk] [VolumeGroupName...] ]\n",
             cmd);
   exit ( ret);
}

int main ( int argc, char **argv) {
   int c = 0;
   int exit_code = 0;
   int len = 0;
   int max_len = 0;
   int opt_A = 0;
   int opt_c = 0;
   int opt_D = 0;
   int opt_s = 0;
   int opt_v = 0;
   int ret = 0;
   char *dummy1 = NULL;
   char *dummy2 = NULL;
   char *options = "cADh?sv" DEBUG_SHORT_OPTION;
   struct option long_options[] = {
      { "activevolumegroups", no_argument, NULL, 'A'},
      { "colon",              no_argument, NULL, 'c'},
      DEBUG_LONG_OPTION
      { "disk",               no_argument, NULL, 'D'},
      { "help",               no_argument, NULL, 'h'},
      { "short",              no_argument, NULL, 's'},
      { "verbose",            no_argument, NULL, 'v'},
      { "version",            no_argument, NULL, 22 },
      { NULL, 0, NULL, 0}
   };
   char *vg_name = NULL;
   vg_t *vg = NULL;

   /* lvm_init(argc, argv); */
   cmd = basename ( argv[0]);

   while ( ( c = getopt_long ( argc, argv, options,
                               long_options, NULL)) != EOF) {
      switch ( c) {
         case 'A':
            opt_A++;
            break;

         case 'c':
            opt_c++;
            break;

         DEBUG_HANDLE_CASE_D;

         case 'D':
            opt_D++;
            break;

         case 'h':
            usage(0);

         case 's':
            opt_s++;
            break;

         case 'v':
            opt_v++;
            break;

         case 22:
            printf ("%s: %s (IOP %d)\n", cmd, lvm_version, LVM_LIB_IOP_VERSION);
            return 0;

         default:
            fprintf ( stderr, "%s -- invalid command line option \"%c\"\n",
                      cmd, c);
         case '?':
            return LVM_EINVALID_CMD_LINE;
      }
   }

   /* not until all commands are converted
   CMD_MINUS_CHK;
   */
   if ( optind < argc && *argv[optind] == '-') {
      fprintf ( stderr, "%s -- invalid option %s\n", cmd, argv[optind]);
      usage ( LVM_EINVALID_CMD_LINE);
   }
   LVMTAB_CHECK;
   LVM_CHECK_IOP;

   if ( opt_c && opt_v) {
      fprintf ( stderr, "%s -- option v is not allowed with option c\n\n", cmd);
      usage ( LVM_EINVALID_CMD_LINE);
   }

   if ( opt_s && opt_v) {
      fprintf ( stderr, "%s -- option v is not allowed with option s\n\n", cmd);
      usage ( LVM_EINVALID_CMD_LINE);
   }

   if ( opt_c && opt_s) {
      fprintf ( stderr, "%s -- option c is not allowed with option s\n\n", cmd);
      usage ( LVM_EINVALID_CMD_LINE);
   }

   if ( opt_A && opt_D) {
      fprintf ( stderr, "%s -- option D is not allowed with option A\n", cmd);
      usage ( LVM_EINVALID_CMD_LINE);
   }

   if ( optind < argc) {
      if ( opt_A) {
         fprintf ( stderr, "%s -- option A is not allowed with volume group "
                           "names\n", cmd);
         usage ( LVM_EINVALID_CMD_LINE);
      }
   } else {
      if ( opt_v > 1) {
         printf ( "%s -- finding all ", cmd);
         if ( opt_A > 0) printf ( "active ");
         printf ( "volume group(s)\n");
      }
      if ( opt_A > 0) argv = vg_check_active_all_vg ();
      else {
         if ( opt_D > 0) argv = vg_check_exist_all_vg ();
         else            argv = lvm_tab_vg_check_exist_all_vg ();
      }
      argc = optind = 0;
      if ( argv != NULL) while ( argv[argc] != NULL) argc++;
   }

   if ( optind == argc) {
      printf ( "%s -- no ", cmd);
      if ( opt_A > 0) printf ( "active ");
      printf ( "volume groups found\n\n");
      return LVM_EVGDISPLAY_NO_VG;
   }

   /* figure out longest volume group name */
   for ( c = optind; optind < argc; optind++) {
      len = strlen ( argv[optind]);
      if ( len > max_len) max_len = len;
   }

   /* loop through all volume groups */
   for ( optind = c; optind < argc; optind++) {
      vg_name = argv[optind];

      if ( opt_v > 1) printf ( "%s -- checking volume group name \"%s\"\n",
                               cmd, vg_name);
      if ( vg_check_name ( vg_name) < 0) {
         fprintf ( stderr, "%s -- \"%s\" is an invalid volume group name\n",
                   cmd, vg_name);
         continue;
      }

      if ( opt_v > 1) printf ( "%s -- checking volume group \"%s\" existence\n",
                               cmd, vg_name);
      if ( ( ret = opt_D > 0 ? vg_check_exist ( vg_name) :
                               lvm_tab_vg_check_exist ( vg_name, NULL))
               == TRUE ||
           ret == -LVM_EVG_READ_VG_EXPORTED ||
           ret == -LVM_EVG_READ_LVM_STRUCT_VERSION) {
         if ( ret == -LVM_EVG_READ_VG_EXPORTED)
            printf ( "%s -- WARNING: volume group \"%s\" is exported\n",
                     cmd, vg_name);
         if ( opt_s > 0) {
            printf ( "%s -- \"%s\"", cmd, vg_name);
            c = max_len - strlen ( vg_name) + 1;
            while ( c-- > 0) putchar ( ' ');
            putchar ( '(');
            if ( vg_check_active ( vg_name) != TRUE) printf ( "inactive)\n");
            else  {
               printf ( "active");
               vg_status ( vg_name, &vg);
               if ( vg->lv_open > 0) printf ( "/used");
               else                  printf ( "/idle");
               printf ( ") %-9s [%-9s used / ",
                        ( dummy1 = lvm_show_size ( vg->pe_total *
                                                   vg->pe_size / 2,
                                                   SHORT)),
                        ( dummy2 = lvm_show_size ( vg->pe_allocated *
                                                  vg->pe_size / 2,
                                                  SHORT)));
               free ( dummy1); dummy1 = NULL;
               free ( dummy2); dummy2 = NULL;
               printf ( "%s free]\n",
                        ( dummy1 = lvm_show_size ( ( vg->pe_total -
                                                    vg->pe_allocated)
                                                   * vg->pe_size / 2, SHORT)));
               free ( dummy1); dummy1 = NULL;
            }
            continue;
         }
         if ( opt_D == 0) {
            if ( opt_v > 1) printf ( "%s -- checking volume group "
                                     "\"%s\" activity\n", cmd, vg_name);
            if ( vg_check_active ( vg_name) == TRUE) {
               if ( opt_v > 1) printf ( "%s -- getting VGDA of \"%s\" from "
                                        "kernel\n", cmd, vg_name);
               if ( opt_v > 0) {
                  if ( ( ret = vg_status_with_pv_and_lv ( vg_name, &vg)) < 0) {
                     fprintf ( stderr,
                               "%s -- ERROR \"%s\" getting status of \"%s\"\n",
                                cmd, lvm_error ( ret), vg_name);
                     continue;
                  }
                  vg_show ( vg);
                  printf ( "\n");
                  lv_show_all_lv_of_vg ( vg);
                  printf ( "\n");
                  pv_show_all_pv_of_vg_short ( vg);
                  printf ( "\n");
               } else {
                  vg_status ( vg_name, &vg);
                  if ( opt_c == 0) {
                     vg_show ( vg);
                     printf ( "\n");
                  } else vg_show_colon ( vg);
               }
            } else {
               printf ( "%s -- \"%s\" is NOT active; try -D\n",
                        cmd, vg_name);
            }
         } else { /* display from disks */
            if ( opt_v > 1) printf ( "%s -- reading volume group data of "
                                     "\"%s\" from disk(s)\n", cmd, vg_name);
            if ( opt_v > 0) {
               if ( ( ret = vg_read_with_pv_and_lv ( vg_name,
                                                     &vg)) < 0 &&
                      ret != -LVM_EVG_READ_VG_EXPORTED) {
                  exit_code = LVM_EVGDISPLAY_VG_READ;
                  if ( ret == -LVM_EVG_READ_LVM_STRUCT_VERSION) {
                     fprintf ( stderr,
                               "%s -- can't show volume group \"%s\" with "
                               "invalid physical volume version\n",
                                cmd, vg_name);
                  } else {
                     fprintf ( stderr,
                               "%s -- ERROR \"%s\" getting data of \"%s\" from "
                               "disk(s)\n",
                               cmd, lvm_error ( ret), vg_name);
                  }
                  continue;
               }
               vg_show ( vg);
               printf ( "\n");
               lv_show_all_lv_of_vg ( vg);
               printf ( "\n");
               pv_show_all_pv_of_vg_short ( vg);
            } else {
               if ( ( ret = vg_read ( vg_name, &vg)) < 0) {
                  exit_code = LVM_EVGDISPLAY_VG_READ;
                  if ( ret == -LVM_EVG_READ_LVM_STRUCT_VERSION) {
                     fprintf ( stderr,
                               "%s -- can't show volume group \"%s\" with "
                               "invalid physical volume version\n",
                                cmd, vg_name);
                  } else if ( -LVM_EPV_READ_ALL_PV_OF_VG_NP) {
                     fprintf ( stderr,
                               "%s -- ERROR: not all physical volumes of \"%s\" "
                               "online\n",
                               cmd, vg_name);
                  } else {
                     fprintf ( stderr,
                               "%s -- ERROR \"%s\" reading data of \"%s\" "
                               "from disk(s)\n",
                               cmd, lvm_error ( ret), vg_name);
                  }
                  continue;
               }
               else {
                  if ( opt_c == 0) {
                     vg_show ( vg);
                     printf ( "\n");
                  } else vg_show_colon ( vg);
               }
            }
         }
      } else if ( ret == -LVM_EPV_READ_ALL_PV_OF_VG_NP) {
         fprintf ( stderr, "%s -- volume group \"%s\" doesn't exist\n",
                   cmd, vg_name);
         exit_code = LVM_EVGDISPLAY_VG_EEXIST;
      } else if ( ret == -LVM_EVG_CHECK_EXIST_PV_COUNT) {
         fprintf ( stderr, "%s -- ERROR: not all physical volumes of "
                           "volume group \"%s\" online\n", cmd, vg_name);
         exit_code = LVM_EVGDISPLAY_PV_COUNT;
      } else if ( ret == -LVM_EVG_CFGRESTORE_READ) {
         fprintf ( stderr, "%s -- ERROR reading lvmtab of \"%s\"\n",
                           cmd, vg_name);
         exit_code = LVM_EVGDISPLAY_VG_CFGRESTORE;
      } else {
         fprintf ( stderr, "%s -- volume group \"%s\" not found\n",
                           cmd, vg_name);
         exit_code = LVM_EVGDISPLAY_VG_NOT_FOUND;
      }
   }


   printf ( "\n");
   return exit_code;
}
