/*
 * tools/lib/pv_read_uuidlist.c
 *
 * Copyright (C) 1997 - 2000  Heinz Mauelshagen, Sistina Software
 *
 * March-May,October-November 1997
 * May,August,November 1998
 * February,March,October 2000
 *
 *
 * 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
 *
 *    08/02/2000 - use debug_enter()/debug_leave()
 *    07/03/2000 - renamed function from
 *                 pv_read_namelist() to pv_read_uuidlist()
 *    17/03/2000 - changed namelist to uuidlist
 *    30/10/2000 - make PV uuidlist a continuous array
 *    09/01/2001 - remove nested if's, multiple UUID copying/checking [AED]
 *    13/02/2001 - pass in a pv ponter, rather than PV name [AED]
 *
 */

#include <liblvm.h>

#define LIST_SIZE (ABS_MAX_PV * NAME_LEN)

int pv_read_uuidlist(pv_t *pv, char **pv_uuidlist)
{
   int pv_handle = -1;
   int ret = 0, i = 0;
   char *src, *dst;
   static char *this_pv_uuidlist = NULL;
   int num;

   debug_enter(__FUNCTION__ " -- CALLED with %s\n", pv ? pv->pv_name : "NULL");

   if (pv == NULL || pv_uuidlist == NULL)
      return -LVM_EPARAM;

   if ((pv_handle = open(pv->pv_name, O_RDONLY)) == -1) {
      ret = -LVM_EPV_READ_UUIDLIST_OPEN;
      goto pv_read_uuidlist_end;
   }

   if (lseek(pv_handle, pv->pv_uuidlist_on_disk.base, SEEK_SET) !=
       pv->pv_uuidlist_on_disk.base) {
      ret = -LVM_EPV_READ_UUIDLIST_LSEEK;
      goto pv_read_uuidlist_end;
   }

   if (this_pv_uuidlist == NULL &&
       (this_pv_uuidlist = malloc(LIST_SIZE)) == NULL) {
      fprintf(stderr, "%s -- malloc error in %s [line %d]\n",
              cmd, __FILE__, __LINE__);
      ret = -LVM_EPV_READ_UUIDLIST_MALLOC;
      goto pv_read_uuidlist_end;
   }

   num = min(pv->pv_uuidlist_on_disk.size, LIST_SIZE);
   if (read(pv_handle, this_pv_uuidlist, num) != num) {
      ret = -LVM_EPV_READ_UUIDLIST_READ;
      goto pv_read_uuidlist_end;
   }

   memset(this_pv_uuidlist + num, 0, LIST_SIZE - num);
   num /= NAME_LEN;
   ret = 0;
   /* Copy valid UUIDs to the start of the list, otherwise ignore */
   src = dst = this_pv_uuidlist;
   for (i = 0; i < num; i++) {
      if (lvm_check_uuid(src) == 0) {
         if (src != dst)
            memcpy(dst, src, NAME_LEN);
         dst += NAME_LEN;
         ret++;
      }
      src += NAME_LEN;
   }
   if (ret)
      *pv_uuidlist = this_pv_uuidlist;

pv_read_uuidlist_end:
   if (pv_handle != -1)
      close(pv_handle);

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