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