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