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