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