1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27
28 /*
29 * System includes
30 */
31
32 #include <stdio.h>
33 #include <limits.h>
34 #include <errno.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <libgen.h>
38 #include <string.h>
39 #include <wait.h>
40 #include <signal.h>
41 #include <malloc.h>
42 #include <sys/types.h>
43 #include <sys/mount.h>
44 #include <sys/stat.h>
45 #include <fcntl.h>
46 #include <sys/systeminfo.h>
47 #include <pkgstrct.h>
48 #include <pkginfo.h>
49 #include <locale.h>
50 #include <libintl.h>
51
52 #include <sys/mnttab.h>
53 #include <sys/mntent.h>
54 #include <sys/vfstab.h>
55
56 /*
57 * consolidation pkg command library includes
58 */
59
60 #include <pkglib.h>
61
62 /*
63 * local pkg command library includes
64 */
65
66 #include "install.h"
67 #include "libinst.h"
68 #include "libadm.h"
69 #include "messages.h"
70
71 extern char **environ;
72
73 static int match_mount; /* This holds the mount of interest. */
74
75 int fs_tab_used = 0;
76 int fs_tab_alloc = 0;
77 static int fs_list = -1;
78
79 struct fstable **fs_tab = NULL;
80
81 #define PKGDBROOT "/var/sadm"
82 #define MOUNT "/sbin/mount"
83 #define UMOUNT "/sbin/umount"
84
85 #define setmntent fopen
86 #define endmntent fclose
87 #define MOUNT_TABLE MNTTAB
88
89 /* returned by already_mounted() */
90 #define MNT_NOT 0
91 #define MNT_EXACT 1
92 #define MNT_AVAIL 2
93
94 /* used with is_remote_src() */
95 #define NOT_REMOTE 0
96 #define REAL_REMOTE 1
97 #define SELF_SERVE 2
98
99 /*
100 * Due to /etc/mnttab files containing entries for multiple nfs hosts
101 * HOST_NM_LN needs to be accommodating. The recommended value in the sysinfo
102 * man page of 257 needs to be expanded. See bugid 4076513.
103 * 1024 chars is defined in the mnttab.h header as the max size of an entry.
104 */
105
106 #define HOST_NM_LN MNT_LINE_MAX
107
108 /* These cachefs definitions should be in mntent.h. Maybe some day. */
109 #define MNTTYPE_CFS "cachefs"
110 #define MNTOPT_BACKFSTYPE "backfstype"
111 #define MNTTYPE_AUTO "autofs"
112
113 /*
114 * Utilities for getting filesystem information from the mount table.
115 *
116 * Note: vanilla SVr4 code (pkginstall/dockspace.c) used the output from
117 * popen() on the "/etc/mount" command. However, we need to get more
118 * information about mounted filesystems, so we use the C interfaces to
119 * the mount table, which also happens to be much faster than running
120 * another process. Since several of the pkg commands need access to the
121 * the code has been placed here, to be included in the libinst library.
122 */
123
124 #define ALLOC_CHUNK 30
125
126 /*
127 * fs_tab_ent_comp - compare fstable entries first by length in reverse
128 * order, then alphabetically.
129 */
130 static int
fs_tab_ent_comp(const void * e1,const void * e2)131 fs_tab_ent_comp(const void *e1, const void *e2)
132 {
133 struct fstable *fs1 = *((struct fstable **)e1);
134 struct fstable *fs2 = *((struct fstable **)e2);
135
136 if (fs1->namlen == fs2->namlen)
137 return (strcmp(fs1->name, fs2->name));
138 else
139 return (fs2->namlen - fs1->namlen);
140 }
141
142 /*
143 * This determines if the source of the mount is from another host. If it's
144 * from this host, then it might be writable. This returns NOT_REMOTE if it's
145 * pure local, REAL_REMOTE if it's being served from another host and
146 * SELF_SERVE if it's being served by the current host.
147 */
148 static int
is_remote_src(char * source)149 is_remote_src(char *source)
150 {
151 static char host_name[HOST_NM_LN];
152 char source_host[HOST_NM_LN], *src_ptr, *src_host_ptr;
153 static int hn_len;
154
155 if (hn_len == 0) {
156 /* Find out what host this is. */
157 (void) sysinfo(SI_HOSTNAME, host_name, HOST_NM_LN);
158 hn_len = strlen(host_name);
159 }
160
161 if (source[0] == '/')
162 return (NOT_REMOTE); /* No server name, so it's local. */
163
164 if (strchr(source, ':') == NULL)
165 return (NOT_REMOTE); /* it's a floppy disk or something */
166
167 src_ptr = source;
168 src_host_ptr = source_host;
169
170 /* Scan to the end of the hostname (find the ":"). */
171 while (*src_ptr != ':')
172 *src_host_ptr++ = *src_ptr++;
173 *src_host_ptr = '\0';
174
175 /* Multiple hosts: failover with multiple servers; this is remote. */
176 if (strchr(source_host, ',') != NULL)
177 return (REAL_REMOTE);
178
179 if (strncmp(source, host_name, hn_len) == 0 &&
180 *(source+hn_len) == ':' || is_local_host(source_host))
181 return (SELF_SERVE); /* Exporting from itself, it's local. */
182
183 return (REAL_REMOTE);
184 }
185
186 /*
187 * This determines if an apparently writeable filesystem is really writeable
188 * or if it's been shared over the network with root-restrictive options.
189 */
190 static int
really_write(char * mountpt)191 really_write(char *mountpt)
192 {
193 char testfile[PATH_MAX];
194 int fd, retval = 0;
195 struct stat status;
196
197 (void) snprintf(testfile, sizeof (testfile), "%s/testXXXXXX", mountpt);
198
199 if (mktemp(testfile) == NULL)
200 return (0); /* may as well be read-only */
201 /* LINTED do not use creat(); use open(path,... */
202 else if ((fd = creat(testfile, 0777)) == -1)
203 return (0); /* can't write */
204 else if (fstat(fd, &status) == -1)
205 retval = 0; /* may as well be read-only */
206 else if (status.st_uid != 0)
207 retval = 0; /* too many restrictions */
208 else
209 retval = 1;
210
211 (void) close(fd);
212 (void) unlink(testfile);
213
214 return (retval);
215 }
216
217 /* This returns the hostname portion of a remote path. */
218 char *
get_server_host(uint32_t n)219 get_server_host(uint32_t n)
220 {
221 static char hostname[HOST_NM_LN], *host_end;
222
223 if (fs_tab_used == 0) {
224 return ("unknown source");
225 }
226
227 if (n < fs_tab_used) {
228 (void) strcpy(hostname, fs_tab[n]->remote_name);
229 if ((host_end = strchr(hostname, ':')) == NULL) {
230 if ((strcmp(fs_tab[n]->fstype, MNTTYPE_AUTO)) == NULL)
231 return ("automounter");
232 else
233 return (fs_tab[n]->fstype);
234 } else {
235 *host_end = '\0';
236 return (hostname);
237 }
238 }
239
240 return ("unknown source");
241 }
242
243 /*
244 * This pulls the path out of a hostpath which may be of the form host:path
245 * where path is an absolute path. NOTE: If path turns out to be relative,
246 * this returns NULL.
247 */
248 static char *
path_part(char * hostpath)249 path_part(char *hostpath)
250 {
251 char *host_end;
252
253 if ((host_end = strchr(hostpath, ':')) == NULL && hostpath[0] == '/')
254 return (hostpath); /* It's already legit. */
255
256 if (*(host_end+1) == '/')
257 return (host_end+1); /* Here's the path part. */
258
259 return (NULL);
260 }
261
262 /*
263 * This scans the filesystems already mounted to see if this remote mount is
264 * already in place on the server. This scans the fs_tab for a remote_name
265 * exactly matching the client's. It stores the current entry number
266 * corresponding to this mount in the static match_mount.
267 *
268 * Returns:
269 * MNT_NOT Couldn't find it.
270 * MNT_EXACT This has actually been manually mounted for us
271 * MNT_AVAIL This is mounted for the server, but needs to be
272 * loopback mounted from the client's perspective.
273 */
274 static int
already_mounted(struct vfstab * vfs,int is_local_host,char * client_path,char * host_path)275 already_mounted(struct vfstab *vfs, int is_local_host, char *client_path,
276 char *host_path)
277 {
278 int i;
279
280 match_mount = -1;
281
282 if (fs_tab_used == 0) {
283 return (MNT_NOT);
284 }
285
286 for (i = 0; i < fs_tab_used; i++) {
287 /*
288 * Determine if this has been manually mounted exactly as we
289 * require. Begin by finding a mount on our current
290 * mountpoint.
291 */
292 if (strcmp(fs_tab[i]->name, client_path) == 0) {
293 /*
294 * Now see if it is really the same mount. This isn't
295 * smart enough to find mounts on top of mounts, but
296 * assuming there is no conspiracy to fool this
297 * function, it will be good enough.
298 */
299 if (is_local_host &&
300 strcmp(fs_tab[i]->remote_name, host_path) == 0) {
301 match_mount = i;
302 return (MNT_EXACT);
303 }
304 }
305
306 /* Determine if this mount is available to the server. */
307 if (strcmp(fs_tab[i]->remote_name, vfs->vfs_special) == 0) {
308 match_mount = i;
309 return (MNT_AVAIL);
310 }
311 }
312 return (MNT_NOT);
313 }
314
315 /*
316 * This function unmounts all of the loopback mounts created for the client.
317 * If no client stuff is mounted, this is completely benign, it finds that
318 * nothing is mounted up and returns. It returns "1" for unmounted everything
319 * OK and "0" for failure.
320 */
321 int
unmount_client()322 unmount_client()
323 {
324 int errcode;
325 int exit_no;
326 int n;
327 int retcode = 1;
328 int status;
329 pid_t pid;
330 pid_t pid_return;
331
332 if (fs_tab_used == 0) {
333 return (1);
334 }
335
336 for (n = 0; n < fs_tab_used-1; n++) {
337 /* If the filesystem is mounted and this utility did it ... */
338 if (fs_tab[n]->cl_mounted && fs_tab[n]->srvr_map) {
339 char *arg[3];
340
341 /* create arglist for umount command */
342
343 arg[0] = UMOUNT;
344 arg[1] = fs_tab[n]->name;
345 arg[2] = (char *)NULL;
346
347 /* flush standard i/o before creating new process */
348
349 (void) fflush(stderr);
350 (void) fflush(stdout);
351
352 /*
353 * create new process to execute command in;
354 * vfork is being used to avoid duplicating the parents
355 * memory space - this means that the child process may
356 * not modify any of the parents memory including the
357 * standard i/o descriptors - all the child can do is
358 * adjust interrupts and open files as a prelude to a
359 * call to exec().
360 */
361
362 pid = vfork();
363 if (pid < 0) {
364 /* fork failed! */
365
366 logerr(WRN_BAD_FORK, errno, strerror(errno));
367 retcode = 0;
368 } else if (pid > 0) {
369 /*
370 * this is the parent process
371 */
372
373 status = 0;
374 pid_return = waitpid(pid, &status, 0);
375
376 if (pid_return != pid) {
377 logerr(WRN_BAD_WAIT, pid, pid_return,
378 (unsigned long)status, errno,
379 strerror(errno));
380 retcode = 0;
381 }
382
383 /*
384 * If the child was stopped or killed by a
385 * signal or exied with any code but 0, we
386 * assume the mount has failed.
387 */
388
389 if (!WIFEXITED(status) ||
390 (errcode = WEXITSTATUS(status))) {
391 retcode = 0;
392 logerr(WRN_FSTAB_UMOUNT,
393 fs_tab[n]->name, errcode);
394 } else {
395 fs_tab[n]->cl_mounted = 0;
396 }
397 } else {
398 /*
399 * this is the child process
400 */
401
402 int i;
403
404 /* reset any signals to default */
405
406 for (i = 0; i < NSIG; i++) {
407 (void) sigset(i, SIG_DFL);
408 }
409
410 /*
411 * Redirect output to /dev/null because the
412 * umount error message may be confusing to
413 * the user.
414 */
415
416 i = open("/dev/null", O_WRONLY);
417 if (i >= 0) {
418 dup2(2, STDERR_FILENO);
419 }
420
421 /* close all file descriptors except stdio */
422
423 closefrom(3);
424
425 exit_no = execve(arg[0], arg, environ);
426 _exit(exit_no);
427 }
428 }
429 }
430
431 return (retcode);
432 }
433
434 /*
435 * This function creates the necessary loopback mounts to emulate the client
436 * configuration with respect to the server. If this is being run on a
437 * standalone or the installation is actually to the local system, this call
438 * is benign since srvr_map won't be set anywhere. It returns "1" for mounted
439 * everything OK and "0" for failure.
440 */
441 int
mount_client()442 mount_client()
443 {
444 int errcode;
445 int exit_no;
446 int n;
447 int retcode = 1;
448 int status;
449 pid_t pid;
450 pid_t pid_return;
451
452 if (fs_tab_used == 0) {
453 return (1);
454 }
455
456 for (n = fs_tab_used-1; n >= 0; n--) {
457 /*
458 * If the filesystem is mounted (meaning available) and the
459 * apparent filesystem can be mapped to a local filesystem
460 * AND the local filesystem is not the same as the target
461 * filesystem, mount it.
462 */
463 if (fs_tab[n]->mounted && fs_tab[n]->srvr_map) {
464 char *arg[6];
465
466 /* create arglist for mount command */
467
468 arg[0] = MOUNT;
469 arg[1] = "-F";
470 arg[2] = "lofs";
471 arg[3] = fs_tab[n]->remote_name;
472 arg[4] = fs_tab[n]->name;
473 arg[5] = (char *)NULL;
474
475 /* flush standard i/o before creating new process */
476
477 (void) fflush(stderr);
478 (void) fflush(stdout);
479
480 /*
481 * create new process to execute command in;
482 * vfork is being used to avoid duplicating the parents
483 * memory space - this means that the child process may
484 * not modify any of the parents memory including the
485 * standard i/o descriptors - all the child can do is
486 * adjust interrupts and open files as a prelude to a
487 * call to exec().
488 */
489
490 pid = vfork();
491 if (pid < 0) {
492 /* fork failed! */
493
494 logerr(WRN_BAD_FORK, errno, strerror(errno));
495 retcode = 0;
496 } else if (pid > 0) {
497 /*
498 * this is the parent process
499 */
500
501 pid_return = waitpid(pid, &status, 0);
502
503 if (pid_return != pid) {
504 logerr(WRN_BAD_WAIT, pid, pid_return,
505 (unsigned long)status, errno,
506 strerror(errno));
507 retcode = 0;
508 }
509
510 /*
511 * If the child was stopped or killed by a
512 * signal or exied with any code but 0, we
513 * assume the mount has failed.
514 */
515
516 if (!WIFEXITED(status) ||
517 (errcode = WEXITSTATUS(status))) {
518 retcode = 0;
519 fs_tab[n]->mnt_failed = 1;
520 logerr(WRN_FSTAB_MOUNT,
521 fs_tab[n]->name, errcode);
522 } else {
523 fs_tab[n]->cl_mounted = 1;
524 }
525 } else {
526 /*
527 * this is the child process
528 */
529
530 int i;
531
532 /* reset all signals to default */
533
534 for (i = 0; i < NSIG; i++) {
535 (void) sigset(i, SIG_DFL);
536 }
537
538 /*
539 * Redirect output to /dev/null because the
540 * mount error message may be confusing to
541 * the user.
542 */
543
544 i = open("/dev/null", O_WRONLY);
545 if (i >= 0) {
546 dup2(i, STDERR_FILENO);
547 }
548
549 /* close all file descriptors except stdio */
550
551 closefrom(3);
552
553 exit_no = execve(arg[0], arg, environ);
554 _exit(exit_no);
555 /*NOTREACHED*/
556 }
557 }
558 }
559 return (retcode);
560 }
561
562 /*
563 * This function maps path, on a loopback filesystem, back to the real server
564 * filesystem. fsys_value is the fs_tab[] entry to which the loopback'd path is
565 * mapped. This returns a pointer to a static area. If the result is needed
566 * for further processing, it should be strdup()'d or something.
567 */
568 char *
server_map(char * path,uint32_t fsys_value)569 server_map(char *path, uint32_t fsys_value)
570 {
571 static char server_construction[PATH_MAX];
572
573 if (fs_tab_used == 0) {
574 (void) strcpy(server_construction, path);
575 } else if (fsys_value < fs_tab_used) {
576 (void) snprintf(server_construction,
577 sizeof (server_construction),
578 "%s%s", fs_tab[fsys_value]->remote_name,
579 path+strlen(fs_tab[fsys_value]->name));
580 } else {
581 (void) strcpy(server_construction, path);
582 }
583
584 return (server_construction);
585 }
586
587 /* This function sets up the standard parts of the fs_tab. */
588 static struct fstable *
fs_tab_init(char * mountp,char * fstype)589 fs_tab_init(char *mountp, char *fstype)
590 {
591 struct fstable *nfte;
592
593 /* Create the array if necessary. */
594 if (fs_list == -1) {
595 fs_list = ar_create(ALLOC_CHUNK,
596 (unsigned)sizeof (struct fstable),
597 "filesystem mount data");
598 if (fs_list == -1) {
599 progerr(ERR_MALLOC, "fs_list", errno, strerror(errno));
600 return (NULL);
601 }
602 }
603
604 /*
605 * Allocate an fstable entry for this mnttab entry.
606 */
607 if ((nfte = *(struct fstable **)ar_next_avail(fs_list))
608 == NULL) {
609 progerr(ERR_MALLOC, "nfte", errno, strerror(errno));
610 return (NULL);
611 }
612
613 /*
614 * Point fs_tab at the head of the array again, since it may have
615 * moved due to realloc in ar_next_avail(). If ar_next_avail() realizes
616 * that there is no more room to grow the array, it reallocates the
617 * array. Because we stored pointer to that array in fs_tab, we need
618 * to make sure that it is updated as well.
619 */
620 if ((fs_tab = (struct fstable **)ar_get_head(fs_list)) == NULL) {
621 progerr(ERR_NOTABLE, "mount", MOUNT_TABLE, strerror(errno));
622 return (NULL);
623 }
624
625 /*
626 * Get the length of the 'mount point' name.
627 */
628 nfte->namlen = strlen(mountp);
629 /*
630 * Allocate space for the 'mount point' name.
631 */
632 if ((nfte->name = malloc(nfte->namlen+1)) == NULL) {
633 progerr(ERR_MALLOC, "name", errno, strerror(errno));
634 return (NULL);
635 }
636 (void) strcpy(nfte->name, mountp);
637
638 if ((nfte->fstype = malloc(strlen(fstype)+1)) == NULL) {
639 progerr(ERR_MALLOC, "fstype", errno, strerror(errno));
640 return (NULL);
641 }
642 (void) strcpy(nfte->fstype, fstype);
643
644 fs_tab_used++;
645
646 return (nfte);
647 }
648
649 /* This function frees all memory associated with the filesystem table. */
650 void
fs_tab_free(void)651 fs_tab_free(void)
652 {
653 int n;
654
655 if (fs_tab_used == 0) {
656 return;
657 }
658
659 for (n = 0; n < fs_tab_used; n++) {
660 free(fs_tab[n]->fstype);
661 free(fs_tab[n]->name);
662 free(fs_tab[n]->remote_name);
663 }
664
665 ar_free(fs_list);
666 }
667
668 /* This function scans a string of mount options for a specific keyword. */
669 static int
hasopt(char * options,char * keyword)670 hasopt(char *options, char *keyword)
671 {
672 char vfs_options[VFS_LINE_MAX], *optptr;
673
674 if (!options) {
675 (void) strcpy(vfs_options, "ro");
676 } else {
677 (void) strcpy(vfs_options, options);
678 }
679
680 while (optptr = strrchr(vfs_options, ',')) {
681 *optptr++ = '\0';
682
683 if (strcmp(optptr, keyword) == 0)
684 return (1);
685 }
686
687 /* Now deal with the remainder. */
688 if (strcmp(vfs_options, keyword) == 0)
689 return (1);
690
691 return (0);
692 }
693
694 /*
695 * This function constructs a new filesystem table (fs_tab[]) entry based on
696 * an /etc/mnttab entry. When it returns, the new entry has been inserted
697 * into fs_tab[].
698 */
699 static int
construct_mt(struct mnttab * mt)700 construct_mt(struct mnttab *mt)
701 {
702 struct fstable *nfte;
703
704 /*
705 * Initialize fstable structure and make the standard entries.
706 */
707 if ((nfte = fs_tab_init(mt->mnt_mountp, mt->mnt_fstype)) == NULL)
708 return (1);
709
710 /*
711 * See if this is served from another host.
712 * Testing the type is cheap; finding the hostname is not.
713 * At this point, we're using the REAL mnttab; since we're not
714 * allowed to mount ourself with "NFS", "NFS" must be remote.
715 * The automount will translate "nfs:self" to a lofs mount.
716 */
717 if (strcmp(mt->mnt_fstype, MNTTYPE_AUTO) == 0 ||
718 strcmp(mt->mnt_fstype, MNTTYPE_NFS) == 0 ||
719 is_remote_src(mt->mnt_special) == REAL_REMOTE)
720 nfte->remote = 1;
721 else
722 nfte->remote = 0;
723
724 /* It's mounted now (by definition), so we don't have to remap it. */
725 nfte->srvr_map = 0;
726 nfte->mounted = 1;
727
728 nfte->remote_name = strdup(mt->mnt_special);
729
730 /*
731 * This checks the mount commands which establish the most
732 * basic level of access. Later further tests may be
733 * necessary to fully qualify this. We set this bit
734 * preliminarily because we have access to the mount data
735 * now.
736 */
737 nfte->writeable = 0; /* Assume read-only. */
738 if (hasmntopt(mt, MNTOPT_RO) == NULL) {
739 nfte->writeable = 1;
740 if (!(nfte->remote))
741 /*
742 * There's no network involved, so this
743 * assessment is confirmed.
744 */
745 nfte->write_tested = 1;
746 } else
747 /* read-only is read-only */
748 nfte->write_tested = 1;
749
750 /* Is this coming to us from a server? */
751 if (nfte->remote && !(nfte->writeable))
752 nfte->served = 1;
753
754 return (0);
755 }
756
757 /*
758 * This function modifies an existing fs_tab[] entry. It was found mounted up
759 * exactly the way we would have mounted it in mount_client() only at the
760 * time we didn't know it was for the client. Now we do, so we're setting the
761 * various permissions to conform to the client view.
762 */
763 static void
mod_existing(struct vfstab * vfsent,int fstab_entry,int is_remote)764 mod_existing(struct vfstab *vfsent, int fstab_entry, int is_remote)
765 {
766 /*
767 * Establish whether the client will see this as served.
768 */
769 if (is_remote && hasopt(vfsent->vfs_mntopts, MNTOPT_RO))
770 fs_tab[fstab_entry]->served = 1;
771
772 fs_tab[fstab_entry]->cl_mounted = 1;
773 }
774
775 /*
776 * This function constructs a new fs_tab[] entry based on
777 * an /etc/vfstab entry. When it returns, the new entry has been inserted
778 * into fstab[].
779 */
780 static int
construct_vfs(struct vfstab * vfsent,char * client_path,char * link_name,int is_remote,int mnt_stat)781 construct_vfs(struct vfstab *vfsent, char *client_path, char *link_name,
782 int is_remote, int mnt_stat)
783 {
784 int use_link;
785 struct fstable *nfte;
786
787 if ((nfte = fs_tab_init(client_path, vfsent->vfs_fstype)) == NULL)
788 return (1);
789
790 nfte->remote = (is_remote == REAL_REMOTE);
791
792 /*
793 * The file system mounted on the client may or may not be writeable.
794 * So we hand it over to fsys() to evaluate. This will have the same
795 * read/write attributes as the corresponding mounted filesystem.
796 */
797 use_link = 0;
798 if (nfte->remote) {
799 /*
800 * Deal here with mount points actually on a system remote
801 * from the server.
802 */
803 if (mnt_stat == MNT_NOT) {
804 /*
805 * This filesystem isn't in the current mount table
806 * meaning it isn't mounted, the current host can't
807 * write to it and there's no point to mapping it for
808 * the server.
809 */
810 link_name = NULL;
811 nfte->mounted = 0;
812 nfte->srvr_map = 0;
813 nfte->writeable = 0;
814 } else { /* It's MNT_AVAIL. */
815 /*
816 * This filesystem is associated with a current
817 * mountpoint. Since it's mounted, it needs to be
818 * remapped and it is writable if the real mounted
819 * filesystem is writeable.
820 */
821 use_link = 1;
822 link_name = strdup(fs_tab[match_mount]->name);
823 nfte->mounted = 1;
824 nfte->srvr_map = 1;
825 nfte->writeable = fs_tab[match_mount]->writeable;
826 nfte->write_tested = fs_tab[match_mount]->write_tested;
827 }
828 } else { /* local filesystem */
829 use_link = 1;
830 nfte->mounted = 1;
831 nfte->srvr_map = 1;
832 nfte->writeable = fs_tab[fsys(link_name)]->writeable;
833 nfte->write_tested = 1;
834 }
835
836 /*
837 * Now we establish whether the client will see this as served.
838 */
839 if (is_remote && hasopt(vfsent->vfs_mntopts, MNTOPT_RO))
840 nfte->served = 1;
841
842 if (use_link) {
843 nfte->remote_name = link_name;
844 } else {
845 nfte->remote_name = strdup(vfsent->vfs_special);
846 }
847
848 return (0);
849 }
850
851 /*
852 * get_mntinfo - get the mount table, now dynamically allocated. Returns 0 if
853 * no problem and 1 if there's a fatal error.
854 */
855 int
get_mntinfo(int map_client,char * vfstab_file)856 get_mntinfo(int map_client, char *vfstab_file)
857 {
858 static char *rn = "/";
859 FILE *pp;
860 struct mnttab mtbuf;
861 struct mnttab *mt = &mtbuf;
862 char *install_root;
863 int is_remote;
864
865 /*
866 * Open the mount table for the current host and establish a global
867 * table that holds data about current mount status.
868 */
869 if ((pp = setmntent(MOUNT_TABLE, "r")) == NULL) {
870 progerr(ERR_NOTABLE, "mount", MOUNT_TABLE, strerror(errno));
871 return (1);
872 }
873
874 /*
875 * First, review the mounted filesystems on the managing host. This
876 * may also be the target host but we haven't decided that for sure
877 * yet.
878 */
879 while (!getmntent(pp, mt))
880 if (construct_mt(mt))
881 return (1);
882
883 (void) endmntent(pp);
884
885 /*
886 * Now, we see if this installation is to a client. If it is, we scan
887 * the client's vfstab to determine what filesystems are
888 * inappropriate to write to. This simply adds the vfstab entries
889 * representing what will be remote file systems for the client.
890 * Everything that isn't remote to the client is already accounted
891 * for in the fs_tab[] so far. If the remote filesystem is really on
892 * this server, we will write through to the server from this client.
893 */
894 install_root = get_inst_root();
895 if (install_root && strcmp(install_root, "/") != 0 && map_client) {
896 /* OK, this is a legitimate remote client. */
897 struct vfstab vfsbuf;
898 struct vfstab *vfs = &vfsbuf;
899 char VFS_TABLE[PATH_MAX];
900
901 /*
902 * Since we use the fsys() function later, and it depends on
903 * an ordered list, we have to sort the list here.
904 */
905 qsort(fs_tab, fs_tab_used,
906 sizeof (struct fstable *), fs_tab_ent_comp);
907
908 /*
909 * Here's where the vfstab for the target is. If we can get
910 * to it, we'll scan it for what the client will see as
911 * remote filesystems, otherwise, we'll just skip this.
912 */
913 if (vfstab_file) {
914 (void) snprintf(VFS_TABLE, sizeof (VFS_TABLE), "%s",
915 vfstab_file);
916 } else {
917 (void) snprintf(VFS_TABLE, sizeof (VFS_TABLE), "%s%s",
918 install_root, VFSTAB);
919 }
920
921 if (access(VFS_TABLE, R_OK) == 0) {
922 char *link_name;
923
924 /*
925 * Open the vfs table for the target host.
926 */
927 if ((pp = setmntent(VFS_TABLE, "r")) == NULL) {
928 progerr(ERR_NOTABLE, "vfs", VFS_TABLE,
929 strerror(errno));
930 return (1);
931 }
932
933 /* Do this for each entry in the vfstab. */
934 while (!getvfsent(pp, vfs)) {
935 char client_mountp[PATH_MAX];
936 int mnt_stat;
937
938 /*
939 * We put it into the fs table if it's
940 * remote mounted (even from this server) or
941 * loopback mounted from the client's point
942 * of view.
943 */
944 if (!(is_remote =
945 is_remote_src(vfs->vfs_special)) &&
946 strcmp(vfs->vfs_fstype, MNTTYPE_LOFS) !=
947 0)
948 continue; /* not interesting */
949
950 /*
951 * Construct client_mountp by prepending the
952 * install_root to the 'mount point' name.
953 */
954 if (strcmp(vfs->vfs_mountp, "/") == 0) {
955 (void) strcpy(client_mountp,
956 install_root);
957 } else {
958 (void) snprintf(client_mountp,
959 sizeof (client_mountp), "%s%s",
960 install_root, vfs->vfs_mountp);
961 }
962
963 /*
964 * We also skip the entry if the vfs_special
965 * path and the client_path are the same.
966 * There's no need to mount it, it's just a
967 * cachefs optimization that mounts a
968 * directory over itself from this server.
969 */
970 if ((is_remote == SELF_SERVE) &&
971 strcmp(path_part(vfs->vfs_special),
972 client_mountp) == 0)
973 continue;
974
975 /* Determine if this is already mounted. */
976 link_name = strdup(path_part(vfs->vfs_special));
977 mnt_stat = already_mounted(vfs,
978 (is_remote != REAL_REMOTE), client_mountp,
979 link_name);
980
981 if (mnt_stat == MNT_EXACT) {
982 mod_existing(vfs, match_mount,
983 is_remote);
984 } else { /* MNT_NOT */
985 if (construct_vfs(vfs, client_mountp,
986 link_name, is_remote, mnt_stat)) {
987 return (1);
988 }
989 }
990 }
991 (void) endmntent(pp);
992 } /* end of if(access()) */
993 } /* end of if(install_root) */
994
995 /* This next one may look stupid, but it can really happen. */
996 if (fs_tab_used <= 0) {
997 progerr(ERR_MNT_NOMOUNTS);
998 return (1);
999 }
1000
1001 /*
1002 * Now that we have the complete list of mounted (or virtually
1003 * mounted) filesystems, we sort the mountpoints in reverse order
1004 * based on the length of the 'mount point' name.
1005 */
1006 qsort(fs_tab, fs_tab_used, sizeof (struct fstable *), fs_tab_ent_comp);
1007 if (strcmp(fs_tab[fs_tab_used-1]->name, rn) != 0) {
1008 progerr(ERR_MNT_NOROOT, fs_tab[fs_tab_used-1]->name, rn, errno,
1009 strerror(errno));
1010 return (1);
1011 } else {
1012 return (0);
1013 }
1014 }
1015
1016 /*
1017 * This function supports dryrun mode by allowing the filesystem table to be
1018 * directly loaded from the continuation file.
1019 */
1020 int
load_fsentry(struct fstable * fs_entry,char * name,char * fstype,char * remote_name)1021 load_fsentry(struct fstable *fs_entry, char *name, char *fstype,
1022 char *remote_name)
1023 {
1024 struct fstable *nfte;
1025
1026 if ((nfte = fs_tab_init(name, fstype)) == NULL)
1027 return (1);
1028
1029 /* Grab the name and fstype from the new structure. */
1030 fs_entry->name = nfte->name;
1031 fs_entry->fstype = nfte->fstype;
1032
1033 /* Copy the basic structure into place. */
1034 (void) memcpy(nfte, fs_entry, sizeof (struct fstable));
1035
1036 /*
1037 * Allocate space for the 'special' name.
1038 */
1039 if ((nfte->remote_name = malloc(strlen(remote_name)+1)) == NULL) {
1040 progerr(ERR_MALLOC, "remote_name", errno, strerror(errno));
1041 return (1);
1042 }
1043
1044 (void) strcpy(nfte->remote_name, remote_name);
1045
1046 return (0);
1047 }
1048
1049 /*
1050 * Given a path, return the table index of the filesystem the file apparently
1051 * resides on. This doesn't put any time into resolving filesystems that
1052 * refer to other filesystems. It just returns the entry containing this
1053 * path.
1054 */
1055 uint32_t
fsys(char * path)1056 fsys(char *path)
1057 {
1058 register int i;
1059 char real_path[PATH_MAX];
1060 char path_copy[PATH_MAX];
1061 char *path2use;
1062 char *cp;
1063 int pathlen;
1064 boolean_t found = B_FALSE;
1065
1066 /*
1067 * The loop below represents our best effort to identify real path of
1068 * a file, which doesn't need to exist. realpath() returns error for
1069 * nonexistent path, therefore we need to cut off trailing components
1070 * of path until we get path which exists and can be resolved by
1071 * realpath(). Lookup of "/dir/symlink/nonexistent-file" would fail
1072 * to resolve symlink without this.
1073 */
1074 (void) strlcpy(path_copy, path, PATH_MAX);
1075 for (cp = dirname(path_copy); strlen(cp) > 1; cp = dirname(cp)) {
1076 if (realpath(cp, real_path) != NULL) {
1077 found = B_TRUE;
1078 break;
1079 } else if (errno != ENOENT)
1080 break;
1081 }
1082 if (found)
1083 path2use = real_path;
1084 else
1085 /* fall back to original path in case of unexpected failure */
1086 path2use = path;
1087
1088 pathlen = strlen(path2use);
1089
1090 /*
1091 * The following algorithm scans the list of attached file systems
1092 * for the one containing path. At this point the file names in
1093 * fs_tab[] are sorted by decreasing length to facilitate the scan.
1094 * The first for() scans past all the file system names too short to
1095 * contain path. The second for() does the actual string comparison.
1096 * It tests first to assure that the comparison is against a complete
1097 * token by assuring that the end of the filesystem name aligns with
1098 * the end of a token in path2use (ie: '/' or NULL) then it does a
1099 * string compare. -- JST
1100 */
1101
1102 if (fs_tab_used == 0) {
1103 return (-1);
1104 }
1105
1106 for (i = 0; i < fs_tab_used; i++)
1107 if (fs_tab[i] == NULL)
1108 continue;
1109 else if (fs_tab[i]->namlen <= pathlen)
1110 break;
1111 for (; i < fs_tab_used; i++) {
1112 int fs_namelen;
1113 char term_char;
1114
1115 if (fs_tab[i] == NULL)
1116 continue;
1117
1118 fs_namelen = fs_tab[i]->namlen;
1119 term_char = path2use[fs_namelen];
1120
1121 /*
1122 * If we're putting the file "/a/kernel" into the filesystem
1123 * "/a", then fs_namelen == 2 and term_char == '/'. If, we're
1124 * putting "/etc/termcap" into "/", fs_namelen == 1 and
1125 * term_char (unfortunately) == 'e'. In the case of
1126 * fs_namelen == 1, we check to make sure the filesystem is
1127 * "/" and if it is, we have a guaranteed fit, otherwise we
1128 * do the string compare. -- JST
1129 */
1130 if ((fs_namelen == 1 && *(fs_tab[i]->name) == '/') ||
1131 ((term_char == '/' || term_char == NULL) &&
1132 strncmp(fs_tab[i]->name, path2use, fs_namelen) == 0)) {
1133 return (i);
1134 }
1135 }
1136
1137 /*
1138 * It only gets here if the root filesystem is fundamentally corrupt.
1139 * (This can happen!)
1140 */
1141 progerr(ERR_FSYS_FELLOUT, path2use);
1142
1143 return (-1);
1144 }
1145
1146 /*
1147 * This function returns the entry in the fs_tab[] corresponding to the
1148 * actual filesystem of record. It won't return a loopback filesystem entry,
1149 * it will return the filesystem that the loopback filesystem is mounted
1150 * over.
1151 */
1152 uint32_t
resolved_fsys(char * path)1153 resolved_fsys(char *path)
1154 {
1155 int i = -1;
1156 char path2use[PATH_MAX];
1157
1158 (void) strcpy(path2use, path);
1159
1160 /* If this isn't a "real" filesystem, resolve the map. */
1161 do {
1162 (void) strcpy(path2use, server_map(path2use, i));
1163 i = fsys(path2use);
1164 } while (fs_tab[i]->srvr_map);
1165
1166 return (i);
1167 }
1168
1169 /*
1170 * This function returns the srvr_map status based upon the fs_tab entry
1171 * number. This tells us if the server path constructed from the package
1172 * install root is really the target filesystem.
1173 */
1174 int
use_srvr_map_n(uint32_t n)1175 use_srvr_map_n(uint32_t n)
1176 {
1177 return ((int)fs_tab[n]->srvr_map);
1178 }
1179
1180 /*
1181 * This function returns the mount status based upon the fs_tab entry
1182 * number. This tells us if there is any hope of gaining access
1183 * to this file system.
1184 */
1185 int
is_mounted_n(uint32_t n)1186 is_mounted_n(uint32_t n)
1187 {
1188 return ((int)fs_tab[n]->mounted);
1189 }
1190
1191 /*
1192 * is_fs_writeable_n - given an fstab index, return 1
1193 * if it's writeable, 0 if read-only.
1194 */
1195 int
is_fs_writeable_n(uint32_t n)1196 is_fs_writeable_n(uint32_t n)
1197 {
1198 /*
1199 * If the write access permissions haven't been confirmed, do that
1200 * now. Note that the only reason we need to do the special check is
1201 * in the case of an NFS mount (remote) because we can't determine if
1202 * root has access in any other way.
1203 */
1204 if (fs_tab[n]->remote && fs_tab[n]->mounted &&
1205 !fs_tab[n]->write_tested) {
1206 if (fs_tab[n]->writeable && !really_write(fs_tab[n]->name))
1207 fs_tab[n]->writeable = 0; /* not really */
1208
1209 fs_tab[n]->write_tested = 1; /* confirmed */
1210 }
1211
1212 return ((int)fs_tab[n]->writeable);
1213 }
1214
1215 /*
1216 * is_remote_fs_n - given an fstab index, return 1
1217 * if it's a remote filesystem, 0 if local.
1218 *
1219 * Note: Upon entry, a valid fsys() is required.
1220 */
1221 int
is_remote_fs_n(uint32_t n)1222 is_remote_fs_n(uint32_t n)
1223 {
1224 return ((int)fs_tab[n]->remote);
1225 }
1226
1227 /* index-driven is_served() */
1228 int
is_served_n(uint32_t n)1229 is_served_n(uint32_t n)
1230 {
1231 return ((int)fs_tab[n]->served);
1232 }
1233
1234 /*
1235 * This returns the number of blocks available on the indicated filesystem.
1236 *
1237 * Note: Upon entry, a valid fsys() is required.
1238 */
1239 fsblkcnt_t
get_blk_free_n(uint32_t n)1240 get_blk_free_n(uint32_t n)
1241 {
1242 return (fs_tab[n]->bfree);
1243 }
1244
1245 /*
1246 * This returns the number of blocks being used on the indicated filesystem.
1247 *
1248 * Note: Upon entry, a valid fsys() is required.
1249 */
1250 fsblkcnt_t
get_blk_used_n(uint32_t n)1251 get_blk_used_n(uint32_t n)
1252 {
1253 return (fs_tab[n]->bused);
1254 }
1255
1256 /*
1257 * This returns the number of inodes available on the indicated filesystem.
1258 *
1259 * Note: Upon entry, a valid fsys() is required.
1260 */
1261 fsblkcnt_t
get_inode_free_n(uint32_t n)1262 get_inode_free_n(uint32_t n)
1263 {
1264 return (fs_tab[n]->ffree);
1265 }
1266
1267 /*
1268 * This returns the number of inodes being used on the indicated filesystem.
1269 *
1270 * Note: Upon entry, a valid fsys() is required.
1271 */
1272 fsblkcnt_t
get_inode_used_n(uint32_t n)1273 get_inode_used_n(uint32_t n)
1274 {
1275 return (fs_tab[n]->fused);
1276 }
1277
1278 /*
1279 * Sets the number of blocks being used on the indicated filesystem.
1280 *
1281 * Note: Upon entry, a valid fsys() is required.
1282 */
1283 void
set_blk_used_n(uint32_t n,fsblkcnt_t value)1284 set_blk_used_n(uint32_t n, fsblkcnt_t value)
1285 {
1286 fs_tab[n]->bused = value;
1287 }
1288
1289 /* Get the filesystem block size. */
1290 fsblkcnt_t
get_blk_size_n(uint32_t n)1291 get_blk_size_n(uint32_t n)
1292 {
1293 return (fs_tab[n]->bsize);
1294 }
1295
1296 /* Get the filesystem fragment size. */
1297 fsblkcnt_t
get_frag_size_n(uint32_t n)1298 get_frag_size_n(uint32_t n)
1299 {
1300 return (fs_tab[n]->bsize);
1301 }
1302
1303 /*
1304 * This returns the name of the indicated filesystem.
1305 */
1306 char *
get_fs_name_n(uint32_t n)1307 get_fs_name_n(uint32_t n)
1308 {
1309 if (fs_tab_used == 0) {
1310 return (NULL);
1311 } else if (n >= fs_tab_used) {
1312 return (NULL);
1313 } else {
1314 return (fs_tab[n]->name);
1315 }
1316 }
1317
1318 /*
1319 * This returns the remote name of the indicated filesystem.
1320 *
1321 * Note: Upon entry, a valid fsys() is required.
1322 */
1323 char *
get_source_name_n(uint32_t n)1324 get_source_name_n(uint32_t n)
1325 {
1326 return (fs_tab[n]->remote_name);
1327 }
1328
1329 /*
1330 * This function returns the srvr_map status based upon the path.
1331 */
1332 int
use_srvr_map(char * path,uint32_t * fsys_value)1333 use_srvr_map(char *path, uint32_t *fsys_value)
1334 {
1335 if (*fsys_value == BADFSYS)
1336 *fsys_value = fsys(path);
1337
1338 return (use_srvr_map_n(*fsys_value));
1339 }
1340
1341 /*
1342 * This function returns the mount status based upon the path.
1343 */
1344 int
is_mounted(char * path,uint32_t * fsys_value)1345 is_mounted(char *path, uint32_t *fsys_value)
1346 {
1347 if (*fsys_value == BADFSYS)
1348 *fsys_value = fsys(path);
1349
1350 return (is_mounted_n(*fsys_value));
1351 }
1352
1353 /*
1354 * is_fs_writeable - given a cfent entry, return 1
1355 * if it's writeable, 0 if read-only.
1356 *
1357 * Note: Upon exit, a valid fsys() is guaranteed. This is
1358 * an interface requirement.
1359 */
1360 int
is_fs_writeable(char * path,uint32_t * fsys_value)1361 is_fs_writeable(char *path, uint32_t *fsys_value)
1362 {
1363 if (*fsys_value == BADFSYS)
1364 *fsys_value = fsys(path);
1365
1366 return (is_fs_writeable_n(*fsys_value));
1367 }
1368
1369 /*
1370 * is_remote_fs - given a cfent entry, return 1
1371 * if it's a remote filesystem, 0 if local.
1372 *
1373 * Also Note: Upon exit, a valid fsys() is guaranteed. This is
1374 * an interface requirement.
1375 */
1376 int
is_remote_fs(char * path,uint32_t * fsys_value)1377 is_remote_fs(char *path, uint32_t *fsys_value)
1378 {
1379 if (*fsys_value == BADFSYS)
1380 *fsys_value = fsys(path);
1381
1382 return (is_remote_fs_n(*fsys_value));
1383 }
1384
1385 /*
1386 * This function returns the served status of the filesystem. Served means a
1387 * client is getting this file from a server and it is not writeable by the
1388 * client. It has nothing to do with whether or not this particular operation
1389 * (eg: pkgadd or pkgrm) will be writing to it.
1390 */
1391 int
is_served(char * path,uint32_t * fsys_value)1392 is_served(char *path, uint32_t *fsys_value)
1393 {
1394 if (*fsys_value == BADFSYS)
1395 *fsys_value = fsys(path);
1396
1397 return (is_served_n(*fsys_value));
1398 }
1399
1400 /*
1401 * get_remote_path - given a filesystem table index, return the
1402 * path of the filesystem on the remote system. Otherwise,
1403 * return NULL if it's a local filesystem.
1404 */
1405 char *
get_remote_path(uint32_t n)1406 get_remote_path(uint32_t n)
1407 {
1408 char *p;
1409
1410 if (!is_remote_fs_n(n))
1411 return (NULL); /* local */
1412 p = strchr(fs_tab[n]->remote_name, ':');
1413 if (!p)
1414 p = fs_tab[n]->remote_name; /* Loopback */
1415 else
1416 p++; /* remote */
1417 return (p);
1418 }
1419
1420 /*
1421 * get_mount_point - given a filesystem table index, return the
1422 * path of the mount point. Otherwise,
1423 * return NULL if it's a local filesystem.
1424 */
1425 char *
get_mount_point(uint32_t n)1426 get_mount_point(uint32_t n)
1427 {
1428 if (!is_remote_fs_n(n))
1429 return (NULL); /* local */
1430 return (fs_tab[n]->name);
1431 }
1432
1433 struct fstable *
get_fs_entry(uint32_t n)1434 get_fs_entry(uint32_t n)
1435 {
1436 if (fs_tab_used == 0) {
1437 return (NULL);
1438 } else if (n >= fs_tab_used) {
1439 return (NULL);
1440 } else {
1441 return (fs_tab[n]);
1442 }
1443 }
1444