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