📄 mount_tfs.c
字号:
#ifndef lintstatic char sccsid[] = "@(#)mount_tfs.c 1.1 92/07/30 Copyr 1988 Sun Micro";#endif/* * Usage: mount_tfs [-r] fs1 fs2 ... fsN dir * * TFS mounts fs1 on fs2 on ... on dir. * * Sets up searchlinks from the directory fs1 to fs2, from fs2 to fs3, ... * from fsN to dir, then TFS-mounts fs1 onto dir. Before TFS-mounting * fs1 onto 'dir', these two steps are taken: * 1) loopback mount / onto /tmp_mnt/Tfs_native * 2) loopback mount /tmp_mnt/Tfs_empty onto 'dir' * * The searchlink from fsN points to /tmp_mnt/Tfs_native/'dir' instead of * 'dir'. The two loopback mounts prevent the tfsd from deadlocking with * itself. (After the TFS mount, the tfsd will be serving filesystem * requests for files under 'dir'. The back layer that the tfsd is serving * is also 'dir'. We want to prevent the tfsd from waiting for itself when * it accesses files in 'dir'. The first loopback mount duplicates the * native file system so that the native version of 'dir' can be accessed * through /tmp_mnt/Tfs_native/'dir'. The second loopback mount of an * empty directory over 'dir' prevents the kernel from using the TFS * version of 'dir' when files are accessed in /tmp_mnt/Tfs_native/'dir'.) * * When the searchlinks between layers are set, searchlinks are also set * in the sub-directories of each layer. * * NOTE: this command does not interact well with NSE exec-sets. * If you activate an environment whose exec-set has /usr/lib as a control * point, and also mount_tfs a directory over /usr/lib, then the tfsd * will deadlock when you try to reference /usr/lib. * * The directories fs1, ..., fsN must be writeable, so that searchlinks * can be set in them. */#include <nse/param.h>#include <stdio.h>#include <pwd.h>#include <nse/util.h>#include <sys/stat.h>#include <sys/dir.h>#include <sys/file.h>#include <mntent.h>#include <errno.h>#include <nse/searchlink.h>#include <nse/tfs_calls.h>#include <nse_impl/tfs.h>#include <nse_impl/tfs_user.h>#include <nse/tfs_mount.h>#define TFSD_ENV_NAME "tfs_mount" /* Environment name given to the * tfsd for TFS mounts */bool_t read_only;char *tfs_loopback_dir = "/tmp_mnt/Tfs_native";char *tfs_empty_dir = "/tmp_mnt/Tfs_empty";int tfs_major_dev;Nse_err do_mounts();Nse_err do_loopback_mounts();Nse_err tfs_mount();void get_mountpt_devid();Nse_err ping_tfsd();void find_subdirs();Nse_err build_subdirs();Nse_err build_searchlinks();Nse_err recursive_set_searchlinks();Nse_err set_searchlink();Nse_err make_directory();void unmount_all();Nse_list nse_stringlist_create();main(argc, argv) int argc; char *argv[];{ char **dir_names; int *dir_owners; int i; char *cp; struct stat statb; char fname[MAXPATHLEN]; Nse_list mtab_list; Nse_list subdir_list; bool_t invoked_from_mount = FALSE; Nse_err err; nse_set_cmdname(argv[0]); if (geteuid() != 0) { fprintf(stderr, "%s: Must be root\n", nse_get_cmdname()); exit(1); } if (argc < 3) { usage(); } argv++; argc--; if (options(&argc, &argv)) { exit (1); } if (argc < 2) { usage(); } if (argc == 4 && NSE_STREQ(argv[2], "tfs")) { /* * Allow this command to be exec'ed from the mount command, * in which case the usage line is: * mount_tfs fsname dir tfs opts */ struct mntent mt; argc -= 2; mt.mnt_opts = argv[3]; read_only = (hasmntopt(&mt, MNTOPT_RO) != NULL); invoked_from_mount = TRUE; } /* * Assert: argc == # of directories * argv[0] contains the name of the frontmost directory * argv[argc - 1] contains the name of the backmost directory * (the one being mounted on) * * First fully qualify the directory names. */ dir_names = (char **) nse_malloc((unsigned)(argc + 1) * sizeof(char *)); dir_owners = (int *) nse_malloc((unsigned)(argc + 1) * sizeof(int)); for (i = 0; i < argc; i++) { if (realpath(argv[i], fname) == NULL) { fprintf(stderr, "%s: ", nse_get_cmdname()); perror(argv[i]); exit (1); } dir_names[i] = NSE_STRDUP(fname); } dir_names[argc] = NULL; dir_owners[argc] = NULL; /* * Make sure that all of the specified directories are indeed * directories. */ for (i = 0; i < argc; i++) { if (stat(dir_names[i], &statb) < 0) { fprintf(stderr, "%s: ", nse_get_cmdname()); perror(argv[i]); exit (1); } if (!NSE_ISDIR(&statb)) { fprintf(stderr, "%s: %s is not a directory\n", nse_get_cmdname(), argv[i]); exit (1); } dir_owners[i] = statb.st_uid; } /* * Don't allow TFS mounts over '/'. */ for (cp = dir_names[argc - 1]; *cp == '/'; cp++) ; if (*cp == '\0') { fprintf(stderr, "%s: Cannot mount over \"/\"\n", nse_get_cmdname()); exit (1); } if (err = nse_mtab_read(&mtab_list)) { nse_err_print(err); exit (1); } /* * Build list of sub-TFS mounts that will be covered by this TFS * mount. This list will be used by build_subdirs() to make the * subdirectories under the new TFS mount so that set_searchlink() * can set searchlinks to the directories currently TFS-mounted on * the subdirectories. This allows the following sequence to work: * 1) TFS mount /foo on /usr/src/sys; 2) TFS mount /bar on * /usr/src, such that the first TFS mount shows through under * /usr/src/sys. */ subdir_list = nse_stringlist_create(); nse_list_iterate(mtab_list, find_subdirs, dir_names[argc - 1], subdir_list); /* * Build searchlinks between all the directories 'fs1' ... 'fsN', * 'dir'. The searchlink from 'fsN' is set to point to * /tmp_mnt/Tfs_native/'dir'. */ for (i = 0; i < argc - 1; i++) { /* * Don't want to build searchlinks as root, because root * may have inadequate permissions. */ setregid(0, group_of_user(dir_owners[i])); setreuid(0, dir_owners[i]); err = (Nse_err) nse_list_iterate_or(subdir_list, build_subdirs, dir_names[i]); if (!err) { err = build_searchlinks(dir_names[i], dir_names[i + 1], (i == argc - 2)); } setreuid(0, 0); setregid(0, 0); if (err) { nse_err_print(err); exit (1); } } err = do_mounts(dir_names[0], dir_names[argc - 1], invoked_from_mount); if (err) { nse_err_print(err); exit (1); } else { exit (0); }}Nse_errdo_mounts(fsname, dir, invoked_from_mount) char *fsname; char *dir; bool_t invoked_from_mount;{ Nse_list mtab_list; struct mntent *mnt; int old_mask; Nse_err err; if (err = ping_tfsd()) { nse_err_print(err); exit (1); } mtab_list = nse_mtablist_create(); /* * Block signals while the mounts are taking place, because if * the process is killed between the loopback mount over 'dir' * and the TFS mount over 'dir', 'dir' will be left empty. */ old_mask = sigblock(sigmask(SIGINT) | sigmask(SIGTERM) | sigmask(SIGQUIT)); if ((err = do_loopback_mounts(dir, mtab_list)) || (err = tfs_mount(fsname, dir, &mnt))) { unmount_all(mtab_list); (void) sigsetmask(old_mask); return err; } /* * Don't add mtab entry for the TFS mount to /etc/mtab if command * was invoked from /etc/mount, because /etc/mount will add this * entry itself. */ if (!invoked_from_mount) { get_mountpt_devid(mnt); (void) nse_list_add_new_data(mtab_list, mnt); } if (err = nse_mtab_add(mtab_list)) { fprintf(stderr, "%s: Warning: ", nse_get_cmdname()); nse_err_print(err); } (void) sigsetmask(old_mask); return NULL;}/* * Make the loopback mounts: 1) / onto /tmp_mnt/Tfs_native, and * 2) /tmp_mnt/Tfs_empty onto 'covered_dir'. */Nse_errdo_loopback_mounts(covered_dir, mtab_list) char *covered_dir; Nse_list mtab_list;{ struct stat statb; int rootino; int rootdev; struct mntent *mnt; Nse_err err; if ((err = make_directory(tfs_loopback_dir)) || (err = make_directory(tfs_empty_dir))) { return err; } if (stat("/", &statb) < 0) { return nse_err_format_errno("Stat of \"/\""); } rootino = statb.st_ino; rootdev = statb.st_dev; if (stat(tfs_loopback_dir, &statb) < 0) { return nse_err_format_errno("Stat of \"%s\"", tfs_loopback_dir); } if (statb.st_ino != rootino || statb.st_dev != rootdev) { if (err = nse_mount_loopback("/", tfs_loopback_dir, FALSE, &mnt)) { return err; } get_mountpt_devid(mnt); (void) nse_list_add_new_data(mtab_list, mnt); } if (err = nse_mount_loopback(tfs_empty_dir, covered_dir, FALSE, &mnt)) { return err; } get_mountpt_devid(mnt); (void) nse_list_add_new_data(mtab_list, mnt); return NULL;}Nse_errtfs_mount(fsname, dir, mntp) char *fsname; char *dir; struct mntent **mntp;{ Tfs_mount_args_rec ma; ma.environ = TFSD_ENV_NAME; ma.tfs_mount_pt = dir; ma.directory = fsname; ma.hostname = _nse_hostname(); ma.pid = 1; ma.writeable_layers = 1; ma.back_owner = -1; ma.back_read_only = FALSE; ma.default_view = ""; ma.conditional_view = ""; return nse_tfs_mount(&ma, dir, _nse_hostname(), read_only, mntp, TFS_VERSION);}/* * Get the device # of the new mountpoint and put it into the mount option * string. */voidget_mountpt_devid(mnt) struct mntent *mnt;{ struct stat statb; char opts[100]; if (stat(mnt->mnt_dir, &statb) == 0) { sprintf(opts, "%s,%s=%04x", mnt->mnt_opts, MNTINFO_DEV, statb.st_dev & 0xffff); free(mnt->mnt_opts); mnt->mnt_opts = NSE_STRDUP(opts); }}/* * Ping the tfsd and make sure it's alive. This ensures that the tfsd is * alive before a loopback mount can cover a directory whose contents may * be necessary to start the tfsd. E.g., if the tfsd is being started * from /usr/etc, and the user wants to TFS mount a directory onto /usr/etc, * then the loopback mount of /tmp_mnt/Tfs_empty onto /usr/etc will be * made before the TFS mount, and /usr/etc will be empty until the TFS * mount is done. */Nse_errping_tfsd(){ return nse_tfs_rpc_call_to_host(_nse_hostname(), RFS_NULL, xdr_void, (char *) NULL, xdr_void, (char *) NULL);}/* * If the mtab entry 'mnt' is for a TFS mount on a subdirectory of 'path', * add it to subdir_list. subdir_list is built so that a TFS mount over * a parent directory of an existing TFS mount will not obscure the * existing TFS mount.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -