• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/mountd/autofs.c

  1 #include <sys/types.h>
  2 #include <linux/types.h>
  3 #include <paths.h>
  4 #include <limits.h>
  5 #include <time.h>
  6 
  7 #include <stdio.h>
  8 #include <signal.h>
  9 #include <stdlib.h>
 10 #include <fcntl.h>
 11 
 12 #include <errno.h>
 13 
 14 #include <string.h>
 15 #include <syslog.h>
 16 #include <unistd.h>
 17 #include <sys/ioctl.h>
 18 #include <sys/types.h>
 19 #include <sys/wait.h>
 20 #include <sys/stat.h>
 21 #include <sys/time.h>
 22 #include <poll.h>
 23 #include <linux/auto_fs4.h>
 24 
 25 #include "include/log.h"
 26 #include "include/sys.h"
 27 #include "include/timer.h"
 28 #include "include/mount.h"
 29 #include "include/signal.h"
 30 #include "include/ucix.h"
 31 #include "include/autofs.h"
 32 
 33 static int fdin = 0; /* data coming out of the kernel */
 34 static int fdout = 0;/* data going into the kernel */
 35 static bool term = false;
 36 static dev_t dev;
 37 
 38 static time_t uci_timeout;
 39 char uci_path[32];
 40 
 41 static void umount_autofs(void)
 42 {
 43         system_printf("umount %s 2> /dev/null", "/tmp/run/mountd/");
 44 }
 45 
 46 static int mount_autofs(void)
 47 {
 48         int pipefd[2];
 49         struct stat st;
 50         log_printf("trying to mount %s as the autofs root\n", "/tmp/run/mountd/");
 51         if(is_mounted(0, "/tmp/run/mountd/"))
 52         {
 53                 log_printf("%s is already mounted\n", "/tmp/run/mountd/");
 54                 return -1;
 55         }
 56         fdout = fdin = -1;
 57         mkdir("/tmp/run/mountd/", 0555);
 58         if(pipe(pipefd) < 0)
 59         {
 60                 log_printf("failed to get kernel pipe\n");
 61                 return -1;
 62         }
 63         if(system_printf("/bin/mount -t autofs -o fd=%d,pgrp=%u,minproto=5,maxproto=5 \"mountd(pid%u)\" %s",
 64                 pipefd[1], (unsigned) getpgrp(), getpid(), "/tmp/run/mountd/") != 0)
 65         {
 66                 log_printf("unable to mount autofs on %s\n", "/tmp/run/mountd/");
 67                 close(pipefd[0]);
 68                 close(pipefd[1]);
 69                 return -1;
 70         }
 71 
 72         close(pipefd[1]);
 73         fdout = pipefd[0];
 74 
 75         fdin = open("/tmp/run/mountd/", O_RDONLY);
 76         if(fdin < 0)
 77         {
 78                 umount_autofs();
 79                 return -1;
 80         }
 81         stat("/tmp/run/mountd/", &st);
 82         return 0;
 83 }
 84 
 85 static void send_ready(unsigned int wait_queue_token)
 86 {
 87         if(ioctl(fdin, AUTOFS_IOC_READY, wait_queue_token) < 0)
 88                 log_printf("failed to report ready to kernel\n");
 89 }
 90 
 91 static void send_fail(unsigned int wait_queue_token)
 92 {
 93         if(ioctl(fdin, AUTOFS_IOC_FAIL, wait_queue_token) < 0)
 94                 log_printf("failed to report fail to kernel\n");
 95 }
 96 
 97 static int autofs_process_request(const struct autofs_v5_packet *pkt)
 98 {
 99         struct stat st;
100         log_printf("kernel is requesting a mount -> %s\n", pkt->name);
101         chdir("/tmp/run/mountd/");
102         if (lstat(pkt->name, &st) == -1 || (S_ISDIR(st.st_mode) && st.st_dev == dev)) {
103                 if(!mount_new("/tmp/run/mountd/", (char*)pkt->name))
104                 {
105                         send_ready(pkt->wait_queue_token);
106                 } else {
107                         send_fail(pkt->wait_queue_token);
108                         log_printf("failed to mount %s\n", pkt->name);
109                 }
110         } else {
111                 send_ready(pkt->wait_queue_token);
112         }
113         chdir("/");
114 
115         return 0;
116 }
117 
118 static void expire_proc(void)
119 {
120         struct autofs_packet_expire pkt;
121         while(ioctl(fdin, AUTOFS_IOC_EXPIRE, &pkt) == 0)
122                 mount_remove("/tmp/run/mountd/", pkt.name);
123 }
124 
125 static int fullread(void *ptr, size_t len)
126 {
127         char *buf = (char *) ptr;
128         while(len > 0)
129         {
130                 ssize_t r = read(fdout, buf, len);
131                 if(r == -1)
132                 {
133                         if (errno == EINTR)
134                                 continue;
135                         break;
136                 }
137                 buf += r;
138                 len -= r;
139         }
140         return len;
141 }
142 
143 static int autofs_in(union autofs_v5_packet_union *pkt)
144 {
145         int res;
146         struct pollfd fds[1];
147 
148         fds[0].fd = fdout;
149         fds[0].events = POLLIN;
150 
151         while(!term)
152         {
153                 res = poll(fds, 1, -1);
154 
155                 if (res == -1)
156                 {
157                         if (errno == EINTR)
158                                 continue;
159                         log_printf("failed while trying to read packet from kernel\n");
160                         return -1;
161                 }
162                 else if ((res > 0) && (fds[0].revents & POLLIN))
163                 {
164                         return fullread(pkt, sizeof(*pkt));
165                 }
166         }
167         return 1;
168 }
169 
170 pid_t autofs_safe_fork(void)
171 {
172         pid_t pid = fork();
173         if(!pid)
174         {
175                 close(fdin);
176                 close(fdout);
177         }
178         return pid;
179 }
180 
181 static void autofs_cleanup(void)
182 {
183         close(fdin);
184         close(fdout);
185         umount_autofs();
186 }
187 
188 static void autofs_end_handler(int sig)
189 {
190         term = true;
191 }
192 
193 static void autofs_init(void)
194 {
195         int kproto_version;
196         char *p;
197         struct uci_context *ctx;
198         signal_init(autofs_end_handler);
199         ctx = ucix_init("mountd");
200         uci_timeout = ucix_get_option_int(ctx, "mountd", "mountd", "timeout", 60);
201         p = ucix_get_option(ctx, "mountd", "mountd", "path");
202         ucix_cleanup(ctx);
203         if(p)
204                 snprintf(uci_path, 31, "%s", p);
205         else
206                 snprintf(uci_path, 31, "/tmp/mounts/");
207         uci_path[31] = '\0';
208         mkdir("/tmp/run/", 0555);
209         mkdir("/tmp/mounts", 0555);
210         system_printf("rm -rf %s*", uci_path);
211         if(uci_timeout < 16)
212                 uci_timeout = 16;
213         umount_autofs();
214         mount_init();
215         if(mount_autofs() < 0)
216         {
217                 closelog();
218                 exit(1);
219         }
220         ioctl(fdin, AUTOFS_IOC_PROTOVER, &kproto_version);
221         if(kproto_version != 5)
222         {
223                 log_printf("only kernel protocol version 5 is tested. You have %d.\n",
224                         kproto_version);
225                 closelog();
226                 exit(1);
227         }
228         ioctl(fdin, AUTOFS_IOC_SETTIMEOUT, &uci_timeout);
229         timer_add(expire_proc, 15);
230 }
231 
232 int autofs_loop(void)
233 {
234         chdir("/");
235         autofs_init();
236         while(!term)
237         {
238                 union autofs_v5_packet_union pkt;
239                 if(autofs_in(&pkt))
240                 {
241                         continue;
242                 }
243                 log_printf("Got a autofs packet\n");
244                 if(pkt.hdr.type == autofs_ptype_missing_indirect)
245                         autofs_process_request(&pkt.missing_indirect);
246                 else
247                         log_printf("unknown packet type %d\n", pkt.hdr.type);
248                 poll(0, 0, 200);
249         }
250         autofs_cleanup();
251         log_printf("... quitting\n");
252         closelog();
253         return 0;
254 }
255 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt