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