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>
63 * File system and volume mount support.
66 #ifdef AUTOMOUNT_FILE_NAME
68 * Name of autmount specification file in a directory with
71 struct qstr _sysio_mount_file_name = { "", 0, 0 };
77 static LIST_HEAD(, mount) mounts;
80 * Initialization. Must be called before any other routine in this module.
87 #ifdef AUTOMOUNT_FILE_NAME
88 _sysio_next_component(AUTOMOUNT_FILE_NAME, &_sysio_mount_file_name);
95 * Mount rooted sub-tree somewhere in the existing name space.
98 _sysio_do_mount(struct filesys *fs,
99 struct pnode_base *rootpb,
101 struct pnode *tocover,
108 * It's really poor form to allow the new root to be a
109 * descendant of the pnode being covered.
112 struct pnode_base *pb;
115 pb && pb != tocover->p_base;
118 if (pb == tocover->p_base)
125 mnt = malloc(sizeof(struct mount));
130 * Init enough to make the mount record usable to the path node
131 * generation routines.
134 if (fs->fs_flags & FS_F_RO) {
136 * Propagate the read-only flag -- Whether they set it or not.
140 mnt->mnt_flags = flags;
142 * Get alias for the new root.
145 _sysio_p_new_alias(tocover ? tocover->p_parent : NULL, rootpb, mnt);
146 if (!mnt->mnt_root) {
151 * It may have been a while since the root inode was validated;
152 * better validate again. And it better be a directory!
154 err = _sysio_p_validate(mnt->mnt_root, NULL, NULL);
158 if (!S_ISDIR(mnt->mnt_root->p_base->pb_ino->i_mode)) {
163 * Cover up the mount point.
165 mnt->mnt_covers = tocover;
166 if (!mnt->mnt_covers) {
168 * New graph; It covers itself.
170 mnt->mnt_covers = tocover = mnt->mnt_root;
172 tocover->p_cover = mnt->mnt_root;
174 LIST_INSERT_HEAD(&mounts, mnt, mnt_link);
181 P_RELE(mnt->mnt_root);
182 _sysio_p_prune(mnt->mnt_root);
189 * Remove mounted sub-tree from the system.
192 _sysio_do_unmount(struct mount *mnt)
197 root = mnt->mnt_root;
198 if (root->p_cover && root->p_cover != root) {
204 assert(mnt->mnt_covers->p_cover == root);
205 if (_sysio_p_prune(root) != 1) {
214 * Drop ref of covered pnode and break linkage in name space.
216 if (root->p_cover != root)
217 P_RELE(mnt->mnt_covers);
218 mnt->mnt_covers->p_cover = NULL;
219 LIST_REMOVE(mnt, mnt_link);
224 root->p_cover = NULL;
227 * Release mount record resource.
237 * Establish the system name space.
240 _sysio_mount_root(const char *source,
245 struct fsswent *fssw;
252 fssw = _sysio_fssw_lookup(fstype);
256 err = (*fssw->fssw_ops.fsswop_mount)(source, flags, data, NULL, &mnt);
260 _sysio_root = mnt->mnt_root;
262 * It is very annoying to have to set the current working directory.
263 * So... If it isn't set, make it the root now.
266 _sysio_cwd = _sysio_root;
274 _sysio_mount(struct pnode *cwd,
277 const char *filesystemtype,
278 unsigned long mountflags,
282 struct fsswent *fssw;
283 struct intent intent;
288 * Find the file system switch entry specified.
290 fssw = _sysio_fssw_lookup(filesystemtype);
295 * Look up the target path node.
297 INTENT_INIT(&intent, INT_GETATTR, NULL, NULL);
298 err = _sysio_namei(cwd, target, 0, &intent, &tgt);
302 if (tgt == _sysio_root) {
304 * Attempting to mount over root.
312 (*fssw->fssw_ops.fsswop_mount)(source,
324 SYSIO_INTERFACE_NAME(mount)(const char *source,
326 const char *filesystemtype,
327 unsigned long mountflags,
331 SYSIO_INTERFACE_DISPLAY_BLOCK;
333 SYSIO_INTERFACE_ENTER;
335 _sysio_mount(_sysio_cwd,
341 SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
345 SYSIO_INTERFACE_NAME(umount)(const char *target)
349 SYSIO_INTERFACE_DISPLAY_BLOCK;
351 SYSIO_INTERFACE_ENTER;
353 * Look up the target path node.
355 err = _sysio_namei(_sysio_cwd, target, 0, NULL, &pno);
358 P_RELE(pno); /* was ref'd */
369 assert(pno->p_mount);
370 err = _sysio_do_unmount(pno->p_mount);
373 SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
377 * Unmount all file systems -- Usually as part of shutting everything down.
383 struct mount *mnt, *nxt;
387 nxt = mounts.lh_first;
388 while ((mnt = nxt)) {
389 nxt = mnt->mnt_link.le_next;
392 * If this is an automount generated mount, the root
393 * has no reference. We can cause the dismount with a
396 if (!_sysio_p_prune(pno))
400 * Need a ref but only if this is not the root of a
401 * disconnected graph. If it is, then it is covered by itself
402 * and, so, already referenced.
404 if (pno->p_cover != pno)
407 err = _sysio_do_unmount(mnt);
410 if (pno->p_cover != pno)
415 if (pno == _sysio_root)
422 #ifdef AUTOMOUNT_FILE_NAME
424 * Parse automount specification formatted as:
426 * <fstype>:<source>[[ \t]+<comma-separated-mount-options>]
429 * The buffer sent is (almost) always modified.
432 parse_automount_spec(char *s, char **fstyp, char **srcp, char **optsp)
436 char *fsty, *src, *opts;
443 while (*s && *s == ' ' && *s == '\t')
456 if (fsty == cp || *cp != ':')
464 while (*s && *s == ' ' && *s == '\t')
485 while (*s && *s == ' ' && *s == '\t')
515 * Parse (and strip) system mount options.
518 parse_opts(char *opts, unsigned *flagsp)
528 while (*cp && *cp != ',')
530 if (src + 2 == cp && strncmp(src, "rw", 2) == 0) {
532 * Do nothing. This is the default.
535 } else if (src + 2 == cp && strncmp(src, "ro", 2) == 0) {
542 else if (src + 4 == cp && strncmp(src, "auto", 4) == 0) {
546 flags |= MOUNT_F_AUTO;
551 * Copy what we didn't consume.
562 src++; /* skip comma */
571 * Attempt automount over the given directory.
574 _sysio_automount(struct pnode *mntpno)
578 struct intnl_stat stbuf;
580 struct ioctx iocontext;
581 struct intnl_xtvec xtvec;
583 char *fstype, *source, *opts;
585 struct fsswent *fssw;
589 * Revalidate -- Paranoia.
591 err = _sysio_p_validate(mntpno, NULL, NULL);
598 ino = mntpno->p_base->pb_ino;
599 err = (*ino->i_ops.inop_getattr)(mntpno, ino, &stbuf);
602 if (stbuf.st_size > 64 * 1024) {
604 * Let's be reasonable.
608 iovec.iov_base = malloc(stbuf.st_size + 1);
611 iovec.iov_len = stbuf.st_size;
612 err = _sysio_open(mntpno, O_RDONLY, 0);
616 xtvec.xtv_len = stbuf.st_size;
617 IOCTX_INIT(&iocontext,
623 _sysio_ioctx_enter(&iocontext);
624 err = (*ino->i_ops.inop_read)(ino, &iocontext);
626 _sysio_ioctx_complete(&iocontext);
627 (void )(*ino->i_ops.inop_close)(ino);
630 cc = _sysio_ioctx_wait(&iocontext);
631 err = (*ino->i_ops.inop_close)(ino);
638 ((char *)iovec.iov_base)[cc] = '\0';
643 err = parse_automount_spec(iovec.iov_base, &fstype, &source, &opts);
648 opts = parse_opts(opts, &flags);
651 * Find the file system switch entry specified.
653 fssw = _sysio_fssw_lookup(fstype);
662 P_REF(mntpno->p_parent);
664 (*fssw->fssw_ops.fsswop_mount)(source,
670 P_RELE(mntpno->p_parent);
674 free(iovec.iov_base);