1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
|
/* The best bits of mii-diag and ethtool mixed into one big jelly roll. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <net/if.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#ifndef TEST
# include <debian-installer/log.h>
# define CONNECTED 1
# define DISCONNECTED 2
# define UNKNOWN 3
#else
# define di_info(fmt, ...) printf(fmt, ## __VA_ARGS__)
# define di_warning(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__)
# define CONNECTED 0
# define DISCONNECTED 0
# define UNKNOWN 1
#endif
#if defined(__linux__)
#define SYSCLASSNET "/sys/class/net/"
#elif defined(__FreeBSD_kernel__)
#include <net/if_media.h>
#endif
#ifdef TEST
int main(int argc, char** argv)
#else
int ethtool_lite (const char * iface)
#endif
{
#ifdef TEST
char* iface;
#endif
#if defined(__linux__)
int len = strlen(SYSCLASSNET) + strlen(iface) + strlen("/carrier") + 1;
char* filename = malloc(len);
snprintf(filename, len, SYSCLASSNET "%s/carrier", iface);
FILE* fp = fopen(filename, "r");
free(filename);
char result[2];
if (fgets(result, sizeof(result), fp) == NULL) {
fclose(fp);
if (errno == EINVAL) {
di_info("ethtool-lite: %s is down", iface);
return DISCONNECTED;
}
di_error("ethtool-lite: getting carrier failed: %s",
strerror(errno));
return UNKNOWN;
}
fclose(fp);
switch (result[0]) {
case '1':
di_info("ethtool-lite: %s: carrier up", iface);
return CONNECTED;
case '0':
di_info("ethtool-lite: %s: carrier down", iface);
return DISCONNECTED;
}
di_info("ethtool-lite: %s: could not determine carrier state; got \"%s\"",
iface, result);
return UNKNOWN;
#elif defined(__FreeBSD_kernel__)
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0)
{
di_warning("ethtool-lite: could not open control socket\n");
return UNKNOWN;
}
#ifdef TEST
if (argc < 2)
{
fprintf(stderr, "ethtool-lite: Error: must pass an interface name\n");
close(fd);
return 1;
}
iface = argv[1];
#endif
struct ifmediareq ifmr;
memset(&ifmr, 0, sizeof(ifmr));
strncpy(ifmr.ifm_name, iface, sizeof(ifmr.ifm_name));
if (ioctl(fd, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
di_warning("ethtool-lite: SIOCGIFMEDIA ioctl on %s failed\n", iface);
close(fd);
return UNKNOWN;
}
close(fd);
if (ifmr.ifm_status & IFM_AVALID) {
if (ifmr.ifm_status & IFM_ACTIVE) {
di_info("ethtool-lite: %s is connected.\n", iface);
return CONNECTED;
} else {
di_info("ethtool-lite: %s is disconnected.\n", iface);
return DISCONNECTED;
}
}
di_warning("ethtool-lite: couldn't determine status for %s\n", iface);
#elif defined(__GNU__)
di_warning("ethtool-lite: unsupported on GNU/Hurd for %s\n", iface);
#endif
return UNKNOWN;
}
|