1 /*
2 * linux/fs/nfsd/nfsctl.c
3 *
4 * Syscall interface to knfsd.
5 *
6 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
7 */
8
9 #include <linux/config.h>
10 #include <linux/module.h>
11 #include <linux/version.h>
12
13 #include <linux/linkage.h>
14 #include <linux/sched.h>
15 #include <linux/errno.h>
16 #include <linux/fs.h>
17 #include <linux/fcntl.h>
18 #include <linux/net.h>
19 #include <linux/in.h>
20 #include <linux/unistd.h>
21 #include <linux/malloc.h>
22 #include <linux/proc_fs.h>
23
24 #include <linux/nfs.h>
25 #include <linux/sunrpc/svc.h>
26 #include <linux/nfsd/nfsd.h>
27 #include <linux/nfsd/cache.h>
28 #include <linux/nfsd/xdr.h>
29 #include <linux/nfsd/syscall.h>
30
31 #include <asm/uaccess.h>
32 #include <linux/smp.h>
33 #include <linux/smp_lock.h>
34
35 extern long sys_call_table[];
36
37 static int nfsctl_svc(struct nfsctl_svc *data);
38 static int nfsctl_addclient(struct nfsctl_client *data);
39 static int nfsctl_delclient(struct nfsctl_client *data);
40 static int nfsctl_export(struct nfsctl_export *data);
41 static int nfsctl_unexport(struct nfsctl_export *data);
42 static int nfsctl_getfh(struct nfsctl_fhparm *, __u8 *);
43 static int nfsctl_getfd(struct nfsctl_fdparm *, __u8 *);
44 static int nfsctl_getfs(struct nfsctl_fsparm *, struct knfsd_fh *);
45 #ifdef notyet
46 static int nfsctl_ugidupdate(struct nfsctl_ugidmap *data);
47 #endif
48
49 static int initialized;
50
51 int exp_procfs_exports(char *buffer, char **start, off_t offset,
52 int length, int *eof, void *data);
53
54 void proc_export_init(void)
55 {
56 if (!proc_mkdir("fs/nfs", 0))
57 return;
58 create_proc_read_entry("fs/nfs/exports", 0, 0, exp_procfs_exports,NULL);
59 }
60
61
62 /*
63 * Initialize nfsd
64 */
65 static void
66 nfsd_init(void)
67 {
68 nfsd_stat_init(); /* Statistics */
69 nfsd_cache_init(); /* RPC reply cache */
70 nfsd_export_init(); /* Exports table */
71 nfsd_lockd_init(); /* lockd->nfsd callbacks */
72 proc_export_init();
73 initialized = 1;
74 }
75
76 static inline int
77 nfsctl_svc(struct nfsctl_svc *data)
78 {
79 return nfsd_svc(data->svc_port, data->svc_nthreads);
80 }
81
82 static inline int
83 nfsctl_addclient(struct nfsctl_client *data)
84 {
85 return exp_addclient(data);
86 }
87
88 static inline int
89 nfsctl_delclient(struct nfsctl_client *data)
90 {
91 return exp_delclient(data);
92 }
93
94 static inline int
95 nfsctl_export(struct nfsctl_export *data)
96 {
97 return exp_export(data);
98 }
99
100 static inline int
101 nfsctl_unexport(struct nfsctl_export *data)
102 {
103 return exp_unexport(data);
104 }
105
106 #ifdef notyet
107 static inline int
108 nfsctl_ugidupdate(nfs_ugidmap *data)
109 {
110 return -EINVAL;
111 }
112 #endif
113
114 static inline int
115 nfsctl_getfs(struct nfsctl_fsparm *data, struct knfsd_fh *res)
116 {
117 struct sockaddr_in *sin;
118 struct svc_client *clp;
119 int err = 0;
120
121 if (data->gd_addr.sa_family != AF_INET)
122 return -EPROTONOSUPPORT;
123 sin = (struct sockaddr_in *)&data->gd_addr;
124 if (data->gd_maxlen > NFS3_FHSIZE)
125 data->gd_maxlen = NFS3_FHSIZE;
126 exp_readlock();
127 if (!(clp = exp_getclient(sin)))
128 err = -EPERM;
129 else
130 err = exp_rootfh(clp, 0, 0, data->gd_path, res, data->gd_maxlen);
131 exp_unlock();
132 return err;
133 }
134
135 static inline int
136 nfsctl_getfd(struct nfsctl_fdparm *data, __u8 *res)
137 {
138 struct sockaddr_in *sin;
139 struct svc_client *clp;
140 int err = 0;
141 struct knfsd_fh fh;
142
143 if (data->gd_addr.sa_family != AF_INET)
144 return -EPROTONOSUPPORT;
145 if (data->gd_version < 2 || data->gd_version > NFSSVC_MAXVERS)
146 return -EINVAL;
147 sin = (struct sockaddr_in *)&data->gd_addr;
148
149 exp_readlock();
150 if (!(clp = exp_getclient(sin)))
151 err = -EPERM;
152 else
153 err = exp_rootfh(clp, 0, 0, data->gd_path, &fh, NFS_FHSIZE);
154 exp_unlock();
155
156 if (err == 0) {
157 if (fh.fh_size > NFS_FHSIZE)
158 err = -EINVAL;
159 else {
160 memset(res,0, NFS_FHSIZE);
161 memcpy(res, fh.fh_base.fh_pad, fh.fh_size);
162 }
163 }
164
165 return err;
166 }
167
168 static inline int
169 nfsctl_getfh(struct nfsctl_fhparm *data, __u8 *res)
170 {
171 struct sockaddr_in *sin;
172 struct svc_client *clp;
173 int err = 0;
174 struct knfsd_fh fh;
175
176 if (data->gf_addr.sa_family != AF_INET)
177 return -EPROTONOSUPPORT;
178 if (data->gf_version < 2 || data->gf_version > NFSSVC_MAXVERS)
179 return -EINVAL;
180 sin = (struct sockaddr_in *)&data->gf_addr;
181
182 exp_readlock();
183 if (!(clp = exp_getclient(sin)))
184 err = -EPERM;
185 else
186 err = exp_rootfh(clp, to_kdev_t(data->gf_dev), data->gf_ino, NULL, &fh, NFS_FHSIZE);
187 exp_unlock();
188
189 if (err == 0) {
190 if (fh.fh_size > NFS_FHSIZE)
191 err = -EINVAL;
192 else {
193 memset(res,0, NFS_FHSIZE);
194 memcpy(res, fh.fh_base.fh_pad, fh.fh_size);
195 }
196 }
197
198 return err;
199 }
200
201 #ifdef CONFIG_NFSD
202 #define handle_sys_nfsservctl sys_nfsservctl
203 #endif
204
205 static struct {
206 int argsize, respsize;
207 } sizes[] = {
208 /* NFSCTL_SVC */ { sizeof(struct nfsctl_svc), 0 },
209 /* NFSCTL_ADDCLIENT */ { sizeof(struct nfsctl_client), 0},
210 /* NFSCTL_DELCLIENT */ { sizeof(struct nfsctl_client), 0},
211 /* NFSCTL_EXPORT */ { sizeof(struct nfsctl_export), 0},
212 /* NFSCTL_UNEXPORT */ { sizeof(struct nfsctl_export), 0},
213 /* NFSCTL_UGIDUPDATE */ { sizeof(struct nfsctl_uidmap), 0},
214 /* NFSCTL_GETFH */ { sizeof(struct nfsctl_fhparm), NFS_FHSIZE},
215 /* NFSCTL_GETFD */ { sizeof(struct nfsctl_fdparm), NFS_FHSIZE},
216 /* NFSCTL_GETFS */ { sizeof(struct nfsctl_fsparm), sizeof(struct knfsd_fh)},
217 };
218 #define CMD_MAX (sizeof(sizes)/sizeof(sizes[0])-1)
219
220 long
221 asmlinkage handle_sys_nfsservctl(int cmd, void *opaque_argp, void *opaque_resp)
222 {
223 struct nfsctl_arg * argp = opaque_argp;
224 union nfsctl_res * resp = opaque_resp;
225 struct nfsctl_arg * arg = NULL;
226 union nfsctl_res * res = NULL;
227 int err;
228 int argsize, respsize;
229
230 MOD_INC_USE_COUNT;
231 lock_kernel ();
232 if (!initialized)
233 nfsd_init();
234 err = -EPERM;
235 if (!capable(CAP_SYS_ADMIN)) {
236 goto done;
237 }
238 err = -EINVAL;
239 if (cmd<0 || cmd > CMD_MAX)
240 goto done;
241 err = -EFAULT;
242 argsize = sizes[cmd].argsize + (int)&((struct nfsctl_arg *)0)->u;
243 respsize = sizes[cmd].respsize; /* maximum */
244 if (!access_ok(VERIFY_READ, argp, argsize)
245 || (resp && !access_ok(VERIFY_WRITE, resp, respsize))) {
246 goto done;
247 }
248 err = -ENOMEM; /* ??? */
249 if (!(arg = kmalloc(sizeof(*arg), GFP_USER)) ||
250 (resp && !(res = kmalloc(sizeof(*res), GFP_USER)))) {
251 goto done;
252 }
253
254 err = -EINVAL;
255 copy_from_user(arg, argp, argsize);
256 if (arg->ca_version != NFSCTL_VERSION) {
257 printk(KERN_WARNING "nfsd: incompatible version in syscall.\n");
258 goto done;
259 }
260
261 switch(cmd) {
262 case NFSCTL_SVC:
263 err = nfsctl_svc(&arg->ca_svc);
264 break;
265 case NFSCTL_ADDCLIENT:
266 err = nfsctl_addclient(&arg->ca_client);
267 break;
268 case NFSCTL_DELCLIENT:
269 err = nfsctl_delclient(&arg->ca_client);
270 break;
271 case NFSCTL_EXPORT:
272 err = nfsctl_export(&arg->ca_export);
273 break;
274 case NFSCTL_UNEXPORT:
275 err = nfsctl_unexport(&arg->ca_export);
276 break;
277 #ifdef notyet
278 case NFSCTL_UGIDUPDATE:
279 err = nfsctl_ugidupdate(&arg->ca_umap);
280 break;
281 #endif
282 case NFSCTL_GETFH:
283 err = nfsctl_getfh(&arg->ca_getfh, res->cr_getfh);
284 break;
285 case NFSCTL_GETFD:
286 err = nfsctl_getfd(&arg->ca_getfd, res->cr_getfh);
287 break;
288 case NFSCTL_GETFS:
289 err = nfsctl_getfs(&arg->ca_getfs, &res->cr_getfs);
290 respsize = res->cr_getfs.fh_size+ (int)&((struct knfsd_fh*)0)->fh_base;
291 break;
292 default:
293 err = -EINVAL;
294 }
295
296 if (!err && resp && respsize)
297 copy_to_user(resp, res, respsize);
298
299 done:
300 if (arg)
301 kfree(arg);
302 if (res)
303 kfree(res);
304
305 unlock_kernel ();
306 MOD_DEC_USE_COUNT;
307 return err;
308 }
309
310 #ifdef MODULE
311 /* New-style module support since 2.1.18 */
312 EXPORT_NO_SYMBOLS;
313 MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
314
315 struct nfsd_linkage nfsd_linkage_s = {
316 do_nfsservctl: handle_sys_nfsservctl,
317 };
318
319 /*
320 * Initialize the module
321 */
322 int
323 init_module(void)
324 {
325 printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
326 nfsd_linkage = &nfsd_linkage_s;
327 return 0;
328 }
329
330 /*
331 * Clean up the mess before unloading the module
332 */
333 void
334 cleanup_module(void)
335 {
336 nfsd_linkage = NULL;
337 nfsd_export_shutdown();
338 nfsd_cache_shutdown();
339 remove_proc_entry("fs/nfs/exports", NULL);
340 remove_proc_entry("fs/nfs", NULL);
341 nfsd_stat_shutdown();
342 nfsd_lockd_shutdown();
343 }
344 #endif
345
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.