mirror of
https://git.openafs.org/openafs.git
synced 2025-01-23 01:11:13 +00:00
ac3e0ed031
Some confusion had ensued about the usage of our printf cast helper functions. Rename these to attempt to allay that confusion, and restore the functions themselves to their original definitions. Essentially, afs_printable_int32_ld() and friends are helpers to go from afs specifc types to things that can be emitted by printf without causing compiler warnings. Also clean up some additional warnings from type mismatches between escapes in printf format strings and the variables being printed. Reviewed-on: http://gerrit.openafs.org/50 Verified-by: Russ Allbery <rra@stanford.edu> Reviewed-by: Russ Allbery <rra@stanford.edu>
369 lines
10 KiB
C
369 lines
10 KiB
C
/*
|
|
* Copyright 2000, International Business Machines Corporation and others.
|
|
* All Rights Reserved.
|
|
*
|
|
* This software has been released under the terms of the IBM Public
|
|
* License. For details, see the LICENSE file in the top-level source
|
|
* directory or online at http://www.openafs.org/dl/license10.html
|
|
*/
|
|
|
|
/*
|
|
System: VICE-TWO
|
|
Module: vutil.c
|
|
Institution: The Information Technology Center, Carnegie-Mellon University
|
|
|
|
*/
|
|
|
|
#include <afsconfig.h>
|
|
#include <afs/param.h>
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <sys/types.h>
|
|
#include <errno.h>
|
|
#ifdef AFS_NT40_ENV
|
|
#include <time.h>
|
|
#include <fcntl.h>
|
|
#else
|
|
#include <sys/time.h>
|
|
#include <sys/file.h>
|
|
#include <unistd.h>
|
|
#endif
|
|
#include <sys/stat.h>
|
|
#ifdef AFS_PTHREAD_ENV
|
|
#include <assert.h>
|
|
#else /* AFS_PTHREAD_ENV */
|
|
#include <afs/assert.h>
|
|
#endif /* AFS_PTHREAD_ENV */
|
|
|
|
#include <rx/xdr.h>
|
|
#include <afs/afsint.h>
|
|
#include "nfs.h"
|
|
#include <afs/errors.h>
|
|
#include "lock.h"
|
|
#include "lwp.h"
|
|
#include <afs/afssyscalls.h>
|
|
#include "ihandle.h"
|
|
#include <afs/afsutil.h>
|
|
#ifdef AFS_NT40_ENV
|
|
#include "ntops.h"
|
|
#include <io.h>
|
|
#endif
|
|
#include "vnode.h"
|
|
#include "volume.h"
|
|
#include "partition.h"
|
|
#include "viceinode.h"
|
|
|
|
#include "volinodes.h"
|
|
#include "vol_prototypes.h"
|
|
|
|
#ifdef AFS_AIX_ENV
|
|
#include <sys/lockf.h>
|
|
#endif
|
|
#if defined(AFS_SUN5_ENV) || defined(AFS_NT40_ENV) || defined(AFS_LINUX20_ENV)
|
|
#include <string.h>
|
|
#else
|
|
#include <strings.h>
|
|
#endif
|
|
|
|
#ifdef O_LARGEFILE
|
|
#define afs_open open64
|
|
#else /* !O_LARGEFILE */
|
|
#define afs_open open
|
|
#endif /* !O_LARGEFILE */
|
|
|
|
/*@printflike@*/ extern void Log(const char *format, ...);
|
|
|
|
#define nFILES (sizeof (stuff)/sizeof(struct stuff))
|
|
|
|
/* Note: the volume creation functions herein leave the destroyMe flag in the
|
|
volume header ON: this means that the volumes will not be attached by the
|
|
file server and WILL BE DESTROYED the next time a system salvage is performed */
|
|
|
|
static void
|
|
RemoveInodes(Device dev, VolumeId vid)
|
|
{
|
|
register int i;
|
|
IHandle_t *handle;
|
|
|
|
/* This relies on the fact that IDEC only needs the device and NT only
|
|
* needs the dev and vid to decrement volume special files.
|
|
*/
|
|
IH_INIT(handle, dev, vid, -1);
|
|
for (i = 0; i < nFILES; i++) {
|
|
Inode inode = *stuff[i].inode;
|
|
if (VALID_INO(inode))
|
|
IH_DEC(handle, inode, vid);
|
|
}
|
|
IH_RELEASE(handle);
|
|
}
|
|
|
|
Volume *
|
|
VCreateVolume(Error * ec, char *partname, VolId volumeId, VolId parentId)
|
|
{ /* Should be the same as volumeId if there is
|
|
* no parent */
|
|
Volume *retVal;
|
|
VOL_LOCK;
|
|
retVal = VCreateVolume_r(ec, partname, volumeId, parentId);
|
|
VOL_UNLOCK;
|
|
return retVal;
|
|
}
|
|
|
|
Volume *
|
|
VCreateVolume_r(Error * ec, char *partname, VolId volumeId, VolId parentId)
|
|
{ /* Should be the same as volumeId if there is
|
|
* no parent */
|
|
VolumeDiskData vol;
|
|
int fd, i;
|
|
char headerName[32], volumePath[64];
|
|
Device device;
|
|
struct DiskPartition64 *partition;
|
|
struct VolumeDiskHeader diskHeader;
|
|
IHandle_t *handle;
|
|
FdHandle_t *fdP;
|
|
Inode nearInode = 0;
|
|
char *part, *name;
|
|
|
|
*ec = 0;
|
|
memset(&vol, 0, sizeof(vol));
|
|
vol.id = volumeId;
|
|
vol.parentId = parentId;
|
|
vol.copyDate = time(0); /* The only date which really means when this
|
|
* @i(instance) of this volume was created.
|
|
* Creation date does not mean this */
|
|
|
|
/* Initialize handle for error case below. */
|
|
handle = NULL;
|
|
|
|
/* Verify that the parition is valid before writing to it. */
|
|
if (!(partition = VGetPartition_r(partname, 0))) {
|
|
Log("VCreateVolume: partition %s is not in service.\n", partname);
|
|
*ec = VNOVOL;
|
|
return NULL;
|
|
}
|
|
#if defined(NEARINODE_HINT)
|
|
nearInodeHash(volumeId, nearInode);
|
|
nearInode %= partition->f_files;
|
|
#endif
|
|
VGetVolumePath(ec, vol.id, &part, &name);
|
|
if (*ec == VNOVOL || !strcmp(partition->name, part)) {
|
|
/* this case is ok */
|
|
} else {
|
|
/* return EXDEV if it's a clone to an alternate partition
|
|
* otherwise assume it's a move */
|
|
if (vol.parentId != vol.id) {
|
|
*ec = EXDEV;
|
|
return NULL;
|
|
}
|
|
}
|
|
VLockPartition_r(partname);
|
|
memset(&tempHeader, 0, sizeof(tempHeader));
|
|
tempHeader.stamp.magic = VOLUMEHEADERMAGIC;
|
|
tempHeader.stamp.version = VOLUMEHEADERVERSION;
|
|
tempHeader.id = vol.id;
|
|
tempHeader.parent = vol.parentId;
|
|
vol.stamp.magic = VOLUMEINFOMAGIC;
|
|
vol.stamp.version = VOLUMEINFOVERSION;
|
|
vol.destroyMe = DESTROY_ME;
|
|
(void)afs_snprintf(headerName, sizeof headerName, VFORMAT, afs_printable_uint32_lu(vol.id));
|
|
(void)afs_snprintf(volumePath, sizeof volumePath, "%s/%s",
|
|
VPartitionPath(partition), headerName);
|
|
fd = afs_open(volumePath, O_CREAT | O_EXCL | O_WRONLY, 0600);
|
|
if (fd == -1) {
|
|
if (errno == EEXIST) {
|
|
Log("VCreateVolume: Header file %s already exists!\n",
|
|
volumePath);
|
|
*ec = VVOLEXISTS;
|
|
} else {
|
|
Log("VCreateVolume: Couldn't create header file %s for volume %u\n", volumePath, vol.id);
|
|
*ec = VNOVOL;
|
|
}
|
|
return NULL;
|
|
}
|
|
device = partition->device;
|
|
|
|
for (i = 0; i < nFILES; i++) {
|
|
register struct stuff *p = &stuff[i];
|
|
if (p->obsolete)
|
|
continue;
|
|
#ifdef AFS_NAMEI_ENV
|
|
*(p->inode) =
|
|
IH_CREATE(NULL, device, VPartitionPath(partition), nearInode,
|
|
(p->inodeType == VI_LINKTABLE) ? vol.parentId : vol.id,
|
|
INODESPECIAL, p->inodeType, vol.parentId);
|
|
if (!(VALID_INO(*(p->inode)))) {
|
|
if (errno == EEXIST) {
|
|
/* Increment the reference count instead. */
|
|
IHandle_t *lh;
|
|
int code;
|
|
|
|
#ifdef AFS_NT40_ENV
|
|
*(p->inode) = nt_MakeSpecIno(VI_LINKTABLE);
|
|
#else
|
|
*(p->inode) = namei_MakeSpecIno(vol.parentId, VI_LINKTABLE);
|
|
#endif
|
|
IH_INIT(lh, device, parentId, *(p->inode));
|
|
fdP = IH_OPEN(lh);
|
|
if (fdP == NULL) {
|
|
IH_RELEASE(lh);
|
|
goto bad;
|
|
}
|
|
code = IH_INC(lh, *(p->inode), parentId);
|
|
FDH_REALLYCLOSE(fdP);
|
|
IH_RELEASE(lh);
|
|
if (code < 0)
|
|
goto bad;
|
|
continue;
|
|
}
|
|
}
|
|
#else
|
|
*(p->inode) =
|
|
IH_CREATE(NULL, device, VPartitionPath(partition), nearInode,
|
|
vol.id, INODESPECIAL, p->inodeType, vol.parentId);
|
|
#endif
|
|
|
|
if (!VALID_INO(*(p->inode))) {
|
|
Log("VCreateVolume: Problem creating %s file associated with volume header %s\n", p->description, volumePath);
|
|
bad:
|
|
if (handle)
|
|
IH_RELEASE(handle);
|
|
RemoveInodes(device, vol.id);
|
|
*ec = VNOVOL;
|
|
close(fd);
|
|
return NULL;
|
|
}
|
|
IH_INIT(handle, device, vol.parentId, *(p->inode));
|
|
fdP = IH_OPEN(handle);
|
|
if (fdP == NULL) {
|
|
Log("VCreateVolume: Problem iopen inode %s (err=%d)\n",
|
|
PrintInode(NULL, *(p->inode)), errno);
|
|
goto bad;
|
|
}
|
|
if (FDH_SEEK(fdP, 0, SEEK_SET) < 0) {
|
|
Log("VCreateVolume: Problem lseek inode %s (err=%d)\n",
|
|
PrintInode(NULL, *(p->inode)), errno);
|
|
FDH_REALLYCLOSE(fdP);
|
|
goto bad;
|
|
}
|
|
if (FDH_WRITE(fdP, (char *)&p->stamp, sizeof(p->stamp)) !=
|
|
sizeof(p->stamp)) {
|
|
Log("VCreateVolume: Problem writing to inode %s (err=%d)\n",
|
|
PrintInode(NULL, *(p->inode)), errno);
|
|
FDH_REALLYCLOSE(fdP);
|
|
goto bad;
|
|
}
|
|
FDH_REALLYCLOSE(fdP);
|
|
IH_RELEASE(handle);
|
|
nearInode = *(p->inode);
|
|
}
|
|
|
|
IH_INIT(handle, device, vol.parentId, tempHeader.volumeInfo);
|
|
fdP = IH_OPEN(handle);
|
|
if (fdP == NULL) {
|
|
Log("VCreateVolume: Problem iopen inode %s (err=%d)\n",
|
|
PrintInode(NULL, tempHeader.volumeInfo), errno);
|
|
unlink(volumePath);
|
|
goto bad;
|
|
}
|
|
if (FDH_SEEK(fdP, 0, SEEK_SET) < 0) {
|
|
Log("VCreateVolume: Problem lseek inode %s (err=%d)\n",
|
|
PrintInode(NULL, tempHeader.volumeInfo), errno);
|
|
FDH_REALLYCLOSE(fdP);
|
|
unlink(volumePath);
|
|
goto bad;
|
|
}
|
|
if (FDH_WRITE(fdP, (char *)&vol, sizeof(vol)) != sizeof(vol)) {
|
|
Log("VCreateVolume: Problem writing to inode %s (err=%d)\n",
|
|
PrintInode(NULL, tempHeader.volumeInfo), errno);
|
|
FDH_REALLYCLOSE(fdP);
|
|
unlink(volumePath);
|
|
goto bad;
|
|
}
|
|
FDH_CLOSE(fdP);
|
|
IH_RELEASE(handle);
|
|
|
|
VolumeHeaderToDisk(&diskHeader, &tempHeader);
|
|
if (write(fd, &diskHeader, sizeof(diskHeader)) != sizeof(diskHeader)) {
|
|
Log("VCreateVolume: Unable to write volume header %s; volume %u not created\n", volumePath, vol.id);
|
|
unlink(volumePath);
|
|
goto bad;
|
|
}
|
|
fsync(fd);
|
|
close(fd);
|
|
return (VAttachVolumeByName_r(ec, partname, headerName, V_SECRETLY));
|
|
}
|
|
|
|
|
|
void
|
|
AssignVolumeName(register VolumeDiskData * vol, char *name, char *ext)
|
|
{
|
|
VOL_LOCK;
|
|
AssignVolumeName_r(vol, name, ext);
|
|
VOL_UNLOCK;
|
|
}
|
|
|
|
void
|
|
AssignVolumeName_r(register VolumeDiskData * vol, char *name, char *ext)
|
|
{
|
|
register char *dot;
|
|
strncpy(vol->name, name, VNAMESIZE - 1);
|
|
vol->name[VNAMESIZE - 1] = '\0';
|
|
dot = strrchr(vol->name, '.');
|
|
if (dot && (strcmp(dot, ".backup") == 0 || strcmp(dot, ".readonly") == 0))
|
|
*dot = 0;
|
|
if (ext)
|
|
strncat(vol->name, ext, VNAMESIZE - 1 - strlen(vol->name));
|
|
}
|
|
|
|
afs_int32
|
|
CopyVolumeHeader_r(VolumeDiskData * from, VolumeDiskData * to)
|
|
{
|
|
/* The id and parentId fields are not copied; these are inviolate--the to volume
|
|
* is assumed to have already been created. The id's cannot be changed once
|
|
* creation has taken place, since they are embedded in the various inodes associated
|
|
* with the volume. The copydate is also inviolate--it always reflects the time
|
|
* this volume was created (compare with the creation date--the creation date of
|
|
* a backup volume is the creation date of the original parent, because the backup
|
|
* is used to backup the parent volume). */
|
|
Date copydate;
|
|
VolumeId id, parent;
|
|
id = to->id;
|
|
parent = to->parentId;
|
|
copydate = to->copyDate;
|
|
memcpy(to, from, sizeof(*from));
|
|
to->id = id;
|
|
to->parentId = parent;
|
|
to->copyDate = copydate;
|
|
to->destroyMe = DESTROY_ME; /* Caller must always clear this!!! */
|
|
to->stamp.magic = VOLUMEINFOMAGIC;
|
|
to->stamp.version = VOLUMEINFOVERSION;
|
|
return 0;
|
|
}
|
|
|
|
afs_int32
|
|
CopyVolumeHeader(VolumeDiskData * from, VolumeDiskData * to)
|
|
{
|
|
afs_int32 code;
|
|
|
|
VOL_LOCK;
|
|
code = CopyVolumeHeader_r(from, to);
|
|
VOL_UNLOCK;
|
|
return (code);
|
|
}
|
|
|
|
void
|
|
ClearVolumeStats(register VolumeDiskData * vol)
|
|
{
|
|
VOL_LOCK;
|
|
ClearVolumeStats_r(vol);
|
|
VOL_UNLOCK;
|
|
}
|
|
|
|
void
|
|
ClearVolumeStats_r(register VolumeDiskData * vol)
|
|
{
|
|
memset(vol->weekUse, 0, sizeof(vol->weekUse));
|
|
vol->dayUse = 0;
|
|
vol->dayUseDate = 0;
|
|
}
|