autofs.c 4.9 KB

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