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