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