mntinfo.c revision bd93c05dbd9b8f1e8d2edf48c777bc881f927608
/* used with is_remote_src() */ * Due to /etc/mnttab files containing entries for multiple nfs hosts * HOST_NM_LN needs to be accommodating. The recommended value in the sysinfo * man page of 257 needs to be expanded. See bugid 4076513. * 1024 chars is defined in the mnttab.h header as the max size of an entry. * Utilities for getting filesystem information from the mount table. * popen() on the "/etc/mount" command. However, we need to get more * information about mounted filesystems, so we use the C interfaces to * the mount table, which also happens to be much faster than running * another process. Since several of the pkg commands need access to the * the code has been placed here, to be included in the libinst library. * fs_tab_ent_comp - compare fstable entries first by length in reverse * order, then alphabetically. * This determines if the source of the mount is from another host. If it's * from this host, then it might be writable. This returns NOT_REMOTE if it's * pure local, REAL_REMOTE if it's being served from another host and * SELF_SERVE if it's being served by the current host. /* Find out what host this is. */ return (
NOT_REMOTE);
/* No server name, so it's local. */ return (
NOT_REMOTE);
/* it's a floppy disk or something */ /* Scan to the end of the hostname (find the ":"). */ /* Multiple hosts: failover with multiple servers; this is remote. */ return (
SELF_SERVE);
/* Exporting from itself, it's local. */ * This determines if an apparently writeable filesystem is really writeable * or if it's been shared over the network with root-restrictive options. return (0);
/* may as well be read-only */ /* LINTED do not use creat(); use open(path,... */ return (0);
/* can't write */ retval = 0;
/* may as well be read-only */ retval = 0;
/* too many restrictions */ /* This returns the hostname portion of a remote path. */ return (
"unknown source");
return (
"unknown source");
* This pulls the path out of a hostpath which may be of the form host:path * where path is an absolute path. NOTE: If path turns out to be relative, return (
hostpath);
/* It's already legit. */ return (
host_end+
1);
/* Here's the path part. */ * This scans the filesystems already mounted to see if this remote mount is * already in place on the server. This scans the fs_tab for a remote_name * exactly matching the client's. It stores the current entry number * corresponding to this mount in the static match_mount. * MNT_NOT Couldn't find it. * MNT_EXACT This has actually been manually mounted for us * MNT_AVAIL This is mounted for the server, but needs to be * loopback mounted from the client's perspective. * Determine if this has been manually mounted exactly as we * require. Begin by finding a mount on our current * Now see if it is really the same mount. This isn't * smart enough to find mounts on top of mounts, but * assuming there is no conspiracy to fool this * function, it will be good enough. /* Determine if this mount is available to the server. */ * This function unmounts all of the loopback mounts created for the client. * If no client stuff is mounted, this is completely benign, it finds that * nothing is mounted up and returns. It returns "1" for unmounted everything * OK and "0" for failure. /* If the filesystem is mounted and this utility did it ... */ /* create arglist for umount command */ /* flush standard i/o before creating new process */ * create new process to execute command in; * vfork is being used to avoid duplicating the parents * memory space - this means that the child process may * not modify any of the parents memory including the * standard i/o descriptors - all the child can do is * adjust interrupts and open files as a prelude to a * this is the parent process * If the child was stopped or killed by a * signal or exied with any code but 0, we * assume the mount has failed. * this is the child process /* reset any signals to default */ for (i = 0; i <
NSIG; i++) {
* Redirect output to /dev/null because the * umount error message may be confusing to /* close all file descriptors except stdio */ * This function creates the necessary loopback mounts to emulate the client * configuration with respect to the server. If this is being run on a * standalone or the installation is actually to the local system, this call * is benign since srvr_map won't be set anywhere. It returns "1" for mounted * everything OK and "0" for failure. * If the filesystem is mounted (meaning available) and the * apparent filesystem can be mapped to a local filesystem * AND the local filesystem is not the same as the target /* create arglist for mount command */ /* flush standard i/o before creating new process */ * create new process to execute command in; * vfork is being used to avoid duplicating the parents * memory space - this means that the child process may * not modify any of the parents memory including the * standard i/o descriptors - all the child can do is * adjust interrupts and open files as a prelude to a * this is the parent process * If the child was stopped or killed by a * signal or exied with any code but 0, we * assume the mount has failed. * this is the child process /* reset all signals to default */ for (i = 0; i <
NSIG; i++) {
* Redirect output to /dev/null because the * mount error message may be confusing to /* close all file descriptors except stdio */ * This function maps path, on a loopback filesystem, back to the real server * filesystem. fsys_value is the fs_tab[] entry to which the loopback'd path is * mapped. This returns a pointer to a static area. If the result is needed * for further processing, it should be strdup()'d or something. /* This function sets up the standard parts of the fs_tab. */ /* Create the array if necessary. */ "filesystem mount data");
* Allocate an fstable entry for this mnttab entry. * Point fs_tab at the head of the array again, since it may have * moved due to realloc in ar_next_avail(). If ar_next_avail() realizes * that there is no more room to grow the array, it reallocates the * array. Because we stored pointer to that array in fs_tab, we need * to make sure that it is updated as well. * Get the length of the 'mount point' name. * Allocate space for the 'mount point' name. /* This function frees all memory associated with the filesystem table. */ /* This function scans a string of mount options for a specific keyword. */ /* Now deal with the remainder. */ * This function constructs a new filesystem table (fs_tab[]) entry based on * an /etc/mnttab entry. When it returns, the new entry has been inserted * Initialize fstable structure and make the standard entries. * See if this is served from another host. * Testing the type is cheap; finding the hostname is not. * At this point, we're using the REAL mnttab; since we're not * allowed to mount ourself with "NFS", "NFS" must be remote. * The automount will translate "nfs:self" to a lofs mount. /* It's mounted now (by definition), so we don't have to remap it. */ * This checks the mount commands which establish the most * basic level of access. Later further tests may be * necessary to fully qualify this. We set this bit * preliminarily because we have access to the mount data * There's no network involved, so this * assessment is confirmed. /* read-only is read-only */ /* Is this coming to us from a server? */ * This function modifies an existing fs_tab[] entry. It was found mounted up * exactly the way we would have mounted it in mount_client() only at the * time we didn't know it was for the client. Now we do, so we're setting the * various permissions to conform to the client view. * Establish whether the client will see this as served. * This function constructs a new fs_tab[] entry based on * an /etc/vfstab entry. When it returns, the new entry has been inserted * The file system mounted on the client may or may not be writeable. * So we hand it over to fsys() to evaluate. This will have the same * read/write attributes as the corresponding mounted filesystem. * Deal here with mount points actually on a system remote * This filesystem isn't in the current mount table * meaning it isn't mounted, the current host can't * write to it and there's no point to mapping it for }
else {
/* It's MNT_AVAIL. */ * This filesystem is associated with a current * mountpoint. Since it's mounted, it needs to be * remapped and it is writable if the real mounted * filesystem is writeable. }
else {
/* local filesystem */ * Now we establish whether the client will see this as served. * get_mntinfo - get the mount table, now dynamically allocated. Returns 0 if * no problem and 1 if there's a fatal error. * Open the mount table for the current host and establish a global * table that holds data about current mount status. * First, review the mounted filesystems on the managing host. This * may also be the target host but we haven't decided that for sure * Now, we see if this installation is to a client. If it is, we scan * the client's vfstab to determine what filesystems are * inappropriate to write to. This simply adds the vfstab entries * representing what will be remote file systems for the client. * Everything that isn't remote to the client is already accounted * for in the fs_tab[] so far. If the remote filesystem is really on * this server, we will write through to the server from this client. /* OK, this is a legitimate remote client. */ * Since we use the fsys() function later, and it depends on * an ordered list, we have to sort the list here. * Here's where the vfstab for the target is. If we can get * to it, we'll scan it for what the client will see as * remote filesystems, otherwise, we'll just skip this. * Open the vfs table for the target host. /* Do this for each entry in the vfstab. */ * We put it into the fs table if it's * remote mounted (even from this server) or * loopback mounted from the client's point continue;
/* not interesting */ * Construct client_mountp by prepending the * install_root to the 'mount point' name. * We also skip the entry if the vfs_special * path and the client_path are the same. /* Determine if this is already mounted. */ }
/* end of if(access()) */ }
/* end of if(install_root) */ /* This next one may look stupid, but it can really happen. */ * Now that we have the complete list of mounted (or virtually * mounted) filesystems, we sort the mountpoints in reverse order * based on the length of the 'mount point' name. * This function supports dryrun mode by allowing the filesystem table to be * directly loaded from the continuation file. /* Grab the name and fstype from the new structure. */ /* Copy the basic structure into place. */ * Allocate space for the 'special' name. * Given a path, return the table index of the filesystem the file apparently * resides on. This doesn't put any time into resolving filesystems that * refer to other filesystems. It just returns the entry containing this * The loop below represents our best effort to identify real path of * a file, which doesn't need to exist. realpath() returns error for * nonexistent path, therefore we need to cut off trailing components * of path until we get path which exists and can be resolved by * to resolve symlink without this. /* fall back to original path in case of unexpected failure */ * The following algorithm scans the list of attached file systems * for the one containing path. At this point the file names in * fs_tab[] are sorted by decreasing length to facilitate the scan. * The first for() scans past all the file system names too short to * contain path. The second for() does the actual string comparison. * It tests first to assure that the comparison is against a complete * token by assuring that the end of the filesystem name aligns with * the end of a token in path2use (ie: '/' or NULL) then it does a * If we're putting the file "/a/kernel" into the filesystem * "/a", then fs_namelen == 2 and term_char == '/'. If, we're * putting "/etc/termcap" into "/", fs_namelen == 1 and * term_char (unfortunately) == 'e'. In the case of * fs_namelen == 1, we check to make sure the filesystem is * "/" and if it is, we have a guaranteed fit, otherwise we * do the string compare. -- JST * It only gets here if the root filesystem is fundamentally corrupt. * This function returns the entry in the fs_tab[] corresponding to the * actual filesystem of record. It won't return a loopback filesystem entry, * it will return the filesystem that the loopback filesystem is mounted /* If this isn't a "real" filesystem, resolve the map. */ * This function returns the srvr_map status based upon the fs_tab entry * number. This tells us if the server path constructed from the package * install root is really the target filesystem. * This function returns the mount status based upon the fs_tab entry * number. This tells us if there is any hope of gaining access * is_fs_writeable_n - given an fstab index, return 1 * if it's writeable, 0 if read-only. * If the write access permissions haven't been confirmed, do that * now. Note that the only reason we need to do the special check is * in the case of an NFS mount (remote) because we can't determine if * root has access in any other way. * is_remote_fs_n - given an fstab index, return 1 * if it's a remote filesystem, 0 if local. * Note: Upon entry, a valid fsys() is required. /* index-driven is_served() */ * This returns the number of blocks available on the indicated filesystem. * Note: Upon entry, a valid fsys() is required. * This returns the number of blocks being used on the indicated filesystem. * Note: Upon entry, a valid fsys() is required. * This returns the number of inodes available on the indicated filesystem. * Note: Upon entry, a valid fsys() is required. * This returns the number of inodes being used on the indicated filesystem. * Note: Upon entry, a valid fsys() is required. * Sets the number of blocks being used on the indicated filesystem. * Note: Upon entry, a valid fsys() is required. /* Get the filesystem block size. */ /* Get the filesystem fragment size. */ * This returns the name of the indicated filesystem. * This returns the remote name of the indicated filesystem. * Note: Upon entry, a valid fsys() is required. * This function returns the srvr_map status based upon the path. * This function returns the mount status based upon the path. * is_fs_writeable - given a cfent entry, return 1 * if it's writeable, 0 if read-only. * Note: Upon exit, a valid fsys() is guaranteed. This is * an interface requirement. * is_remote_fs - given a cfent entry, return 1 * if it's a remote filesystem, 0 if local. * Also Note: Upon exit, a valid fsys() is guaranteed. This is * an interface requirement. * This function returns the served status of the filesystem. Served means a * client is getting this file from a server and it is not writeable by the * client. It has nothing to do with whether or not this particular operation * (eg: pkgadd or pkgrm) will be writing to it. * get_remote_path - given a filesystem table index, return the * path of the filesystem on the remote system. Otherwise, * return NULL if it's a local filesystem. return (
NULL);
/* local */ * get_mount_point - given a filesystem table index, return the * path of the mount point. Otherwise, * return NULL if it's a local filesystem. return (
NULL);
/* local */