wol.c 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. /*****************************************************************************
  2. *
  3. * wol.c - Wake-On-LAN utility to wake a networked PC
  4. *
  5. * by R. Edwards (bob@cs.anu.edu.au), January 2000
  6. * (in_ether routine adapted from net-tools-1.51/lib/ether.c by
  7. * Fred N. van Kempen)
  8. * added file input, some minor changes for compiling for NetWare
  9. * added switches -q and -d=<ms>, added Win32 target support
  10. * by G. Knauf (gk@gknw.de), 30-Jan-2001
  11. * added switches -b=<bcast> and -p=<port>
  12. * by G. Knauf (gk@gknw.de), 10-Okt-2001
  13. * added OS/2 target support
  14. * by G. Knauf (gk@gknw.de), 24-May-2002
  15. *
  16. * This utility allows a PC with WOL configured to be powered on by
  17. * sending a "Magic Packet" to it's network adaptor (see:
  18. * http://www.amd.com/products/npd/overview/20212.html).
  19. * Only the ethernet dest address needs to be given to make this work.
  20. * Current version uses a UDP broadcast to send out the Magic Packet.
  21. *
  22. * compile with: gcc -Wall -o wol wol.c
  23. * with Solaris: (g)cc -o wol wol.c -lsocket -lnsl
  24. * with MingW32: gcc -Wall -o wol wol.c -lwsock32
  25. *
  26. * usage: wol <dest address>
  27. * where <dest address> is in [ddd.ddd.ddd.ddd-]xx:xx:xx:xx:xx:xx format.
  28. * or: wol [-q] [-b=<bcast>] [-p=<port>] [-d=<ms>] -f=<File name>
  29. * where <File name> is a file containing one dest address per line,
  30. * optional followed by a hostname or ip separated by a blank.
  31. * -b sets optional broadcast address, -p sets optional port,
  32. * -q supresses output, -d=<ms> delays ms milliseconds between sending.
  33. *
  34. * Released under GNU Public License January, 2000.
  35. */
  36. #define VERSION "1.12.2 (c) G.Knauf http://www.gknw.de/"
  37. #include <errno.h>
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40. #include <string.h>
  41. #ifdef WATTCP
  42. #define strncasecmp strnicmp
  43. #include <ctype.h>
  44. #include <dos.h>
  45. #include <tcp.h>
  46. #else
  47. #ifdef WIN32 /* Win32 platform */
  48. #define USE_WINSOCKAPI
  49. #define delay Sleep
  50. #if (defined(__LCC__) || defined(__BORLANDC__))
  51. #define strncasecmp strnicmp
  52. #else
  53. #define strncasecmp _strnicmp
  54. #endif
  55. #elif defined(N_PLAT_NLM) /* NetWare platform */
  56. #ifdef __NOVELL_LIBC__
  57. #include <ctype.h>
  58. #else
  59. extern int isdigit(int c); /* no ctype.h for NW3.x */
  60. #include <nwthread.h>
  61. #define strncasecmp strnicmp
  62. #endif
  63. #elif defined(__OS2__) /* OS/2 platform */
  64. #ifdef __EMX__
  65. #define strncasecmp strnicmp
  66. #endif
  67. extern int DosSleep(long t);
  68. #define delay DosSleep
  69. #else /* all other platforms */
  70. #define delay(t) usleep(t*1000)
  71. #endif
  72. #ifndef N_PLAT_NLM /* ! NetWare platform */
  73. #include <ctype.h>
  74. #endif
  75. #ifndef WIN32 /* ! Win32 platform */
  76. #include <unistd.h>
  77. #endif
  78. #ifdef USE_WINSOCKAPI /* Winsock2 platforms */
  79. #ifdef N_PLAT_NLM /* NetWare platform */
  80. #include <ws2nlm.h>
  81. #else
  82. #include <winsock.h>
  83. #endif
  84. #define close(s) { \
  85. closesocket(s); \
  86. WSACleanup(); \
  87. }
  88. #else /* Socket platforms */
  89. #include <sys/types.h>
  90. #include <sys/socket.h>
  91. #include <netinet/in.h>
  92. #if defined(__OS2__) && !defined(__EMX__)
  93. #include <utils.h>
  94. #else
  95. #include <arpa/inet.h>
  96. #endif
  97. #endif
  98. #endif
  99. static int read_file (char *destfile);
  100. static int in_ether (char *bufp, unsigned char *addr);
  101. static int send_wol (char *dest, char *host);
  102. char *progname;
  103. int quiet = 0;
  104. int twait = 0;
  105. unsigned int port = 60000;
  106. unsigned long bcast = 0xffffffff;
  107. int main (int argc, char *argv[]) {
  108. int cmdindx = 0;
  109. progname = argv[0];
  110. if (argc > 1) {
  111. /* parse input parameters */
  112. for (argc--, argv++; *argv; argc--, argv++) {
  113. char *bp;
  114. char *ep;
  115. if (strncasecmp (*argv, "-", 1) == 0) {
  116. if (strncasecmp (*argv, "-F=", 3) == 0) {
  117. bp = *argv + 3;
  118. read_file (bp);
  119. } else if (strncasecmp (*argv, "-B=", 3) == 0) {
  120. bp = *argv + 3;
  121. bcast = inet_addr(bp);
  122. if (bcast == -1) {
  123. fprintf (stderr, "%s: expected address argument at %s\n", progname, *argv);
  124. exit (1);
  125. }
  126. } else if (strncasecmp (*argv, "-D=", 3) == 0) {
  127. bp = *argv + 3;
  128. twait = strtol (bp, &ep, 0);
  129. if (ep == bp || *ep != '\0') {
  130. fprintf (stderr, "%s: expected integer argument at %s\n", progname, *argv);
  131. exit (1);
  132. }
  133. } else if (strncasecmp (*argv, "-P=", 3) == 0) {
  134. bp = *argv + 3;
  135. port = strtol (bp, &ep, 0);
  136. if (ep == bp || *ep != '\0') {
  137. fprintf (stderr, "%s: expected integer argument at %s\n", progname, *argv);
  138. exit (1);
  139. }
  140. } else if (strncasecmp (*argv, "-Q", 2) == 0) {
  141. quiet = 1;
  142. } else if (strncasecmp (*argv, "-V", 2) == 0) {
  143. fprintf (stderr, "\r%s Version %s\n", progname, VERSION);
  144. exit (0);
  145. } else {
  146. fprintf (stderr, "\r%s: invalid or unknown option %s\n", progname, *argv);
  147. exit (1);
  148. }
  149. } else {
  150. send_wol (*argv, "");
  151. }
  152. cmdindx++;
  153. }
  154. return (0);
  155. } else {
  156. /* No arguments given -> usage message */
  157. fprintf (stderr, "\rUsage: %s [-q] [-b=<bcast>] [-p=<port>] [-d=<ms>] -f=<file> | <dest>\n", progname);
  158. fprintf (stderr, " need at least hardware address or file option\n");
  159. return (-1);
  160. }
  161. }
  162. static int in_ether (char *bufp, unsigned char *addr) {
  163. char c, *orig;
  164. int i;
  165. unsigned char *ptr = addr;
  166. unsigned val;
  167. i = 0;
  168. orig = bufp;
  169. while ((*bufp != '\0') && (i < 6)) {
  170. val = 0;
  171. c = *bufp++;
  172. if (isdigit(c))
  173. val = c - '0';
  174. else if (c >= 'a' && c <= 'f')
  175. val = c - 'a' + 10;
  176. else if (c >= 'A' && c <= 'F')
  177. val = c - 'A' + 10;
  178. else {
  179. #ifdef DEBUG
  180. fprintf (stderr, "\rin_ether(%s): invalid ether address!\n", orig);
  181. #endif
  182. errno = EINVAL;
  183. return (-1);
  184. }
  185. val <<= 4;
  186. c = *bufp;
  187. if (isdigit(c))
  188. val |= c - '0';
  189. else if (c >= 'a' && c <= 'f')
  190. val |= c - 'a' + 10;
  191. else if (c >= 'A' && c <= 'F')
  192. val |= c - 'A' + 10;
  193. else if (c == ':' || c == 0)
  194. val >>= 4;
  195. else {
  196. #ifdef DEBUG
  197. fprintf (stderr, "\rin_ether(%s): invalid ether address!\n", orig);
  198. #endif
  199. errno = EINVAL;
  200. return (-1);
  201. }
  202. if (c != 0)
  203. bufp++;
  204. *ptr++ = (unsigned char) (val & 0377);
  205. i++;
  206. /* We might get a semicolon here - not required. */
  207. if (*bufp == ':') {
  208. if (i == 6) {
  209. ; /* nothing */
  210. }
  211. bufp++;
  212. }
  213. }
  214. if (bufp - orig != 17) {
  215. return (-1);
  216. } else {
  217. return (0);
  218. }
  219. } /* in_ether */
  220. static int read_file (char *destfile) {
  221. FILE *pfile = NULL;
  222. char dest[64];
  223. char host[32];
  224. char buffer[512];
  225. pfile = fopen (destfile, "r+");
  226. if (pfile) {
  227. while (fgets (buffer, 511, pfile) != NULL) {
  228. if (buffer[0] != '#' && buffer[0] != ';') {
  229. dest[0] = host[0] = '\0';
  230. sscanf (buffer, "%s %s", dest, host);
  231. send_wol (dest, host);
  232. }
  233. }
  234. fclose (pfile);
  235. return (0);
  236. } else {
  237. fprintf (stderr, "\r%s: destfile '%s' not found\n", progname, destfile);
  238. return (-1);
  239. }
  240. }
  241. static int send_wol (char *dest, char *host) {
  242. int i, j;
  243. int packet;
  244. struct sockaddr_in sap;
  245. unsigned char ethaddr[8];
  246. unsigned char *ptr;
  247. unsigned char buf [128];
  248. unsigned long bc;
  249. char mask[32];
  250. char *tmp;
  251. #ifdef USE_WINSOCKAPI
  252. WORD wVersionRequested;
  253. WSADATA wsaData;
  254. int err;
  255. #endif
  256. #ifdef WATTCP
  257. static udp_Socket sock;
  258. udp_Socket *s;
  259. #else
  260. int optval = 1;
  261. #endif
  262. /* Fetch the broascast address if present. */
  263. if ((tmp = strstr(dest,"-"))) {
  264. printf("found: %s\n", tmp);
  265. tmp[0] = 32;
  266. sscanf (dest, "%s %s", mask, dest);
  267. bc = inet_addr(mask);
  268. printf("bc: string %s address %08lX\n", mask, bc);
  269. if (bc == -1) {
  270. fprintf (stderr, "\r%s: expected address argument at %s\n", progname, mask);
  271. return (-1);
  272. }
  273. } else
  274. bc = bcast;
  275. /* Fetch the hardware address. */
  276. if (in_ether (dest, ethaddr) < 0) {
  277. fprintf (stderr, "\r%s: invalid hardware address\n", progname);
  278. return (-1);
  279. }
  280. #ifdef USE_WINSOCKAPI
  281. /* I would like to have Socket Vers. 1.1 */
  282. wVersionRequested = MAKEWORD(1, 1);
  283. err = WSAStartup (wVersionRequested, &wsaData);
  284. if (err != 0) {
  285. fprintf (stderr, "\r%s: couldn't init Winsock Version 1.1\n", progname);
  286. WSACleanup ();
  287. return (-1);
  288. }
  289. #endif
  290. /* setup the packet socket */
  291. #ifdef WATTCP
  292. sock_init();
  293. s = &sock;
  294. if (!udp_open( s, 0, bc, port, NULL )) {
  295. #else
  296. if ((packet = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
  297. #endif
  298. fprintf (stderr, "\r%s: socket failed\n", progname);
  299. #ifdef USE_WINSOCKAPI
  300. WSACleanup ();
  301. #endif
  302. return (-1);
  303. }
  304. #ifndef WATTCP
  305. /* Set socket options */
  306. if (setsockopt (packet, SOL_SOCKET, SO_BROADCAST, (char *)&optval, sizeof (optval)) < 0) {
  307. fprintf (stderr, "\r%s: setsocket failed %s\n", progname, strerror (errno));
  308. close (packet);
  309. return (-1);
  310. }
  311. /* Set up broadcast address */
  312. sap.sin_family = AF_INET;
  313. sap.sin_addr.s_addr = bc; /* broadcast address */
  314. sap.sin_port = htons(port);
  315. #endif
  316. /* Build the message to send - 6 x 0xff then 16 x dest address */
  317. ptr = buf;
  318. for (i = 0; i < 6; i++)
  319. *ptr++ = 0xff;
  320. for (j = 0; j < 16; j++)
  321. for (i = 0; i < 6; i++)
  322. *ptr++ = ethaddr [i];
  323. /* Send the packet out */
  324. #ifdef WATTCP
  325. sock_write( s, buf, 102 );
  326. sock_close( s );
  327. #else
  328. if (sendto (packet, (char *)buf, 102, 0, (struct sockaddr *)&sap, sizeof (sap)) < 0) {
  329. fprintf (stderr, "\r%s: sendto failed, %s\n", progname, strerror(errno));
  330. close (packet);
  331. return (-1);
  332. }
  333. close (packet);
  334. #endif
  335. if (!quiet) fprintf (stderr, "\r%s: packet sent to %04X:%08lX-%s %s\n",
  336. progname, port, (unsigned long)htonl(bc), dest, host);
  337. if (twait > 0 ) {
  338. delay (twait);
  339. }
  340. return (0);
  341. }