00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #ifndef _GNU_SOURCE
00020 #define _GNU_SOURCE
00021 #endif
00022
00023 #include <stdio.h>
00024 #include <stdarg.h>
00025 #include <stdlib.h>
00026 #include <string.h>
00027 #include <errno.h>
00028 #include <time.h>
00029 #include <getopt.h>
00030 #include <unistd.h>
00031 #include <signal.h>
00032 #include <arpa/inet.h>
00033 #include <sys/types.h>
00034 #include <sys/socket.h>
00035 #include <sys/un.h>
00036 #include <sys/param.h>
00037 #include <sys/ioctl.h>
00038 #include <linux/if.h>
00039
00040 #include "util.h"
00041 #include "dyn_mnlib.h"
00042 #include "agentapi.h"
00043 #include "fixed_fd_zero.h"
00044 #include "device_info.h"
00045 #include "dyn_ip.h"
00046
00047 #define PID_FILE "/var/run/device_info.pid"
00048 #define MAXLINE 100
00049
00050 static char *default_socket_path = DEFAULT_DEVICE_INFO_PATH;
00051 static char *default_config_file_path = "/etc/device_info.conf";
00052 static char *config_file_path = NULL;
00053 static char *socket_path = NULL;
00054 static fd_set set;
00055 static int debug = 0;
00056
00057 static struct device_info_config *config = NULL;
00058
00059 struct device_info_config {
00060 unsigned char hw[ETH_ALEN];
00061 int priority;
00062 int line;
00063 struct device_info_config *next;
00064 };
00065
00066
00067 void DEBUG(char *format, ...)
00068 {
00069 va_list ap;
00070
00071 if (!debug)
00072 return;
00073
00074 va_start(ap, format);
00075 vfprintf(stdout, format, ap);
00076 fflush(stdout);
00077 va_end(ap);
00078 }
00079
00080
00081 static int open_socket(char *path)
00082 {
00083 if (!path) {
00084 fprintf(stderr, "open_socket: path is NULL\n");
00085 return -1;
00086 }
00087 return api_open_socket(path, NULL, NULL, (int)0666);
00088 }
00089
00090
00091 static void clean_up(int sig)
00092 {
00093 unlink(PID_FILE);
00094 exit(sig);
00095 }
00096
00097
00098 static struct device_info_config *find_entry(char *hw)
00099 {
00100 struct device_info_config *conf = config;
00101
00102 if (hw == NULL)
00103 return NULL;
00104
00105 while (conf != NULL) {
00106 if (!memcmp(hw, conf->hw, ETH_ALEN))
00107 return conf;
00108 conf = conf->next;
00109 }
00110
00111 return NULL;
00112 }
00113
00114
00115 static int send_reply(int sock, struct sockaddr_un *addr,
00116 struct device_info_query *query)
00117 {
00118 int r;
00119 if (addr == NULL || query == NULL) {
00120 fprintf(stderr, "send_reply: NULL argument\n");
00121 return -1;
00122 }
00123
00124 DEBUG("\tsending reply: index = %d, prio %d\n",
00125 query->device_index, query->priority);
00126
00127 r = sendto(sock, query, sizeof(struct device_info_query), 0,
00128 (struct sockaddr *)addr, sizeof(struct sockaddr_un));
00129 if (r != sizeof(struct device_info_query)) {
00130 fprintf(stderr, "send_reply: sendto %d/%d bytes: %s\n",
00131 r, sizeof(query), strerror(errno));
00132 return -1;
00133 }
00134
00135 return r;
00136 }
00137
00138
00139 static int handle_request(int sock)
00140 {
00141 struct sockaddr_un addr;
00142 struct device_info_query query;
00143 struct device_info_config *config;
00144 struct idxmap *idxmap, *idx;
00145 struct ifreq ifr;
00146 int n, len, found = 0, s;
00147
00148 len = sizeof(addr);
00149 n = recvfrom(sock, &query, sizeof(query), 0, (struct sockaddr *) &addr,
00150 (unsigned int *)&len);
00151 if (n != sizeof(query)) {
00152 fprintf(stderr, "handle_request: couldn't receive whole "
00153 "message %d/%d\n", n, sizeof(query));
00154 return -1;
00155 }
00156
00157
00158 DEBUG("received query\n\tquery.device_index = %d\n",
00159 query.device_index);
00160 memset(&ifr, 0, sizeof(ifr));
00161
00162
00163 idxmap = dyn_ip_get_interface_map();
00164 idx = idxmap;
00165 while (idx != NULL) {
00166 if (idx->index == query.device_index) {
00167 memcpy(ifr.ifr_name, idx->name, sizeof(ifr.ifr_name));
00168 DEBUG("\tdevice name: %s\n", ifr.ifr_name);
00169 found = 1;
00170 break;
00171 }
00172 idx = idx->next;
00173 }
00174 dyn_ip_free_interface_map(idxmap);
00175 if (!found) {
00176 fprintf(stderr, "handle_request: Couldn't find ifname\n");
00177 return -1;
00178 }
00179
00180 ifr.ifr_ifindex = query.device_index;
00181 s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
00182 if (s < 0) {
00183 fprintf(stderr, "handle_request: socket failed: %s\n",
00184 strerror(errno));
00185 return -1;
00186 }
00187 if (ioctl(s, SIOCGIFHWADDR, &ifr) != 0) {
00188 fprintf(stderr, "handle_request: SIOCGIFHWADDR ioctl: %s\n",
00189 strerror(errno));
00190 return -1;
00191 }
00192 config = find_entry(ifr.ifr_hwaddr.sa_data);
00193 found = 1;
00194 if (!config) {
00195 DEBUG("handle_request: entry not found (%s)\n",
00196 ether_hwtoa((unsigned char *)&ifr.ifr_hwaddr.sa_data));
00197 found = 0;
00198 query.priority = -2;
00199 } else {
00200 query.priority = config->priority;
00201 DEBUG("\tquery.priority = %d\n", query.priority);
00202 }
00203
00204
00205 n = send_reply(sock, &addr, &query);
00206 if (n < 0) {
00207 fprintf(stderr, "handle_request: Couldn't send reply\n");
00208 return -1;
00209 }
00210
00211 return 0;
00212 }
00213
00214
00215 static void parse_config(int sig)
00216 {
00217 FILE *file;
00218 char buffer[MAXLINE];
00219 struct device_info_config *conf = config, *first = config;
00220 int line = 0, n;
00221 unsigned int hw[6];
00222
00223
00224 if (debug && sig == SIGHUP)
00225 DEBUG("HUP signal received. Rereading config file\n");
00226
00227 if (config_file_path == NULL) {
00228 fprintf(stderr, "parse_config: path is NULL\n");
00229 return;
00230 }
00231 file = fopen(config_file_path, "r");
00232 if (file == NULL) {
00233 fprintf(stderr, "parse_config: Can't open file %s\n",
00234 strerror(errno));
00235 return;
00236 }
00237
00238 while (fgets(buffer, MAXLINE, file) != NULL) {
00239 buffer[strlen(buffer)-1]='\0';
00240 ++line;
00241 if (buffer[0] == '#' ||
00242 buffer[0] == '\n' ||
00243 buffer[0] == '\t' ||
00244 buffer[0] == ' ' ||
00245 strlen(buffer) == 0) {
00246 continue;
00247 }
00248
00249 if (conf == NULL) {
00250 DEBUG("Reading first time the configuration file\n");
00251 conf = malloc(sizeof(struct device_info_config));
00252 first = conf;
00253 }
00254 else {
00255 conf->next = malloc(sizeof(struct device_info_config));
00256 conf = conf->next;
00257 }
00258 if (conf == NULL) {
00259 fprintf(stderr, "parse_config: Memory allocation "
00260 "failed\n");
00261 fclose(file);
00262 return;
00263 }
00264 n = sscanf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x %d",
00265 &hw[0], &hw[1], &hw[2], &hw[3], &hw[4], &hw[5],
00266 &conf->priority);
00267 if (n != 7) {
00268 fprintf(stderr, "parse_config: Couldn't parse "
00269 "line %d '%s'\n", line, buffer);
00270 fclose(file);
00271 return;
00272 }
00273 conf->line = line;
00274 conf->hw[0] = (unsigned char)hw[0];
00275 conf->hw[1] = (unsigned char)hw[1];
00276 conf->hw[2] = (unsigned char)hw[2];
00277 conf->hw[3] = (unsigned char)hw[3];
00278 conf->hw[4] = (unsigned char)hw[4];
00279 conf->hw[5] = (unsigned char)hw[5];
00280 DEBUG("%s prio %d (line %d)\n",
00281 ether_hwtoa((unsigned char *)conf->hw),
00282 conf->priority, conf->line);
00283 }
00284
00285 fclose(file);
00286 config = first;
00287
00288 return;
00289 }
00290
00291
00292 int main(int argc, char *argv[])
00293 {
00294 int s, foreground = 0, c, n;
00295
00296 socket_path = default_socket_path;
00297 config_file_path = default_config_file_path;
00298 while (1) {
00299 int option_index = 0;
00300 static struct option long_options[] = {
00301 {"fg", no_argument, NULL, 'f'},
00302 {"debug", no_argument, NULL, 'd'},
00303 {0, 0, 0, 0}
00304 };
00305
00306 c = getopt_long (argc, argv, "fdc:s:",
00307 long_options, &option_index);
00308 if (c == -1)
00309 break;
00310
00311 switch (c) {
00312 case 'f':
00313 switch (option_index) {
00314 case 0:
00315 fprintf(stderr,"Option: %s\n",
00316 long_options[option_index].name);
00317 foreground = 1;
00318 }
00319 break;
00320 case 'c':
00321 config_file_path = malloc(MAXPATHLEN);
00322 if (config_file_path == NULL) {
00323 fprintf(stderr, "malloc for config: %s\n",
00324 strerror(errno));
00325 exit(1);
00326 }
00327 dynamics_strlcpy(config_file_path, optarg, MAXPATHLEN);
00328 break;
00329 case 's':
00330 socket_path = malloc(MAXPATHLEN);
00331 if (socket_path == NULL) {
00332 fprintf(stderr, "malloc for path: %s\n",
00333 strerror(errno));
00334 exit(1);
00335 }
00336 dynamics_strlcpy(socket_path, optarg, MAXPATHLEN);
00337 break;
00338 case 'd':
00339 debug = 1;
00340 break;
00341 case '?':
00342 fprintf(stderr, "device_info -c <configuration file> "
00343 "[-s <API socket>] [--fg]\n");
00344 exit(1);
00345 default:
00346 fprintf(stderr, "?? getopt returned character code "
00347 "0%o ??\n", c);
00348 }
00349 }
00350
00351 parse_config(0);
00352 if (config == NULL) {
00353 fprintf(stderr, "Configuration file parsing failed\n");
00354 exit(1);
00355 }
00356
00357 s = open_socket(socket_path);
00358 if (s < 0) {
00359 fprintf(stderr, "Open socket failed\n");
00360 exit(1);
00361 }
00362
00363 DEBUG("Initializing mn admin socket path\n");
00364 c = dynamics_mn_init(NULL);
00365 if (c == API_FAILED || c == API_ERROR) {
00366 fprintf(stderr, "MN admin socket path initialization "
00367 "failed\n");
00368 exit(1);
00369 }
00370 DEBUG("Registering device info socket path\n");
00371
00372 if (dynamics_mn_register_dev_info_socket(socket_path, 3)
00373 != API_SUCCESS) {
00374 fprintf(stderr, "API device info socket initialization "
00375 "failed\n");
00376 exit(1);
00377 }
00378 DEBUG("\tregistered\n");
00379
00380 if (!foreground && dynamics_fork_daemon() < 0) {
00381 fprintf(stderr, "fork failed\n");
00382 exit(1);
00383 }
00384 dynamics_write_pid_file(PID_FILE);
00385
00386 signal(SIGHUP, parse_config);
00387 signal(SIGTERM, clean_up);
00388 signal(SIGINT, clean_up);
00389
00390 for (;;) {
00391 FD_ZERO(&set);
00392 FD_SET(s, &set);
00393
00394 n = select(FD_SETSIZE, &set, NULL, NULL, NULL);
00395 if (n < 0 && errno != EINTR)
00396 fprintf(stderr, "select: %s\n",
00397 strerror(errno));
00398
00399 if (n == 1 && FD_ISSET(s, &set))
00400 handle_request(s);
00401 }
00402
00403 return 0;
00404 }