2 * This Cplant(TM) source code is the property of Sandia National
5 * This Cplant(TM) source code is copyrighted by Sandia National
8 * The redistribution of this Cplant(TM) source code is subject to the
9 * terms of the GNU Lesser General Public License
10 * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
12 * Cplant(TM) Copyright 1998-2003 Sandia Corporation.
13 * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
14 * license for use of this work by or on behalf of the US Government.
15 * Export of this program may require a license from the United States
20 * This library is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU Lesser General Public
22 * License as published by the Free Software Foundation; either
23 * version 2.1 of the License, or (at your option) any later version.
25 * This library is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28 * Lesser General Public License for more details.
30 * You should have received a copy of the GNU Lesser General Public
31 * License along with this library; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 * Questions or comments about this library should be sent to:
37 * Sandia National Laboratories, New Mexico
39 * Albuquerque, NM 87185-1110
48 #include <sys/types.h>
50 #ifdef AUTOMOUNT_FILE_NAME
54 #include <sys/queue.h>
60 #ifdef AUTOMOUNT_FILE_NAME
65 * File system and volume mount support.
68 #ifdef AUTOMOUNT_FILE_NAME
70 * Name of autmount specification file in a directory with
73 struct qstr _sysio_mount_file_name = { "", 0, 0 };
79 static LIST_HEAD(, mount) mounts;
82 * Initialization. Must be called before any other routine in this module.
89 #ifdef AUTOMOUNT_FILE_NAME
90 _sysio_next_component(AUTOMOUNT_FILE_NAME, &_sysio_mount_file_name);
97 * Mount rooted sub-tree somewhere in the existing name space.
100 _sysio_do_mount(struct filesys *fs,
101 struct pnode_base *rootpb,
103 struct pnode *tocover,
110 * It's really poor form to allow the new root to be a
111 * descendant of the pnode being covered.
114 struct pnode_base *pb;
117 pb && pb != tocover->p_base;
120 if (pb == tocover->p_base)
127 mnt = malloc(sizeof(struct mount));
132 * Init enough to make the mount record usable to the path node
133 * generation routines.
136 if (fs->fs_flags & FS_F_RO) {
138 * Propagate the read-only flag -- Whether they set it or not.
142 mnt->mnt_flags = flags;
144 * Get alias for the new root.
147 _sysio_p_new_alias(tocover ? tocover->p_parent : NULL, rootpb, mnt);
148 if (!mnt->mnt_root) {
153 * It may have been a while since the root inode was validated;
154 * better validate again. And it better be a directory!
156 err = _sysio_p_validate(mnt->mnt_root, NULL, NULL);
160 if (!S_ISDIR(mnt->mnt_root->p_base->pb_ino->i_mode)) {
165 * Cover up the mount point.
167 mnt->mnt_covers = tocover;
168 if (!mnt->mnt_covers) {
170 * New graph; It covers itself.
172 mnt->mnt_covers = tocover = mnt->mnt_root;
174 tocover->p_cover = mnt->mnt_root;
176 LIST_INSERT_HEAD(&mounts, mnt, mnt_link);
183 P_RELE(mnt->mnt_root);
184 _sysio_p_prune(mnt->mnt_root);
191 * Remove mounted sub-tree from the system.
194 _sysio_do_unmount(struct mount *mnt)
199 root = mnt->mnt_root;
200 if (root->p_cover && root->p_cover != root) {
206 assert(mnt->mnt_covers->p_cover == root);
207 if (_sysio_p_prune(root) != 1) {
216 * Drop ref of covered pnode and break linkage in name space.
218 if (root->p_cover != root)
219 P_RELE(mnt->mnt_covers);
220 mnt->mnt_covers->p_cover = NULL;
221 LIST_REMOVE(mnt, mnt_link);
226 root->p_cover = NULL;
229 * Release mount record resource.
239 * Establish the system name space.
242 _sysio_mount_root(const char *source,
247 struct fsswent *fssw;
254 fssw = _sysio_fssw_lookup(fstype);
258 err = (*fssw->fssw_ops.fsswop_mount)(source, flags, data, NULL, &mnt);
262 _sysio_root = mnt->mnt_root;
264 * It is very annoying to have to set the current working directory.
265 * So... If it isn't set, make it the root now.
268 _sysio_cwd = _sysio_root;
276 _sysio_mount(struct pnode *cwd,
279 const char *filesystemtype,
280 unsigned long mountflags,
284 struct fsswent *fssw;
285 struct intent intent;
290 * Find the file system switch entry specified.
292 fssw = _sysio_fssw_lookup(filesystemtype);
297 * Look up the target path node.
299 INTENT_INIT(&intent, INT_GETATTR, NULL, NULL);
300 err = _sysio_namei(cwd, target, 0, &intent, &tgt);
304 if (tgt == _sysio_root) {
306 * Attempting to mount over root.
314 (*fssw->fssw_ops.fsswop_mount)(source,
326 SYSIO_INTERFACE_NAME(mount)(const char *source,
328 const char *filesystemtype,
329 unsigned long mountflags,
333 SYSIO_INTERFACE_DISPLAY_BLOCK;
335 SYSIO_INTERFACE_ENTER;
337 _sysio_mount(_sysio_cwd,
343 SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
347 SYSIO_INTERFACE_NAME(umount)(const char *target)
351 SYSIO_INTERFACE_DISPLAY_BLOCK;
353 SYSIO_INTERFACE_ENTER;
355 * Look up the target path node.
357 err = _sysio_namei(_sysio_cwd, target, 0, NULL, &pno);
360 P_RELE(pno); /* was ref'd */
371 assert(pno->p_mount);
372 err = _sysio_do_unmount(pno->p_mount);
375 SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
379 * Unmount all file systems -- Usually as part of shutting everything down.
385 struct mount *mnt, *nxt;
389 nxt = mounts.lh_first;
390 while ((mnt = nxt)) {
391 nxt = mnt->mnt_link.le_next;
394 * If this is an automount generated mount, the root
395 * has no reference. We can cause the dismount with a
398 if (!_sysio_p_prune(pno))
402 * Need a ref but only if this is not the root of a
403 * disconnected graph. If it is, then it is covered by itself
404 * and, so, already referenced.
406 if (pno->p_cover != pno)
409 err = _sysio_do_unmount(mnt);
412 if (pno->p_cover != pno)
417 if (pno == _sysio_root)
424 #ifdef AUTOMOUNT_FILE_NAME
426 * Parse automount specification formatted as:
428 * <fstype>:<source>[[ \t]+<comma-separated-mount-options>]
431 * The buffer sent is (almost) always modified.
434 parse_automount_spec(char *s, char **fstyp, char **srcp, char **optsp)
438 char *fsty, *src, *opts;
445 while (*s && *s == ' ' && *s == '\t')
458 if (fsty == cp || *cp != ':')
466 while (*s && *s == ' ' && *s == '\t')
487 while (*s && *s == ' ' && *s == '\t')
517 * Parse (and strip) system mount options.
520 parse_opts(char *opts, unsigned *flagsp)
530 while (*cp && *cp != ',')
532 if (src + 2 == cp && strncmp(src, "rw", 2) == 0) {
534 * Do nothing. This is the default.
537 } else if (src + 2 == cp && strncmp(src, "ro", 2) == 0) {
544 else if (src + 4 == cp && strncmp(src, "auto", 4) == 0) {
548 flags |= MOUNT_F_AUTO;
553 * Copy what we didn't consume.
564 src++; /* skip comma */
573 * Attempt automount over the given directory.
576 _sysio_automount(struct pnode *mntpno)
580 struct intnl_stat stbuf;
582 struct ioctx iocontext;
583 struct intnl_xtvec xtvec;
585 char *fstype, *source, *opts;
587 struct fsswent *fssw;
591 * Revalidate -- Paranoia.
593 err = _sysio_p_validate(mntpno, NULL, NULL);
600 ino = mntpno->p_base->pb_ino;
601 err = (*ino->i_ops.inop_getattr)(mntpno, ino, &stbuf);
604 if (stbuf.st_size > 64 * 1024) {
606 * Let's be reasonable.
610 iovec.iov_base = malloc(stbuf.st_size + 1);
613 iovec.iov_len = stbuf.st_size;
614 err = _sysio_open(mntpno, O_RDONLY, 0);
618 xtvec.xtv_len = stbuf.st_size;
619 IOCTX_INIT(&iocontext,
626 _sysio_ioctx_enter(&iocontext);
627 err = (*ino->i_ops.inop_read)(ino, &iocontext);
629 _sysio_ioctx_complete(&iocontext);
630 (void )(*ino->i_ops.inop_close)(ino);
633 cc = _sysio_ioctx_wait(&iocontext);
634 err = (*ino->i_ops.inop_close)(ino);
641 ((char *)iovec.iov_base)[cc] = '\0';
646 err = parse_automount_spec(iovec.iov_base, &fstype, &source, &opts);
651 opts = parse_opts(opts, &flags);
654 * Find the file system switch entry specified.
656 fssw = _sysio_fssw_lookup(fstype);
665 P_REF(mntpno->p_parent);
667 (*fssw->fssw_ops.fsswop_mount)(source,
673 P_RELE(mntpno->p_parent);
677 free(iovec.iov_base);