uss: Suppress more warnings from lex.yy.c
[openafs.git] / src / uss / uss_vol.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 volume operations used by the AFS user
12  *      account facility.
13  */
14
15 /*
16  * --------------------- Required definitions ---------------------
17  */
18 #include <afsconfig.h>
19 #include <afs/param.h>
20
21 #include <roken.h>
22
23 #include <afs/com_err.h>
24 #include <afs/vlserver.h>
25 #include <afs/vldbint.h>
26 #include <afs/auth.h>
27 #include <afs/cellconfig.h>
28 #include <rx/rx_globals.h>
29 #include <afs/volser.h>
30 #include <afs/volser_prototypes.h>
31 #include <afs/volint.h>
32 #include <afs/keys.h>
33 #include <afs/afsutil.h>
34 #include <ubik.h>
35
36 #include "uss_vol.h"            /*Interface to this module */
37 #include "uss_common.h"         /*Common definitions */
38 #include "uss_procs.h"          /*Defs from procs module */
39 #include "uss_fs.h"             /*CacheManager ops */
40 #include "uss_acl.h"
41
42 extern int line;
43
44 /*
45  * ---------------------- Private definitions ---------------------
46  */
47 #undef USS_VOL_DB
48 #undef USS_VOL_DB_SHOW_OVERRIDES
49
50
51 /*
52  * --------------------- Exported definitions ---------------------
53  */
54 /*
55  * The Volume Server interface imports the Ubik connection
56  * structure to use, expecting it to be named "cstruct".  This
57  * is why we have two names here.  Thus, the UV_CreateVolume()
58  * will work and we can avoid nasty little core dumps.
59  */
60 struct ubik_client *uconn_vldbP;        /*Ubik connection struct */
61 struct ubik_client *cstruct;    /*Required name for above */
62
63 /*
64  * ------------------------ Private globals -----------------------
65  */
66 static int initDone = 0;        /*Module initialized? */
67 static int NoAuthFlag = 0;      /*Use -noauth? */
68 static struct rx_connection
69  *serverconns[VLDB_MAXSERVERS]; /*Connection(s) to VLDB
70                                  * server(s) */
71
72
73 /*-----------------------------------------------------------------------
74  * static InitThisModule
75  *
76  * Description:
77  *      Set up this module, namely set up all the client state for
78  *      dealing with the Volume Location Server(s), including
79  *      network connections.
80  *
81  * Arguments:
82  *      a_noAuthFlag : Do we need authentication?
83  *      a_confDir    : Configuration directory to use.
84  *      a_cellName   : Cell we want to talk to.
85  *
86  * Returns:
87  *      0 if everything went fine, or
88  *      lower-level error code otherwise.
89  *
90  * Environment:
91  *      This routine will only be called once.
92  *
93  * Side Effects:
94  *      As advertised.
95  *------------------------------------------------------------------------*/
96
97 static afs_int32
98 InitThisModule(int a_noAuthFlag, char *a_confDir, char *a_cellName)
99 {                               /*InitThisModule */
100 #ifdef USS_VOL_DB
101     static char rn[] = "uss_vol:InitThisModule";
102 #endif
103     afs_int32 code;     /*Return code */
104     struct afsconf_dir *tdir;   /*Ptr to conf dir info */
105     struct afsconf_cell info;   /*Info about chosen cell */
106     afs_int32 scIndex;          /*Chosen security index */
107     afs_int32 secFlags;
108     struct rx_securityClass *sc;        /*Generated security object */
109     afs_int32 i;                /*Loop index */
110
111     /*
112      * Only once, guys, will 'ya?
113      */
114     if (initDone) {
115 #ifdef USS_VOL_DB
116         printf("[%s] Called multiple times!\n", rn);
117 #endif /* USS_VOL_DB */
118         return (0);
119     }
120
121     /*
122      * Set up our Rx environment.
123      */
124 #ifdef USS_VOL_DB
125     printf("[%s] Initializing Rx environment\n", rn);
126 #endif /* USS_VOL_DB */
127     code = rx_Init(0);
128     if (code) {
129         fprintf(stderr, "%s:  Couldn't initialize Rx.\n", uss_whoami);
130         return (code);
131     }
132     rx_SetRxDeadTime(50);
133
134     /*
135      * Find out all about our configuration.
136      */
137 #ifdef USS_VOL_DB
138     printf("[%s] Handling configuration info\n", rn);
139 #endif /* USS_VOL_DB */
140     tdir = afsconf_Open(a_confDir);
141     if (!tdir) {
142         fprintf(stderr, "%s: Couldn't open configuration directory (%s).\n",
143                 uss_whoami, a_confDir);
144         return (-1);
145     }
146     code = afsconf_GetCellInfo(tdir, a_cellName, AFSCONF_VLDBSERVICE, &info);
147     if (code) {
148         printf("%s: Can't find VLDB server(s) for cell %s\n", uss_whoami,
149                a_cellName);
150         exit(1);
151     }
152 #ifdef USS_VOL_DB
153     printf("[%s] Getting tickets if needed\n", rn);
154 #endif /* USS_VOL_DB */
155
156     secFlags = AFSCONF_SECOPTS_FALLBACK_NULL;
157     if (a_noAuthFlag)
158         secFlags |= AFSCONF_SECOPTS_NOAUTH;
159
160     code = afsconf_PickClientSecObj(tdir, secFlags, &info, a_cellName,
161                                     &sc, &scIndex, NULL);
162     if (code) {
163         printf("%s: Can't create client security object\n", uss_whoami);
164         exit(1);
165     }
166     if (scIndex == RX_SECIDX_NULL && !a_noAuthFlag) {
167         fprintf(stderr,
168                 "%s: Couldn't get AFS tokens, running unauthenticated.\n",
169                 uss_whoami);
170     }
171
172     /*
173      * Tell UV module about default authentication.
174      */
175 #ifdef USS_VOL_DB
176     printf("[%s] Setting UV security: obj 0x%x, index %d\n", rn, sc, scIndex);
177 #endif /* USS_VOL_DB */
178     UV_SetSecurity(sc, scIndex);
179     if (info.numServers > VLDB_MAXSERVERS) {
180         fprintf(stderr, "%s: info.numServers=%d (> VLDB_MAXSERVERS=%d)\n",
181                 uss_whoami, info.numServers, VLDB_MAXSERVERS);
182         exit(1);
183     }
184
185     /*
186      * Connect to each VLDB server for the chosen cell.
187      */
188     for (i = 0; i < info.numServers; i++) {
189 #ifdef USS_VOL_DB
190         printf
191             ("[%s] Connecting to VLDB server 0x%x, port %d, service id %d\n",
192              rn, info.hostAddr[i].sin_addr.s_addr, info.hostAddr[i].sin_port,
193              USER_SERVICE_ID);
194 #endif /* USS_VOL_DB */
195         serverconns[i] =
196             rx_NewConnection(info.hostAddr[i].sin_addr.s_addr,
197                              info.hostAddr[i].sin_port, USER_SERVICE_ID, sc,
198                              scIndex);
199     }
200
201     /*
202      * Set up to execute Ubik transactions on the VLDB.
203      */
204 #ifdef USS_VOL_DB
205     printf("[%s] Initializing Ubik interface\n", rn);
206 #endif /* USS_VOL_DB */
207     code = ubik_ClientInit(serverconns, &uconn_vldbP);
208     if (code) {
209         fprintf(stderr, "%s: Ubik client init failed.\n", uss_whoami);
210         return (code);
211     }
212 #ifdef USS_VOL_DB
213     printf("[%s] VLDB ubik connection structure at 0x%x\n", rn, uconn_vldbP);
214 #endif /* USS_VOL_DB */
215
216     /*
217      * Place the ubik VLDB connection structure in its advertised
218      * location.
219      */
220     cstruct = uconn_vldbP;
221
222     /*
223      * Success!
224      */
225     initDone = 1;
226     return (0);
227
228 }                               /*InitThisModule */
229
230
231 /*-----------------------------------------------------------------------
232  * static HostIDToHostName
233  *
234  * Description:
235  *      Given a host ID (in network byte order), figure out the
236  *      corresponding host name.
237  *
238  * Arguments:
239  *      a_hostID   : Host ID in network byte order.
240  *      a_hostName : Ptr to host name buffer.
241  *
242  * Returns:
243  *      Nothing.
244  *
245  * Environment:
246  *      This routine simply calls the hostutil_GetNameByINet()
247  *      function exported by the utility library (util.a).
248  *
249  * Side Effects:
250  *      As advertised.
251  *------------------------------------------------------------------------*/
252
253 static void
254 HostIDToHostName(afs_int32 a_hostID, char *a_hostName)
255 {                               /*HostIDToHostName */
256
257     strcpy(a_hostName, hostutil_GetNameByINet(a_hostID));
258
259 }                               /*HostIDToHostName */
260
261
262 /*-----------------------------------------------------------------------
263  * static PartIDToPartName
264  *
265  * Description:
266  *      Given a partition ID (in network byte order), figure out the
267  *      corresponding partition name.
268  *
269  * Arguments:
270  *      a_partID   : Partition ID in network byte order.
271  *      a_partName : Ptr to partition name buffer.
272  *
273  * Returns:
274  *      0 if everything went well, or
275  *      -1 if the given partition ID couldn't be translated.
276  *
277  * Environment:
278  *      Nothing interesting.
279  *
280  * Side Effects:
281  *      As advertised.
282  *------------------------------------------------------------------------*/
283
284 static afs_int32
285 PartIDToPartName(afs_int32 a_partID, char *a_partName)
286 {                               /*PartIDToPartName */
287 #ifdef USS_VOL_DB
288     static char rn[] = "PartIDToPartName";
289 #endif
290 #ifdef USS_VOL_DB
291     printf("[%s] Translating partition id %d to its name\n", rn, a_partID);
292 #endif /* USS_VOL_DB */
293
294     if ((a_partID < 0) || (a_partID > VOLMAXPARTS))
295         return (-1);
296
297     if (a_partID < 26) {
298         strcpy(a_partName, "/vicep");
299         a_partName[6] = a_partID + 'a';
300         a_partName[7] = '\0';
301     } else {
302         strcpy(a_partName, "/vicep");
303         a_partID -= 26;
304         a_partName[6] = 'a' + (a_partID / 26);
305         a_partName[7] = 'a' + (a_partID % 26);
306         a_partName[8] = '\0';
307     }
308
309 #ifdef USS_VOL_DB
310     printf("[%s] Translation for part ID %d is '%s'\n", rn, a_partID,
311            a_partName);
312 #endif /* USS_VOL_DB */
313     return (0);
314
315 }                               /*PartIDToPartName */
316
317
318 /*------------------------------------------------------------------------
319  * EXPORTED uss_Vol_GetServer
320  *
321  * Environment:
322  *      Nothing interesting.
323  *
324  * Side Effects:
325  *      As advertised.
326  *------------------------------------------------------------------------*/
327
328 afs_int32
329 uss_vol_GetServer(char *a_name)
330 {                               /*uss_vol_GetServer */
331
332     struct hostent *th;
333     afs_int32 addr;
334     afs_int32 b1, b2, b3, b4;
335     afs_int32 code;
336
337     code = sscanf(a_name, "%d.%d.%d.%d", &b1, &b2, &b3, &b4);
338     if (code == 4) {
339         /*
340          * Parsed as 128.2.9.4, or similar; return it in network
341          * byte order (128 in byte 0).
342          */
343         addr = (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
344         return htonl(addr);
345     }
346
347     th = gethostbyname(a_name);
348     if (!th)
349         return (0);
350     memcpy(&addr, th->h_addr, sizeof(addr));
351     return (addr);
352
353 }                               /*uss_vol_GetServer */
354
355 /* XXX - This function is unused, and could be deleted */
356 #if 0
357 /*------------------------------------------------------------------------
358  * static GetVolumeType
359  *
360  * Description:
361  *      Translate the given char string representing a volume type to the
362  *      numeric representation.
363  *
364  * Arguments:
365  *      a_type : Char string volume type.
366  *
367  * Returns:
368  *      One of ROVOL, RWVOL, BACKVOL, or -1 on failure.
369  *
370  * Environment:
371  *      Nothing interesting.
372  *
373  * Side Effects:
374  *      As advertised.
375  *------------------------------------------------------------------------*/
376
377 static afs_int32
378 GetVolumeType(char *a_type)
379 {                               /*GetVolumeType */
380
381     if (!strcmp(a_type, "ro"))
382         return (ROVOL);
383     else if (!strcmp(a_type, "rw"))
384         return (RWVOL);
385     else if (!strcmp(a_type, "bk"))
386         return (BACKVOL);
387     else
388         return (-1);
389
390 }                               /*GetVolumeType */
391 #endif
392
393 /*------------------------------------------------------------------------
394  * EXPORTED uss_Vol_GetPartitionID
395  *
396  * Environment:
397  *      It is assumed that partition names may begin with ``/vicep''.
398  *
399  * Side Effects:
400  *      As advertised.
401  *------------------------------------------------------------------------*/
402
403 afs_int32
404 uss_vol_GetPartitionID(char *a_name)
405 {                               /*uss_vol_GetPartitionID */
406
407     char tc;
408     char ascii[3];
409
410     tc = *a_name;
411     if (tc == 0)
412         return (-1);
413
414     /*
415      * Numbers go straight through.
416      */
417     if (tc >= '0' && tc <= '9') {
418         return (atoi(a_name));
419     }
420
421     /*
422      * Otherwise, check for vicepa or /vicepa, or just plain "a"
423      */
424     ascii[2] = 0;
425     if (strlen(a_name) <= 2) {
426         strcpy(ascii, a_name);
427     } else if (!strncmp(a_name, "/vicep", 6)) {
428         strncpy(ascii, a_name + 6, 2);
429     } else if (!strncmp(a_name, "vicep", 5)) {
430         strncpy(ascii, a_name + 5, 2);
431     } else
432         return (-1);
433
434     /*
435      * Now, partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab,
436      * .../vicepzz, and are numbered from 0.  Do the appropriate conversion.
437      */
438     if (ascii[1] == 0) {
439         /*
440          * Single-char name, 0..25
441          */
442         if (ascii[0] < 'a' || ascii[0] > 'z')
443             return (-1);        /* wrongo */
444         return (ascii[0] - 'a');
445     } else {
446         /*
447          * Two-char name, 26 .. <whatever>
448          */
449         if (ascii[0] < 'a' || ascii[0] > 'z')
450             return (-1);
451         if (ascii[1] < 'a' || ascii[1] > 'z')
452             return (-1);
453         return ((ascii[0] - 'a') * 26 + (ascii[1] - 'a') + 26);
454     }
455 }                               /*uss_vol_GetPartitionID */
456
457
458 /*-----------------------------------------------------------------------
459  * static CheckDoubleMount
460  *
461  * Description:
462  *      Make sure we're not trying to mount a volume in the same place
463  *      twice.
464  *
465  * Arguments:
466  *      a_mp    : Mountpoint pathname to check.
467  *      a_oldmp : Ptr to buffer into which the old value of the
468  *                mountpoint is placed (if any).
469  *
470  * Returns:
471  *      0                 if the volume was not previously mounted.
472  *      uss_procs_ANCIENT if there was already a mountpoint AND the
473  *                        user was already recorded in the password
474  *                        file.
475  *      uss_procs_YOUNG   if there was a mountpoint for the user taken
476  *                        from the directory pool, yet the user was not
477  *                        yet in the password file.
478  *
479  * Environment:
480  *      Nothing interesting.
481  *
482  * Side Effects:
483  *      May fill in the a_oldmp buffer with the value of the old
484  *      mountpoint.
485  *------------------------------------------------------------------------*/
486
487 static int
488 CheckDoubleMount(char *a_mp, char *a_oldmp)
489 {                               /*CheckDoubleMount */
490
491 #ifdef USS_VOL_DB
492     static char rn[] = "uss_vol:CheckDoubleMount";
493 #endif
494     int start, len, mlen, tlen;
495     int i = 0;
496     struct passwd *pws;
497     struct stat stbuf;
498
499     pws = getpwuid(atoi(uss_Uid));
500     if (pws != NULL) {
501         /*
502          * User exists in the password file, so they've been fully
503          * created and integrated.  Return the ``ancient'' mountpoint.
504          */
505         strcpy(a_oldmp, pws->pw_dir);
506         return (uss_procs_ANCIENT);
507     }
508
509     if (uss_NumGroups) {
510         /*
511          * $AUTO used. Search among the possible directories.
512          */
513         len = strlen(uss_Auto);
514         mlen = strlen(a_mp);
515         while (strncmp(&a_mp[i], uss_Auto, len)) {
516             a_oldmp[i] = a_mp[i];
517             if (++i > (mlen - len)) {
518                 i = -1;
519                 break;
520             }
521         }
522         if ((start = i) != -1) {
523             /*
524              * $AUTO used in mountpoint.
525              */
526             for (i = 0; i < uss_NumGroups; i++) {
527                 /*
528                  * Copy in the base and tail components.
529                  */
530                 tlen = strlen(uss_DirPool[i]);
531                 strncpy(&a_oldmp[start], uss_DirPool[i], tlen);
532                 strcpy(&a_oldmp[start + tlen], &a_mp[start + len]);
533 #ifdef USS_VOL_DB
534                 printf("%s: Checking '%s' for mount point\n", rn, a_oldmp);
535 #endif /* USS_VOL_DB */
536                 if (lstat(a_oldmp, &stbuf) == 0)        /*mp exists */
537                     if (strcmp(a_oldmp, a_mp))
538                         /* and is different */
539                         /*
540                          * The old mount point exists and is different
541                          * from the current one, so return the fact
542                          * that we have a ``young'' mountpoint.
543                          */
544                         return (uss_procs_YOUNG);
545             }                   /*Check each $AUTO directory */
546         }
547     }
548
549     /*$AUTO has been used */
550     /*
551      * No luck finding the old mount point, so we just return that
552      * this is the first time we've seen this volume.
553      */
554     return (0);
555
556 }                               /*CheckDoubleMount */
557
558
559 /*------------------------------------------------------------------------
560  * EXPORTED uss_vol_CreateVol
561  *
562  * Environment:
563  *      Called from the code generated by the uss grammar.
564  *
565  * Side Effects:
566  *      As advertised.
567  *------------------------------------------------------------------------*/
568
569 afs_int32
570 uss_vol_CreateVol(char *a_volname, char *a_server, char *a_partition,
571                   char *a_quota, char *a_mpoint, char *a_owner,
572                   char *a_acl)
573 {                               /*uss_vol_CreateVol */
574 #ifdef USS_VOL_DB
575     static char rn[] = "uss_vol_CreateVol";     /*Routine name */
576 #endif
577     afs_int32 pname;            /*Partition name */
578     afs_uint32 volid;           /*Volume ID */
579     afs_int32 code;             /*return code */
580     afs_int32 saddr;            /*Socket info for server */
581     int VolExistFlag = 0;       /*Does the volume exist? */
582     int mpExistFlag = 0;        /*Does the mountpoint exist? */
583     char *Oldmpoint = NULL;     /*Old mountpoint name, if any */
584     char tmp_str[uss_MAX_SIZE]; /*Useful string buffer */
585     int o;                      /*Owner's user id */
586     char userinput[64];         /*User's input */
587     struct uss_subdir *new_dir; /*Used to remember original ACL */
588
589     /*
590      * Don't do anything if there's already a problem.
591      */
592     if (uss_syntax_err)
593         return (1);
594
595 #ifdef USS_VOL_DB
596     fprintf(stderr, "%s:uss_vol_CreateVol params:\n", rn);
597     fprintf(stderr,
598             "%s: volname '%s', server '%s', partition '%s', quota '%s', mpoint '%s', owner '%s', acl '%s'\n",
599             rn, a_volname, a_server, a_partition, a_quota, a_mpoint, a_owner,
600             a_acl);
601 #endif /* USS_VOL_DB */
602
603     /*
604      * All of the parameters passed in are taken from the template
605      * file.  Override these values if the user has explicitly set
606      * them, namely if the uss commons have non-null strings.
607      */
608     if (uss_Server[0] != '\0') {
609 #ifdef USS_VOL_DB_SHOW_OVERRIDES
610         if (uss_verbose)
611             fprintf(stderr,
612                     "%s: Overriding server field: template value is '%s', overridden to '%s'\n",
613                     rn, a_server, uss_Server);
614 #endif /* USS_VOL_DB_SHOW_OVERRIDES */
615         a_server = uss_Server;
616     }
617
618     if (uss_Partition[0] != '\0') {
619 #ifdef USS_VOL_DB_SHOW_OVERRIDES
620         if (uss_verbose)
621             fprintf(stderr,
622                     "%s: Overriding partition field: template value is '%s', overridden to '%s'\n",
623                     rn, a_partition, uss_Partition);
624 #endif /* USS_VOL_DB_SHOW_OVERRIDES */
625         a_partition = uss_Partition;
626     }
627
628     if (uss_MountPoint[0] != '\0') {
629 #ifdef USS_VOL_DB_SHOW_OVERRIDES
630         if (uss_verbose)
631             fprintf(stderr,
632                     "%s: overriding mountpoint field: template value is '%s', overridden to '%s'\n",
633                     rn, a_mpoint, uss_MountPoint);
634 #endif /* USS_VOL_DB_SHOW_OVERRIDES */
635         a_mpoint = uss_MountPoint;
636     }
637 #ifdef USS_VOL_DB_SHOW_OVERRIDES
638     printf("%s: Params after overrides:\n", uss_whoami);
639     printf
640         ("%s: volname '%s', server '%s', partition '%s', quota '%s', mpoint '%s', owner '%s', acl '%s'\n",
641          uss_whoami, a_volname, a_server, a_partition, a_quota, a_mpoint,
642          a_owner, a_acl);
643 #endif /* USS_VOL_DB_SHOW_OVERRIDES */
644
645     if (uss_verbose)
646         fprintf(stderr,
647                 "Creating volume '%s' on server '%s', partition '%s'\n",
648                 a_volname, a_server, a_partition);
649
650     saddr = uss_vol_GetServer(a_server);
651     if (!saddr) {
652         uss_procs_PrintErr(line,
653                            "File server '%s' not found in config info\n",
654                            a_server);
655         return (1);
656     }
657     pname = uss_vol_GetPartitionID(a_partition);
658     if (pname < 0) {
659         uss_procs_PrintErr(line, "Couldn't interpret partition name '%s'\n",
660                            a_partition);
661         return (1);
662     }
663
664     /*
665      * Make sure our VLDB connection(s) is/are set up before actually
666      * trying to perform a volume creation creation.
667      */
668     if (!initDone) {
669         code = InitThisModule(NoAuthFlag, uss_ConfDir, uss_Cell);
670         if (code) {
671             afs_com_err(uss_whoami, code,
672                     "while inititializing VLDB connection(s)\n");
673             return (code);
674         }
675     }
676     /*Initialize VLDB connection(s) */
677     if (!uss_DryRun) {
678 #ifdef USS_VOL_DB
679         printf("%s: Creating volume on srv 0x%x, part %d, vol name '%s'\n",
680                rn, saddr, pname, a_volname);
681 #endif /* USS_VOL_DB */
682         code = UV_CreateVolume(saddr, pname, a_volname, &volid);
683         if (code) {
684             if (code == VL_NAMEEXIST) {
685                 VolExistFlag = 1;
686                 fprintf(stderr,
687                         "%s: Warning; Volume '%s' exists, using existing one.\n",
688                         uss_whoami, a_volname);
689
690                 /*
691                  * We should get the volid here if we want to use it, but
692                  * we don't need it right now.  What we DO need, though, is
693                  * to ask our caller if it's OK to overwrite the user's files
694                  * if they're pre-existing.
695                  */
696                 if (!uss_OverwriteThisOne) {
697                     printf
698                         ("Overwrite files in pre-existing '%s' volume? [y, n]: ",
699                          a_volname);
700                     scanf("%s", userinput);
701                     if ((userinput[0] == 'y') || (userinput[0] == 'Y')) {
702                         printf("\t[Overwriting allowed]\n");
703                         uss_OverwriteThisOne = 1;
704                     } else
705                         printf("\t[Overwriting not permitted]\n");
706                 }               /*Overwriting not previously allowed */
707             } /*Volume already existed */
708             else {
709                 uss_procs_PrintErr(line,
710                                    "Couldn't create volume '%s' [error %d]: %s\n",
711                                    a_volname, code, strerror(errno));
712                 return (1);
713             }                   /*Failure was NOT because it already existed */
714         }                       /*UV_CreateVolume failed */
715     } /*Not a dry run */
716     else {
717         fprintf(stderr,
718                 "\t[Dry run: Creating volume '%s' on '%s', partition '%s']\n",
719                 a_volname, a_server, a_partition);
720     }                           /*Not a dry run */
721
722     /* OK, we want to make sure we don't double-mount the volume.
723      * If the volume existed, it can be the case that it is
724      * already mounted somewhere else (because of $AUTO or others).
725      * Let's check for that.  Note: we never enter this portion of
726      * the code if we're doing a dry run.
727      */
728     if (VolExistFlag) {
729         if ((Oldmpoint = (char *)malloc(strlen(a_mpoint) + 50)) == NULL) {
730             fprintf(stderr, "%s: No more memory!\n", uss_whoami);
731             return (1);
732         }
733
734         mpExistFlag = CheckDoubleMount(a_mpoint, Oldmpoint);
735         if (mpExistFlag == uss_procs_ANCIENT) {
736             fprintf(stderr,
737                     "%s:\t*** WARNING ***; This user (%s) is already in passwd file (or equivalent). IGNORED.\n",
738                     uss_whoami, uss_User);
739             free(Oldmpoint);
740             uss_syntax_err = 1; /*I know, I know, it's not a SYNTAX error */
741             uss_ignoreFlag = 1;
742             return (0);
743         }
744         if (mpExistFlag == uss_procs_YOUNG) {
745             fprintf(stderr,
746                     "%s: Warning; Volume '%s' is already mounted on %s.  Using the existing one.\n",
747                     uss_whoami, a_volname, Oldmpoint);
748             a_mpoint = Oldmpoint;
749         }
750     }
751
752     if (mpExistFlag == 0) {
753         extern int local_Cell;
754         /*
755          * Let's mount it.
756          */
757         if (local_Cell)
758             sprintf(tmp_str, "#%s.", a_volname);
759         else
760             sprintf(tmp_str, "#%s:%s.", uss_Cell, a_volname);
761         if (!uss_DryRun) {
762             if (symlink(tmp_str, a_mpoint)) {
763                 if (errno == EEXIST) {
764                     fprintf(stderr,
765                             "%s: Warning: Mount point '%s' already exists.\n",
766                             uss_whoami, a_mpoint);
767                 } else {
768                     fprintf(stderr,
769                             "%s: Can't mount volume '%s' on '%s': %s\n",
770                             uss_whoami, a_volname, a_mpoint, strerror(errno));
771                     if (Oldmpoint)
772                         free(Oldmpoint);
773                     return (1);
774                 }               /*There was already something mounted there */
775             }                   /*Mount failed */
776         } /*Dry run */
777         else {
778             fprintf(stderr, "\t[Dry run: Mounting '%s' at '%s']\n", tmp_str,
779                     a_mpoint);
780         }                       /*Not a dry run */
781     }
782
783     /*Mount point didn't already exist */
784     /*
785      * Set the volume disk quota.
786      */
787     if (!uss_DryRun) {
788         if ((code = uss_acl_SetDiskQuota(a_mpoint, atoi(a_quota))))
789             return (code);
790     } /*Dry run */
791     else {
792         fprintf(stderr,
793                 "\t[Dry run: Setting disk quota for '%s' to %s blocks]\n",
794                 a_mpoint, a_quota);
795     }                           /*Not a dry run */
796
797     /*Copy mpoint into $MTPT for others to use */
798     strcpy(uss_MountPoint, a_mpoint);
799
800     o = uss_procs_GetOwner(a_owner);
801     if (!uss_DryRun) {
802         if (chown(a_mpoint, o, -1)) {
803             fprintf(stderr,
804                     "%s: Can't chown() mountpoint '%s' to owner '%s' (uid %d): %s\n",
805                     uss_whoami, a_mpoint, a_owner, o, strerror(errno));
806             if (Oldmpoint)
807                 free(Oldmpoint);
808             return (1);
809         }                       /*chown failed */
810     } /*Dry run */
811     else {
812         fprintf(stderr,
813                 "\t[Dry run: chown() mountpoint '%s' to be owned by user]\n",
814                 a_mpoint);
815     }                           /*Not a dry run */
816
817     /*
818      * Set the ACL on the user's home directory so that, for the duration of
819      * the account creation, only the uss_AccountCreator has any rights on the
820      * files therein.  Make sure to clear this ACL to remove anyone that might
821      * already be there due to volume creation defaults.  We will set this ACL
822      * properly, as well as all ACLs of future subdirectories,as the very last
823      * thing we do to the new account.
824      */
825     new_dir = (struct uss_subdir *)malloc(sizeof(struct uss_subdir));
826     new_dir->previous = uss_currentDir;
827     new_dir->path = (char *)malloc(strlen(a_mpoint) + 1);
828     strcpy(new_dir->path, a_mpoint);
829     new_dir->finalACL = (char *)malloc(strlen(a_acl) + 1);
830     strcpy(new_dir->finalACL, a_acl);
831     uss_currentDir = new_dir;
832     sprintf(tmp_str, "%s %s all", a_mpoint, uss_AccountCreator);
833
834     if (Oldmpoint)
835         free(Oldmpoint);
836
837     if (!uss_DryRun) {
838         if (uss_verbose)
839             fprintf(stderr, "Setting ACL: '%s'\n", tmp_str);
840         if (uss_acl_SetAccess(tmp_str, 1, 0))
841             return (1);
842     } /*For real */
843     else {
844         fprintf(stderr, "\t[Dry run: uss_acl_SetAccess(%s)]\n", tmp_str);
845     }
846     return (0);
847 }                               /*uss_vol_CreateVol */
848
849
850 /*------------------------------------------------------------------------
851  * EXPORTED uss_vol_DeleteVol
852  *
853  * Environment:
854  *      Nothing interesting.
855  *
856  * Side Effects:
857  *      As advertised.
858  *------------------------------------------------------------------------*/
859
860 afs_int32
861 uss_vol_DeleteVol(char *a_volName, afs_int32 a_volID, char *a_servName,
862                   afs_int32 a_servID, char *a_partName, afs_int32  a_partID)
863 {                               /*uss_vol_DeleteVol */
864
865 #ifdef USS_VOL_DB
866     static char rn[] = "uss_vol_DeleteVol";     /*Routine name */
867 #endif
868     afs_int32 code = 0; /*Return code */
869
870     /*
871      * Make sure we've initialized our VLDB connection(s) before
872      * proceeding apace.
873      */
874     if (!initDone) {
875         code = InitThisModule(NoAuthFlag, uss_ConfDir, uss_Cell);
876         if (code)
877             return (code);
878     }
879
880     if (!uss_DryRun) {
881         /*
882          * Go for the deletion.
883          */
884 #ifdef USS_VOL_DB
885         printf
886             ("%s: Deleting volume '%s' (ID %d) on FileServer '%s' (0x%x), partition '%s' (%d)\n",
887              rn, a_volName, a_volID, a_servName, a_servID, a_partName,
888              a_partID);
889 #endif /* USS_VOL_DB */
890
891         code = UV_DeleteVolume(a_servID, a_partID, a_volID);
892         if (code)
893             printf("%s: Can't delete volume '%s'\n", uss_whoami, a_volName);
894     } else
895         printf("\t[Dry run - volume '%s' NOT removed]\n", a_volName);
896
897     return (code);
898
899 }                               /*uss_vol_DeleteVol */
900
901
902 /*------------------------------------------------------------------------
903  * static GetServerAndPart
904  *
905  * Description:
906  *      Given a VLDB entry, return the server and partition IDs for
907  *      the read/write volume.
908  *
909  * Arguments:
910  *      a_vldbEntryP : Ptr to VLDB entry.
911  *      a_servIDP    : Ptr to server ID to set.
912  *      a_partIDP    : Ptr to partition ID to set.
913  *
914  * Returns:
915  *      0 if everything went well, or
916  *      -1 otherwise.
917  *
918  * Environment:
919  *      Nothing interesting.
920  *
921  * Side Effects:
922  *      As advertised.
923  *------------------------------------------------------------------------*/
924
925 static afs_int32
926 GetServerAndPart(struct nvldbentry *a_vldbEntryP, afs_int32 *a_servIDP,
927                  afs_int32 *a_partIDP)
928 {                               /*GetServerAndPart */
929
930     /*
931      * It really looks like all we need to do is pull off the
932      * first entry's info.
933      */
934     *a_servIDP = a_vldbEntryP->serverNumber[0];
935     *a_partIDP = a_vldbEntryP->serverPartition[0];
936     return (0);
937
938 }                               /*GetServerAndPart */
939
940
941 /*------------------------------------------------------------------------
942  * static ovlentry_to_nvlentry
943  *
944  * Description:
945  *      Converts a vldbentry to nvldbentry.
946  *
947  * Arguments:
948  *      oentryp   IN  : Ptr to vldbentry.
949  *      nentryp   OUT : Ptr to nvldbentry.
950  *
951  * Returns:
952  *      None
953  *
954  * Environment:
955  *      Nothing interesting.
956  *
957  * Side Effects:
958  *      None.
959  *------------------------------------------------------------------------*/
960
961 static void
962 ovlentry_to_nvlentry(struct vldbentry *oentryp,
963                      struct nvldbentry *nentryp)
964 {
965     int i;
966
967     memset(nentryp, 0, sizeof(struct nvldbentry));
968     strncpy(nentryp->name, oentryp->name, sizeof(nentryp->name));
969     for (i = 0; i < oentryp->nServers; i++) {
970         nentryp->serverNumber[i] = oentryp->serverNumber[i];
971         nentryp->serverPartition[i] = oentryp->serverPartition[i];
972         nentryp->serverFlags[i] = oentryp->serverFlags[i];
973     }
974     nentryp->nServers = oentryp->nServers;
975     for (i = 0; i < MAXTYPES; i++)
976         nentryp->volumeId[i] = oentryp->volumeId[i];
977     nentryp->cloneId = oentryp->cloneId;
978     nentryp->flags = oentryp->flags;
979 }
980
981
982 /*------------------------------------------------------------------------
983  * static uss_vol_GetEntryByID
984  *
985  * Description:
986  *      Obtains a nvldbentry whether new or old forms of
987  *      ubik_VL_GetEntryByID are required.
988  *
989  * Arguments:
990  *      cstruct      : Ptr to ubik_client.
991  *      volid        : Volume ID for which entry is being obtained.
992  *      voltype      : Required volume type
993  *      entryp       : Ptr to nvldbentry to receive the output on success.
994  *
995  * Returns:
996  *      0 if everything went well, or
997  *      ubik return code otherwise.
998  *
999  * Environment:
1000  *      Nothing interesting.
1001  *
1002  * Side Effects:
1003  *      None.
1004  *------------------------------------------------------------------------*/
1005
1006 static int
1007 uss_vol_GetEntryByID(struct ubik_client *cstruct, afs_uint32 volid,
1008                      afs_int32 voltype, struct nvldbentry *entryp)
1009 {
1010     struct vldbentry oentry;
1011     int code;
1012
1013     code = ubik_VL_GetEntryByIDN(cstruct, 0, volid, voltype, entryp);
1014     if (code == RXGEN_OPCODE) {
1015         code =
1016             ubik_VL_GetEntryByID(cstruct, 0, volid, voltype, &oentry);
1017         if (!code)
1018             ovlentry_to_nvlentry(&oentry, entryp);
1019     }
1020     return code;
1021 }
1022
1023
1024 /*------------------------------------------------------------------------
1025  * EXPORTED uss_vol_GetVolInfoFromMountPoint
1026  *
1027  * Environment:
1028  *      If the mountpoint path provided is not
1029  *
1030  * Side Effects:
1031  *      As advertised.
1032  *------------------------------------------------------------------------*/
1033
1034 afs_int32
1035 uss_vol_GetVolInfoFromMountPoint(char *a_mountpoint)
1036 {                               /*uss_vol_GetVolInfoFromMountPoint */
1037 #ifdef USS_VOL_DB
1038     static char rn[] = "uss_vol_GetVolInfoFromMountPoint";
1039 #endif
1040     afs_int32 code;     /*Return code */
1041     uss_VolumeStatus_t *statusP;        /*Ptr to returned status */
1042     afs_int32 volID;            /*Volume ID */
1043     struct nvldbentry vldbEntry;        /*VLDB entry for volume */
1044     afs_int32 serverID;         /*Addr of host FileServer */
1045     afs_int32 partID;           /*Volume's partition ID */
1046
1047     /*
1048      * Set up to ask the CacheManager to give us all the info
1049      * it has about the given mountpoint.
1050      */
1051     code = uss_fs_GetVolStat(a_mountpoint, uss_fs_OutBuff, USS_FS_MAX_SIZE);
1052 #ifdef USS_VOL_DB
1053     printf("[%s] Result of uss_fs_GetVolStat: code = %d, errno = %d\n", rn,
1054            code, errno);
1055 #endif /* USS_VOL_DB */
1056     if (code) {
1057         if (errno == EINVAL || errno == ENOENT || errno == ENODEV) {
1058             /*
1059              * We were given a mountpoint pathname that doesn't
1060              * point to a volume, or a mountpoint that has already
1061              * been deleted.  This means that there is no info
1062              * to get from this pathname.  Zero out the volume,
1063              * server & partition info and return successfully.
1064              */
1065             uss_Volume[0] = '\0';
1066             uss_Server[0] = '\0';
1067             uss_Partition[0] = '\0';
1068             uss_VolumeID = 0;
1069             uss_ServerID = 0;
1070             uss_PartitionID = 0;
1071             if (uss_verbose) {
1072                 printf("%s: Warning: Mountpoint pathname '%s': ", uss_whoami,
1073                        a_mountpoint);
1074                 if (errno == EINVAL)
1075                     printf("Volume not reachable\n");
1076                 else if (errno == ENODEV)
1077                     printf("No such device\n");
1078                 else
1079                     printf("Not found\n");
1080             }
1081             return (0);
1082         } else {
1083             printf("%s: Can't get volume information from mountpoint '%s'\n",
1084                    uss_whoami, a_mountpoint);
1085             return (code);
1086         }
1087     }
1088
1089     /*Can't get volume status */
1090     /*
1091      * Pull out the volume name from the returned information and store
1092      * it in the common area.  It resides right after the basic volume
1093      * status structure.
1094      */
1095     statusP = (uss_VolumeStatus_t *) uss_fs_OutBuff;
1096     strcpy(uss_Volume, (((char *)statusP) + sizeof(*statusP)));
1097     volID = statusP->Vid;
1098     uss_VolumeID = volID;
1099     if (volID == 0) {
1100         printf("%s: Illegal volume ID: %d\n", uss_whoami, volID);
1101         return (-1);
1102     }
1103
1104     /*
1105      * With the volume name in hand, find out where that volume
1106      * lives.  Make sure our VLDB stuff has been initialized first.
1107      */
1108     if (!initDone) {
1109         code = InitThisModule(NoAuthFlag, uss_ConfDir, uss_Cell);
1110         if (code)
1111             return (code);
1112     }
1113     code = uss_vol_GetEntryByID( uconn_vldbP, volID, -1, &vldbEntry);
1114     if (code) {
1115         printf("%s: Can't fetch VLDB entry for volume ID %d\n", uss_whoami,
1116                volID);
1117         return (code);
1118     }
1119
1120     /*
1121      * Translate the given VLDB entry from network to host format, then
1122      * checking on the volume's validity.  Specifically, it must be a
1123      * read/write volume and must only exist on one server.
1124      */
1125     MapHostToNetwork(&vldbEntry);
1126     if (vldbEntry.volumeId[RWVOL] != volID) {
1127         printf("%s: Volume '%s' (ID %d) is not a read/write volume!!\n",
1128                uss_whoami, uss_Volume, volID);
1129         return (-1);
1130     }
1131     if (vldbEntry.nServers != 1) {
1132         printf("%s: Volume '%s' (ID %d) exists on multiple servers!!\n",
1133                uss_whoami, uss_Volume, volID);
1134         return (-1);
1135     }
1136
1137     /*
1138      * Pull out the int32words containing the server and partition info
1139      * for the read/write volume.
1140      */
1141     code = GetServerAndPart(&vldbEntry, &serverID, &partID);
1142     if (code) {
1143         printf
1144             ("%s: Can't get server/partition info from VLDB entry for volume '%s' (ID %d)\n",
1145              uss_whoami, uss_Volume, volID);
1146         return (-1);
1147     }
1148
1149     /*
1150      * Store the raw data, then translate the FileServer address to a
1151      * host name, and the partition ID to a partition name.
1152      */
1153     uss_ServerID = serverID;
1154     uss_PartitionID = partID;
1155     HostIDToHostName(serverID, uss_Server);
1156 #ifdef USS_VOL_DB
1157     printf("[%s] Server ID 0x%x translated to '%s'\n", rn, serverID,
1158            uss_Server);
1159 #endif /* USS_VOL_DB */
1160     code = PartIDToPartName(partID, uss_Partition);
1161     if (code) {
1162         printf("%s: Error translating partition ID %d to partition name\n",
1163                uss_whoami, partID);
1164         return (code);
1165     }
1166
1167     /*
1168      * We got it, home boy.
1169      */
1170     return (0);
1171
1172 }                               /*uss_vol_GetVolInfoFromMountPoint */