]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - lib/libautofs/libautofs.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / lib / libautofs / libautofs.c
1 /*
2  * Copyright (c) 2004 Alfred Perlstein <alfred@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  * $Id: libautofs.c,v 1.5 2004/09/08 08:44:12 bright Exp $
28  */
29 #include <err.h>
30 #include <ctype.h>
31 #include <err.h>
32 #include <errno.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <fcntl.h>
38
39 #include <sys/types.h>
40 #include <sys/param.h>
41 #include <sys/mount.h>
42 #include <sys/poll.h>
43 #include <sys/stat.h>
44 #include <sys/sysctl.h>
45
46 #ifdef AUTOFSSTANDALONE
47 #include "../autofs/autofs.h"
48 #else
49 #include <fs/autofs/autofs.h>
50 #endif
51
52 #include "libautofs.h"
53
54 struct auto_handle {
55         char    ah_mp[MNAMELEN];
56         fsid_t  ah_fsid;
57         int     ah_fd;
58 };
59
60 static int      autofs_sysctl(int, fsid_t *, void *, size_t *, void *, size_t);
61 static void     safe_free(void *ptr);
62 static int      getmntlst(struct statfs **sfsp, int *cntp);
63
64 static void
65 safe_free(void *ptr)
66 {
67         int saved_errno;
68
69         saved_errno = errno;
70         free(ptr);
71         errno = saved_errno;
72 }
73
74 int
75 getmntlst(struct statfs **sfsp, int *cntp)
76 {
77         int cnt;
78         long bufsize;
79
80         *sfsp = NULL;
81         cnt = getfsstat(NULL, 0, MNT_NOWAIT);
82         bufsize = cnt * sizeof(**sfsp);
83         /*fprintf(stderr, "getmntlst bufsize %ld, cnt %d\n", bufsize, cnt);*/
84         *sfsp = malloc(bufsize);
85         if (sfsp == NULL)
86                 goto err;
87         cnt = getfsstat(*sfsp, bufsize, MNT_NOWAIT);
88         if (cnt == -1)
89                 goto err;
90         *cntp = cnt;
91         /*fprintf(stderr, "getmntlst ok, cnt %d\n", cnt);*/
92         return (0);
93 err:
94         safe_free(sfsp);
95         *sfsp = NULL;
96         /*fprintf(stderr, "getmntlst bad\n");*/
97         return (-1);
98 }
99
100 /* get a handle based on a path. */
101 int
102 autoh_get(const char *path, autoh_t *ahp)
103 {
104         struct statfs *sfsp, *sp;
105         int cnt, fd, i;
106         autoh_t ret;
107
108         ret = NULL;
109         /*
110          * We use getfsstat to prevent avoid the lookups on the mountpoints
111          * that statfs(2) would do.
112          */
113         if (getmntlst(&sfsp, &cnt))
114                 goto err;
115         for (i = 0; i < cnt; i++) {
116                 if (strcmp(sfsp[i].f_mntonname, path) == 0)
117                         break;
118         }
119         if (i == cnt) {
120                 /*fprintf(stderr, "autoh_get bad %d %d\n", i, cnt);*/
121                 errno = ENOENT;
122                 goto err;
123         }
124         sp = &sfsp[i];
125         if (strcmp(sp->f_fstypename, "autofs")) {
126                 errno = ENOTTY;
127                 goto err;
128         }
129         fd = open(sp->f_mntonname, O_RDONLY);
130         if (fd == -1)
131                 goto err;
132         ret = malloc(sizeof(*ret));
133         if (ret == NULL)
134                 goto err;
135
136         ret->ah_fsid = sp->f_fsid;
137         ret->ah_fd = fd;
138         strlcpy(ret->ah_mp, sp->f_mntonname, sizeof(ret->ah_mp));
139         safe_free(sfsp);
140         *ahp = ret;
141         return (0);
142 err:
143         safe_free(ret);
144         safe_free(sfsp);
145         return (-1);
146 }
147
148 /* release. */
149 void
150 autoh_free(autoh_t ah)
151 {
152         int saved_errno;
153
154         saved_errno = errno;
155         close(ah->ah_fd);
156         free(ah);
157         errno = saved_errno;
158 }
159
160 /*
161  * Get an array of pointers to all the currently mounted autofs
162  * instances.
163  */
164 int
165 autoh_getall(autoh_t **arrayp, int *cntp)
166 {
167         struct statfs *sfsp;
168         int cnt, i, pos;
169         autoh_t *array;
170
171         array = NULL;
172         /*
173          * We use getfsstat to prevent avoid the lookups on the mountpoints
174          * that statfs(2) would do.
175          */
176         if (getmntlst(&sfsp, &cnt))
177                 goto err;
178         array = *arrayp = calloc(cnt + 1, sizeof(**arrayp));
179         if (array == NULL)
180                 goto err;
181         for (i = 0, pos = 0; i < cnt; i++) {
182                 if (autoh_get(sfsp[i].f_mntonname, &array[pos]) == -1) {
183                         /* not an autofs entry, that's ok, otherwise bail */
184                         if (errno == ENOTTY)
185                                 continue;
186                         goto err;
187                 }
188                 pos++;
189         }
190         if (pos == 0) {
191                 errno = ENOENT;
192                 goto err;
193         }
194         *arrayp = array;
195         *cntp = pos;
196         safe_free(sfsp);
197         return (0);
198 err:
199         safe_free(sfsp);
200         if (array)
201                 autoh_freeall(array);
202         return (-1);
203 }
204
205 /* release. */
206 void
207 autoh_freeall(autoh_t *ah)
208 {
209         autoh_t *ahp;
210
211         ahp = ah;
212
213         while (*ahp != NULL) {
214                 autoh_free(*ahp);
215                 ahp++;
216         }
217         safe_free(ah);
218 }
219
220 /* return fd to select on. */
221 int
222 autoh_fd(autoh_t ah)
223 {
224
225         return (ah->ah_fd);
226 }
227
228 const char *
229 autoh_mp(autoh_t ah)
230 {
231
232         return (ah->ah_mp);
233 }
234
235 static int do_autoreq_get(autoh_t ah, autoreq_t *reqp, int *cntp);
236
237 /* get an array of pending requests */
238 int
239 autoreq_get(autoh_t ah, autoreq_t **reqpp, int *cntp)
240 {
241         int cnt, i;
242         autoreq_t req, *reqp;
243
244         if (do_autoreq_get(ah, &req, &cnt))
245                 return (-1);
246
247         reqp = calloc(cnt + 1, sizeof(*reqp));
248         if (reqp == NULL) {
249                 safe_free(req);
250                 return (-1);
251         }
252         for (i = 0; i < cnt; i++)
253                 reqp[i] = &req[i];
254         *reqpp = reqp;
255         *cntp = cnt;
256         return (0);
257 }
258
259 int
260 do_autoreq_get(autoh_t ah, autoreq_t *reqp, int *cntp)
261 {
262         size_t olen;
263         struct autofs_userreq *reqs;
264         int cnt, error;
265         int vers;
266
267         vers = AUTOFS_PROTOVERS;
268
269         error = 0;
270         reqs = NULL;
271         olen = 0;
272         cnt = 0;
273         error = autofs_sysctl(AUTOFS_CTL_GETREQS, &ah->ah_fsid, NULL, &olen,
274             &vers, sizeof(vers));
275         if (error == -1)
276                 goto out;
277         if (olen == 0)
278                 goto out;
279
280         reqs = malloc(olen);
281         if (reqs == NULL)
282                 goto out;
283         error = autofs_sysctl(AUTOFS_CTL_GETREQS, &ah->ah_fsid, reqs, &olen,
284             &vers, sizeof(vers));
285         if (error == -1)
286                 goto out;
287 out:
288         if (error) {
289                 safe_free(reqs);
290                 return (-1);
291         }
292         cnt = olen / sizeof(*reqs);
293         *cntp = cnt;
294         *reqp = reqs;
295         return (0);
296 }
297
298 /* free an array of requests */
299 void
300 autoreq_free(autoh_t ah __unused, autoreq_t *req)
301 {
302
303         free(*req);
304         free(req);
305 }
306
307 /* serve a request */
308 int
309 autoreq_serv(autoh_t ah, autoreq_t req)
310 {
311         int error;
312
313         error = autofs_sysctl(AUTOFS_CTL_SERVREQ, &ah->ah_fsid, NULL, NULL,
314             req, sizeof(*req));
315         return (error);
316 }
317
318 enum autoreq_op
319 autoreq_getop(autoreq_t req)
320 {
321
322         switch (req->au_op) {
323         case AREQ_LOOKUP:
324                 return (AUTOREQ_OP_LOOKUP);
325         case AREQ_STAT:
326                 return (AUTOREQ_OP_STAT);
327         case AREQ_READDIR:
328                 return (AUTOREQ_OP_READDIR);
329         default:
330                 return (AUTOREQ_OP_UNKNOWN);
331         }
332 }
333
334 /* get a request's file name. */
335 const char      *
336 autoreq_getpath(autoreq_t req)
337 {
338
339         return (req->au_name);
340 }
341
342 /* get a request's inode.  a indirect mount may return AUTO_INODE_NONE. */
343 autoino_t
344 autoreq_getino(autoreq_t req)
345 {
346
347         return (req->au_ino);
348 }
349
350 void
351 autoreq_setino(autoreq_t req, autoino_t ino)
352 {
353
354         req->au_ino = ino;
355 }
356
357 /* get a request's directory inode. */
358 autoino_t
359 autoreq_getdirino(autoreq_t req)
360 {
361
362         return (req->au_dino);
363 }
364
365 void
366 autoreq_seterrno(autoreq_t req, int error)
367 {
368
369         req->au_errno = error;
370 }
371
372 void
373 autoreq_setaux(autoreq_t req, void *auxdata, size_t auxlen)
374 {
375
376         req->au_auxdata = auxdata;
377         req->au_auxlen = auxlen;
378 }
379
380 void
381 autoreq_getaux(autoreq_t req, void **auxdatap, size_t *auxlenp)
382 {
383
384         *auxdatap = req->au_auxdata;
385         *auxlenp = req->au_auxlen;
386 }
387
388 void
389 autoreq_seteof(autoreq_t req, int eof)
390 {
391
392         req->au_eofflag = eof;
393 }
394
395 void
396 autoreq_getoffset(autoreq_t req, off_t *offp)
397 {
398
399         *offp = req->au_offset - AUTOFS_USEROFF;
400 }
401
402 void
403 autoreq_getxid(autoreq_t req, int *xid)
404 {
405
406         *xid = req->au_xid;
407 }
408
409 /* toggle by path. args = handle, AUTO_?, pid (-1 to disable), path. */
410 int
411 autoh_togglepath(autoh_t ah, int op, pid_t pid,  const char *path)
412 {
413         int fd, ret;
414
415         fd = open(path, O_RDONLY);
416         if (fd == -1)
417                 return (-1);
418         ret = autoh_togglefd(ah, op, pid, fd);
419         close(fd);
420         return (ret);
421 }
422
423 /* toggle by fd. args = handle, AUTO_?, pid (-1 to disable), fd. */
424 int
425 autoh_togglefd(autoh_t ah, int op, pid_t pid, int fd)
426 {
427         struct stat sb;
428         struct autofs_mounterreq mr;
429         int error, realop;
430
431         switch (op) {
432         case AUTO_DIRECT:
433                 realop = AUTOFS_CTL_TRIGGER;
434                 break;
435         case AUTO_INDIRECT:
436                 realop = AUTOFS_CTL_SUBTRIGGER;
437                 break;
438         case AUTO_MOUNTER:
439                 realop = AUTOFS_CTL_MOUNTER;
440                 break;
441         case AUTO_BROWSE:
442                 realop = AUTOFS_CTL_BROWSE;
443                 break;
444         default:
445                 errno = ENOTTY;
446                 return (-1);
447         }
448
449         if (fstat(fd, &sb))
450                 return (-1);
451         bzero(&mr, sizeof(mr));
452         mr.amu_ino = sb.st_ino;
453         mr.amu_pid = pid;
454         error = autofs_sysctl(realop, &ah->ah_fsid, NULL, NULL,
455             &mr, sizeof(mr));
456         return (error);
457 }
458
459 int
460 autofs_sysctl(op, fsid, oldp, oldlenp, newp, newlen)
461         int op;
462         fsid_t *fsid;
463         void *oldp;
464         size_t *oldlenp;
465         void *newp;
466         size_t newlen;
467 {
468         struct vfsidctl vc;
469
470         bzero(&vc, sizeof(vc));
471         vc.vc_op = op;
472         strcpy(vc.vc_fstypename, "*");
473         vc.vc_vers = VFS_CTL_VERS1;
474         vc.vc_fsid = *fsid;
475         vc.vc_ptr = newp;
476         vc.vc_len = newlen;
477         return (sysctlbyname("vfs.autofs.ctl", oldp, oldlenp, &vc, sizeof(vc)));
478 }
479