/*
 * tools/lvremove.c
 *
 * Copyright (C) 1997 - 2001  Heinz Mauelshagen, Sistina Software
 *
 * March 1997
 * April-June,September 1998
 * January,July,October 1999
 * February,November 2000
 * January,July 2001
 *
 * 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
 *
 *    09/11/1997 - added lvmtab handling
 *    30/04/1998 - changed to lv_status_byname
 *    16/05/1998 - added lvmtab checking
 *    27/06/1998 - changed lvm_tab_* calling convention
 *    04/09/1998 - corrected some messages
 *    12/01/1999 - don't continue with next LV in case of an erro with one LV
 *    39/07/1999 - support snapshot logical volume deletion
 *    06/10/1999 - implemented support for long options
 *    15/02/2000 - use lvm_error()
 *    07/11/2000 - used LVM_VG_NAME environment variable
 *    23/01/2001 - added call to lvm_init (JT)
 *    25/07/2001 - avoid misleading "(null)" in error message (AGK)
 *
 */


#include <lvm_user.h>

char *cmd = NULL;

#ifdef DEBUG
int opt_d = 0;
#endif

int main ( int argc, char **argv)
{
   int c = 0;
   int c1 = 0;
   int opt_A = 1;
   int opt_A_set = 0;
   int opt_f = 0;
   int opt_v = 0;
   int ret = 0;
   char buffer[NAME_LEN];
   char *options = "A:fh?v" DEBUG_SHORT_OPTION;
   struct option long_options[] = {
      { "autobackup", required_argument, NULL, 'A'},
      DEBUG_LONG_OPTION
      { "force",      no_argument, NULL, 'f'},
      { "help",       no_argument, NULL, 'h'},
      { "verbose",    no_argument, NULL, 'v'},
      { NULL,         0,           NULL, 0}
   };
   char *vg_name = NULL;
   char *lv_name = NULL;
   vg_t *vg = NULL;
   lv_t *lv = NULL;

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

   LVMTAB_CHECK;

   while ( ( c = getopt_long ( argc, argv, options,
                               long_options, NULL)) != EOF) {
      switch ( c) {
         case 'A':
            opt_A_set++;
            if ( opt_A > 1) {
               fprintf ( stderr, "%s -- A option already given\n\n", cmd);
               return LVM_EINVALID_CMD_LINE;
            }
            if ( strcmp ( optarg, "y") == 0);
            else if ( strcmp ( optarg, "n") == 0) opt_A = 0;
            else {
               fprintf ( stderr, "%s -- invalid option argument \"%s\"\n\n",
                                 cmd, optarg);
               return LVM_EINVALID_CMD_LINE;
            }
            break;

         DEBUG_HANDLE_CASE_D;

         case 'h':
         case '?':
            printf ( "\n%s (IOP %d)\n\n%s -- Logical Volume Remove\n\n"
                     "Synopsis:\n"
                     "---------\n\n"
                     "%s\n"
                     "\t[-A/--autobackup y/n]\n"
                     DEBUG_HELP		     
                     "\t[-f/--force]\n"
                     "\t[-h/--help]\n"
                     "\t[-v/--verbose]\n"
                     "\tLogicalVolume[Path] [LogicalVolume[Path]...]\n\n",
                     lvm_version, LVM_LIB_IOP_VERSION,  cmd, cmd);
            return 0;
            break;

         case 'f':
            if ( opt_f > 0) {
               fprintf ( stderr, "%s -- f option already given\n\n", cmd);
               return LVM_EINVALID_CMD_LINE;
            }
            opt_f++;
            break;

         case 'v':
            if ( opt_v > 0) {
               fprintf ( stderr, "%s -- v option already given\n\n", cmd);
               return LVM_EINVALID_CMD_LINE;
            }
            opt_v++;
            break;

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

   CMD_MINUS_CHK;
   CMD_CHECK_OPT_A_SET;

   if ( optind == argc) {
      fprintf ( stderr, "%s -- please enter a logical volume path\n\n", cmd);
      return LVM_ELVREMOVE_LV_MISSING;
   }

   LVM_CHECK_IOP;
   LVM_LOCK ( 0);

   for ( ; optind < argc; optind++) {
      lv_name = argv[optind];
   
      LVM_CHECK_DEFAULT_VG_NAME ( lv_name, buffer, sizeof ( buffer));

      if ( lv_name == NULL) {
         fprintf ( stderr, "%s -- a path needs supplying for "
                           "logical volume argument \"%s\"\n\n",
                           cmd, argv[optind]);
         return LVM_ELVREMOVE_LV_CHECK_NAME;
      }

      if ( opt_v > 0) printf ( "%s -- checking logical volume name \"%s\"\n",
                               cmd, lv_name);
      if ( ( ret = lv_check_name ( lv_name)) < 0) {
         fprintf ( stderr, "%s -- ERROR: no valid logical volume "
                           "name \"%s\"\n\n", cmd, lv_name);
         return LVM_ELVREMOVE_LV_CHECK_NAME;
      }

      /* does VG exist? */
      vg_name = vg_name_of_lv ( lv_name);


      if ( opt_v > 0) printf ( "%s -- checking existence of volume "
                               "group \"%s\"\n",
                               cmd, vg_name);
      if ( lvm_tab_vg_check_exist ( vg_name, NULL) != TRUE) {
         fprintf ( stderr, "%s -- volume group \"%s\" doesn't exist\n\n",
                   cmd, vg_name);
         return LVM_ELVREMOVE_VG_CHECK_EXIST;
      }
   
      if ( opt_v > 0) printf ( "%s -- checking for active volume group "
                               "\"%s\"\n",
                               cmd, vg_name);
      if ( vg_check_active ( vg_name) != TRUE) {
         fprintf ( stderr, "%s -- can't remove logical volume in "
                           "inactive volume group \"%s\"\n\n", cmd, vg_name);
         return LVM_ELVREMOVE_VG_CHECK_ACTIVE;
      }
   
      if ( opt_v > 0) printf ( "%s -- getting status of volume group \"%s\" "
                               "from kernel\n", cmd, vg_name);
      if ( vg_status ( vg_name, &vg) < 0) {
         fprintf ( stderr, "%s -- can't remove logical volume in inactive"
                           " volume group \"%s\"\n\n", cmd, vg_name);
         return LVM_ELVREMOVE_VG_STATUS;
      }
   
      if ( opt_v > 0) printf ( "%s -- getting status of logical volume "
                               "%s from VGDA in kernel\n", cmd, lv_name);
      if ( ( ret = lv_status_byname ( vg_name, lv_name, &lv)) < 0) {
         if ( ret == -ENXIO) {
            fprintf ( stderr, "%s -- logical volume \"%s\" doesn't exist\n\n",
                              cmd, lv_name);
         } else {
            fprintf ( stderr, "%s -- ERROR \"%s\" getting status"
                              " of logical volume \"%s\"\n\n",
                              cmd, lvm_error ( ret), lv_name);
         }
         return LVM_ELVREMOVE_LV_STATUS;
      }
   
      if ( lv->lv_access & LV_SNAPSHOT_ORG) {
         fprintf ( stderr, "%s -- can't remove logical volume \"%s\" "
                           "under snapshot\n\n",
                           cmd,
                           lv_name);
         return LVM_ELVREMOVE_LV_SNAPSHOT;
      }

      if ( lv->lv_open > 0) {
         fprintf ( stderr, "%s -- can't remove open %s "
                           "logical volume \"%s\"\n\n",
                           cmd,
                           lv->lv_access & LV_SNAPSHOT ? "snapshot" : "",
                           lv_name);
         return LVM_ELVREMOVE_LV_OPEN;
      }
   
      if ( opt_v > 0) printf ( "%s -- reading data of volume group \"%s\" "
                               "from disk(s)\n", cmd, lv_name);
      if ( ( ret = lvm_tab_vg_read_with_pv_and_lv ( vg_name, &vg)) != 0) {
         fprintf ( stderr, "%s -- ERROR \"%s\" reading data of volume "
                           "group \"%s\"\n\n",
                           cmd, lvm_error ( ret), vg_name);
         return LVM_ELVREMOVE_VG_READ;
      }

      if ( opt_f == 0) {
         c = 0;
         while ( c != 'y' && c != 'n') {
            if ( c == '\n' || c == 0)
               printf ( "%s -- do you really want to remove \"%s\"? [y/n]: ",
                        cmd, lv_name);
            c = tolower ( getchar ());
         }
         c1 = c;
         while ( c != '\n') c = tolower ( getchar ());
         if ( c1 == 'n') {
            printf ( "%s -- logical volume \"%s\" not removed\n", cmd, lv_name);
            continue;
         }
      }

      /* release it in structures */
      if ( opt_v > 0) printf ( "%s -- releasing logical volume \"%s\"\n",
                               cmd, lv_name);
      if ( ( ret = lv_release ( vg, lv_name)) != 0) {
         fprintf ( stderr, "%s -- ERROR \"%s\" releasing logical "
                           "volume \"%s\"\n\n", 
                           cmd, lvm_error ( ret), lv_name);
         return LVM_ELVREMOVE_LV_RELEASE;
      }
   

      lvm_dont_interrupt ( 0);
   
      /* remove it from kernel */
      if ( opt_v > 0) printf ( "%s -- removing logical volume from VGDA "
                               "in kernel\n", cmd);
      if ( ( ret = lv_remove ( vg, lv, lv_name)) != 0) {
         fprintf ( stderr, "%s -- ERROR \"%s\" removing logical "
                           "volume \"%s\"\n\n", 
                           cmd, lvm_error ( ret), lv_name);
         return -LVM_ELVREMOVE_LV_REMOVE;
      }

      if ( opt_v > 0) printf ( "%s -- unlinking special file \"%s\"\n",
         cmd, lv_name);

      if(!lvm_check_devfs() && unlink(lv_name) == -1)
         fprintf(stderr, "%s -- ERROR \"%s\" unlinking special file \"%s\"\n",
					  cmd, lvm_error ( errno), lv_name);
   
      /* store it on disks */
      if ( opt_v > 0) printf ( "%s -- storing volume group data on disk(s)\n",
                               cmd);
      if ( ( ret = vg_write_with_pv_and_lv ( vg)) != 0) {
         fprintf ( stderr, "%s -- ERROR \"%s\" storing data of volume "
                           "group \"%s\" on disks\n\n", 
                           cmd, lvm_error ( ret), vg_name);
         return LVM_ELVREMOVE_VG_WRITE;
      }


      if ( opt_v > 0) printf ( "%s -- changing lvmtab\n", cmd);
      if ( vg_cfgbackup ( vg_name, LVMTAB_DIR, opt_v, vg) == 0 &&
           opt_A > 0) {
         printf ( "%s -- doing automatic backup of volume group \"%s\"\n",
                  cmd, vg_name);
         vg_cfgbackup ( vg_name, VG_BACKUP_DIR, opt_v, vg);
      } else {
         printf ( "%s -- WARNING: you don't have an automatic "
                  "backup of \"%s\"\n",
                  cmd, vg_name);
      }

      lvm_interrupt ();

      printf ( "%s -- logical volume \"%s\" successfully removed\n",
               cmd, lv_name);
      if ( argc - optind > 1 && opt_v > 0) printf ( "\n");
   }

   LVM_UNLOCK ( 0);

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