2030a928c807e101850c17e68bed0cd98fb6654b
[openafs.git] / src / uss / uss_fs.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  *      Implementation of the AFS system operations exported by the
12  *      Cache Manager.
13  */
14
15 /*
16  * --------------------- Required definitions ---------------------
17  */
18 #include <afsconfig.h>
19 #include <afs/param.h>
20
21
22 #include "uss_fs.h"             /*Interface to this module */
23 #include <sys/types.h>
24 #include <errno.h>
25 #include <sys/socket.h>
26 #ifdef  AFS_SUN5_ENV
27 #include <sys/ioccom.h>
28 #endif
29 #include <netinet/in.h>
30
31 #include <string.h>
32 #include <unistd.h>
33
34 #include <afs/venus.h>
35 #include <rx/rx.h>
36 #include <afs/sys_prototypes.h>
37 #include "uss_common.h"
38
39
40 /*
41  * ---------------------- Private definitions ---------------------
42  */
43 #undef USS_FS_DB
44
45
46 /*
47  * ------------------------ Private globals -----------------------
48  */
49 static struct ViceIoctl blob;   /*Param-passing area */
50 static struct ViceIoctl *blobP = &blob; /*Ptr to above */
51
52
53 /*------------------------------------------------------------------------
54  * static InAFS
55  *
56  * Description:
57  *      Is the given pathname in AFS?
58  *
59  * Arguments:
60  *      a_path : Pathname to examine.
61  *
62  * Returns:
63  *      0 if the pathname is NOT in AFS,
64  *      1 if it is.
65  *
66  * Environment:
67  *      Nothing interesting.
68  *
69  * Side Effects:
70  *      As advertised.
71  *------------------------------------------------------------------------*/
72
73 static int
74 InAFS(char *a_path)
75 {                               /*InAFS */
76     afs_int32 code;
77
78     blob.in = NULL;
79     blob.in_size = 0;
80     blob.out_size = USS_FS_MAX_SIZE;
81     blob.out = uss_fs_OutBuff;
82
83     code = pioctl(a_path, VIOC_FILE_CELL_NAME, blobP, 1);
84     if (code) {
85         if ((errno == EINVAL) || (errno == ENOENT))
86             return (0);
87     }
88     return (1);
89
90 }                               /*InAFS */
91
92
93 /*------------------------------------------------------------------------
94  * static ParentAndComponent
95  *
96  * Description:
97  *      Calculate the parent directory of the given pathname, along
98  *      with the final component.
99  *
100  * Arguments:
101  *      char *a_path         : Pathname to ancestorize.
102  *      char *a_parentBuff   : Ptr to parent buffer to use.
103  *      char **a_componentPP : Ptr to the final component.
104  *
105  *
106  * Returns:
107  *      Ptr to the buffer containing the parent dir name.
108  *
109  * Environment:
110  *      Nothing interesting.
111  *
112  * Side Effects:
113  *      As advertised.
114  *------------------------------------------------------------------------*/
115
116 static char *
117 ParentAndComponent(char *a_path, char *a_parentBuff, char **a_componentPP)
118 {                               /*ParentAndComponent */
119     char *rightSlashP;
120
121     /*
122      * Copy over the original pathname, then find the location of the
123      * rightmost slash.  If there is one, we chop off the string at
124      * point.  Otherwise, it is a single pathname component whose
125      * parent must be the current working directory.  In this case,
126      * we cheat and return ``.''.
127      */
128     strcpy(a_parentBuff, a_path);
129     rightSlashP = (char *)strrchr(a_parentBuff, '/');
130     if (rightSlashP) {
131         *rightSlashP = 0;
132         *a_componentPP = rightSlashP + 1;
133     } else {
134         strcpy(a_parentBuff, ".");
135         *a_componentPP = a_path;
136     }
137
138     return (a_parentBuff);
139
140 }                               /*ParentAndComponent */
141
142
143 /*------------------------------------------------------------------------
144  * static CarefulPioctl
145  *
146  * Description:
147  *      Execute a pioctl(), but be careful to refresh the Cache Manager's
148  *      volume mapping in case we get an ENODEV the first time.
149  *
150  * Arguments:
151  *      char *a_path              : pioctl() pathname argument.
152  *      int a_opcode              : pioctl() opcode.
153  *      struct ViceIoctl *a_blobP : pioctl() blob pointer.
154  *      int a_sl                  : pioctl() symlink info.
155  *
156  * Returns:
157  *      Whatever the pioctl() returned, either the after the first
158  *      call if we didn't get an ENODEV, or the results of the second
159  *      call if we did.
160  *
161  * Environment:
162  *      Nothing interesting.
163  *
164  * Side Effects:
165  *      As advertised.
166  *------------------------------------------------------------------------*/
167
168 static int
169 CarefulPioctl(char *a_path, int a_opcode, struct ViceIoctl *a_blobP, int a_sl)
170 {                               /*CarefulPioctl */
171 #ifdef USS_FS_DB
172     static char rn[] = "uss_fs:CarefulPioctl";
173 #endif
174     afs_int32 code;
175
176     /*
177      * Call the pioctl() the first time, return if things worked
178      * out ``normally''.
179      */
180 #ifdef USS_FS_DB
181     printf("%s: First pioctl call\n", rn);
182 #endif /* USS_FS_DB */
183     code = pioctl(a_path, a_opcode, a_blobP, a_sl);
184 #ifdef USS_FS_DB
185     if (code)
186         printf("%s: First pioctl call fails, errno is %d\n", rn, errno);
187 #endif /* USS_FS_DB */
188     if ((code == 0) || (code && (errno != ENODEV)))
189         return (code);
190
191     /*
192      * Hmm, it's possible out volume mappings are stale.  Let's
193      * bring them up to date, then try again.
194      */
195 #ifdef USS_FS_DB
196     printf("%s: First pioctl got a NODEV\n", rn);
197 #endif /* USS_FS_DB */
198     code = uss_fs_CkBackups();
199     code = pioctl(a_path, a_opcode, a_blobP, a_sl);
200     return (code);
201
202 }                               /*CarefulPioctl */
203
204
205 /*------------------------------------------------------------------------
206  * EXPORTED uss_fs_GetACL
207  *
208  * Environment:
209  *      Nothing interesting.
210  *
211  * Side Effects:
212  *      As advertised.
213  *------------------------------------------------------------------------*/
214
215 afs_int32
216 uss_fs_GetACL(char *a_dirPath, char *a_aclBuff, afs_int32 a_aclBuffBytes)
217 {                               /*uss_fs_GetACL */
218 #ifdef USS_FS_DB
219     static char rn[] = "uss_fs_GetACL"; /*Routine name */
220 #endif
221     afs_int32 code;     /*pioctl() result */
222
223     blob.in = NULL;
224     blob.in_size = 0;
225     blob.out = a_aclBuff;
226     blob.out_size = a_aclBuffBytes;
227
228 #ifdef USS_FS_DB
229     printf("%s: in 0x%x (%d bytes), out 0x%x, (%d bytes)\n", rn, blob.in,
230            blob.in_size, blob.out, blob.out_size);
231 #endif /* USS_FS_DB */
232
233     code = CarefulPioctl(a_dirPath, VIOCGETAL, blobP, 1);
234
235 #ifdef USS_FS_DB
236     if (code)
237         printf("%s: pioctl() failed, errno %d\n", rn, errno);
238 #endif /* USS_FS_DB */
239
240     return (code);
241
242 }                               /*uss_fs_GetACL */
243
244
245 /*------------------------------------------------------------------------
246  * EXPORTED uss_fs_SetACL
247  *
248  * Environment:
249  *      Nothing interesting.
250  *
251  * Side Effects:
252  *      As advertised.
253  *------------------------------------------------------------------------*/
254
255 afs_int32
256 uss_fs_SetACL(char *a_dirPath, char *a_aclBuff, afs_int32 a_aclBuffBytes)
257 {                               /*uss_fs_SetACL */
258 #ifdef USS_FS_DB
259     static char rn[] = "uss_fs_SetACL"; /*Routine name */
260 #endif
261     afs_int32 code;     /*pioctl() result */
262
263     blob.in = a_aclBuff;
264     blob.in_size = a_aclBuffBytes;
265     blob.out = NULL;
266     blob.out_size = 0;
267
268 #ifdef USS_FS_DB
269     printf("%s: in 0x%x (%d bytes), out 0x%x, (%d bytes)\n", rn, blob.in,
270            blob.in_size, blob.out, blob.out_size);
271     printf("%s: ACL value for dir '%s' is '%s'\n", rn, a_dirPath, a_aclBuff);
272 #endif /* USS_FS_DB */
273
274     code = CarefulPioctl(a_dirPath, VIOCSETAL, blobP, 1);
275
276 #ifdef USS_FS_DB
277     if (code)
278         printf("%s: pioctl() failed, errno %d", rn, errno);
279 #endif /* USS_FS_DB */
280
281     return (code);
282
283 }                               /*uss_fs_SetACL */
284
285
286 /*------------------------------------------------------------------------
287  * EXPORTED uss_fs_GetVolStat
288  *
289  * Environment:
290  *      Nothing interesting.
291  *
292  * Side Effects:
293  *      As advertised.
294  *------------------------------------------------------------------------*/
295
296 afs_int32
297 uss_fs_GetVolStat(char *a_mountpoint, char *a_volStatBuff,
298                   afs_int32 a_volStatBuffBytes)
299 {                               /*uss_fs_GetVolStat */
300 #ifdef USS_FS_DB
301     static char rn[] = "uss_fs_GetVolStat";     /*Routine name */
302 #endif
303     afs_int32 code;     /*pioctl() result */
304
305     blob.in = NULL;
306     blob.in_size = 0;
307     blob.out = a_volStatBuff;
308     blob.out_size = a_volStatBuffBytes;
309
310 #ifdef USS_FS_DB
311     printf("%s: in 0x%x (%d bytes), out 0x%x, (%d bytes)\n", rn, blob.in,
312            blob.in_size, blob.out, blob.out_size);
313 #endif /* USS_FS_DB */
314
315     code = CarefulPioctl(a_mountpoint, VIOCGETVOLSTAT, blobP, 1);
316
317 #ifdef USS_FS_DB
318     if (code)
319         printf("%s: pioctl() failed, errno %d", rn, errno);
320 #endif /* USS_FS_DB */
321
322     return (code);
323
324 }                               /*uss_fs_GetVolStat */
325
326
327 /*------------------------------------------------------------------------
328  * EXPORTED uss_fs_SetVolStat
329  *
330  * Environment:
331  *      Nothing interesting.
332  *
333  * Side Effects:
334  *      As advertised.
335  *------------------------------------------------------------------------*/
336
337 afs_int32
338 uss_fs_SetVolStat(char *a_mountpoint, char *a_volStatBuff,
339                   afs_int32 a_volStatBuffBytes)
340 {                               /*uss_fs_SetVolStat */
341 #ifdef USS_FS_DB
342     static char rn[] = "uss_fs_SetVolStat";     /*Routine name */
343 #endif
344     afs_int32 code;     /*pioctl() result */
345
346     blob.in = a_volStatBuff;
347     blob.in_size = a_volStatBuffBytes;
348     blob.out = a_volStatBuff;
349     blob.out_size = USS_FS_MAX_SIZE;
350
351 #ifdef USS_FS_DB
352     printf("%s: in 0x%x (%d bytes), out 0x%x, (%d bytes)\n", rn, blob.in,
353            blob.in_size, blob.out, blob.out_size);
354 #endif /* USS_FS_DB */
355
356     code = CarefulPioctl(a_mountpoint, VIOCSETVOLSTAT, blobP, 1);
357
358 #ifdef USS_FS_DB
359     if (code)
360         printf("%s: pioctl() failed, errno %d", rn, errno);
361 #endif /* USS_FS_DB */
362
363     return (code);
364
365 }                               /*uss_fs_SetVolStat */
366
367
368 /*------------------------------------------------------------------------
369  * EXPORTED uss_fs_CkBackups
370  *
371  * Environment:
372  *      We are NOT careful here, since it's OK to get ENODEVs.
373  *
374  * Side Effects:
375  *      As advertised.
376  *------------------------------------------------------------------------*/
377
378 afs_int32
379 uss_fs_CkBackups(void)
380 {                               /*uss_fs_CkBackups */
381 #ifdef USS_FS_DB
382     static char rn[] = "uss_fs_CkBackups";      /*Routine name */
383 #endif
384     afs_int32 code;     /*pioctl() result */
385
386     blob.in = NULL;
387     blob.in_size = 0;
388     blob.out = NULL;
389     blob.out_size = 0;
390
391 #ifdef USS_FS_DB
392     printf("%s: in 0x%x (%d bytes), out 0x%x, (%d bytes)\n", rn, blob.in,
393            blob.in_size, blob.out, blob.out_size);
394 #endif /* USS_FS_DB */
395
396     code = pioctl(NULL,         /*No pathname needed here */
397                   VIOCCKBACK,   /*CheckBackups */
398                   &blob,        /*Params */
399                   1);           /*Symlink disposition */
400 #ifdef USS_FS_DB
401     if (code)
402         printf("%s: pioctl() failed, errno %d", rn, errno);
403 #endif /* USS_FS_DB */
404
405     return (code);
406
407 }                               /*uss_fs_CkBackups */
408
409
410 /*------------------------------------------------------------------------
411  * EXPORTED uss_fs_MkMountPoint
412  *
413  * Environment:
414  *      Uses uss_fs_OutBuff to construct the mountpoint contents.
415  *
416  * Side Effects:
417  *      As advertised.
418  *------------------------------------------------------------------------*/
419
420 afs_int32
421 uss_fs_MkMountPoint(char *a_volname, char *a_cellname, afs_int32 a_rw,
422                     char *a_mountpoint)
423 {                               /*uss_fs_MkMountPoint */
424     extern int local_Cell;
425     static char rn[] = "uss_fs_MkMountPoint";   /*Routine name */
426     afs_int32 code;     /*pioctl() result */
427     char *tp;                   /*Temporary */
428
429 #ifdef USS_FS_DB
430     printf
431         ("%s: a_volname='%s', a_cellname='%s', a_rw=%d, a_mountpoint='%s'\n",
432          rn, a_volname, a_cellname, a_rw, a_mountpoint);
433 #endif /* USS_FS_DB */
434
435     /*
436      * Make sure the parent directory is in AFS.
437      */
438     if (!InAFS(ParentAndComponent(a_mountpoint, uss_fs_OutBuff, &tp))) {
439         printf("%s: Mountpoints must be created within AFS\n", rn);
440         return (-1);
441     }
442
443     /*
444      * Build the contents of the mountpoint we'll create.  It's safe to
445      * use the uss_fs_OutBuff for this construction.  Note: the last
446      * char, by convention, is a dot.
447      */
448     if (local_Cell) {
449         sprintf(uss_fs_OutBuff, "%s%s.", (a_rw ? "%" : "#"), a_volname);
450     } else {
451         sprintf(uss_fs_OutBuff, "%s%s:%s.", (a_rw ? "%" : "#"), a_cellname,
452                 a_volname);
453     }
454
455     /*
456      * Now, create the symlink with the above value.
457      */
458     code = symlink(uss_fs_OutBuff, a_mountpoint);
459     if (code) {
460 #ifdef USS_FS_DB
461         printf("%s: Mountpoint creation (symlink) failed, errno is %d\n", rn,
462                errno);
463 #endif /* USS_FS_DB */
464         return (-1);
465     }
466     return 0;
467 }                               /*uss_fs_MkMountPoint */
468
469
470 /*------------------------------------------------------------------------
471  * EXPORTED uss_fs_RmMountPoint
472  *
473  * Environment:
474  *      Nothing interesting.
475  *
476  * Side Effects:
477  *      As advertised.
478  *------------------------------------------------------------------------*/
479
480 afs_int32
481 uss_fs_RmMountPoint(char *a_mountpoint)
482 {                               /*uss_fs_RmMountPoint */
483     static char rn[] = "uss_fs_RmMountPoint";   /*Routine name */
484     afs_int32 code;     /*pioctl() result */
485     char *parentDirP;           /*Ptr to parent */
486     char *componentP;           /*Ptr to last component */
487
488     /*
489      * Get the parent & final component names.
490      */
491     parentDirP = ParentAndComponent(a_mountpoint, uss_fs_InBuff, &componentP);
492
493     blob.in = componentP;
494     blob.in_size = strlen(componentP) + 1;
495     blob.out = uss_fs_OutBuff;
496     blob.out_size = USS_FS_MAX_SIZE;
497
498 #ifdef USS_FS_DB
499     printf("%s: AFS_STAT_MT_PT, in 0x%x (%d bytes), out 0x%x, (%d bytes)\n",
500            rn, blob.in, blob.in_size, blob.out, blob.out_size);
501 #endif /* USS_FS_DB */
502
503     code = CarefulPioctl(parentDirP, VIOC_AFS_STAT_MT_PT, blobP, 1);
504     if (code) {
505 #ifdef USS_FS_DB
506         printf("%s: STAT_MT_PT pioctl() failed, errno %d", rn, errno);
507 #endif /* USS_FS_DB */
508         if (errno == EINVAL)
509             printf("%s: '%s' is not a mountpoint\n", rn, a_mountpoint);
510         return (code);
511     }
512
513     /*
514      * Now that we know we have a proper mountpoint, nuke it.
515      */
516     blob.in = componentP;
517     blob.in_size = strlen(componentP) + 1;
518     blob.out = NULL;
519     blob.out_size = 0;
520
521     if (!uss_DryRun) {
522 #ifdef USS_FS_DB
523         printf
524             ("%s: AFS_DELETE_MT_PT, in 0x%x (%d bytes), out 0x%x, (%d bytes)\n",
525              rn, blob.in, blob.in_size, blob.out, blob.out_size);
526 #endif /* USS_FS_DB */
527
528         code = pioctl(parentDirP, VIOC_AFS_DELETE_MT_PT, blobP, 1);
529         if (code) {
530 #ifdef USS_FS_DB
531             printf("%s: DELETE_MT_PT pioctl() failed, errno %d", rn, errno);
532 #endif /* USS_FS_DB */
533         }
534     } else
535         printf("\t[Dry run - mount point '%s' NOT removed]\n", componentP);
536
537     return (code);
538
539 }                               /*uss_fs_RmMountPoint */
540
541
542 #include <afs/auth.h>
543 struct tokenInfo {
544     struct ktc_token token;
545     struct ktc_principal service;
546     struct ktc_principal client;
547     int deleted;
548 };
549
550 /*
551  * Build a list of tokens, delete the bad ones (the ones to remove from the
552  * permissions list,) destroy all tokens, and then re-register the good ones.
553  * Ugly, but it works.
554  */
555 int
556 uss_fs_UnlogToken(char *celln)
557 {
558     int count = 0, index, index2;
559     afs_int32 code = 0, cnt = 0;
560     struct ktc_principal serviceName;
561     struct tokenInfo *tokenInfoP, *tp;
562
563     do {
564         code = ktc_ListTokens(count, &count, &serviceName);
565         cnt++;
566     } while (!code);
567     count = cnt - 1;
568     tokenInfoP =
569         (struct tokenInfo *)malloc((sizeof(struct tokenInfo) * count));
570     for (code = index = index2 = 0; (!code) && (index < count); index++) {
571         tp = tokenInfoP + index;
572         code = ktc_ListTokens(index2, &index2, &tp->service);
573         if (!code) {
574             code =
575                 ktc_GetToken(&tp->service, &tp->token,
576                              sizeof(struct ktc_token), &tp->client);
577             if (!code) {
578                 tp->deleted = (!strcmp(celln, tp->client.cell) ? 1 : 0);
579                 if (tp->deleted)
580                     cnt = 1;
581             }
582         }
583     }
584     if ((code = ktc_ForgetAllTokens())) {
585         printf("uss_fs_UnlogToken: could not discard tickets, code %d\n",
586                code);
587         exit(1);
588     }
589     for (code = index = 0; index < count; index++) {
590         tp = tokenInfoP + index;
591         if (!(tp->deleted)) {
592             code = ktc_SetToken(&tp->service, &tp->token, &tp->client, 0);
593             if (code) {
594                 printf
595                     ("uss_fs_UnlogToken: Couldn't re-register token, code = %d\n",
596                      code);
597             }
598         }
599     }
600     return 0;
601 }