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