splint-fileserver-volserver-cleanup-20030602
[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 void AssignVolumeName();
68 void AssignVolumeName_r();
69 void ClearVolumeStats();
70 void ClearVolumeStats_r();
71
72
73 #define nFILES  (sizeof (stuff)/sizeof(struct stuff))
74
75 /* Note:  the volume creation functions herein leave the destroyMe flag in the
76    volume header ON:  this means that the volumes will not be attached by the
77    file server and WILL BE DESTROYED the next time a system salvage is performed */
78
79 static void RemoveInodes(Device dev, VolumeId vid)
80 {
81     register int i;
82     IHandle_t *handle;
83
84     /* This relies on the fact that IDEC only needs the device and NT only
85      * needs the dev and vid to decrement volume special files.
86      */
87     IH_INIT(handle, dev, vid, -1);
88     for (i = 0; i<nFILES; i++) {
89         Inode inode = *stuff[i].inode;
90         if (VALID_INO(inode))
91             IH_DEC(handle, inode, vid);
92     }
93     IH_RELEASE(handle);
94 }
95
96 Volume *VCreateVolume(ec, partname, volumeId, parentId)
97     Error *ec;
98     char *partname;
99     VolId volumeId;
100     VolId parentId;     /* Should be the same as volumeId if there is
101                            no parent */
102 {
103     Volume *retVal;
104     VOL_LOCK
105     retVal = VCreateVolume_r(ec, partname, volumeId, parentId);
106     VOL_UNLOCK
107     return retVal;
108 }
109
110 Volume *VCreateVolume_r(ec, partname, volumeId, parentId)
111     Error *ec;
112     char *partname;
113     VolId volumeId;
114     VolId parentId;     /* Should be the same as volumeId if there is
115                            no parent */
116 {
117     VolumeDiskData vol;
118     int fd, i;
119     char headerName[32], volumePath[64];
120     Device device;
121     struct DiskPartition *partition;
122     struct VolumeDiskHeader diskHeader;
123     IHandle_t *handle;
124     FdHandle_t *fdP;
125     Inode nearInode=0; 
126
127     *ec = 0;
128     memset(&vol, 0, sizeof (vol));
129     vol.id = volumeId;
130     vol.parentId = parentId;
131     vol.copyDate = time(0);     /* The only date which really means when this
132                                    @i(instance) of this volume was created.
133                                    Creation date does not mean this */
134
135     /* Initialize handle for error case below. */
136     handle = NULL;
137
138     /* Verify that the parition is valid before writing to it. */
139     if (!(partition = VGetPartition(partname, 0))) {
140         Log("VCreateVolume: partition %s is not in service.\n", partname);
141         *ec = VNOVOL;
142         return NULL;
143     }
144 #if     defined(NEARINODE_HINT)
145     nearInodeHash(volumeId,nearInode);
146     nearInode %= partition->f_files;
147 #endif
148     VLockPartition(partname);
149     memset(&tempHeader, 0, sizeof (tempHeader));
150     tempHeader.stamp.magic = VOLUMEHEADERMAGIC;
151     tempHeader.stamp.version = VOLUMEHEADERVERSION;
152     tempHeader.id = vol.id;
153     tempHeader.parent = vol.parentId;
154     vol.stamp.magic = VOLUMEINFOMAGIC;
155     vol.stamp.version = VOLUMEINFOVERSION;
156     vol.destroyMe = DESTROY_ME;
157     sprintf(headerName, VFORMAT, vol.id);
158     sprintf(volumePath, "%s/%s", VPartitionPath(partition), headerName);
159     fd = open(volumePath, O_CREAT|O_EXCL|O_WRONLY, 0600);
160     if (fd == -1) {
161         if (errno == EEXIST) {
162             Log("VCreateVolume: Header file %s already exists!\n", volumePath);
163             *ec = VVOLEXISTS;
164         }
165         else {
166             Log("VCreateVolume: Couldn't create header file %s for volume %u\n", volumePath, vol.id);
167             *ec = VNOVOL;
168         }
169         return NULL;
170     }
171     device = partition->device;
172
173     for (i = 0; i<nFILES; i++) {
174         register struct stuff *p = &stuff[i];
175         if (p->obsolete)
176             continue;
177 #ifdef AFS_NAMEI_ENV
178         *(p->inode) = IH_CREATE(NULL, device, VPartitionPath(partition),
179                                 nearInode, 
180                                 (p->inodeType == VI_LINKTABLE) ? vol.parentId :
181                                 vol.id,
182                                 INODESPECIAL, p->inodeType,
183                                 vol.parentId);
184         if (!(VALID_INO(*(p->inode)))) {
185             if (errno == EEXIST) {
186                 /* Increment the reference count instead. */
187                 IHandle_t *lh;
188                 int code;
189
190 #ifdef AFS_NT40_ENV
191                 *(p->inode) = nt_MakeSpecIno(VI_LINKTABLE);
192 #else
193                 *(p->inode) = namei_MakeSpecIno(vol.parentId, VI_LINKTABLE);
194 #endif
195                 IH_INIT(lh, device, parentId, *(p->inode));
196                 fdP = IH_OPEN(lh);
197                 if (fdP == NULL) {
198                     IH_RELEASE(lh);
199                     goto bad;
200                 }
201                 code = IH_INC(lh, *(p->inode), parentId);
202                 FDH_REALLYCLOSE(fdP);
203                 IH_RELEASE(lh);
204                 if (code<0)
205                     goto bad;
206                 continue;
207             }
208         }
209 #else
210         *(p->inode) = IH_CREATE(NULL, device, VPartitionPath(partition),
211                                 nearInode, vol.id, INODESPECIAL, p->inodeType,
212                                 vol.parentId);
213 #endif
214  
215         if (!VALID_INO(*(p->inode))) {
216             Log("VCreateVolume:  Problem creating %s file associated with volume header %s\n", p->description, volumePath);
217           bad:
218             if(handle)
219                 IH_RELEASE(handle);
220             RemoveInodes(device, vol.id);
221             *ec = VNOVOL;
222             close(fd);
223             return NULL;
224         }
225         IH_INIT(handle, device, vol.parentId, *(p->inode));
226         fdP = IH_OPEN(handle);
227         if (fdP == NULL) {
228             Log("VCreateVolume:  Problem iopen inode %s (err=%d)\n",
229                 PrintInode(NULL, *(p->inode)), errno);
230            goto bad;
231        }
232        if (FDH_SEEK(fdP, 0, SEEK_SET) < 0) {
233            Log("VCreateVolume:  Problem lseek inode %s (err=%d)\n",
234                PrintInode(NULL, *(p->inode)), errno);
235            FDH_REALLYCLOSE(fdP);
236            goto bad;
237        }
238        if (FDH_WRITE(fdP, (char*)&p->stamp, sizeof(p->stamp)) != sizeof(p->stamp)) {
239            Log("VCreateVolume:  Problem writing to  inode %s (err=%d)\n",
240                PrintInode(NULL, *(p->inode)), errno);
241            FDH_REALLYCLOSE(fdP);
242            goto bad;
243        }
244         FDH_REALLYCLOSE(fdP);
245         IH_RELEASE(handle);
246        nearInode = *(p->inode);
247     }
248
249     IH_INIT(handle, device, vol.parentId, tempHeader.volumeInfo);
250     fdP = IH_OPEN(handle);
251     if (fdP == NULL) {
252         Log("VCreateVolume:  Problem iopen inode %d (err=%d)\n", tempHeader.volumeInfo, errno);
253         unlink(volumePath);
254         goto bad;
255        }
256     if (FDH_SEEK(fdP, 0, SEEK_SET) < 0) {
257         Log("VCreateVolume:  Problem lseek inode %d (err=%d)\n", tempHeader.volumeInfo, errno);
258         FDH_REALLYCLOSE(fdP);
259         unlink(volumePath);
260         goto bad;
261        }
262     if (FDH_WRITE(fdP, (char*)&vol, sizeof(vol)) != sizeof(vol)) {
263         Log("VCreateVolume:  Problem writing to  inode %d (err=%d)\n", tempHeader.volumeInfo, errno);
264         FDH_REALLYCLOSE(fdP);
265         unlink(volumePath);
266         goto bad;
267        }
268     FDH_CLOSE(fdP);
269     IH_RELEASE(handle);
270
271     VolumeHeaderToDisk(&diskHeader, &tempHeader);
272     if (write(fd, &diskHeader, sizeof (diskHeader)) != sizeof (diskHeader)) {
273         Log("VCreateVolume: Unable to write volume header %s; volume %u not created\n", volumePath, vol.id);
274         unlink(volumePath);
275         goto bad;
276     }
277     fsync(fd);
278     close(fd);
279     return (VAttachVolumeByName(ec, partname, headerName, V_SECRETLY));
280 }
281
282
283 void
284 AssignVolumeName(vol, name, ext)
285     register VolumeDiskData *vol;
286     char *name,*ext;
287 {
288     VOL_LOCK
289     AssignVolumeName_r(vol, name, ext);
290     VOL_UNLOCK
291 }
292
293 void
294 AssignVolumeName_r(vol, name, ext)
295     register VolumeDiskData *vol;
296     char *name,*ext;
297 {
298     register char *dot;
299     strncpy(vol->name, name, VNAMESIZE-1);
300     vol->name[VNAMESIZE-1] = '\0';
301     dot = strrchr(vol->name, '.');
302     if (dot && (strcmp(dot,".backup") == 0 || strcmp(dot, ".readonly") == 0))
303         *dot = 0;
304     if (ext)
305         strncat(vol->name, ext, VNAMESIZE-1-strlen(vol->name));
306 }
307
308 afs_int32 CopyVolumeHeader_r(from, to)
309     VolumeDiskData *from, *to;
310 {
311     /* The id and parentId fields are not copied; these are inviolate--the to volume
312        is assumed to have already been created.  The id's cannot be changed once
313        creation has taken place, since they are embedded in the various inodes associated
314        with the volume.  The copydate is also inviolate--it always reflects the time
315        this volume was created (compare with the creation date--the creation date of
316        a backup volume is the creation date of the original parent, because the backup
317        is used to backup the parent volume). */
318     Date copydate;
319     VolumeId id, parent;
320     id = to->id;
321     parent = to->parentId;
322     copydate = to->copyDate;
323     memcpy(to, from, sizeof(*from));
324     to->id = id;
325     to->parentId = parent;
326     to->copyDate = copydate;
327     to->destroyMe = DESTROY_ME; /* Caller must always clear this!!! */
328     to->stamp.magic = VOLUMEINFOMAGIC;
329     to->stamp.version = VOLUMEINFOVERSION;
330     return 0;
331 }
332
333 afs_int32 CopyVolumeHeader(from, to)
334     VolumeDiskData *from, *to;
335 {
336     afs_int32 code;
337
338     VOL_LOCK
339     code = CopyVolumeHeader_r(from, to);
340     VOL_UNLOCK
341     return(code);
342 }
343
344 void
345 ClearVolumeStats(vol)
346     register VolumeDiskData *vol;
347 {
348     VOL_LOCK
349     ClearVolumeStats_r(vol);
350     VOL_UNLOCK
351 }
352
353 void
354 ClearVolumeStats_r(vol)
355     register VolumeDiskData *vol;
356 {
357     memset(vol->weekUse, 0, sizeof(vol->weekUse));
358     vol->dayUse = 0;
359     vol->dayUseDate = 0;
360 }