1 /*
2 * wol - wake on lan client
3 *
4 * main program
5 *
6 * $Id: wol.c,v 1.18 2004/04/18 11:42:11 wol Exp $
7 *
8 * Copyright (C) 2000,2001,2002,2003,2004 Thomas Krennwallner <krennwallner@aon.at>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
23 * USA.
24 */
25
26
27
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif /* HAVE_CONFIG_H */
31
32 #include <stdio.h>
33 #include <unistd.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <getopt.h>
37 #include <errno.h>
38 #include <error.h>
39
40 #include "wrappers.h"
41 #include "xalloc.h"
42 #include "wol.h"
43 #include "magic.h"
44 #include "net.h"
45 #include "macfile.h"
46 #include "getpass4.h"
47
48
49
50 /* My name is argv[0], used by error() */
51 char *program_name;
52
53 /* pointer to a MAC address */
54 static char *mac_str = NULL;
55
56 /* IP Address or hostname magic packet is addressed to */
57 static char *host_str = DEFAULT_IPADDR;
58
59 /* filename with mac addresses */
60 static char *pathname = NULL;
61
62 /* udp port */
63 static unsigned int port = DEFAULT_PORT;
64
65 /* SecureON password */
66 static char *passwd = NULL;
67
68 /* default is not to read from stdin */
69 static int request_stdin = 0;
70
71 /* be verbose */
72 static int verbose = 0;
73
74 /* send proxy packet */
75 static int proxy_mode = 0;
76
77 /* how long to wait between packets */
78 static int msecs = 0;
79
80 /* a magic packet */
81 static struct magic *magic = NULL;
82
83 /* socket file descriptor */
84 static int sockfd = -1;
85
86
87
88 static void
usage(int status)89 usage (int status)
90 {
91 if (status)
92 {
93 fprintf (stderr, _("Try `%s --help' for more information.\n"), program_name);
94 }
95 else
96 {
97 fprintf (stdout, _("\
98 Usage: %s [OPTION] ... MAC-ADDRESS ...\n\
99 Wake On LAN client - wakes up magic packet compliant machines.\n\n\
100 --help display this help and exit\n\
101 -V, --version output version information and exit\n\
102 -v, --verbose verbose output\n\
103 -w, --wait=NUM wait NUM millisecs after sending\n\
104 -h, --host=HOST broadcast to this IP address or hostname\n\
105 -i, --ipaddr=HOST same as --host\n\
106 -p, --port=NUM broadcast to this UDP port\n\
107 -f, --file=FILE read addresses from file FILE (\"-\" reads from stdin)\n\
108 --passwd[=PASS] send SecureON password PASS (if no PASS is given, you\n\
109 will be prompted for the password)\n\
110 \n\
111 Each MAC-ADDRESS is written as x:x:x:x:x:x, where x is a hexadecimal number\n\
112 between 0 and ff which represents one byte of the address, which is in\n\
113 network byte order (big endian).\n"), program_name);
114
115 fprintf (stdout, _("\n\
116 PASS is written as x-x-x-x-x-x, where x is a hexadecimal number between 0\n\
117 and ff which represents one byte of the password.\n"));
118
119 fprintf (stdout, _("\nReport bugs to <krennwallner@aon.at>\n"));
120 }
121
122 exit (status);
123 }
124
125
126
127 static void
version(void)128 version (void)
129 {
130 fprintf (stdout, PACKAGE " " VERSION "\n\n");
131 fprintf (stdout, _("\
132 Copyright (C) 2000-2004 Thomas Krennwallner <krennwallner@aon.at>\n\
133 This is free software; see the source for copying conditions. There is NO\n\
134 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\
135 \n"));
136 }
137
138
139
140 /* parse command line and set various globals */
141 static int
parse_args(int argc,char * argv[])142 parse_args (int argc, char *argv[])
143 {
144 int c;
145 int option_index;
146 int password_set = 0;
147 char *options = "Vvw:h:i:p:f:s:-";
148 static struct option long_options[] =
149 {
150 { "help", no_argument, NULL, 'H' },
151 { "version", no_argument, NULL, 'V' },
152 { "verbose", no_argument, NULL, 'v' },
153 { "wait", required_argument, NULL, 'w' },
154 { "host", required_argument, NULL, 'h' },
155 { "ipaddr", required_argument, NULL, 'i' },
156 { "port", required_argument, NULL, 'p' },
157 { "file", required_argument, NULL, 'f' },
158 { "passwd", optional_argument, NULL, 'P' },
159 /* { "proxy", required_argument, NULL, 's' }, */
160 { NULL, 0, NULL, 0 }
161 };
162
163
164 if (argc == 1)
165 {
166 error (0, 0, _("Too few arguments."));
167 usage (1);
168 }
169
170
171
172 for (;;)
173 {
174 c = getopt_long (argc, argv, options, long_options, &option_index);
175 if (c == -1) break;
176
177 switch (c)
178 {
179 case 'H':
180 usage (0);
181 break;
182
183
184 case 'V':
185 version ();
186 exit (0);
187 break;
188
189
190 case 'v':
191 verbose = 1;
192 break;
193
194
195 case 'w':
196 if (sscanf (optarg, "%u", &msecs) != 1)
197 {
198 error (0, 0, _("Invalid time given"));
199 usage (1);
200 }
201 msecs *= 1000;
202 break;
203
204
205 /* case 's': */
206 /* proxy_mode = 1; */
207 case 'h':
208 case 'i':
209 host_str = optarg;
210 break;
211
212
213 case 'p':
214 if ((sscanf (optarg, "%5u", &port) != 1) ||
215 port > 65535 || port == 0)
216 {
217 error (0, 0, _("Invalid port given"));
218 usage (1);
219 }
220 break;
221
222
223 case 'f':
224 pathname = optarg;
225 break;
226
227
228 case 'P':
229 if (optarg == NULL)
230 {
231 size_t n;
232
233 if (password_set)
234 break;
235
236 if (getpass4 (_("Password"), &passwd, &n, stdin) == -1)
237 {
238 error (1, 0, "getpass4 failed");
239 }
240 password_set = 1;
241 }
242 else
243 {
244 passwd = optarg;
245 }
246 break;
247
248
249 case '?':
250 break;
251 }
252 }
253
254 if ((optind == argc) && (pathname == NULL))
255 {
256 error (0, 0, _("You must specify at least one MAC-ADDRESS."));
257 usage (1);
258 }
259
260 /* check if stdin is requested */
261 if (optind < argc)
262 {
263 int i;
264
265 for (i = optind; i < argc; ++i)
266 {
267 if (argv[i][0] == '-' && argv[i][1] == 0)
268 {
269 request_stdin = 1;
270 break;
271 }
272 }
273 }
274 else if (pathname != NULL)
275 {
276 if (!strncmp (pathname, "-", 1))
277 {
278 request_stdin = 1;
279 }
280 }
281
282 /* return the offset of the GNU getopt sorted parameters */
283 return optind;
284 }
285
286
287
288 static int
assemble_and_send(struct magic * m,const char * mac_str,const char * host_str,unsigned int portnum,const char * pass_str,int socketfd)289 assemble_and_send (struct magic *m,
290 const char *mac_str,
291 const char *host_str,
292 unsigned int portnum,
293 const char *pass_str,
294 int socketfd)
295 {
296 int ret = magic_assemble (m, mac_str, pass_str);
297
298 switch (ret)
299 {
300 case -1:
301 error (0, errno, _("Cannot assemble magic packet for '%s'"), mac_str);
302 errno = 0;
303 return -1;
304
305 case -2:
306 error (0, 0, _("Invalid password given for '%s'"), mac_str);
307 errno = 0;
308 return -1;
309 }
310
311 if (udp_send (socketfd, host_str, portnum, m->packet, m->size))
312 {
313 error (0, errno, _("Cannot send magic packet for '%s' to %s:%d"),
314 mac_str, host_str, portnum);
315 errno = 0;
316 return -1;
317 }
318
319 fprintf (stdout, _("Waking up %s"), mac_str);
320 if (verbose)
321 {
322 fprintf (stdout, _(" with %s:%d"), host_str, portnum);
323 }
324 fprintf (stdout, _("...\n"));
325
326 if (msecs)
327 {
328 usleep (msecs);
329 }
330
331 return 0;
332 }
333
334
335
336 int
main(int argc,char * argv[])337 main (int argc, char *argv[])
338 {
339 int i;
340 int ret = 0;
341
342 /* my name is ... */
343 program_name = argv[0];
344
345 #if ENABLE_NLS
346 setlocale (LC_ALL, "");
347 bindtextdomain (PACKAGE, LOCALEDIR);
348 textdomain (PACKAGE);
349 #endif /* ENABLE_NLS */
350
351 i = parse_args (argc, argv);
352
353 magic = magic_create (passwd != NULL);
354 if (magic == NULL)
355 {
356 exit (1);
357 }
358
359 if (!proxy_mode)
360 {
361 sockfd = udp_open ();
362 }
363 else
364 {
365 sockfd = tcp_open (host_str, port);
366 }
367
368 if (sockfd < 0)
369 {
370 exit (1);
371 }
372
373
374 /* loop through possible MAC addresses */
375 if (!request_stdin)
376 {
377 if (!proxy_mode)
378 {
379 for (; i < argc; i++)
380 {
381 ret -= assemble_and_send (magic, argv[i], host_str, port, passwd, sockfd);
382 }
383 }
384 else
385 {
386 /* FIXME: proxy mode */
387 }
388 }
389
390
391 /* -f given */
392 if (pathname || request_stdin)
393 {
394 FILE *fp;
395
396 if (request_stdin)
397 {
398 fp = stdin;
399 }
400 else
401 {
402 fp = fopen (pathname, "r");
403 if (fp == NULL)
404 {
405 error (1, errno, "%s", pathname);
406 }
407 }
408
409 if (!proxy_mode)
410 {
411 /* loop through fp */
412 for (;;)
413 {
414 if (macfile_parse (fp, &mac_str, &host_str, &port, &passwd)) break;
415
416 if (port == 0 || port > 65535)
417 {
418 port = DEFAULT_PORT;
419 }
420
421 ret -= assemble_and_send (magic, mac_str, host_str, port, passwd, sockfd);
422
423 XFREE (mac_str);
424 XFREE (host_str);
425 XFREE (passwd);
426 }
427 }
428 else
429 {
430 /* FIXME: proxy mode */
431 }
432
433 fclose (fp);
434 }
435
436 net_close (sockfd);
437
438 magic_destroy (magic);
439
440 exit (ret != 0);
441 }
442