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