autofs.c 5.0 KB

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