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