launcher.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. /*
  2. * ZeroTier One - Global Peer to Peer Ethernet
  3. * Copyright (C) 2012-2013 ZeroTier Networks LLC
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. * --
  19. *
  20. * ZeroTier may be used and distributed under the terms of the GPLv3, which
  21. * are available at: http://www.gnu.org/licenses/gpl-3.0.html
  22. *
  23. * If you would like to embed ZeroTier into a commercial application or
  24. * redistribute it in a modified binary form, please contact ZeroTier Networks
  25. * LLC. Start here: http://www.zerotier.com/
  26. */
  27. /* Launcher for Linux/Unix/Mac */
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <dirent.h>
  32. #include <unistd.h>
  33. #include <signal.h>
  34. #include <errno.h>
  35. #include <time.h>
  36. #include <sys/types.h>
  37. #include <sys/stat.h>
  38. #include <sys/wait.h>
  39. #include "launcher.h"
  40. /* Must match first 16 bytes of EMBEDDED_VERSION_STAMP in Node.cpp */
  41. static const unsigned char EMBEDDED_VERSION_STAMP_KEY[16] = { 0x6d,0xfe,0xff,0x01,0x90,0xfa,0x89,0x57,0x88,0xa1,0xaa,0xdc,0xdd,0xde,0xb0,0x33 };
  42. const unsigned char EMBEDDED_LAUNCHER_VERSION_STAMP[20] = {
  43. 0x96,0xf0,0x00,0x08,0x18,0xff,0xc9,0xde,0xad,0xf0,0x0f,0xbe,0xef,0x30,0xce,0xa1, /* key */
  44. ZT_LAUNCHER_VERSION_MAJOR,
  45. ZT_LAUNCHER_VERSION_MINOR,
  46. (unsigned char)(((unsigned int)ZT_LAUNCHER_VERSION_REVISION) & 0xff), /* little-endian */
  47. (unsigned char)((((unsigned int)ZT_LAUNCHER_VERSION_REVISION) >> 8) & 0xff)
  48. };
  49. #define ZT_BINARY_NAME "zerotier-one"
  50. #define ZT_BINARY_UPDATE_PREFIX "zerotier-one_update."
  51. #define ZT_LAUNCHER_PIDFILE "zerotier-launcher.pid"
  52. #define ZT_ONE_PIDFILE "zerotier-one.pid"
  53. /* Load a file into newly malloc()'ed memory, len set to size */
  54. static unsigned char *loadFile(const char *path,unsigned long *len)
  55. {
  56. unsigned char *fbuf = (unsigned char *)0;
  57. FILE *f = fopen(path,"rb");
  58. if (f) {
  59. if (!fseek(f,0,SEEK_END)) {
  60. long l = ftell(f);
  61. if (l > 0) {
  62. fseek(f,0,SEEK_SET);
  63. fbuf = malloc(l);
  64. if (fbuf) {
  65. if (fread(fbuf,l,1,f) != 1) {
  66. free(fbuf);
  67. fbuf = (unsigned char *)0;
  68. } else *len = (unsigned long)l;
  69. }
  70. }
  71. }
  72. fclose(f);
  73. }
  74. return fbuf;
  75. }
  76. /* Scans a ZeroTier binary and determines its version from its embedded version code */
  77. static int findVersion(const unsigned char *bin,unsigned long len,unsigned int *major,unsigned int *minor,unsigned int *revision)
  78. {
  79. unsigned long i;
  80. if (len > 20) {
  81. for(i=0;i<(len - 20);++i) {
  82. if ((bin[i] == EMBEDDED_VERSION_STAMP_KEY[0])&&(!memcmp(bin + i,EMBEDDED_VERSION_STAMP_KEY,16))) {
  83. *major = bin[i + 16];
  84. *minor = bin[i + 17];
  85. *revision = ((unsigned int)bin[i + 18] & 0xff) | (((unsigned int)bin[i + 19] << 8) & 0xff00);
  86. return 1;
  87. }
  88. }
  89. }
  90. return 0;
  91. }
  92. /* Scan for updates and, if found, replace the main binary if possible */
  93. static int doUpdateBinaryIfNewer()
  94. {
  95. long pfxLen = strlen(ZT_BINARY_UPDATE_PREFIX);
  96. struct dirent dbuf,*d;
  97. int needUpdate;
  98. unsigned int major = 0,minor = 0,revision = 0;
  99. unsigned int existingMajor = 0,existingMinor = 0,existingRevision = 0;
  100. unsigned long binLen;
  101. unsigned char *bin;
  102. char oldname[1024];
  103. DIR *dir;
  104. binLen = 0;
  105. bin = loadFile(ZT_BINARY_NAME,&binLen);
  106. if (!((bin)&&(binLen)&&(findVersion(bin,binLen,&existingMajor,&existingMinor,&existingRevision)))) {
  107. if (bin)
  108. free(bin);
  109. return 0;
  110. }
  111. free(bin);
  112. dir = opendir(".");
  113. if (!dir)
  114. return 0;
  115. while (!readdir_r(dir,&dbuf,&d)) {
  116. if (!d) break;
  117. if (!strncasecmp(d->d_name,ZT_BINARY_UPDATE_PREFIX,pfxLen)) {
  118. binLen = 0;
  119. unsigned char *bin = loadFile(d->d_name,&binLen);
  120. if ((bin)&&(binLen)&&(findVersion(bin,binLen,&major,&minor,&revision))) {
  121. needUpdate = 0;
  122. if (major > existingMajor)
  123. needUpdate = 1;
  124. else if (major == existingMajor) {
  125. if (minor > existingMinor)
  126. needUpdate = 1;
  127. else if (minor == existingMinor) {
  128. if (revision > existingRevision)
  129. needUpdate = 1;
  130. }
  131. }
  132. free(bin);
  133. if (needUpdate) {
  134. /* fprintf(stderr,"zerotier-launcher: replacing %s with %s\n",ZT_BINARY_NAME,d->d_name); */
  135. sprintf(oldname,"%s.OLD",ZT_BINARY_NAME);
  136. if (!rename(ZT_BINARY_NAME,oldname)) {
  137. /* fprintf(stderr,"zerotier-launcher: %s -> %s\n",ZT_BINARY_NAME,oldname); */
  138. if (!rename(d->d_name,ZT_BINARY_NAME)) {
  139. /* fprintf(stderr,"zerotier-launcher: %s -> %s\nzerotier-launcher: delete %s\n",d->d_name,ZT_BINARY_NAME,oldname); */
  140. chmod(ZT_BINARY_NAME,0755);
  141. unlink(oldname);
  142. return 1;
  143. }
  144. }
  145. break;
  146. }
  147. }
  148. if (bin)
  149. free(bin);
  150. }
  151. }
  152. closedir(dir);
  153. return 0;
  154. }
  155. static volatile long childPid = 0;
  156. static void sigRepeater(int sig)
  157. {
  158. if (childPid > 0)
  159. kill(childPid,sig);
  160. }
  161. int main(int argc,char **argv)
  162. {
  163. const char *zerotierHome = ZT_DEFAULT_HOME;
  164. FILE *pidf;
  165. int status,exitCode;
  166. unsigned long timeStart;
  167. unsigned int numSubTwoSecondRuns;
  168. /* Pass on certain signals transparently to the subprogram to do with as it will */
  169. signal(SIGHUP,&sigRepeater);
  170. signal(SIGPIPE,SIG_IGN);
  171. signal(SIGUSR1,&sigRepeater);
  172. signal(SIGUSR2,&sigRepeater);
  173. signal(SIGALRM,SIG_IGN);
  174. signal(SIGURG,SIG_IGN);
  175. signal(SIGTERM,&sigRepeater);
  176. signal(SIGQUIT,&sigRepeater);
  177. if (argc == 2)
  178. zerotierHome = argv[1];
  179. if (chdir(zerotierHome)) {
  180. fprintf(stderr,"%s: fatal error: could not chdir to %s\n",argv[0],zerotierHome);
  181. return ZT_EXEC_RETURN_VALUE_UNRECOVERABLE_ERROR;
  182. }
  183. pidf = fopen(ZT_LAUNCHER_PIDFILE,"w");
  184. if (pidf) {
  185. fprintf(pidf,"%d",(int)getpid());
  186. fclose(pidf);
  187. }
  188. numSubTwoSecondRuns = 0;
  189. exitCode = ZT_EXEC_RETURN_VALUE_NORMAL_TERMINATION;
  190. restart_subprogram:
  191. /* We actually do this on every loop, which is fine. It picks up any
  192. * newer versions that are waiting and swaps them out for the current
  193. * running binary. */
  194. doUpdateBinaryIfNewer();
  195. timeStart = time(0);
  196. childPid = fork();
  197. if (childPid < 0) {
  198. fprintf(stderr,"%s: fatal error: could not fork(): %s\n",argv[0],strerror(errno));
  199. return ZT_EXEC_RETURN_VALUE_UNRECOVERABLE_ERROR;
  200. } else if (childPid) {
  201. pidf = fopen(ZT_ONE_PIDFILE,"w");
  202. if (pidf) {
  203. fprintf(pidf,"%d",(int)childPid);
  204. fclose(pidf);
  205. }
  206. status = ZT_EXEC_RETURN_VALUE_NO_BINARY;
  207. wait_for_subprogram_exit:
  208. if ((long)waitpid(childPid,&status,0) >= 0) {
  209. if (WIFEXITED(status)) {
  210. unlink(ZT_ONE_PIDFILE);
  211. if ((time(0) - timeStart) < 2) {
  212. /* Terminate abnormally if we appear to be looping in a tight loop
  213. * to avoid fork bombing if one exits abnormally without an abnormal
  214. * exit code. */
  215. if (++numSubTwoSecondRuns >= 16) {
  216. fprintf(stderr,"%s: fatal error: program exiting immediately in infinite loop\n",argv[0]);
  217. return ZT_EXEC_RETURN_VALUE_UNRECOVERABLE_ERROR;
  218. }
  219. }
  220. switch(WEXITSTATUS(status)) {
  221. case ZT_EXEC_RETURN_VALUE_NORMAL_TERMINATION:
  222. exitCode = ZT_EXEC_RETURN_VALUE_NORMAL_TERMINATION;
  223. goto exit_launcher;
  224. case ZT_EXEC_RETURN_VALUE_NO_BINARY:
  225. fprintf(stderr,"%s: fatal error: binary zerotier-one not found at %s\n",argv[0],zerotierHome);
  226. exitCode = ZT_EXEC_RETURN_VALUE_UNRECOVERABLE_ERROR;
  227. goto exit_launcher;
  228. case ZT_EXEC_RETURN_VALUE_TERMINATED_FOR_UPGRADE:
  229. case ZT_EXEC_RETURN_VALUE_PLEASE_RESTART:
  230. goto restart_subprogram;
  231. default:
  232. exitCode = status;
  233. goto exit_launcher;
  234. }
  235. }
  236. } else if (errno != EINTR) {
  237. fprintf(stderr,"%s: fatal error: waitpid() failed: %s\n",argv[0],strerror(errno));
  238. exitCode = ZT_EXEC_RETURN_VALUE_UNRECOVERABLE_ERROR;
  239. goto exit_launcher;
  240. } else {
  241. goto wait_for_subprogram_exit;
  242. }
  243. } else {
  244. execl(ZT_BINARY_NAME,ZT_BINARY_NAME,zerotierHome,(char *)0);
  245. exit(ZT_EXEC_RETURN_VALUE_NO_BINARY); /* only reached if execl succeeds */
  246. }
  247. exit_launcher:
  248. unlink(ZT_LAUNCHER_PIDFILE);
  249. return exitCode;
  250. }