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