/*
 * tools/lib/vg_setup_for_merge.c
 *
 * Copyright (C) 1997 - 2001  Heinz Mauelshagen, Sistina Software
 *
 * June 1998
 * January,February 1999
 * January 2000
 * November 2001
 *
 *
 * This LVM library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This LVM library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this LVM library; if not, write to the Free
 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 * MA 02111-1307, USA
 *
 */

/*
 * Changelog
 *
 *    26/01/1999 - made volume group directory prefix a preprocessor option
 *    20/02/1999 - avoided lv_create_kdev_t()
 *    08/02/2000 - use debug_enter()/debug_leave()
 *    22/11/2001 - support for nonsequential PV numbers
 *
 */

#include <liblvm.h>

int vg_setup_for_merge ( vg_t *vg_to, vg_t *vg_from) {
   int l = 0;
   int l1 = 0;
   int l2 = 0;
   int p = 0;
   int p1 = 0;
   int np = 0;
   int pe = 0;
   int vg_to_lv_index = -1;
   int vg_from_lv_index = -1;
   int ret = 0;
   char lv_name_this[NAME_LEN] = { 0, };

   debug_enter ( "vg_setup_for_merge -- CALLED\n");

   if ( vg_to == NULL || vg_from == NULL) {
      ret = -LVM_EPARAM;
      goto vg_setup_for_merge_end;
   }

   if ( vg_from->pv_cur + vg_to->pv_cur > vg_to->pv_max) {
      ret = -LVM_EVG_SETUP_FOR_MERGE_PV_MAX;
      goto vg_setup_for_merge_end;
   }

   if ( vg_from->lv_cur + vg_to->lv_cur > vg_to->lv_max) {
      ret = -LVM_EVG_SETUP_FOR_MERGE_LV_MAX;
      goto vg_setup_for_merge_end;
   }

   if ( vg_from->pe_size != vg_to->pe_size) {
      ret = -LVM_EVG_SETUP_FOR_MERGE_PE_SIZE;
      goto vg_setup_for_merge_end;
   }


   /* Find first free PV slot to merge into */
   for ( np = 0; vg_to->pv[np] != NULL; np++) {}

   /* Fill PV slots, correcting PV numbers and names */
   for ( p = np, p1 = 0; vg_from->pv[p1] != NULL; p++, p1++) {
      int pv_number = _find_unused_pv_number ( vg_to);
      vg_to->pv[p] = vg_from->pv[p1];
      vg_to->pv[p]->pv_number = pv_number;
      vg_to->pv[p]->pv_status = 0;
      strcpy ( vg_to->pv[p]->vg_name, vg_to->vg_name);
   }

   /* Correct current PV, LV and PE count */
   vg_to->pv_cur += vg_from->pv_cur;
   vg_to->pv_act += vg_from->pv_act;
   vg_to->lv_cur += vg_from->lv_cur;
   vg_to->pe_total += vg_from->pe_total;
   vg_to->pe_allocated += vg_from->pe_allocated;

   /* Scan through all LVs of VG to merge from */
   for ( l = 0; l < vg_from->lv_max; l++) {
      if ( vg_from->lv[l] != NULL) {
         vg_from_lv_index = l;

         /* Find free LV slot in VG to merge into */
         for ( l1 = 0; l1 < vg_to->lv_max; l1++) {
            if ( vg_to->lv[l1] == NULL) {
               vg_to_lv_index = l1;
               break;
            }
         }
         if ( l1 >= vg_to->lv_max) {
            ret = -LVM_EVG_SETUP_FOR_MERGE_LV_MAX;
            goto vg_setup_for_merge_end;
         }

         /* Scan through all PVs of VG to merge from */
         for ( p = 0; vg_from->pv[p] != NULL; p++) {
            for ( pe = 0; pe < vg_from->pv[p]->pe_total; pe++)
               if ( vg_from->pv[p]->pe[pe].lv_num == vg_from_lv_index + 1)
                  vg_from->pv[p]->pe[pe].lv_num = vg_to_lv_index + 1;
         }

         vg_to->lv[vg_to_lv_index] = vg_from->lv[vg_from_lv_index];
         strcpy ( vg_to->lv[vg_to_lv_index]->vg_name, vg_to->vg_name);
         strcpy ( vg_to->lv[vg_to_lv_index]->lv_name,
                  lv_change_vgname ( vg_to->vg_name,
                                     vg_to->lv[vg_to_lv_index]->lv_name));
         for ( l1 = 0; l1 < vg_to->lv_max; l1++) {
            if ( l1 == vg_to_lv_index) continue;
            if ( vg_to->lv[l1] != NULL) {
               if ( strcmp ( vg_to->lv[vg_to_lv_index]->lv_name,
                             vg_to->lv[l1]->lv_name) == 0) {
                  l2 = vg_to_lv_index + 1;
                  do {
                     memset ( lv_name_this, 0, sizeof ( lv_name_this));
                     snprintf ( lv_name_this, sizeof ( lv_name_this) - 1,
                                              LVM_DIR_PREFIX "%s/lvol%d",
                                              vg_to->vg_name, l2);
                     l2++;
                  } while ( lvm_tab_lv_check_exist ( lv_name_this) == TRUE);
                  strcpy ( vg_to->lv[vg_to_lv_index]->lv_name, lv_name_this);
                  break;
               }
            }
         }
         vg_to->lv[vg_to_lv_index]->lv_number = vg_to_lv_index;
      }
   }

   if ( vg_check_consistency_with_pv_and_lv ( vg_to) < 0)
      ret = -LVM_EVG_SETUP_FOR_MERGE_VG_CHECK_CONSISTENCY_WITH_PV_AND_LV;

vg_setup_for_merge_end:

   debug_leave ( "vg_setup_for_merge -- LEAVING with ret: %d\n", ret);
   return ret;
}
