main.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. /*
  2. * Copyright (C) 2008 dhewg, #wiidev efnet
  3. *
  4. * this file is part of geckoloader
  5. * http://wiibrew.org/index.php?title=Geckoloader
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20. */
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include <fcntl.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <unistd.h>
  28. #include <errno.h>
  29. #include <libgen.h>
  30. #ifndef _WIN32
  31. #include <sys/socket.h>
  32. #include <netinet/in.h>
  33. #include <arpa/inet.h>
  34. #include <netdb.h>
  35. #else
  36. #include <winsock2.h>
  37. #endif
  38. #include <zlib.h>
  39. #include "gecko.h"
  40. #define WIILOAD_VERSION_MAYOR 0
  41. #define WIILOAD_VERSION_MINOR 5
  42. #define LD_TCP_PORT 4299
  43. #define MAX_ARGS_LEN 1024
  44. #ifndef O_BINARY
  45. #define O_BINARY 0
  46. #endif
  47. typedef unsigned char u8;
  48. typedef unsigned short u16;
  49. typedef unsigned int u32;
  50. typedef unsigned long long u64;
  51. typedef signed char s8;
  52. typedef signed short s16;
  53. typedef signed int s32;
  54. typedef signed long long s64;
  55. typedef enum { false, true } bool;
  56. #ifndef __WIN32__
  57. static const char *desc_export = "export";
  58. #ifndef __APPLE__
  59. static const char *desc_gecko = "/dev/ttyUSB0";
  60. #else
  61. static const char *desc_gecko = "/dev/tty.usbserial-GECKUSB0";
  62. #endif
  63. #else
  64. static const char *desc_export = "set";
  65. static const char *desc_gecko = "COM4";
  66. #endif
  67. static const char *envvar = "WIILOAD";
  68. static bool send_gecko (const char *dev, const u8 *buf, u32 len, u32 len_un,
  69. const char *args, u16 args_len) {
  70. u8 b[4];
  71. u32 left, block;
  72. const u8 *p;
  73. if (gecko_open (dev)) {
  74. fprintf (stderr, "unable to open the device '%s'\n", dev);
  75. return false;
  76. }
  77. printf ("sending upload request\n");
  78. b[0] = 'H';
  79. b[1] = 'A';
  80. b[2] = 'X';
  81. b[3] = 'X';
  82. if (gecko_write (b, 4)) {
  83. gecko_close ();
  84. fprintf (stderr, "error sending data\n");
  85. return false;
  86. }
  87. b[0] = WIILOAD_VERSION_MAYOR;
  88. b[1] = WIILOAD_VERSION_MINOR;
  89. b[2] = (args_len >> 8) & 0xff;
  90. b[3] = args_len & 0xff;
  91. if (gecko_write (b, 4)) {
  92. gecko_close ();
  93. fprintf (stderr, "error sending data\n");
  94. return false;
  95. }
  96. printf ("sending file size (%u bytes)\n", len);
  97. b[0] = (len >> 24) & 0xff;
  98. b[1] = (len >> 16) & 0xff;
  99. b[2] = (len >> 8) & 0xff;
  100. b[3] = len & 0xff;
  101. if (gecko_write (b, 4)) {
  102. gecko_close ();
  103. fprintf (stderr, "error sending data\n");
  104. return false;
  105. }
  106. b[0] = (len_un >> 24) & 0xff;
  107. b[1] = (len_un >> 16) & 0xff;
  108. b[2] = (len_un >> 8) & 0xff;
  109. b[3] = len_un & 0xff;
  110. if (gecko_write (b, 4)) {
  111. gecko_close ();
  112. fprintf (stderr, "error sending data\n");
  113. return false;
  114. }
  115. printf ("sending data");
  116. fflush (stdout);
  117. left = len;
  118. p = buf;
  119. while (left) {
  120. block = left;
  121. if (block > 63488)
  122. block = 63488;
  123. left -= block;
  124. if (gecko_write (p, block)) {
  125. fprintf (stderr, "error sending block\n");
  126. break;
  127. }
  128. p += block;
  129. printf (".");
  130. fflush (stdout);
  131. }
  132. printf ("\n");
  133. if (args_len) {
  134. printf ("sending arguments (%u bytes)\n", args_len);
  135. if (gecko_write ((u8 *) args, args_len)) {
  136. gecko_close ();
  137. return false;
  138. }
  139. }
  140. gecko_close ();
  141. return true;
  142. }
  143. static bool tcp_write (int s, const u8 *buf, u32 len) {
  144. s32 left, block;
  145. const u8 *p;
  146. left = len;
  147. p = buf;
  148. while (left) {
  149. block = send (s, p, left, 0);
  150. if (block < 0) {
  151. perror ("send failed");
  152. return false;
  153. }
  154. left -= block;
  155. p += block;
  156. }
  157. return true;
  158. }
  159. static bool send_tcp (const char *host, const u8 *buf, u32 len, u32 len_un,
  160. const char *args, u16 args_len) {
  161. struct sockaddr_in sa;
  162. struct hostent *he;
  163. int s, bc;
  164. u8 b[4];
  165. off_t left, block;
  166. const u8 *p;
  167. #ifdef __WIN32__
  168. WSADATA wsa_data;
  169. if (WSAStartup (MAKEWORD(2,2), &wsa_data)) {
  170. printf ("WSAStartup failed\n");
  171. return false;
  172. }
  173. #endif
  174. memset (&sa, 0, sizeof (sa));
  175. sa.sin_addr.s_addr = inet_addr (host);
  176. if (sa.sin_addr.s_addr == INADDR_NONE) {
  177. printf ("resolving %s\n", host);
  178. he = gethostbyname (host);
  179. if (!he) {
  180. #ifndef __WIN32__
  181. herror ("error resolving hostname");
  182. #else
  183. fprintf (stderr, "error resolving hostname\n");
  184. #endif
  185. return false;
  186. }
  187. if (he->h_addrtype != AF_INET) {
  188. fprintf (stderr, "unsupported address");
  189. return false;
  190. }
  191. sa.sin_addr.s_addr = *((u32 *) he->h_addr);
  192. }
  193. s = socket (PF_INET, SOCK_STREAM, 0);
  194. if (s < 0) {
  195. perror ("error creating socket");
  196. return false;
  197. }
  198. sa.sin_port = htons (LD_TCP_PORT);
  199. sa.sin_family = AF_INET;
  200. printf ("connecting to %s:%d\n", inet_ntoa (sa.sin_addr), LD_TCP_PORT);
  201. if (connect (s, (struct sockaddr *) &sa, sizeof (sa)) == -1) {
  202. perror ("error connecting");
  203. close (s);
  204. return false;
  205. }
  206. printf ("sending upload request\n");
  207. b[0] = 'H';
  208. b[1] = 'A';
  209. b[2] = 'X';
  210. b[3] = 'X';
  211. if (!tcp_write (s, b, 4)) {
  212. close (s);
  213. return false;
  214. }
  215. b[0] = WIILOAD_VERSION_MAYOR;
  216. b[1] = WIILOAD_VERSION_MINOR;
  217. b[2] = (args_len >> 8) & 0xff;
  218. b[3] = args_len & 0xff;
  219. if (!tcp_write (s, b, 4)) {
  220. close (s);
  221. return false;
  222. }
  223. printf ("sending file size (%u bytes)\n", len);
  224. b[0] = (len >> 24) & 0xff;
  225. b[1] = (len >> 16) & 0xff;
  226. b[2] = (len >> 8) & 0xff;
  227. b[3] = len & 0xff;
  228. if (!tcp_write (s, b, 4)) {
  229. close (s);
  230. return false;
  231. }
  232. b[0] = (len_un >> 24) & 0xff;
  233. b[1] = (len_un >> 16) & 0xff;
  234. b[2] = (len_un >> 8) & 0xff;
  235. b[3] = len_un & 0xff;
  236. if (!tcp_write (s, b, 4)) {
  237. close (s);
  238. return false;
  239. }
  240. printf ("sending data");
  241. fflush (stdout);
  242. left = len;
  243. p = buf;
  244. bc = 0;
  245. while (left) {
  246. block = left;
  247. if (block > 4 * 1024)
  248. block = 4 * 1024;
  249. left -= block;
  250. if (!tcp_write (s, p, block)) {
  251. close (s);
  252. return false;
  253. }
  254. p += block;
  255. bc++;
  256. if (!(bc % 16)) {
  257. printf (".");
  258. fflush (stdout);
  259. }
  260. }
  261. printf ("\n");
  262. if (args_len) {
  263. printf ("sending arguments (%u bytes)\n", args_len);
  264. if (!tcp_write (s, (u8 *) args, args_len)) {
  265. close (s);
  266. return false;
  267. }
  268. }
  269. #ifndef __WIN32__
  270. close (s);
  271. #else
  272. shutdown (s, SD_SEND);
  273. closesocket (s);
  274. WSACleanup ();
  275. #endif
  276. return true;
  277. }
  278. static void usage (const char *argv0) {
  279. fprintf (stderr, "set the environment variable %s to a valid "
  280. "destination.\n\n"
  281. "examples:\n"
  282. "\tusbgecko mode:\n"
  283. "\t\t%s %s=%s\n\n"
  284. "\ttcp mode:\n"
  285. "\t\t%s %s=tcp:wii\n"
  286. "\t\t%s %s=tcp:192.168.0.30\n\n"
  287. "usage:\n"
  288. "\t%s <filename> <application arguments>\n\n",
  289. envvar,
  290. desc_export, envvar, desc_gecko,
  291. desc_export, envvar,
  292. desc_export, envvar,
  293. argv0);
  294. exit (EXIT_FAILURE);
  295. }
  296. int main (int argc, char **argv) {
  297. int fd;
  298. struct stat st;
  299. char *ev;
  300. bool compress = true;
  301. u8 *buf, *bufz;
  302. off_t fsize;
  303. uLongf bufzlen = 0;
  304. u32 len, len_un;
  305. int i, c;
  306. char args[MAX_ARGS_LEN];
  307. char *arg_pos;
  308. u16 args_len, args_left;
  309. bool res;
  310. printf ("wiiload v%u.%u\n"
  311. "coded by dhewg, #wiidev efnet\n\n",
  312. WIILOAD_VERSION_MAYOR, WIILOAD_VERSION_MINOR);
  313. if (argc < 2)
  314. usage (*argv);
  315. ev = getenv (envvar);
  316. if (!ev)
  317. usage (*argv);
  318. fd = open (argv[1], O_RDONLY | O_BINARY);
  319. if (fd < 0) {
  320. perror ("error opening the file");
  321. exit (EXIT_FAILURE);
  322. }
  323. if (fstat (fd, &st)) {
  324. close (fd);
  325. perror ("error stat'ing the file");
  326. exit (EXIT_FAILURE);
  327. }
  328. fsize = st.st_size;
  329. if (fsize < 64 || fsize > 20 * 1024 * 1024) {
  330. close (fd);
  331. fprintf (stderr, "error: invalid file size\n");
  332. exit (EXIT_FAILURE);
  333. }
  334. buf = malloc (fsize);
  335. if (!buf) {
  336. close (fd);
  337. fprintf (stderr, "out of memory\n");
  338. exit (EXIT_FAILURE);
  339. }
  340. if (read (fd, buf, fsize) != fsize) {
  341. close (fd);
  342. free (buf);
  343. perror ("error reading the file");
  344. exit (EXIT_FAILURE);
  345. }
  346. close (fd);
  347. len = fsize;
  348. len_un = 0;
  349. if (!memcmp(buf, "PK\x03\x04", 4))
  350. compress = false;
  351. if (compress) {
  352. bufzlen = (uLongf) ((float) fsize * 1.02);
  353. bufz = malloc (bufzlen);
  354. if (!bufz) {
  355. fprintf (stderr, "out of memory\n");
  356. exit (EXIT_FAILURE);
  357. }
  358. printf("compressing %u bytes...", (u32) fsize);
  359. fflush(stdout);
  360. res = compress2 (bufz, &bufzlen, buf, fsize, 6);
  361. if (res != Z_OK) {
  362. free(buf);
  363. free(bufz);
  364. fprintf (stderr, "error compressing data: %d\n", res);
  365. exit (EXIT_FAILURE);
  366. }
  367. if (bufzlen < (u32) fsize) {
  368. printf(" %.2f%%\n", 100.0f * (float) bufzlen / (float) fsize);
  369. len = bufzlen;
  370. len_un = fsize;
  371. free(buf);
  372. buf = bufz;
  373. } else {
  374. printf(" compressed size gained size, discarding\n");
  375. free(bufz);
  376. }
  377. }
  378. args_len = 0;
  379. arg_pos = args;
  380. args_left = MAX_ARGS_LEN;
  381. c = snprintf (arg_pos, args_left, "%s", basename (argv[1]));
  382. arg_pos += c + 1;
  383. args_left -= c + 1;
  384. if (argc > 2) {
  385. for (i = 2; i < argc; ++i) {
  386. c = snprintf (arg_pos, args_left, "%s", argv[i]);
  387. if (c >= args_left) {
  388. free (buf);
  389. fprintf (stderr, "argument string too long\n");
  390. exit (EXIT_FAILURE);
  391. }
  392. arg_pos += c + 1;
  393. args_left -= c + 1;
  394. }
  395. if (args_left < 1) {
  396. free (buf);
  397. fprintf (stderr, "argument string too long\n");
  398. exit (EXIT_FAILURE);
  399. }
  400. }
  401. arg_pos[0] = 0;
  402. args_len = MAX_ARGS_LEN - args_left + 1;
  403. if (strncmp (ev, "tcp:", 4)) {
  404. if (stat (ev, &st))
  405. usage (*argv);
  406. res = send_gecko (ev, buf, len, len_un, args, args_len);
  407. } else {
  408. if (strlen (ev) < 5)
  409. usage (*argv);
  410. res = send_tcp (&ev[4], buf, len, len_un, args, args_len);
  411. }
  412. if (res)
  413. printf ("done.\n");
  414. else
  415. printf ("transfer failed.\n");
  416. free (buf);
  417. return 0;
  418. }