2 * Copyright (c) 2004 Alfred Perlstein <alfred@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
26 * $Id: autodriver.c,v 1.9 2004/09/08 08:12:21 bright Exp $
38 #include <sys/dirent.h>
39 #include <sys/types.h>
40 #include <sys/param.h>
41 #include <sys/mount.h>
45 #include <libautofs.h>
48 char *ae_mnt
; /* autofs mountpoint. */
49 char *ae_path
; /* path under mount. */
50 char *ae_type
; /* fs to be mounted type. */
51 char *ae_opts
; /* options passed to mount. */
52 char *ae_rpath
; /* remote path */
53 char *ae_free
; /* freeme! */
54 char *ae_fullpath
; /* full path to mount */
55 int ae_line
; /* line it came from in the conf. */
56 int ae_indirect
; /* is this an indirect mount? */
57 int ae_direct
; /* is this a direct mount? */
58 int ae_browse
; /* browseable? */
59 struct autoentry
*ae_next
; /* next. */
62 struct autoentry
*entries
;
63 const char *mount_prog
= "mount";
64 const char *fstype
= "autofs";
66 void *xmalloc(size_t);
67 void *xcalloc(size_t number
, size_t size
);
69 void populate_tab(void);
70 void doreq(autoh_t
, autoreq_t
);
71 void dotheneedful(autoh_t
);
73 int poll_handles(autoh_t
*array
, int cnt
);
74 int mount_indirect(struct autofs_userreq
*req
, struct autoentry
*ent
);
75 int mount_direct(struct autofs_userreq
*req
, struct autoentry
*ent
);
76 int mount_browse(struct autofs_userreq
*req
, struct autoentry
*ent
);
78 #define DSTR(s) sizeof(s) - 1, s
80 struct dirent dumbents
[] = {
81 {50, sizeof(struct dirent
), DT_DIR
, DSTR("one") },
82 {51, sizeof(struct dirent
), DT_DIR
, DSTR(".") },
83 {52, sizeof(struct dirent
), DT_DIR
, DSTR("..") },
84 {50, sizeof(struct dirent
), DT_DIR
, DSTR("two") },
94 err(1, "malloc %d", (int) size
);
99 xcalloc(size_t number
, size_t size
)
103 ret
= calloc(number
, size
);
105 err(1, "calloc %d %d", (int)number
, (int)size
);
114 char *cp
, *p
, *line
, *opt
;
116 struct autoentry
*ent
;
117 int i
, lineno
, x
, gotopt
;
118 const char *expecting
= "expecting 'direct', 'indirect' or 'browse'";
119 const char *tabfiles
[] = {
120 "/etc/autotab", "/usr/local/etc/autotab", "./autotab", NULL
124 for (i
= 0; (tab
= tabfiles
[i
]) != NULL
; i
++) {
126 fp
= fopen(tab
, "r");
128 warn("fopen %s", tab
);
133 err(1, "no config file available.");
136 fprintf(stderr
, "using config file: %s\n", tab
);
138 while ((cp
= fgetln(fp
, &len
)) != NULL
) {
140 while (len
> 0 && isspace(cp
[len
- 1]))
142 line
= xmalloc(len
+ 1);
143 bcopy(cp
, line
, len
);
146 if ((cp
= strchr(line
, '#')) != NULL
)
155 ent
= xcalloc(1, sizeof(*ent
));
156 if ((p
= strsep(&cp
, " \t")) == NULL
)
159 if ((p
= strsep(&cp
, " \t")) == NULL
)
162 if ((p
= strsep(&cp
, " \t")) == NULL
)
165 if ((p
= strsep(&cp
, " \t")) == NULL
)
168 if ((p
= strsep(&cp
, " \t")) == NULL
)
171 if ((p
= strsep(&cp
, " \t")) == NULL
)
175 while ((p
= strsep(&opt
, ",")) != NULL
) {
176 if (strcmp(p
, "indirect") == 0) {
177 ent
->ae_indirect
= 1;
179 } else if (strcmp(p
, "direct") == 0) {
182 } else if (strcmp(p
, "browse") == 0) {
186 warnx("unreconized option '%s', %s",
192 warnx("no options specified %s", expecting
);
195 if (ent
->ae_direct
&& ent
->ae_indirect
) {
196 warnx("direct and indirect are mutually exclusive");
200 x
= asprintf(&ent
->ae_fullpath
, "%s/%s",
201 ent
->ae_mnt
, ent
->ae_path
);
205 if (strlen(ent
->ae_fullpath
) + 1 > PATH_MAX
) {
206 warnx("Error in file %s, line %d, "
207 "mountpath (%s) exceeds PATH_MAX (%d)",
208 tab
, lineno
, ent
->ae_fullpath
, PATH_MAX
);
211 ent
->ae_line
= lineno
;
213 ent
->ae_next
= entries
;
217 warnx("Parse error in file %s, line %d", tab
, lineno
);
219 free(ent
->ae_fullpath
);
224 err(1, "error with file %s", tab
);
230 struct autoentry
*ent
;
237 for (ent
= entries
; ent
!= NULL
; ent
= ent
->ae_next
) {
240 error
= asprintf(&path
, "%s/%s", ent
->ae_mnt
, ent
->ae_path
);
243 error
= asprintf(&cmd
, "mkdir -p %s", path
);
248 warn("system: %s", cmd
);
251 if (autoh_get(ent
->ae_mnt
, &ah
)) {
252 warn("autoh_get %s", path
);
255 error
= autoh_togglepath(ah
, AUTO_MOUNTER
, getpid(), path
);
257 err(1, "AUTO_MOUNTER %s", path
);
260 if (ent
->ae_browse
) {
261 error
= autoh_togglepath(ah
, AUTO_BROWSE
, getpid(),
264 err(1, "AUTO_BROWSE %s", path
);
266 if (ent
->ae_direct
) {
267 error
= autoh_togglepath(ah
, AUTO_DIRECT
, getpid(),
270 err(1, "AUTO_DIRECT %s", path
);
272 if (ent
->ae_indirect
) {
273 error
= autoh_togglepath(ah
, AUTO_INDIRECT
, getpid(),
276 err(1, "AUTO_INDIRECT %s", path
);
285 * Process an autofs request, scan the list of entries in the config
286 * looking for our node, if found mount it.
289 doreq(autoh_t ah
, autoreq_t req
)
291 struct autoentry
*ent
;
299 autoreq_seterrno(req
, 0);
300 for (ent
= entries
; ent
!= NULL
; ent
= ent
->ae_next
) {
301 fprintf(stderr
, "comparing {%s,%s} to {%s,%s}\n",
302 mnt
, ent
->ae_mnt
, autoreq_getpath(req
), ent
->ae_path
);
303 fprintf(stderr
, "comparing {%d,%d} to {%d,%d}\n",
305 (int)strlen(ent
->ae_mnt
),
306 (int)strlen(autoreq_getpath(req
)),
307 (int)strlen(ent
->ae_path
));
308 autoreq_getxid(req
, &xid
);
309 fprintf(stderr
, "req xid %d\n", xid
);
310 if ((mcmp
= strcmp(mnt
, ent
->ae_mnt
)) != 0) {
311 fprintf(stderr
, "mcmp = %d\n", mcmp
);
314 if (mount_direct(req
, ent
))
316 if (mount_indirect(req
, ent
))
318 if (mount_browse(req
, ent
))
321 fprintf(stderr
, "no entry found...\n");
322 autoreq_seterrno(req
, ENOENT
);
324 error
= autoreq_serv(ah
, req
);
326 warn("AUTOFS_CTL_SERVREQ");
331 mount_indirect(req
, ent
)
332 struct autofs_userreq
*req
;
333 struct autoentry
*ent
;
339 if (ent
->ae_indirect
!= 1) {
340 fprintf(stderr
, "not indirect.\n");
343 fprintf(stderr
, "indirect mount...\n");
345 * handle lookups, fake all stat(2) requests... this is bad,
346 * but we're a driver so we don't care...
347 * If we don't care about the type of request, then just return.
349 switch (autoreq_getop(req
)) {
350 case AUTOREQ_OP_LOOKUP
:
352 case AUTOREQ_OP_STAT
:
353 fprintf(stderr
, "stat\n");
356 fprintf(stderr
, "unknown\n");
359 if (stat(ent
->ae_fullpath
, &sb
))
361 if (sb
.st_ino
!= autoreq_getdirino(req
)) {
362 fprintf(stderr
, "st_ino %d != dirino %d\n",
363 (int)sb
.st_ino
, (int)autoreq_getdirino(req
));
366 x
= asprintf(&path
, "%s/%s", ent
->ae_fullpath
, autoreq_getpath(req
));
368 autoreq_seterrno(req
, ENAMETOOLONG
);
371 if (mkdir(path
, 0555) == -1)
372 warn("mkdir %s", path
);
373 error
= asprintf(&cmd
, "%s -t %s -o %s %s/%s %s", mount_prog
,
374 ent
->ae_type
, ent
->ae_opts
, ent
->ae_rpath
, autoreq_getpath(req
), path
);
375 fprintf(stderr
, "running:\n\t%s\n", cmd
);
377 fprintf(stderr
, "error = %d\n", error
);
380 if (rmdir(path
) == -1)
381 warn("rmdir %s", path
);
382 autoreq_seterrno(req
, ENOENT
);
384 if (stat(path
, &sb
) != -1)
385 autoreq_setino(req
, sb
.st_ino
);
387 /* req->au_flags = 1; */
394 mount_direct(req
, ent
)
395 struct autofs_userreq
*req
;
396 struct autoentry
*ent
;
402 if (ent
->ae_direct
!= 1) {
403 fprintf(stderr
, "not direct.\n");
406 fprintf(stderr
, "direct mount...\n");
408 * handle lookups, fake all stat(2) requests... this is bad,
409 * but we're a driver so we don't care...
410 * If we don't care about the type of request, then just return.
412 switch (autoreq_getop(req
)) {
413 case AUTOREQ_OP_LOOKUP
:
415 case AUTOREQ_OP_STAT
:
420 if (stat(ent
->ae_fullpath
, &sb
))
422 if (sb
.st_ino
!= autoreq_getino(req
))
424 error
= asprintf(&cmd
, "%s -t %s -o %s %s %s", mount_prog
,
425 ent
->ae_type
, ent
->ae_opts
, ent
->ae_rpath
, ent
->ae_fullpath
);
428 fprintf(stderr
, "running:\n\t%s\n", cmd
);
430 fprintf(stderr
, "error = %d\n", error
);
433 autoreq_seterrno(req
, ENOENT
);
436 /* XXX: fix ONLIST in kernel */
437 /* req->au_flags = 1; */
442 mount_browse(req
, ent
)
443 struct autofs_userreq
*req
;
444 struct autoentry
*ent
;
448 if (ent
->ae_browse
!= 1)
450 if (autoreq_getop(req
) != AUTOREQ_OP_READDIR
)
452 autoreq_getoffset(req
, &off
);
453 if (off
< sizeof(dumbents
))
454 autoreq_setaux(req
, dumbents
, sizeof(dumbents
));
455 fprintf(stderr
, "mount_browse: offset %d, size %d\n",
456 (int)off
, (int)sizeof(dumbents
));
457 autoreq_seteof(req
, 1);
462 * Ask the filesystem passed in if it has a pending request.
463 * if so process them.
466 dotheneedful(autoh_t ah
)
471 if (autoreq_get(ah
, &reqs
, &cnt
))
472 err(1, "autoreq_get");
474 for (i
= 0; i
< cnt
; i
++) {
475 fprintf(stderr
, "processing request for '%s' '%s'\n",
476 autoh_mp(ah
), autoreq_getpath(reqs
[i
]));
483 poll_handles(autoh_t
*array
, int cnt
)
485 int i
, saved_errno
, x
;
486 static struct pollfd
*pfd
= NULL
;
488 pfd
= reallocf(pfd
, cnt
* sizeof(*pfd
));
491 for (i
= 0; i
< cnt
; i
++) {
492 pfd
[i
].fd
= autoh_fd(array
[i
]);
493 pfd
[i
].events
= POLLPRI
;
496 fprintf(stderr
, "start polling...\n");
497 x
= poll(pfd
, cnt
, 10000);
499 fprintf(stderr
, "done polling...\n");
503 /* at least one fs is ready... */
515 fprintf(stderr
, "starting event loop...\n");
517 if (autoh_getall(&array
, &cnt
))
518 err(1, "autoh_getall");
519 if (poll_handles(array
, cnt
))
520 err(1, "poll_handles");
521 for (i
= 0; i
< cnt
; i
++) {
522 dotheneedful(array
[i
]);
524 autoh_freeall(array
);
529 main(int argc __unused
, char **argv __unused
)
533 errx(1, "autodriver needs to be run as root to work.");