relax restrictions on *chown: allow owner to change group if member
[unix-history] / usr / src / sys / ufs / ffs / ffs_vfsops.c
CommitLineData
da7c5cc6
KM
1/*
2 * Copyright (c) 1982 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
86b729dd 6 * @(#)ffs_vfsops.c 6.13 (Berkeley) %G%
da7c5cc6 7 */
71e4e98b 8
94368568
JB
9#include "param.h"
10#include "systm.h"
11#include "dir.h"
12#include "user.h"
13#include "inode.h"
14#include "proc.h"
15#include "fs.h"
16#include "buf.h"
17#include "mount.h"
18#include "file.h"
19#include "conf.h"
71e4e98b
SL
20
21smount()
22{
23 register struct a {
24 char *fspec;
25 char *freg;
26 int ronly;
715baff1 27 } *uap = (struct a *)u.u_ap;
71e4e98b
SL
28 dev_t dev;
29 register struct inode *ip;
30 register struct fs *fs;
715baff1 31 register struct nameidata *ndp = &u.u_nd;
76335100 32 u_int len;
71e4e98b 33
715baff1 34 u.u_error = getmdev(&dev, uap->fspec);
71e4e98b
SL
35 if (u.u_error)
36 return;
715baff1
KM
37 ndp->ni_nameiop = LOOKUP | NOCACHE | FOLLOW;
38 ndp->ni_segflg = UIO_USERSPACE;
39 ndp->ni_dirp = (caddr_t)uap->freg;
40 ip = namei(ndp);
71e4e98b
SL
41 if (ip == NULL)
42 return;
6d07f4cd 43 if (ip->i_count != 1) {
71e4e98b
SL
44 iput(ip);
45 u.u_error = EBUSY;
46 return;
47 }
6d07f4cd
KM
48 if ((ip->i_mode&IFMT) != IFDIR) {
49 iput(ip);
50 u.u_error = ENOTDIR;
51 return;
52 }
71e4e98b
SL
53 fs = mountfs(dev, uap->ronly, ip);
54 if (fs == 0)
55 return;
76335100 56 (void) copyinstr(uap->freg, fs->fs_fsmnt, sizeof(fs->fs_fsmnt)-1, &len);
32af08ce 57 bzero(fs->fs_fsmnt + len, sizeof (fs->fs_fsmnt) - len);
71e4e98b
SL
58}
59
71e4e98b
SL
60/* this routine has races if running twice */
61struct fs *
62mountfs(dev, ronly, ip)
63 dev_t dev;
64 int ronly;
65 struct inode *ip;
66{
67 register struct mount *mp = 0;
68 struct buf *tp = 0;
69 register struct buf *bp = 0;
70 register struct fs *fs;
71 int blks;
72 caddr_t space;
73 int i, size;
1c281610 74 register error;
6d07f4cd 75 int needclose = 0;
71e4e98b 76
1c281610 77 error =
71e4e98b 78 (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE);
1c281610 79 if (error)
71e4e98b 80 goto out;
6d07f4cd 81 needclose = 1;
71e4e98b
SL
82 tp = bread(dev, SBLOCK, SBSIZE);
83 if (tp->b_flags & B_ERROR)
84 goto out;
85 for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
86 if (mp->m_bufp != 0 && dev == mp->m_dev) {
87 mp = 0;
1c281610 88 error = EBUSY;
86b729dd 89 needclose = 0;
71e4e98b
SL
90 goto out;
91 }
92 for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
93 if (mp->m_bufp == 0)
94 goto found;
95 mp = 0;
1c281610 96 error = EMFILE; /* needs translation */
71e4e98b
SL
97 goto out;
98found:
99 mp->m_bufp = tp; /* just to reserve this slot */
100 mp->m_dev = NODEV;
101 fs = tp->b_un.b_fs;
1c281610
MK
102 if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE
103 || fs->fs_bsize < sizeof(struct fs)) {
104 error = EINVAL; /* also needs translation */
105 goto out;
106 }
71e4e98b
SL
107 bp = geteblk((int)fs->fs_sbsize);
108 mp->m_bufp = bp;
109 bcopy((caddr_t)tp->b_un.b_addr, (caddr_t)bp->b_un.b_addr,
110 (u_int)fs->fs_sbsize);
111 brelse(tp);
112 tp = 0;
113 fs = bp->b_un.b_fs;
71e4e98b
SL
114 fs->fs_ronly = (ronly != 0);
115 if (ronly == 0)
116 fs->fs_fmod = 1;
117 blks = howmany(fs->fs_cssize, fs->fs_fsize);
118 space = wmemall(vmemall, (int)fs->fs_cssize);
1c281610
MK
119 if (space == 0) {
120 error = ENOMEM;
71e4e98b 121 goto out;
1c281610 122 }
71e4e98b
SL
123 for (i = 0; i < blks; i += fs->fs_frag) {
124 size = fs->fs_bsize;
125 if (i + fs->fs_frag > blks)
126 size = (blks - i) * fs->fs_fsize;
127 tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size);
128 if (tp->b_flags&B_ERROR) {
129 wmemfree(space, (int)fs->fs_cssize);
130 goto out;
131 }
132 bcopy((caddr_t)tp->b_un.b_addr, space, (u_int)size);
60f9c9e3 133 fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space;
71e4e98b
SL
134 space += size;
135 brelse(tp);
136 tp = 0;
137 }
138 mp->m_inodp = ip;
139 mp->m_dev = dev;
140 if (ip) {
141 ip->i_flag |= IMOUNT;
142 iunlock(ip);
143 }
144 return (fs);
145out:
1c281610
MK
146 if (error == 0)
147 error = EIO;
71e4e98b
SL
148 if (ip)
149 iput(ip);
150 if (mp)
151 mp->m_bufp = 0;
152 if (bp)
153 brelse(bp);
154 if (tp)
155 brelse(tp);
86b729dd
MK
156 if (needclose) {
157 (*bdevsw[major(dev)].d_close)(dev, ronly? FREAD : FREAD|FWRITE);
158 binval(dev);
159 }
1c281610 160 u.u_error = error;
71e4e98b
SL
161 return (0);
162}
163
164umount()
165{
166 struct a {
167 char *fspec;
715baff1 168 } *uap = (struct a *)u.u_ap;
71e4e98b 169
715baff1 170 u.u_error = unmount1(uap->fspec, 0);
71e4e98b
SL
171}
172
715baff1
KM
173unmount1(fname, forcibly)
174 caddr_t fname;
71e4e98b
SL
175 int forcibly;
176{
177 dev_t dev;
178 register struct mount *mp;
179 int stillopen, flag, error;
180 register struct inode *ip;
181 register struct fs *fs;
182
715baff1 183 error = getmdev(&dev, fname);
71e4e98b
SL
184 if (error)
185 return (error);
186 for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
187 if (mp->m_bufp != NULL && dev == mp->m_dev)
188 goto found;
189 return (EINVAL);
190found:
191 xumount(dev); /* remove unused sticky files from text table */
f93197fc 192 nchinval(dev); /* flush the name cache */
71e4e98b
SL
193 update();
194#ifdef QUOTA
195 if ((stillopen = iflush(dev, mp->m_qinod)) < 0 && !forcibly)
196#else
197 if ((stillopen = iflush(dev)) < 0 && !forcibly)
198#endif
199 return (EBUSY);
200 if (stillopen < 0)
201 return (EBUSY); /* XXX */
202#ifdef QUOTA
203 closedq(mp);
204 /*
205 * Here we have to iflush again to get rid of the quota inode.
206 * A drag, but it would be ugly to cheat, & this doesn't happen often
207 */
208 (void)iflush(dev, (struct inode *)NULL);
209#endif
210 ip = mp->m_inodp;
211 ip->i_flag &= ~IMOUNT;
212 irele(ip);
213 fs = mp->m_bufp->b_un.b_fs;
214 wmemfree((caddr_t)fs->fs_csp[0], (int)fs->fs_cssize);
215 flag = !fs->fs_ronly;
216 brelse(mp->m_bufp);
217 mp->m_bufp = 0;
218 mp->m_dev = 0;
219 mpurge(mp - &mount[0]);
220 if (!stillopen) {
221 (*bdevsw[major(dev)].d_close)(dev, flag);
222 binval(dev);
223 }
224 return (0);
225}
226
227sbupdate(mp)
228 struct mount *mp;
229{
230 register struct fs *fs = mp->m_bufp->b_un.b_fs;
231 register struct buf *bp;
232 int blks;
233 caddr_t space;
234 int i, size;
235
236 bp = getblk(mp->m_dev, SBLOCK, (int)fs->fs_sbsize);
237 bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize);
238 bwrite(bp);
239 blks = howmany(fs->fs_cssize, fs->fs_fsize);
240 space = (caddr_t)fs->fs_csp[0];
241 for (i = 0; i < blks; i += fs->fs_frag) {
242 size = fs->fs_bsize;
243 if (i + fs->fs_frag > blks)
244 size = (blks - i) * fs->fs_fsize;
245 bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size);
246 bcopy(space, bp->b_un.b_addr, (u_int)size);
247 space += size;
248 bwrite(bp);
249 }
250}
251
252/*
253 * Common code for mount and umount.
254 * Check that the user's argument is a reasonable
255 * thing on which to mount, and return the device number if so.
256 */
715baff1
KM
257getmdev(pdev, fname)
258 caddr_t fname;
71e4e98b
SL
259 dev_t *pdev;
260{
261 dev_t dev;
262 register struct inode *ip;
715baff1 263 register struct nameidata *ndp = &u.u_nd;
71e4e98b
SL
264
265 if (!suser())
266 return (u.u_error);
715baff1
KM
267 ndp->ni_nameiop = LOOKUP | FOLLOW;
268 ndp->ni_segflg = UIO_USERSPACE;
269 ndp->ni_dirp = fname;
270 ip = namei(ndp);
6d07f4cd
KM
271 if (ip == NULL) {
272 if (u.u_error == ENOENT)
273 return (ENODEV); /* needs translation */
71e4e98b 274 return (u.u_error);
6d07f4cd 275 }
e95cdf5c
MK
276 if ((ip->i_mode&IFMT) != IFBLK) {
277 iput(ip);
71e4e98b 278 return (ENOTBLK);
e95cdf5c 279 }
71e4e98b 280 dev = (dev_t)ip->i_rdev;
e95cdf5c 281 iput(ip);
71e4e98b
SL
282 if (major(dev) >= nblkdev)
283 return (ENXIO);
71e4e98b
SL
284 *pdev = dev;
285 return (0);
286}