diff options
Diffstat (limited to 'contrib/wakeonlan/wol.c')
-rw-r--r-- | contrib/wakeonlan/wol.c | 374 |
1 files changed, 374 insertions, 0 deletions
diff --git a/contrib/wakeonlan/wol.c b/contrib/wakeonlan/wol.c new file mode 100644 index 00000000..07b7e4fc --- /dev/null +++ b/contrib/wakeonlan/wol.c @@ -0,0 +1,374 @@ +/***************************************************************************** + * + * wol.c - Wake-On-LAN utility to wake a networked PC + * + * by R. Edwards (bob@cs.anu.edu.au), January 2000 + * (in_ether routine adapted from net-tools-1.51/lib/ether.c by + * Fred N. van Kempen) + * added file input, some minor changes for compiling for NetWare + * added switches -q and -d=<ms>, added Win32 target support + * by G. Knauf (gk@gknw.de), 30-Jan-2001 + * added switches -b=<bcast> and -p=<port> + * by G. Knauf (gk@gknw.de), 10-Okt-2001 + * added OS/2 target support + * by G. Knauf (gk@gknw.de), 24-May-2002 + * + * This utility allows a PC with WOL configured to be powered on by + * sending a "Magic Packet" to it's network adaptor (see: + * http://www.amd.com/products/npd/overview/20212.html). + * Only the ethernet dest address needs to be given to make this work. + * Current version uses a UDP broadcast to send out the Magic Packet. + * + * compile with: gcc -Wall -o wol wol.c + * with Solaris: (g)cc -o wol wol.c -lsocket -lnsl + * with MingW32: gcc -Wall -o wol wol.c -lwsock32 + * + * usage: wol <dest address> + * where <dest address> is in [ddd.ddd.ddd.ddd-]xx:xx:xx:xx:xx:xx format. + * or: wol [-q] [-b=<bcast>] [-p=<port>] [-d=<ms>] -f=<File name> + * where <File name> is a file containing one dest address per line, + * optional followed by a hostname or ip separated by a blank. + * -b sets optional broadcast address, -p sets optional port, + * -q supresses output, -d=<ms> delays ms milliseconds between sending. + * + * Released under GNU Public License January, 2000. + */ + +#define VERSION "1.12.2 (c) G.Knauf http://www.gknw.de/" + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifdef WATTCP + #define strncasecmp strnicmp + #include <ctype.h> + #include <dos.h> + #include <tcp.h> +#else +#ifdef WIN32 /* Win32 platform */ + #define USE_WINSOCKAPI + #define delay Sleep + #if (defined(__LCC__) || defined(__BORLANDC__)) + #define strncasecmp strnicmp + #else + #define strncasecmp _strnicmp + #endif +#elif defined(N_PLAT_NLM) /* NetWare platform */ +#ifdef __NOVELL_LIBC__ + #include <ctype.h> +#else + extern int isdigit(int c); /* no ctype.h for NW3.x */ + #include <nwthread.h> + #define strncasecmp strnicmp +#endif +#elif defined(__OS2__) /* OS/2 platform */ + #ifdef __EMX__ + #define strncasecmp strnicmp + #endif + extern int DosSleep(long t); + #define delay DosSleep +#else /* all other platforms */ + #define delay(t) usleep(t*1000) +#endif +#ifndef N_PLAT_NLM /* ! NetWare platform */ + #include <ctype.h> +#endif +#ifndef WIN32 /* ! Win32 platform */ + #include <unistd.h> +#endif +#ifdef USE_WINSOCKAPI /* Winsock2 platforms */ + #ifdef N_PLAT_NLM /* NetWare platform */ + #include <ws2nlm.h> + #else + #include <winsock.h> + #endif + #define close(s) { \ + closesocket(s); \ + WSACleanup(); \ + } +#else /* Socket platforms */ + #include <sys/types.h> + #include <sys/socket.h> + #include <netinet/in.h> + #if defined(__OS2__) && !defined(__EMX__) + #include <utils.h> + #else + #include <arpa/inet.h> + #endif +#endif + +#endif + +static int read_file (char *destfile); +static int in_ether (char *bufp, unsigned char *addr); +static int send_wol (char *dest, char *host); + + +char *progname; +int quiet = 0; +int twait = 0; +unsigned int port = 60000; +unsigned long bcast = 0xffffffff; + +int main (int argc, char *argv[]) { + + int cmdindx = 0; + progname = argv[0]; + + if (argc > 1) { + /* parse input parameters */ + for (argc--, argv++; *argv; argc--, argv++) { + char *bp; + char *ep; + + if (strncasecmp (*argv, "-", 1) == 0) { + if (strncasecmp (*argv, "-F=", 3) == 0) { + bp = *argv + 3; + read_file (bp); + } else if (strncasecmp (*argv, "-B=", 3) == 0) { + bp = *argv + 3; + bcast = inet_addr(bp); + if (bcast == -1) { + fprintf (stderr, "%s: expected address argument at %s\n", progname, *argv); + exit (1); + } + } else if (strncasecmp (*argv, "-D=", 3) == 0) { + bp = *argv + 3; + twait = strtol (bp, &ep, 0); + if (ep == bp || *ep != '\0') { + fprintf (stderr, "%s: expected integer argument at %s\n", progname, *argv); + exit (1); + } + } else if (strncasecmp (*argv, "-P=", 3) == 0) { + bp = *argv + 3; + port = strtol (bp, &ep, 0); + if (ep == bp || *ep != '\0') { + fprintf (stderr, "%s: expected integer argument at %s\n", progname, *argv); + exit (1); + } + } else if (strncasecmp (*argv, "-Q", 2) == 0) { + quiet = 1; + } else if (strncasecmp (*argv, "-V", 2) == 0) { + fprintf (stderr, "\r%s Version %s\n", progname, VERSION); + exit (0); + } else { + fprintf (stderr, "\r%s: invalid or unknown option %s\n", progname, *argv); + exit (1); + } + } else { + send_wol (*argv, ""); + } + cmdindx++; + } + return (0); + } else { + /* No arguments given -> usage message */ + fprintf (stderr, "\rUsage: %s [-q] [-b=<bcast>] [-p=<port>] [-d=<ms>] -f=<file> | <dest>\n", progname); + fprintf (stderr, " need at least hardware address or file option\n"); + return (-1); + } +} + + + +static int in_ether (char *bufp, unsigned char *addr) { + + char c, *orig; + int i; + unsigned char *ptr = addr; + unsigned val; + + i = 0; + orig = bufp; + while ((*bufp != '\0') && (i < 6)) { + val = 0; + c = *bufp++; + if (isdigit(c)) + val = c - '0'; + else if (c >= 'a' && c <= 'f') + val = c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + val = c - 'A' + 10; + else { +#ifdef DEBUG + fprintf (stderr, "\rin_ether(%s): invalid ether address!\n", orig); +#endif + errno = EINVAL; + return (-1); + } + val <<= 4; + c = *bufp; + if (isdigit(c)) + val |= c - '0'; + else if (c >= 'a' && c <= 'f') + val |= c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + val |= c - 'A' + 10; + else if (c == ':' || c == 0) + val >>= 4; + else { +#ifdef DEBUG + fprintf (stderr, "\rin_ether(%s): invalid ether address!\n", orig); +#endif + errno = EINVAL; + return (-1); + } + if (c != 0) + bufp++; + *ptr++ = (unsigned char) (val & 0377); + i++; + + /* We might get a semicolon here - not required. */ + if (*bufp == ':') { + if (i == 6) { + ; /* nothing */ + } + bufp++; + } + } + if (bufp - orig != 17) { + return (-1); + } else { + return (0); + } +} /* in_ether */ + + +static int read_file (char *destfile) { + + FILE *pfile = NULL; + char dest[64]; + char host[32]; + char buffer[512]; + + pfile = fopen (destfile, "r+"); + + if (pfile) { + while (fgets (buffer, 511, pfile) != NULL) { + if (buffer[0] != '#' && buffer[0] != ';') { + dest[0] = host[0] = '\0'; + sscanf (buffer, "%s %s", dest, host); + send_wol (dest, host); + } + } + fclose (pfile); + return (0); + } else { + fprintf (stderr, "\r%s: destfile '%s' not found\n", progname, destfile); + return (-1); + } +} + + +static int send_wol (char *dest, char *host) { + + int i, j; + int packet; + struct sockaddr_in sap; + unsigned char ethaddr[8]; + unsigned char *ptr; + unsigned char buf [128]; + unsigned long bc; + char mask[32]; + char *tmp; +#ifdef USE_WINSOCKAPI + WORD wVersionRequested; + WSADATA wsaData; + int err; +#endif +#ifdef WATTCP + static udp_Socket sock; + udp_Socket *s; +#else + int optval = 1; +#endif + + /* Fetch the broascast address if present. */ + if ((tmp = strstr(dest,"-"))) { +printf("found: %s\n", tmp); + tmp[0] = 32; + sscanf (dest, "%s %s", mask, dest); + bc = inet_addr(mask); +printf("bc: string %s address %08lX\n", mask, bc); + if (bc == -1) { + fprintf (stderr, "\r%s: expected address argument at %s\n", progname, mask); + return (-1); + } + } else + bc = bcast; + + /* Fetch the hardware address. */ + if (in_ether (dest, ethaddr) < 0) { + fprintf (stderr, "\r%s: invalid hardware address\n", progname); + return (-1); + } + +#ifdef USE_WINSOCKAPI + /* I would like to have Socket Vers. 1.1 */ + wVersionRequested = MAKEWORD(1, 1); + err = WSAStartup (wVersionRequested, &wsaData); + if (err != 0) { + fprintf (stderr, "\r%s: couldn't init Winsock Version 1.1\n", progname); + WSACleanup (); + return (-1); + } +#endif + + /* setup the packet socket */ +#ifdef WATTCP + sock_init(); + s = &sock; + if (!udp_open( s, 0, bc, port, NULL )) { +#else + if ((packet = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { +#endif + fprintf (stderr, "\r%s: socket failed\n", progname); +#ifdef USE_WINSOCKAPI + WSACleanup (); +#endif + return (-1); + } + +#ifndef WATTCP + /* Set socket options */ + if (setsockopt (packet, SOL_SOCKET, SO_BROADCAST, (char *)&optval, sizeof (optval)) < 0) { + fprintf (stderr, "\r%s: setsocket failed %s\n", progname, strerror (errno)); + close (packet); + return (-1); + } + + /* Set up broadcast address */ + sap.sin_family = AF_INET; + sap.sin_addr.s_addr = bc; /* broadcast address */ + sap.sin_port = htons(port); +#endif + + /* Build the message to send - 6 x 0xff then 16 x dest address */ + ptr = buf; + for (i = 0; i < 6; i++) + *ptr++ = 0xff; + for (j = 0; j < 16; j++) + for (i = 0; i < 6; i++) + *ptr++ = ethaddr [i]; + + /* Send the packet out */ +#ifdef WATTCP + sock_write( s, buf, 102 ); + sock_close( s ); +#else + if (sendto (packet, (char *)buf, 102, 0, (struct sockaddr *)&sap, sizeof (sap)) < 0) { + fprintf (stderr, "\r%s: sendto failed, %s\n", progname, strerror(errno)); + close (packet); + return (-1); + } + close (packet); +#endif + if (!quiet) fprintf (stderr, "\r%s: packet sent to %04X:%08lX-%s %s\n", + progname, port, (unsigned long)htonl(bc), dest, host); + if (twait > 0 ) { + delay (twait); + } + return (0); +} + |