updated on Fri Jan 20 20:16:25 UTC 2012
[aur-mirror.git] / wiiload / main.c
blob12c9c6931be70ff5ae64f017562825b7add2efe4
1 /*
2 * Copyright (C) 2008 dhewg, #wiidev efnet
4 * this file is part of geckoloader
5 * http://wiibrew.org/index.php?title=Geckoloader
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.
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.
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
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <errno.h>
30 #include <libgen.h>
31 #ifndef _WIN32
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
35 #include <netdb.h>
36 #else
37 #include <winsock2.h>
38 #endif
40 #include <zlib.h>
42 #include "gecko.h"
44 #define WIILOAD_VERSION_MAYOR 0
45 #define WIILOAD_VERSION_MINOR 5
47 #define LD_TCP_PORT 4299
49 #define MAX_ARGS_LEN 1024
51 #ifndef O_BINARY
52 #define O_BINARY 0
53 #endif
55 typedef unsigned char u8;
56 typedef unsigned short u16;
57 typedef unsigned int u32;
58 typedef unsigned long long u64;
59 typedef signed char s8;
60 typedef signed short s16;
61 typedef signed int s32;
62 typedef signed long long s64;
64 typedef enum { false, true } bool;
66 #ifndef __WIN32__
67 static const char *desc_export = "export";
68 #ifndef __APPLE__
69 static const char *desc_gecko = "/dev/ttyUSB0";
70 #else
71 static const char *desc_gecko = "/dev/tty.usbserial-GECKUSB0";
72 #endif
73 #else
74 static const char *desc_export = "set";
75 static const char *desc_gecko = "COM4";
76 #endif
78 static const char *envvar = "WIILOAD";
80 static bool send_gecko (const char *dev, const u8 *buf, u32 len, u32 len_un,
81 const char *args, u16 args_len) {
82 u8 b[4];
83 u32 left, block;
84 const u8 *p;
86 if (gecko_open (dev)) {
87 fprintf (stderr, "unable to open the device '%s'\n", dev);
88 return false;
91 printf ("sending upload request\n");
93 b[0] = 'H';
94 b[1] = 'A';
95 b[2] = 'X';
96 b[3] = 'X';
98 if (gecko_write (b, 4)) {
99 gecko_close ();
100 fprintf (stderr, "error sending data\n");
101 return false;
104 b[0] = WIILOAD_VERSION_MAYOR;
105 b[1] = WIILOAD_VERSION_MINOR;
106 b[2] = (args_len >> 8) & 0xff;
107 b[3] = args_len & 0xff;
109 if (gecko_write (b, 4)) {
110 gecko_close ();
111 fprintf (stderr, "error sending data\n");
112 return false;
115 printf ("sending file size (%u bytes)\n", len);
117 b[0] = (len >> 24) & 0xff;
118 b[1] = (len >> 16) & 0xff;
119 b[2] = (len >> 8) & 0xff;
120 b[3] = len & 0xff;
122 if (gecko_write (b, 4)) {
123 gecko_close ();
124 fprintf (stderr, "error sending data\n");
125 return false;
128 b[0] = (len_un >> 24) & 0xff;
129 b[1] = (len_un >> 16) & 0xff;
130 b[2] = (len_un >> 8) & 0xff;
131 b[3] = len_un & 0xff;
133 if (gecko_write (b, 4)) {
134 gecko_close ();
135 fprintf (stderr, "error sending data\n");
136 return false;
139 printf ("sending data");
140 fflush (stdout);
142 left = len;
143 p = buf;
144 while (left) {
145 block = left;
146 if (block > 63488)
147 block = 63488;
148 left -= block;
150 if (gecko_write (p, block)) {
151 fprintf (stderr, "error sending block\n");
152 break;
154 p += block;
156 printf (".");
157 fflush (stdout);
160 printf ("\n");
162 if (args_len) {
163 printf ("sending arguments (%u bytes)\n", args_len);
165 if (gecko_write ((u8 *) args, args_len)) {
166 gecko_close ();
167 return false;
171 gecko_close ();
173 return true;
176 static bool tcp_write (int s, const u8 *buf, u32 len) {
177 s32 left, block;
178 const u8 *p;
180 left = len;
181 p = buf;
182 while (left) {
183 block = send (s, p, left, 0);
185 if (block < 0) {
186 perror ("send failed");
187 return false;
190 left -= block;
191 p += block;
194 return true;
197 static bool send_tcp (const char *host, const u8 *buf, u32 len, u32 len_un,
198 const char *args, u16 args_len) {
199 struct sockaddr_in sa;
200 struct hostent *he;
201 int s, bc;
202 u8 b[4];
203 off_t left, block;
204 const u8 *p;
206 #ifdef __WIN32__
207 WSADATA wsa_data;
208 if (WSAStartup (MAKEWORD(2,2), &wsa_data)) {
209 printf ("WSAStartup failed\n");
210 return false;
212 #endif
214 memset (&sa, 0, sizeof (sa));
216 sa.sin_addr.s_addr = inet_addr (host);
218 if (sa.sin_addr.s_addr == INADDR_NONE) {
219 printf ("resolving %s\n", host);
221 he = gethostbyname (host);
223 if (!he) {
224 #ifndef __WIN32__
225 herror ("error resolving hostname");
226 #else
227 fprintf (stderr, "error resolving hostname\n");
228 #endif
229 return false;
232 if (he->h_addrtype != AF_INET) {
233 fprintf (stderr, "unsupported address");
234 return false;
237 sa.sin_addr.s_addr = *((u32 *) he->h_addr);
240 s = socket (PF_INET, SOCK_STREAM, 0);
242 if (s < 0) {
243 perror ("error creating socket");
244 return false;
247 sa.sin_port = htons (LD_TCP_PORT);
248 sa.sin_family = AF_INET;
250 printf ("connecting to %s:%d\n", inet_ntoa (sa.sin_addr), LD_TCP_PORT);
252 if (connect (s, (struct sockaddr *) &sa, sizeof (sa)) == -1) {
253 perror ("error connecting");
254 close (s);
255 return false;
258 printf ("sending upload request\n");
260 b[0] = 'H';
261 b[1] = 'A';
262 b[2] = 'X';
263 b[3] = 'X';
265 if (!tcp_write (s, b, 4)) {
266 close (s);
267 return false;
270 b[0] = WIILOAD_VERSION_MAYOR;
271 b[1] = WIILOAD_VERSION_MINOR;
272 b[2] = (args_len >> 8) & 0xff;
273 b[3] = args_len & 0xff;
275 if (!tcp_write (s, b, 4)) {
276 close (s);
277 return false;
280 printf ("sending file size (%u bytes)\n", len);
282 b[0] = (len >> 24) & 0xff;
283 b[1] = (len >> 16) & 0xff;
284 b[2] = (len >> 8) & 0xff;
285 b[3] = len & 0xff;
287 if (!tcp_write (s, b, 4)) {
288 close (s);
289 return false;
292 b[0] = (len_un >> 24) & 0xff;
293 b[1] = (len_un >> 16) & 0xff;
294 b[2] = (len_un >> 8) & 0xff;
295 b[3] = len_un & 0xff;
297 if (!tcp_write (s, b, 4)) {
298 close (s);
299 return false;
302 printf ("sending data");
303 fflush (stdout);
305 left = len;
306 p = buf;
307 bc = 0;
308 while (left) {
309 block = left;
310 if (block > 4 * 1024)
311 block = 4 * 1024;
312 left -= block;
314 if (!tcp_write (s, p, block)) {
315 close (s);
316 return false;
319 p += block;
320 bc++;
322 if (!(bc % 16)) {
323 printf (".");
324 fflush (stdout);
328 printf ("\n");
330 if (args_len) {
331 printf ("sending arguments (%u bytes)\n", args_len);
333 if (!tcp_write (s, (u8 *) args, args_len)) {
334 close (s);
335 return false;
339 #ifndef __WIN32__
340 close (s);
341 #else
342 shutdown (s, SD_SEND);
343 closesocket (s);
344 WSACleanup ();
345 #endif
347 return true;
350 static void usage (const char *argv0) {
351 fprintf (stderr, "set the environment variable %s to a valid "
352 "destination.\n\n"
353 "examples:\n"
354 "\tusbgecko mode:\n"
355 "\t\t%s %s=%s\n\n"
356 "\ttcp mode:\n"
357 "\t\t%s %s=tcp:wii\n"
358 "\t\t%s %s=tcp:192.168.0.30\n\n"
359 "usage:\n"
360 "\t%s <filename> <application arguments>\n\n",
361 envvar,
362 desc_export, envvar, desc_gecko,
363 desc_export, envvar,
364 desc_export, envvar,
365 argv0);
366 exit (EXIT_FAILURE);
369 int main (int argc, char **argv) {
370 int fd;
371 struct stat st;
372 char *ev;
373 bool compress = true;
374 u8 *buf, *bufz;
375 off_t fsize;
376 uLongf bufzlen = 0;
377 u32 len, len_un;
379 int i, c;
380 char args[MAX_ARGS_LEN];
381 char *arg_pos;
382 u16 args_len, args_left;
384 bool res;
386 printf ("wiiload v%u.%u\n"
387 "coded by dhewg, #wiidev efnet\n\n",
388 WIILOAD_VERSION_MAYOR, WIILOAD_VERSION_MINOR);
390 if (argc < 2)
391 usage (*argv);
393 ev = getenv (envvar);
394 if (!ev)
395 usage (*argv);
397 fd = open (argv[1], O_RDONLY | O_BINARY);
398 if (fd < 0) {
399 perror ("error opening the file");
400 exit (EXIT_FAILURE);
403 if (fstat (fd, &st)) {
404 close (fd);
405 perror ("error stat'ing the file");
406 exit (EXIT_FAILURE);
409 fsize = st.st_size;
411 if (fsize < 512 || fsize > 20 * 1024 * 1024) {
412 close (fd);
413 fprintf (stderr, "error: invalid file size\n");
414 exit (EXIT_FAILURE);
417 buf = malloc (fsize);
418 if (!buf) {
419 close (fd);
420 fprintf (stderr, "out of memory\n");
421 exit (EXIT_FAILURE);
424 if (read (fd, buf, fsize) != fsize) {
425 close (fd);
426 free (buf);
427 perror ("error reading the file");
428 exit (EXIT_FAILURE);
430 close (fd);
432 len = fsize;
433 len_un = 0;
435 if (!memcmp(buf, "PK\x03\x04", 4))
436 compress = false;
438 if (compress) {
439 bufzlen = (uLongf) ((float) fsize * 1.02);
441 bufz = malloc (bufzlen);
442 if (!bufz) {
443 fprintf (stderr, "out of memory\n");
444 exit (EXIT_FAILURE);
447 printf("compressing %u bytes...", (u32) fsize);
448 fflush(stdout);
450 res = compress2 (bufz, &bufzlen, buf, fsize, 6);
451 if (res != Z_OK) {
452 free(buf);
453 free(bufz);
454 fprintf (stderr, "error compressing data: %d\n", res);
455 exit (EXIT_FAILURE);
458 if (bufzlen < (u32) fsize) {
459 printf(" %.2f%%\n", 100.0f * (float) bufzlen / (float) fsize);
461 len = bufzlen;
462 len_un = fsize;
463 free(buf);
464 buf = bufz;
465 } else {
466 printf(" compressed size gained size, discarding\n");
467 free(bufz);
471 args_len = 0;
473 arg_pos = args;
474 args_left = MAX_ARGS_LEN;
476 c = snprintf (arg_pos, args_left, "%s", basename (argv[1]));
477 arg_pos += c + 1;
478 args_left -= c + 1;
480 if (argc > 2) {
481 for (i = 2; i < argc; ++i) {
482 c = snprintf (arg_pos, args_left, "%s", argv[i]);
484 if (c >= args_left) {
485 free (buf);
486 fprintf (stderr, "argument string too long\n");
487 exit (EXIT_FAILURE);
490 arg_pos += c + 1;
491 args_left -= c + 1;
494 if (args_left < 1) {
495 free (buf);
496 fprintf (stderr, "argument string too long\n");
497 exit (EXIT_FAILURE);
501 arg_pos[0] = 0;
502 args_len = MAX_ARGS_LEN - args_left + 1;
504 if (strncmp (ev, "tcp:", 4)) {
505 if (stat (ev, &st))
506 usage (*argv);
508 res = send_gecko (ev, buf, len, len_un, args, args_len);
509 } else {
510 if (strlen (ev) < 5)
511 usage (*argv);
513 res = send_tcp (&ev[4], buf, len, len_un, args, args_len);
516 if (res)
517 printf ("done.\n");
518 else
519 printf ("transfer failed.\n");
521 free (buf);
523 return 0;