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