38d7e1f97a6fb9dc98c6758bbd197e6ca3fdab97
[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
21     ("$Header$");
22
23 #include <stdio.h>
24 #include <sys/types.h>
25 #include <errno.h>
26 #ifdef AFS_NT40_ENV
27 #include <time.h>
28 #include <fcntl.h>
29 #else
30 #include <sys/time.h>
31 #include <sys/file.h>
32 #include <unistd.h>
33 #endif
34 #include <sys/stat.h>
35 #ifdef AFS_PTHREAD_ENV
36 #include <assert.h>
37 #else /* AFS_PTHREAD_ENV */
38 #include <afs/assert.h>
39 #endif /* AFS_PTHREAD_ENV */
40
41 #include <rx/xdr.h>
42 #include <afs/afsint.h>
43 #include "nfs.h"
44 #include <afs/errors.h>
45 #include "lock.h"
46 #include "lwp.h"
47 #include <afs/afssyscalls.h>
48 #include "ihandle.h"
49 #include <afs/afsutil.h>
50 #ifdef AFS_NT40_ENV
51 #include "ntops.h"
52 #include <io.h>
53 #endif
54 #include "vnode.h"
55 #include "volume.h"
56 #include "partition.h"
57 #include "viceinode.h"
58
59 #include "volinodes.h"
60 #ifdef  AFS_AIX_ENV
61 #include <sys/lockf.h>
62 #endif
63 #if defined(AFS_SUN5_ENV) || defined(AFS_NT40_ENV) || defined(AFS_LINUX20_ENV)
64 #include <string.h>
65 #else
66 #include <strings.h>
67 #endif
68
69 #ifdef O_LARGEFILE
70 #define afs_open        open64
71 #else /* !O_LARGEFILE */
72 #define afs_open        open
73 #endif /* !O_LARGEFILE */
74
75 /*@printflike@*/ extern void Log(const char *format, ...);
76
77 void AssignVolumeName(register VolumeDiskData * vol, char *name, char *ext);
78 void AssignVolumeName_r(register VolumeDiskData * vol, char *name, char *ext);
79 void ClearVolumeStats(register VolumeDiskData * vol);
80 void ClearVolumeStats_r(register VolumeDiskData * vol);
81
82
83 #define nFILES  (sizeof (stuff)/sizeof(struct stuff))
84
85 /* Note:  the volume creation functions herein leave the destroyMe flag in the
86    volume header ON:  this means that the volumes will not be attached by the
87    file server and WILL BE DESTROYED the next time a system salvage is performed */
88
89 static void
90 RemoveInodes(Device dev, VolumeId vid)
91 {
92     register int i;
93     IHandle_t *handle;
94
95     /* This relies on the fact that IDEC only needs the device and NT only
96      * needs the dev and vid to decrement volume special files.
97      */
98     IH_INIT(handle, dev, vid, -1);
99     for (i = 0; i < nFILES; i++) {
100         Inode inode = *stuff[i].inode;
101         if (VALID_INO(inode))
102             IH_DEC(handle, inode, vid);
103     }
104     IH_RELEASE(handle);
105 }
106
107 Volume *
108 VCreateVolume(Error * ec, char *partname, VolId volumeId, VolId parentId)
109 {                               /* Should be the same as volumeId if there is
110                                  * no parent */
111     Volume *retVal;
112     VOL_LOCK;
113     retVal = VCreateVolume_r(ec, partname, volumeId, parentId);
114     VOL_UNLOCK;
115     return retVal;
116 }
117
118 Volume *
119 VCreateVolume_r(Error * ec, char *partname, VolId volumeId, VolId parentId)
120 {                               /* Should be the same as volumeId if there is
121                                  * no parent */
122     VolumeDiskData vol;
123     int fd, i;
124     char headerName[32], volumePath[64];
125     Device device;
126     struct DiskPartition *partition;
127     struct VolumeDiskHeader diskHeader;
128     IHandle_t *handle;
129     FdHandle_t *fdP;
130     Inode nearInode = 0;
131
132     *ec = 0;
133     memset(&vol, 0, sizeof(vol));
134     vol.id = volumeId;
135     vol.parentId = parentId;
136     vol.copyDate = time(0);     /* The only date which really means when this
137                                  * @i(instance) of this volume was created.
138                                  * Creation date does not mean this */
139
140     /* Initialize handle for error case below. */
141     handle = NULL;
142
143     /* Verify that the parition is valid before writing to it. */
144     if (!(partition = VGetPartition_r(partname, 0))) {
145         Log("VCreateVolume: partition %s is not in service.\n", partname);
146         *ec = VNOVOL;
147         return NULL;
148     }
149 #if     defined(NEARINODE_HINT)
150     nearInodeHash(volumeId, nearInode);
151     nearInode %= partition->f_files;
152 #endif
153     VLockPartition_r(partname);
154     memset(&tempHeader, 0, sizeof(tempHeader));
155     tempHeader.stamp.magic = VOLUMEHEADERMAGIC;
156     tempHeader.stamp.version = VOLUMEHEADERVERSION;
157     tempHeader.id = vol.id;
158     tempHeader.parent = vol.parentId;
159     vol.stamp.magic = VOLUMEINFOMAGIC;
160     vol.stamp.version = VOLUMEINFOVERSION;
161     vol.destroyMe = DESTROY_ME;
162     (void)afs_snprintf(headerName, sizeof headerName, VFORMAT, vol.id);
163     (void)afs_snprintf(volumePath, sizeof volumePath, "%s/%s",
164                        VPartitionPath(partition), headerName);
165     fd = afs_open(volumePath, O_CREAT | O_EXCL | O_WRONLY, 0600);
166     if (fd == -1) {
167         if (errno == EEXIST) {
168             Log("VCreateVolume: Header file %s already exists!\n",
169                 volumePath);
170             *ec = VVOLEXISTS;
171         } else {
172             Log("VCreateVolume: Couldn't create header file %s for volume %u\n", volumePath, vol.id);
173             *ec = VNOVOL;
174         }
175         return NULL;
176     }
177     device = partition->device;
178
179     for (i = 0; i < nFILES; i++) {
180         register struct stuff *p = &stuff[i];
181         if (p->obsolete)
182             continue;
183 #ifdef AFS_NAMEI_ENV
184         *(p->inode) =
185             IH_CREATE(NULL, device, VPartitionPath(partition), nearInode,
186                       (p->inodeType == VI_LINKTABLE) ? vol.parentId : vol.id,
187                       INODESPECIAL, p->inodeType, vol.parentId);
188         if (!(VALID_INO(*(p->inode)))) {
189             if (errno == EEXIST) {
190                 /* Increment the reference count instead. */
191                 IHandle_t *lh;
192                 int code;
193
194 #ifdef AFS_NT40_ENV
195                 *(p->inode) = nt_MakeSpecIno(VI_LINKTABLE);
196 #else
197                 *(p->inode) = namei_MakeSpecIno(vol.parentId, VI_LINKTABLE);
198 #endif
199                 IH_INIT(lh, device, parentId, *(p->inode));
200                 fdP = IH_OPEN(lh);
201                 if (fdP == NULL) {
202                     IH_RELEASE(lh);
203                     goto bad;
204                 }
205                 code = IH_INC(lh, *(p->inode), parentId);
206                 FDH_REALLYCLOSE(fdP);
207                 IH_RELEASE(lh);
208                 if (code < 0)
209                     goto bad;
210                 continue;
211             }
212         }
213 #else
214         *(p->inode) =
215             IH_CREATE(NULL, device, VPartitionPath(partition), nearInode,
216                       vol.id, INODESPECIAL, p->inodeType, vol.parentId);
217 #endif
218
219         if (!VALID_INO(*(p->inode))) {
220             Log("VCreateVolume:  Problem creating %s file associated with volume header %s\n", p->description, volumePath);
221           bad:
222             if (handle)
223                 IH_RELEASE(handle);
224             RemoveInodes(device, vol.id);
225             *ec = VNOVOL;
226             close(fd);
227             return NULL;
228         }
229         IH_INIT(handle, device, vol.parentId, *(p->inode));
230         fdP = IH_OPEN(handle);
231         if (fdP == NULL) {
232             Log("VCreateVolume:  Problem iopen inode %s (err=%d)\n",
233                 PrintInode(NULL, *(p->inode)), errno);
234             goto bad;
235         }
236         if (FDH_SEEK(fdP, 0, SEEK_SET) < 0) {
237             Log("VCreateVolume:  Problem lseek inode %s (err=%d)\n",
238                 PrintInode(NULL, *(p->inode)), errno);
239             FDH_REALLYCLOSE(fdP);
240             goto bad;
241         }
242         if (FDH_WRITE(fdP, (char *)&p->stamp, sizeof(p->stamp)) !=
243             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 %s (err=%d)\n",
258             PrintInode(NULL, 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 %s (err=%d)\n",
264             PrintInode(NULL, 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 %s (err=%d)\n",
271             PrintInode(NULL, 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_r(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
313 CopyVolumeHeader_r(VolumeDiskData * from, VolumeDiskData * to)
314 {
315     /* The id and parentId fields are not copied; these are inviolate--the to volume
316      * is assumed to have already been created.  The id's cannot be changed once
317      * creation has taken place, since they are embedded in the various inodes associated
318      * with the volume.  The copydate is also inviolate--it always reflects the time
319      * this volume was created (compare with the creation date--the creation date of
320      * a backup volume is the creation date of the original parent, because the backup
321      * is used to backup the parent volume). */
322     Date copydate;
323     VolumeId id, parent;
324     id = to->id;
325     parent = to->parentId;
326     copydate = to->copyDate;
327     memcpy(to, from, sizeof(*from));
328     to->id = id;
329     to->parentId = parent;
330     to->copyDate = copydate;
331     to->destroyMe = DESTROY_ME; /* Caller must always clear this!!! */
332     to->stamp.magic = VOLUMEINFOMAGIC;
333     to->stamp.version = VOLUMEINFOVERSION;
334     return 0;
335 }
336
337 afs_int32
338 CopyVolumeHeader(VolumeDiskData * from, VolumeDiskData * to)
339 {
340     afs_int32 code;
341
342     VOL_LOCK;
343     code = CopyVolumeHeader_r(from, to);
344     VOL_UNLOCK;
345     return (code);
346 }
347
348 void
349 ClearVolumeStats(register VolumeDiskData * vol)
350 {
351     VOL_LOCK;
352     ClearVolumeStats_r(vol);
353     VOL_UNLOCK;
354 }
355
356 void
357 ClearVolumeStats_r(register VolumeDiskData * vol)
358 {
359     memset(vol->weekUse, 0, sizeof(vol->weekUse));
360     vol->dayUse = 0;
361     vol->dayUseDate = 0;
362 }