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