let ipkg fail when a package file to be installed is not found
[openwrt.git] / openwrt / package / ether-wake / files / ether-wake.c
1 /* ether-wake.c: Send a magic packet to wake up sleeping machines. */
2
3 static char version_msg[] =
4 "ether-wake.c: v1.09 11/12/2003 Donald Becker, http://www.scyld.com/";
5 static char brief_usage_msg[] =
6 "usage: ether-wake [-i <ifname>] [-p aa:bb:cc:dd[:ee:ff]] 00:11:22:33:44:55\n"
7 "   Use '-u' to see the complete set of options.\n";
8 static char usage_msg[] =
9 "usage: ether-wake [-i <ifname>] [-p aa:bb:cc:dd[:ee:ff]] 00:11:22:33:44:55\n"
10 "\n"
11 "       This program generates and transmits a Wake-On-LAN (WOL)\n"
12 "       \"Magic Packet\", used for restarting machines that have been\n"
13 "       soft-powered-down (ACPI D3-warm state).\n"
14 "       It currently generates the standard AMD Magic Packet format, with\n"
15 "       an optional password appended.\n"
16 "\n"
17 "       The single required parameter is the Ethernet MAC (station) address\n"
18 "       of the machine to wake or a host ID with known NSS 'ethers' entry.\n"
19 "       The MAC address may be found with the 'arp' program while the target\n"
20 "       machine is awake.\n"
21 "\n"
22 "       Options:\n"
23 "               -b      Send wake-up packet to the broadcast address.\n"
24 "               -D      Increase the debug level.\n"
25 "               -i ifname       Use interface IFNAME instead of the default 'eth0'.\n"
26 "               -p <pw>         Append the four or six byte password PW to the packet.\n"
27 "                                       A password is only required for a few adapter types.\n"
28 "                                       The password may be specified in ethernet hex format\n"
29 "                                       or dotted decimal (Internet address)\n"
30 "               -p 00:22:44:66:88:aa\n"
31 "               -p 192.168.1.1\n";
32
33 /*
34         This program generates and transmits a Wake-On-LAN (WOL) "Magic Packet",
35         used for restarting machines that have been soft-powered-down
36         (ACPI D3-warm state).  It currently generates the standard AMD Magic Packet
37         format, with an optional password appended.
38
39         This software may be used and distributed according to the terms
40         of the GNU Public License, incorporated herein by reference.
41         Contact the author for use under other terms.
42
43         This source file was originally part of the network tricks package, and
44         is now distributed to support the Scyld Beowulf system.
45         Copyright 1999-2003 Donald Becker and Scyld Computing Corporation.
46
47         The author may be reached as becker@scyld, or C/O
48          Scyld Computing Corporation
49          914 Bay Ridge Road, Suite 220
50          Annapolis MD 21403
51
52   Notes:
53   On some systems dropping root capability allows the process to be
54   dumped, traced or debugged.
55   If someone traces this program, they get control of a raw socket.
56   Linux handles this safely, but beware when porting this program.
57
58   An alternative to needing 'root' is using a UDP broadcast socket, however
59   doing so only works with adapters configured for unicast+broadcast Rx
60   filter.  That configuration consumes more power.
61 */
62 \f
63 #include <unistd.h>
64 #include <stdlib.h>
65 #include <stdio.h>
66 #include <errno.h>
67 #include <ctype.h>
68 #include <string.h>
69
70 #if 0                                                   /* Only exists on some versions. */
71 #include <ioctls.h>
72 #endif
73
74 #include <sys/socket.h>
75
76 #include <sys/types.h>
77 #include <sys/ioctl.h>
78 #include <linux/if.h>
79
80 #include <features.h>
81 #if __GLIBC__ >= 2 && __GLIBC_MINOR >= 1
82 #include <netpacket/packet.h>
83 #include <net/ethernet.h>
84 #else
85 #include <asm/types.h>
86 #include <linux/if_packet.h>
87 #include <linux/if_ether.h>
88 #endif
89 #include <netdb.h>
90 #include <netinet/ether.h>
91
92 /* Grrr, no consistency between include versions.
93    Enable this if setsockopt() isn't declared with your library. */
94 #if 0
95 extern int setsockopt __P ((int __fd, int __level, int __optname,
96                                                         __ptr_t __optval, int __optlen));
97 #else                           /* New, correct head files.  */
98 #include <sys/socket.h>
99 #endif
100
101 u_char outpack[1000];
102 int outpack_sz = 0;
103 int debug = 0;
104 u_char wol_passwd[6];
105 int wol_passwd_sz = 0;
106
107 static int opt_no_src_addr = 0, opt_broadcast = 0;
108
109 static int get_dest_addr(const char *arg, struct ether_addr *eaddr);
110 static int get_fill(unsigned char *pkt, struct ether_addr *eaddr);
111 static int get_wol_pw(const char *optarg);
112
113 int main(int argc, char *argv[])
114 {
115         char *ifname = "eth0";
116         int one = 1;                            /* True, for socket options. */
117         int s;                                          /* Raw socket */
118         int errflag = 0, verbose = 0, do_version = 0;
119         int perm_failure = 0;
120         int i, c, pktsize;
121 #if defined(PF_PACKET)
122         struct sockaddr_ll whereto;
123 #else
124         struct sockaddr whereto;        /* who to wake up */
125 #endif
126         struct ether_addr eaddr;
127
128         while ((c = getopt(argc, argv, "bDi:p:uvV")) != -1)
129                 switch (c) {
130                 case 'b': opt_broadcast++;      break;
131                 case 'D': debug++;                      break;
132                 case 'i': ifname = optarg;      break;
133                 case 'p': get_wol_pw(optarg); break;
134                 case 'u': printf(usage_msg); return 0;
135                 case 'v': verbose++;            break;
136                 case 'V': do_version++;         break;
137                 case '?':
138                         errflag++;
139                 }
140         if (verbose || do_version)
141                 printf("%s\n", version_msg);
142         if (errflag) {
143                 fprintf(stderr, brief_usage_msg);
144                 return 3;
145         }
146
147         if (optind == argc) {
148                 fprintf(stderr, "Specify the Ethernet address as 00:11:22:33:44:55.\n");
149                 return 3;
150         }
151
152         /* Note: PF_INET, SOCK_DGRAM, IPPROTO_UDP would allow SIOCGIFHWADDR to
153            work as non-root, but we need SOCK_PACKET to specify the Ethernet
154            destination address. */
155 #if defined(PF_PACKET)
156         s = socket(PF_PACKET, SOCK_RAW, 0);
157 #else
158         s = socket(AF_INET, SOCK_PACKET, SOCK_PACKET);
159 #endif
160         if (s < 0) {
161                 if (errno == EPERM)
162                         fprintf(stderr, "ether-wake: This program must be run as root.\n");
163                 else
164                         perror("ether-wake: socket");
165                 perm_failure++;
166         }
167         /* Don't revert if debugging allows a normal user to get the raw socket. */
168         setuid(getuid());
169
170         /* We look up the station address before reporting failure so that
171            errors may be reported even when run as a normal user.
172         */
173         if (get_dest_addr(argv[optind], &eaddr) != 0)
174                 return 3;
175         if (perm_failure && ! debug)
176                 return 2;
177
178         pktsize = get_fill(outpack, &eaddr);
179
180         /* Fill in the source address, if possible.
181            The code to retrieve the local station address is Linux specific. */
182         if (! opt_no_src_addr) {
183                 struct ifreq if_hwaddr;
184                 unsigned char *hwaddr = if_hwaddr.ifr_hwaddr.sa_data;
185
186                 strcpy(if_hwaddr.ifr_name, ifname);
187                 if (ioctl(s, SIOCGIFHWADDR, &if_hwaddr) < 0) {
188                         fprintf(stderr, "SIOCGIFHWADDR on %s failed: %s\n", ifname,
189                                         strerror(errno));
190                         /* Magic packets still work if our source address is bogus, but
191                            we fail just to be anal. */
192                         return 1;
193                 }
194                 memcpy(outpack+6, if_hwaddr.ifr_hwaddr.sa_data, 6);
195
196                 if (verbose) {
197                         printf("The hardware address (SIOCGIFHWADDR) of %s is type %d  "
198                                    "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", ifname,
199                                    if_hwaddr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1],
200                                    hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);
201                 }
202         }
203
204         if (wol_passwd_sz > 0) {
205                 memcpy(outpack+pktsize, wol_passwd, wol_passwd_sz);
206                 pktsize += wol_passwd_sz;
207         }
208
209         if (verbose > 1) {
210                 printf("The final packet is: ");
211                 for (i = 0; i < pktsize; i++)
212                         printf(" %2.2x", outpack[i]);
213                 printf(".\n");
214         }
215
216         /* This is necessary for broadcasts to work */
217         if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)&one, sizeof(one)) < 0)
218                 perror("setsockopt: SO_BROADCAST");
219
220 #if defined(PF_PACKET)
221         {
222                 struct ifreq ifr;
223                 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
224                 if (ioctl(s, SIOCGIFINDEX, &ifr) == -1) {
225                         fprintf(stderr, "SIOCGIFINDEX on %s failed: %s\n", ifname,
226                                         strerror(errno));
227                         return 1;
228                 }
229                 memset(&whereto, 0, sizeof(whereto));
230                 whereto.sll_family = AF_PACKET;
231                 whereto.sll_ifindex = ifr.ifr_ifindex;
232                 /* The manual page incorrectly claims the address must be filled.
233                    We do so because the code may change to match the docs. */
234                 whereto.sll_halen = ETH_ALEN;
235                 memcpy(whereto.sll_addr, outpack, ETH_ALEN);
236
237         }
238 #else
239         whereto.sa_family = 0;
240         strcpy(whereto.sa_data, ifname);
241 #endif
242
243         if ((i = sendto(s, outpack, pktsize, 0, (struct sockaddr *)&whereto,
244                                         sizeof(whereto))) < 0)
245                 perror("sendto");
246         else if (debug)
247                 printf("Sendto worked ! %d.\n", i);
248
249 #ifdef USE_SEND
250         if (bind(s, (struct sockaddr *)&whereto, sizeof(whereto)) < 0)
251                 perror("bind");
252         else if (send(s, outpack, 100, 0) < 0)
253                 perror("send");
254 #endif
255 #ifdef USE_SENDMSG
256         {
257                 struct msghdr msghdr = { 0,};
258                 struct iovec iovector[1];
259                 msghdr.msg_name = &whereto;
260                 msghdr.msg_namelen = sizeof(whereto);
261                 msghdr.msg_iov = iovector;
262                 msghdr.msg_iovlen = 1;
263                 iovector[0].iov_base = outpack;
264                 iovector[0].iov_len = pktsize;
265                 if ((i = sendmsg(s, &msghdr, 0)) < 0)
266                         perror("sendmsg");
267                 else if (debug)
268                         printf("sendmsg worked, %d (%d).\n", i, errno);
269         }
270 #endif
271
272         return 0;
273 }
274
275 /* Convert the host ID string to a MAC address.
276    The string may be a
277         Host name
278     IP address string
279         MAC address string
280 */
281
282 static int get_dest_addr(const char *hostid, struct ether_addr *eaddr)
283 {
284         struct ether_addr *eap;
285
286         eap = ether_aton(hostid);
287         if (eap) {
288                 *eaddr = *eap;
289                 if (debug)
290                         fprintf(stderr, "The target station address is %s.\n",
291                                         ether_ntoa(eaddr));
292         } else if (ether_hostton(hostid, eaddr) == 0) {
293                 if (debug)
294                         fprintf(stderr, "Station address for hostname %s is %s.\n",
295                                         hostid, ether_ntoa(eaddr));
296         } else {
297                 (void)fprintf(stderr,
298                                           "ether-wake: The Magic Packet host address must be "
299                                           "specified as\n"
300                                           "  - a station address, 00:11:22:33:44:55, or\n"
301                                           "  - a hostname with a known 'ethers' entry.\n");
302                 return -1;
303         }
304         return 0;
305 }
306
307
308 static int get_fill(unsigned char *pkt, struct ether_addr *eaddr)
309 {
310         int offset, i;
311         unsigned char *station_addr = eaddr->ether_addr_octet;
312
313         if (opt_broadcast)
314                 memset(pkt+0, 0xff, 6);
315         else
316                 memcpy(pkt, station_addr, 6);
317         memcpy(pkt+6, station_addr, 6);
318         pkt[12] = 0x08;                         /* Or 0x0806 for ARP, 0x8035 for RARP */
319         pkt[13] = 0x42;
320         offset = 14;
321
322         memset(pkt+offset, 0xff, 6);
323         offset += 6;
324
325         for (i = 0; i < 16; i++) {
326                 memcpy(pkt+offset, station_addr, 6);
327                 offset += 6;
328         }
329         if (debug) {
330                 fprintf(stderr, "Packet is ");
331                 for (i = 0; i < offset; i++)
332                         fprintf(stderr, " %2.2x", pkt[i]);
333                 fprintf(stderr, ".\n");
334         }
335         return offset;
336 }
337
338 static int get_wol_pw(const char *optarg)
339 {
340         int passwd[6];
341         int byte_cnt;
342         int i;
343
344         byte_cnt = sscanf(optarg, "%2x:%2x:%2x:%2x:%2x:%2x",
345                                           &passwd[0], &passwd[1], &passwd[2],
346                                           &passwd[3], &passwd[4], &passwd[5]);
347         if (byte_cnt < 4)
348                 byte_cnt = sscanf(optarg, "%d.%d.%d.%d",
349                                                   &passwd[0], &passwd[1], &passwd[2], &passwd[3]);
350         if (byte_cnt < 4) {
351                 fprintf(stderr, "Unable to read the Wake-On-LAN password.\n");
352                 return 0;
353         }
354         printf(" The Magic packet password is %2.2x %2.2x %2.2x %2.2x (%d).\n",
355                    passwd[0], passwd[1], passwd[2], passwd[3], byte_cnt);
356         for (i = 0; i < byte_cnt; i++)
357                 wol_passwd[i] = passwd[i];
358         return wol_passwd_sz = byte_cnt;
359 }
360
361 #if 0
362 {
363         to = (struct sockaddr_in *)&whereto;
364         to->sin_family = AF_INET;
365         if (inet_aton(target, &to->sin_addr)) {
366                 hostname = target;
367         }
368         memset (&sa, 0, sizeof sa);
369         sa.sa_family = AF_INET;
370         strncpy (sa.sa_data, interface, sizeof sa.sa_data);
371         sendto (sock, buf, bufix + len, 0, &sa, sizeof sa);
372         strncpy (sa.sa_data, interface, sizeof sa.sa_data);
373 #if 1
374         sendto (sock, buf, bufix + len, 0, &sa, sizeof sa);
375 #else
376         bind (sock, &sa, sizeof sa);
377         connect();
378         send (sock, buf, bufix + len, 0);
379 #endif
380 }
381 #endif
382
383 \f
384 /*
385  * Local variables:
386  *  compile-command: "gcc -O -Wall -o ether-wake ether-wake.c"
387  *  c-indent-level: 4
388  *  c-basic-offset: 4
389  *  c-indent-level: 4
390  *  tab-width: 4
391  * End:
392  */