1
0
Files
irix-657m-src/eoe/cmd/lv/mklv.c
2022-09-29 17:59:04 +03:00

455 lines
10 KiB
C

/**************************************************************************
* *
* Copyright (C) 1988, Silicon Graphics, Inc. *
* *
* These coded instructions, statements, and computer programs contain *
* unpublished proprietary information of Silicon Graphics, Inc., and *
* are protected by Federal copyright law. They may not be disclosed *
* to third parties or copied or duplicated in any form, in whole or *
* in part, without the prior written consent of Silicon Graphics, Inc. *
* *
**************************************************************************/
#ident "$Revision: 1.18 $"
#include <sys/param.h>
#include <sys/types.h>
#include <sys/dvh.h>
#include <sys/dkio.h>
#include <sys/fcntl.h>
#include <stdio.h>
#include <ctype.h>
#include <sys/sema.h>
#include <sys/uuid.h>
#include <sys/fs/efs.h>
#include <sys/fs/xfs_types.h>
#include <sys/fs/xfs_inum.h>
#include <sys/fs/xfs_sb.h>
#include <sys/utsname.h>
#include <time.h>
#include <ustat.h>
#include <sys/lv.h>
#include "lvutils.h"
extern int errno;
struct volmember memhead = {0};
struct logvol *loghead = NULL;
int readonly = 0;
char *progname;
int force = 0;
int raw = 0;
struct logvol *devnametovol();
char *makevolid(), *pathtolabname();
char *fname = "/etc/lvtab";
main(ac, av)
int ac;
char **av;
{
register struct logvol *vol;
register int i, j, c;
char namebuf[MAXDEVPATHLEN];
int lvfd;
struct lvioarg arg;
int extending = 0;
int writerr = 0;
int setuperr = 0;
extern int optind;
extern char *optarg;
progname = av[0];
if (getuid() != 0)
{
fprintf(stderr,"must be superuser to run %s\n", progname);
exit(-1);
}
/* Check for correct usage */
if( ac < 2 )
{
ucrap:
fprintf(stderr,"usage: mklv [-f] [-l lvtabname] lvname \n");
exit(-1);
}
/*
* Parse the arguments.
*/
while ((c = getopt(ac, av, "fl:")) != EOF)
{
switch (c) {
case 'f':
force = 1;
break;
case 'l':
fname = optarg;
break;
default: goto ucrap;
}
}
ac -= optind;
if (ac <= 0) goto ucrap;
av = &av[optind];
importlvtab(fname);
vol = devnametovol(*av);
if (!vol)
{
fprintf(stderr, "mklv: %s not found in lvtab.\n", *av);
exit(-1);
}
if (!(vol->status & L_GOODTABENT))
{
fprintf(stderr,"mklv: bad lvtab entry for %s.\n", *av);
exit(-1);
}
volmemsetup(vol);
if (checkvolpaths(vol)) setuperr = 1;
if (getvolheads(vol)) setuperr = 1;
if (partcheck(vol)) setuperr = 1;
if (setuperr)
{
(void)printbadvol(vol, stderr, NEW_VOLUME);
exit(-1);
}
/* Now we must check to see if this is a brand-new logical volume,
* or extension of an existing one. We call getlvlabs to obtain
* any already-existing labels.
*
* If all specified member devices already have logical volume labels
* we just notify the user & quit.
*
* If there are labels on a contiguous range of devices starting
* at the first one specified, we assume we are extending; in this
* case we must do additional checks to verify that the existing
* volume is a proper subset of the extended one now specified.
*
* If there is a mixture of missing/present labels in some less
* orderly pattern, something is wrong; again we notify & quit.
*
* Note: if the 'force' flag is set, these checks are skipped.
*/
if (force) goto writeit;
getlvlabs(vol);
check_dev_connections(1);
if (vol->status & L_GOTALL_LABELS)
{
fprintf(stderr,"mklv: all devices specified for %s \n",vol->tabent->devname);
fprintf(stderr,"are already part of Logical Volume(s).\n");
exit(-1);
}
if (vol->status & L_BADPARTIAL)
{
fprintf(stderr,"mklv: one or more devices specified for %s \n",vol->tabent->devname);
fprintf(stderr,"are already part of a Logical Volume\n");
exit(-1);
}
if ((vol->status & L_GOODPARTIAL))
{
extending = 1;
vol_labels_check(vol);
vol_devs_check(vol);
if (vol->status !=
(L_GOODPARTIAL | L_GOODTABENT | L_GOODLABELS | L_DEVSCHEKD))
{
(void)printbadvol(vol, stderr, EXISTING_VOLUME);
exit(-1);
}
if (vol_to_tab_check(vol, PARTIAL_VOL))
exit(-1);
}
writeit:
if (extending)
vol->volid = vol->vmem[0]->lvlab->volid;
else
vol->volid = makevolid();
if (buildlv(vol, vol->tabent->stripe, vol->tabent->gran))
{
(void)printbadvol(vol, stderr, NEW_VOLUME);
exit(-1);
}
if (extending && comparelv(vol->lv,
&vol->vmem[0]->lvlab->lvdescrip,
PARTIAL_VOL))
{
fprintf(stderr,"mklv: devices specified for %s already contain a Logical Volume\n",vol->tabent->devname);
fprintf(stderr,"which is inconsistent with the volume specified.\n");
exit(-1);
}
makelabels(vol);
for (i = 0; i < vol->ndevs; i++)
{
if (writelabel(vol->vmem[i], raw))
{
writerr = 1;
break;
}
}
/* If a write of a label failed, we have left the overall volume in
* an inconsistent state. We will attempt to restore the previous
* state in this case.
*/
if (writerr)
{
fprintf(stderr,"mklv: attempting to restore initial state\n");
for (j = 0; j < i; j++) restorelabel(vol->vmem[j]);
exit(-1);
}
exit(lvdev_init(vol, vol->lv, 1));
}
/* makevolid(): this creates the 'system' id of the logical volume:
* (a concatenation of systemname & date).
*/
char *
makevolid()
{
static char buf[MAXVNAMELEN];
time_t tim;
struct utsname ut;
uname(&ut);
tim = time(0);
sprintf(buf, "%s: %s", ut.sysname, ctime(&tim));
return (buf);
}
/* partcheck: goes through all the pathnames for a volume checking for:
* a) illegal partition type (volheader, track replacement etc).
* b) Zero size (ie non-set-up partitions).
* c) Mounted filesystems.
* d) appearent superblocks on them. This check is skipped if the 'force' flag
* is set. If a superblock does exist, and the user elects to go ahead,
* it is wiped: this prevents later conflicts where disks could get
* mounted both as part of a filesystem spanning the whole volume, and,
* bogusly, as the old filesystem on the individual disk.
* BUT: with the exception: we don't wipe out any filesystem on the first
* drive of a nonstriped volume, since we may be extending an fs which
* was formerly on a regular partition.
*/
partcheck(vol)
register struct logvol *vol;
{
register vmp vmem;
register int i, fd;
struct efs efs;
xfs_sb_t xfs;
int ptype;
struct ustat ust;
for (i = 0; i < vol->ndevs; i++)
{
vmem = vol->vmem[i];
if (partsize(vmem) == 0)
{
vmem->status |= WRONG_PSIZE;
return (-1);
}
/* Now check for mounted filesystems */
if (ustat(vmem->dev, &ust) == 0)
{
fprintf(stderr,"mklv: %s contains a mounted filesystem.\n",vmem->pathname);
exit(-1);
}
ptype = partype(vmem);
switch (ptype)
{
case PTYPE_VOLHDR:
case PTYPE_VOLUME:
{
vmem->status |= ILLEGAL_PTYPE;
return (-1);
}
case PTYPE_LVOL:
/* It is not unreasonable for the first member in a volume
* to already have a superblock on it: we may be extending
* an existing volume. So skip the check in this case.
*/
if (i == 0) continue;
default:
if (force) continue;
if ((fd = open(vmem->pathname, O_RDWR)) < 0)
{
vmem->status |= CANT_ACCESS;
return (-1);
}
(void) lseek(fd, EFS_SUPERBB * DEV_BSIZE, 0);
if (read(fd, &efs, sizeof (efs)) != sizeof (efs))
{
vmem->status |= CANT_ACCESS;
close(fd);
return (-1);
}
(void) lseek(fd, XFS_SB_DADDR * DEV_BSIZE, 0);
if (read(fd, &xfs, sizeof (xfs)) != sizeof (xfs))
{
vmem->status |= CANT_ACCESS;
close(fd);
return (-1);
}
if (IS_EFS_MAGIC(efs.fs_magic) ||
xfs.sb_magicnum == XFS_SB_MAGIC)
{
printf("mklv: %s appears to contain a filesystem.\n",vmem->pathname);
/* If the volume isn't striped, we should NOT wipe any
* filesystem on the FIRST disk since we may be extending
* a filesystem which was formerly on a regular partition. */
if ((i == 0) && (vol->tabent->stripe == 1))
{
if (reply("OK"))
exit(0);
else
{
close (fd);
continue;
}
}
printf("This will be wiped out if we proceed. ");
if (reply("OK"))
{
exit(0);
}
}
bzero((char *)&efs, sizeof(efs));
(void) lseek(fd, EFS_SUPERBB * DEV_BSIZE, 0);
if (write(fd, &efs, sizeof (efs)) != sizeof (efs))
{
vmem->status |= CANT_ACCESS;
close(fd);
return (-1);
}
bzero((char *)&xfs, sizeof(xfs));
(void) lseek(fd, XFS_SB_DADDR * DEV_BSIZE, 0);
if (write(fd, &xfs, sizeof (xfs)) != sizeof (xfs))
{
vmem->status |= CANT_ACCESS;
close(fd);
return (-1);
}
close(fd);
}
}
return (0);
}
/*
* Restorelabel(): attempt to restore the previous state. If there was a
* previous label, put that back.
* If there wasn't, wipe out any label and restore the PTYPE to what it was.
*/
restorelabel(vmem)
register struct volmember *vmem;
{
register char *labelname;
register struct volume_header *vh;
register int i;
register int empty;
register int bytes;
register int vfd;
register int dev_bsize;
daddr_t lbn;
unsigned offset;
register int part;
struct partition_table *pt;
if (!vmem->vhinfo)
{
if (getdvh(vmem) < 0) return (-1);
}
else if ((vfd = membfd(vmem)) < 0) return (-1);
vh = &vmem->vhinfo->vh;
dev_bsize = vmem->vhinfo->dev_bsize;
/* delete first */
labelname = pathtolabname(vmem->pathname);
(void)vd_delete(labelname, vh);
sortdir(vh->vh_vd); /* keep in sorted order just for appearances */
if (!vmem->lvlab)
{
vh->vh_pt[pathtopart(vmem->pathname)].pt_type = vmem->ptype;
goto pushvh;
}
/* Reallocate a directory slot. */
empty = -1;
for (i = 0; i < NVDIR; i++)
{
if (empty < 0 && vh->vh_vd[i].vd_nbytes == 0)
{
empty = i;
break;
}
}
if (empty == -1) {
fprintf(stderr,"%s: volume header directory full\n",progname);
return (-1);
}
bytes = roundblk(vmem->labsize, dev_bsize); /* round up to blks */
if((lbn = vh_contig(vmem, bytes)) == -1)
{
fprintf(stderr,"%s: can't restore label for %s\n",
progname, labelname);
return(-1); /* shouldn't ever happen here... */
}
offset = lbn * dev_bsize;
lseek(vfd, offset, 0);
if (write(vfd, (caddr_t)vmem->lvlab, bytes) != bytes)
{
fprintf(stderr,"%s: can't restore label for %s\n",
progname, vmem->pathname);
return (-1);
}
strcpy(vh->vh_vd[empty].vd_name, labelname);
vh->vh_vd[empty].vd_nbytes = bytes;
vh->vh_vd[empty].vd_lbn = lbn;
sortdir(vh->vh_vd); /* keep in sorted order just for appearances,
and in case any older programs counted on it. */
pushvh:
if (putdvh(vmem) < 0) return (-1);
return(0);
}