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