b2fafa18d631608db6d9977832a0ec0b975512fd
[openafs.git] / src / vol / vutil.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11         System:         VICE-TWO
12         Module:         vutil.c
13         Institution:    The Information Technology Center, Carnegie-Mellon University
14
15  */
16
17 #include <afsconfig.h>
18 #include <afs/param.h>
19
20 RCSID("$Header$");
21
22 #include <stdio.h>
23 #include <sys/types.h>
24 #include <errno.h>
25 #ifdef AFS_NT40_ENV
26 #include <time.h>
27 #include <fcntl.h>
28 #else
29 #include <sys/time.h>
30 #include <sys/file.h>
31 #include <unistd.h>
32 #endif
33 #include <sys/stat.h>
34 #ifdef AFS_PTHREAD_ENV
35 #include <assert.h>
36 #else /* AFS_PTHREAD_ENV */
37 #include <afs/assert.h>
38 #endif /* AFS_PTHREAD_ENV */
39
40 #include <rx/xdr.h>
41 #include <afs/afsint.h>
42 #include "nfs.h"
43 #include <afs/errors.h>
44 #include "lock.h"
45 #include "lwp.h"
46 #include <afs/afssyscalls.h>
47 #include "ihandle.h"
48 #ifdef AFS_NT40_ENV
49 #include "ntops.h"
50 #include <io.h>
51 #endif
52 #include "vnode.h"
53 #include "volume.h"
54 #include "partition.h"
55 #include "viceinode.h"
56
57 #include "volinodes.h"
58 #ifdef  AFS_AIX_ENV
59 #include <sys/lockf.h>
60 #endif
61 #if defined(AFS_SUN5_ENV) || defined(AFS_NT40_ENV) || defined(AFS_LINUX20_ENV)
62 #include <string.h>
63 #else
64 #include <strings.h>
65 #endif
66
67
68 #define nFILES  (sizeof (stuff)/sizeof(struct stuff))
69
70 /* Note:  the volume creation functions herein leave the destroyMe flag in the
71    volume header ON:  this means that the volumes will not be attached by the
72    file server and WILL BE DESTROYED the next time a system salvage is performed */
73
74 static void RemoveInodes(Device dev, int vid)
75 {
76     register int i;
77     IHandle_t *handle;
78
79     /* This relies on the fact that IDEC only needs the device and NT only
80      * needs the dev and vid to decrement volume special files.
81      */
82     IH_INIT(handle, dev, vid, -1);
83     for (i = 0; i<nFILES; i++) {
84         Inode inode = *stuff[i].inode;
85         if (VALID_INO(inode))
86             IH_DEC(handle, inode, vid);
87     }
88     IH_RELEASE(handle);
89 }
90
91 Volume *VCreateVolume(ec, partname, volumeId, parentId)
92     Error *ec;
93     char *partname;
94     VolId volumeId;
95     VolId parentId;     /* Should be the same as volumeId if there is
96                            no parent */
97 {
98     Volume *retVal;
99     VOL_LOCK
100     retVal = VCreateVolume_r(ec, partname, volumeId, parentId);
101     VOL_UNLOCK
102     return retVal;
103 }
104
105 Volume *VCreateVolume_r(ec, partname, volumeId, parentId)
106     Error *ec;
107     char *partname;
108     VolId volumeId;
109     VolId parentId;     /* Should be the same as volumeId if there is
110                            no parent */
111 {
112     VolumeDiskData vol;
113     int fd, fd1, i;
114     char headerName[32], volumePath[64];
115     struct stat status;
116     Device device;
117     struct DiskPartition *partition;
118     struct VolumeDiskHeader diskHeader;
119     int code;
120     IHandle_t *handle;
121     FdHandle_t *fdP;
122     Inode nearInode=0; 
123
124     
125
126     *ec = 0;
127     memset(&vol, 0, sizeof (vol));
128     vol.id = volumeId;
129     vol.parentId = parentId;
130     vol.copyDate = time(0);     /* The only date which really means when this
131                                    @i(instance) of this volume was created.
132                                    Creation date does not mean this */
133
134     /* Initialize handle for error case below. */
135     handle = NULL;
136
137     /* Verify that the parition is valid before writing to it. */
138     if (!(partition = VGetPartition(partname, 0))) {
139         Log("VCreateVolume: partition %s is not in service.\n", partname);
140         *ec = VNOVOL;
141         return NULL;
142     }
143 #if     defined(NEARINODE_HINT)
144     nearInodeHash(volumeId,nearInode);
145     nearInode %= partition->f_files;
146 #endif
147     VLockPartition(partname);
148     memset(&tempHeader, 0, sizeof (tempHeader));
149     tempHeader.stamp.magic = VOLUMEHEADERMAGIC;
150     tempHeader.stamp.version = VOLUMEHEADERVERSION;
151     tempHeader.id = vol.id;
152     tempHeader.parent = vol.parentId;
153     vol.stamp.magic = VOLUMEINFOMAGIC;
154     vol.stamp.version = VOLUMEINFOVERSION;
155     vol.destroyMe = DESTROY_ME;
156     sprintf(headerName, VFORMAT, vol.id);
157     sprintf(volumePath, "%s/%s", VPartitionPath(partition), headerName);
158     fd = open(volumePath, O_CREAT|O_EXCL|O_WRONLY, 0600);
159     if (fd == -1) {
160         if (errno == EEXIST) {
161             Log("VCreateVolume: Header file %s already exists!\n", volumePath);
162             *ec = VVOLEXISTS;
163         }
164         else {
165             Log("VCreateVolume: Couldn't create header file %s for volume %u\n", volumePath, vol.id);
166             *ec = VNOVOL;
167         }
168         return NULL;
169     }
170     device = partition->device;
171
172     for (i = 0; i<nFILES; i++) {
173         register struct stuff *p = &stuff[i];
174         if (p->obsolete)
175             continue;
176 #ifdef AFS_NAMEI_ENV
177         *(p->inode) = IH_CREATE(NULL, device, VPartitionPath(partition),
178                                 nearInode, 
179                                 (p->inodeType == VI_LINKTABLE) ? vol.parentId :
180                                 vol.id,
181                                 INODESPECIAL, p->inodeType,
182                                 vol.parentId);
183         if (!(VALID_INO(*(p->inode)))) {
184             if (errno == EEXIST) {
185                 /* Increment the reference count instead. */
186                 IHandle_t *lh;
187                 int code;
188
189 #ifdef AFS_NT40_ENV
190                 *(p->inode) = nt_MakeSpecIno(VI_LINKTABLE);
191 #else
192                 *(p->inode) = namei_MakeSpecIno(vol.parentId, VI_LINKTABLE);
193 #endif
194                 IH_INIT(lh, device, parentId, *(p->inode));
195                 fdP = IH_OPEN(lh);
196                 if (fdP == NULL) {
197                     IH_RELEASE(lh);
198                     goto bad;
199                 }
200                 code = IH_INC(lh, *(p->inode), parentId);
201                 FDH_REALLYCLOSE(fdP);
202                 IH_RELEASE(lh);
203                 if (code<0)
204                     goto bad;
205                 continue;
206             }
207         }
208 #else
209         *(p->inode) = IH_CREATE(NULL, device, VPartitionPath(partition),
210                                 nearInode, vol.id, INODESPECIAL, p->inodeType,
211                                 vol.parentId);
212 #endif
213  
214         if (!VALID_INO(*(p->inode))) {
215             Log("VCreateVolume:  Problem creating %s file associated with volume header %s\n", p->description, volumePath);
216           bad:
217             if(handle)
218                 IH_RELEASE(handle);
219             RemoveInodes(device, vol.id);
220             *ec = VNOVOL;
221             close(fd);
222             return NULL;
223         }
224         IH_INIT(handle, device, vol.parentId, *(p->inode));
225         fdP = IH_OPEN(handle);
226         if (fdP == NULL) {
227             Log("VCreateVolume:  Problem iopen inode %s (err=%d)\n",
228                 PrintInode(NULL, *(p->inode)), errno);
229            goto bad;
230        }
231        if (FDH_SEEK(fdP, 0, SEEK_SET) < 0) {
232            Log("VCreateVolume:  Problem lseek inode %s (err=%d)\n",
233                PrintInode(NULL, *(p->inode)), errno);
234            FDH_REALLYCLOSE(fdP);
235            goto bad;
236        }
237        if (FDH_WRITE(fdP, (char*)&p->stamp, sizeof(p->stamp)) != sizeof(p->stamp)) {
238            Log("VCreateVolume:  Problem writing to  inode %s (err=%d)\n",
239                PrintInode(NULL, *(p->inode)), errno);
240            FDH_REALLYCLOSE(fdP);
241            goto bad;
242        }
243         FDH_REALLYCLOSE(fdP);
244         IH_RELEASE(handle);
245        nearInode = *(p->inode);
246     }
247
248     IH_INIT(handle, device, vol.parentId, tempHeader.volumeInfo);
249     fdP = IH_OPEN(handle);
250     if (fdP == NULL) {
251         Log("VCreateVolume:  Problem iopen inode %d (err=%d)\n", tempHeader.volumeInfo, errno);
252         unlink(volumePath);
253         goto bad;
254        }
255     if (FDH_SEEK(fdP, 0, SEEK_SET) < 0) {
256         Log("VCreateVolume:  Problem lseek inode %d (err=%d)\n", tempHeader.volumeInfo, errno);
257         FDH_REALLYCLOSE(fdP);
258         unlink(volumePath);
259         goto bad;
260        }
261     if (FDH_WRITE(fdP, (char*)&vol, sizeof(vol)) != sizeof(vol)) {
262         Log("VCreateVolume:  Problem writing to  inode %d (err=%d)\n", tempHeader.volumeInfo, errno);
263         FDH_REALLYCLOSE(fdP);
264         unlink(volumePath);
265         goto bad;
266        }
267     FDH_CLOSE(fdP);
268     IH_RELEASE(handle);
269
270     VolumeHeaderToDisk(&diskHeader, &tempHeader);
271     if (write(fd, &diskHeader, sizeof (diskHeader)) != sizeof (diskHeader)) {
272         Log("VCreateVolume: Unable to write volume header %s; volume %u not created\n", volumePath, vol.id);
273         unlink(volumePath);
274         goto bad;
275     }
276     fsync(fd);
277     close(fd);
278     return (VAttachVolumeByName(ec, partname, headerName, V_SECRETLY));
279 }
280
281
282 AssignVolumeName(vol, name, ext)
283     register VolumeDiskData *vol;
284     char *name,*ext;
285 {
286     VOL_LOCK
287     AssignVolumeName_r(vol, name, ext);
288     VOL_UNLOCK
289 }
290
291 AssignVolumeName_r(vol, name, ext)
292     register VolumeDiskData *vol;
293     char *name,*ext;
294 {
295     register char *dot;
296     strncpy(vol->name, name, VNAMESIZE-1);
297     vol->name[VNAMESIZE-1] = '\0';
298     dot = strrchr(vol->name, '.');
299     if (dot && (strcmp(dot,".backup") == 0 || strcmp(dot, ".readonly") == 0))
300         *dot = 0;
301     if (ext)
302         strncat(vol->name, ext, VNAMESIZE-1-strlen(vol->name));
303 }
304
305 afs_int32 CopyVolumeHeader_r(from, to)
306     VolumeDiskData *from, *to;
307 {
308     /* The id and parentId fields are not copied; these are inviolate--the to volume
309        is assumed to have already been created.  The id's cannot be changed once
310        creation has taken place, since they are embedded in the various inodes associated
311        with the volume.  The copydate is also inviolate--it always reflects the time
312        this volume was created (compare with the creation date--the creation date of
313        a backup volume is the creation date of the original parent, because the backup
314        is used to backup the parent volume). */
315     Date copydate;
316     VolumeId id, parent;
317     id = to->id;
318     parent = to->parentId;
319     copydate = to->copyDate;
320     memcpy(to, from, sizeof(*from));
321     to->id = id;
322     to->parentId = parent;
323     to->copyDate = copydate;
324     to->destroyMe = DESTROY_ME; /* Caller must always clear this!!! */
325     to->stamp.magic = VOLUMEINFOMAGIC;
326     to->stamp.version = VOLUMEINFOVERSION;
327     return 0;
328 }
329
330 afs_int32 CopyVolumeHeader(from, to)
331     VolumeDiskData *from, *to;
332 {
333     afs_int32 code;
334
335     VOL_LOCK
336     code = CopyVolumeHeader_r(from, to);
337     VOL_UNLOCK
338     return(code);
339 }
340
341 ClearVolumeStats(vol)
342     register VolumeDiskData *vol;
343 {
344     VOL_LOCK
345     ClearVolumeStats_r(vol);
346     VOL_UNLOCK
347 }
348
349 ClearVolumeStats_r(vol)
350     register VolumeDiskData *vol;
351 {
352     memset(vol->weekUse, 0, sizeof(vol->weekUse));
353     vol->dayUse = 0;
354     vol->dayUseDate = 0;
355 }