This source file includes following definitions.
- kvp_acquire_lock
- kvp_release_lock
- kvp_update_file
- kvp_update_mem_state
- kvp_file_init
- kvp_key_delete
- kvp_key_add_or_modify
- kvp_get_value
- kvp_pool_enumerate
- kvp_get_os_info
- kvp_get_if_name
- kvp_if_name_to_mac
- kvp_process_ipconfig_file
- kvp_get_ipconfig_info
- hweight32
- kvp_process_ip_address
- kvp_get_ip_info
- kvp_mac_to_ip
- expand_ipv6
- is_ipv4
- parse_ip_val_buffer
- kvp_write_file
- process_ip_string
- kvp_set_ip_info
- kvp_get_domain_name
- print_usage
- main
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 #include <sys/poll.h>
26 #include <sys/utsname.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <errno.h>
33 #include <arpa/inet.h>
34 #include <linux/hyperv.h>
35 #include <ifaddrs.h>
36 #include <netdb.h>
37 #include <syslog.h>
38 #include <sys/stat.h>
39 #include <fcntl.h>
40 #include <dirent.h>
41 #include <net/if.h>
42 #include <limits.h>
43 #include <getopt.h>
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58 enum key_index {
59 FullyQualifiedDomainName = 0,
60 IntegrationServicesVersion,
61 NetworkAddressIPv4,
62 NetworkAddressIPv6,
63 OSBuildNumber,
64 OSName,
65 OSMajorVersion,
66 OSMinorVersion,
67 OSVersion,
68 ProcessorArchitecture
69 };
70
71
72 enum {
73 IPADDR = 0,
74 NETMASK,
75 GATEWAY,
76 DNS
77 };
78
79 static int in_hand_shake = 1;
80
81 static char *os_name = "";
82 static char *os_major = "";
83 static char *os_minor = "";
84 static char *processor_arch;
85 static char *os_build;
86 static char *os_version;
87 static char *lic_version = "Unknown version";
88 static char full_domain_name[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
89 static struct utsname uts_buf;
90
91
92
93
94
95 #define KVP_CONFIG_LOC "/var/lib/hyperv"
96
97 #ifndef KVP_SCRIPTS_PATH
98 #define KVP_SCRIPTS_PATH "/usr/libexec/hypervkvpd/"
99 #endif
100
101 #define KVP_NET_DIR "/sys/class/net/"
102
103 #define MAX_FILE_NAME 100
104 #define ENTRIES_PER_BLOCK 50
105
106 struct kvp_record {
107 char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
108 char value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
109 };
110
111 struct kvp_file_state {
112 int fd;
113 int num_blocks;
114 struct kvp_record *records;
115 int num_records;
116 char fname[MAX_FILE_NAME];
117 };
118
119 static struct kvp_file_state kvp_file_info[KVP_POOL_COUNT];
120
121 static void kvp_acquire_lock(int pool)
122 {
123 struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0};
124 fl.l_pid = getpid();
125
126 if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) {
127 syslog(LOG_ERR, "Failed to acquire the lock pool: %d; error: %d %s", pool,
128 errno, strerror(errno));
129 exit(EXIT_FAILURE);
130 }
131 }
132
133 static void kvp_release_lock(int pool)
134 {
135 struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0};
136 fl.l_pid = getpid();
137
138 if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) {
139 syslog(LOG_ERR, "Failed to release the lock pool: %d; error: %d %s", pool,
140 errno, strerror(errno));
141 exit(EXIT_FAILURE);
142 }
143 }
144
145 static void kvp_update_file(int pool)
146 {
147 FILE *filep;
148
149
150
151
152
153 kvp_acquire_lock(pool);
154
155 filep = fopen(kvp_file_info[pool].fname, "we");
156 if (!filep) {
157 syslog(LOG_ERR, "Failed to open file, pool: %d; error: %d %s", pool,
158 errno, strerror(errno));
159 kvp_release_lock(pool);
160 exit(EXIT_FAILURE);
161 }
162
163 fwrite(kvp_file_info[pool].records, sizeof(struct kvp_record),
164 kvp_file_info[pool].num_records, filep);
165
166 if (ferror(filep) || fclose(filep)) {
167 kvp_release_lock(pool);
168 syslog(LOG_ERR, "Failed to write file, pool: %d", pool);
169 exit(EXIT_FAILURE);
170 }
171
172 kvp_release_lock(pool);
173 }
174
175 static void kvp_update_mem_state(int pool)
176 {
177 FILE *filep;
178 size_t records_read = 0;
179 struct kvp_record *record = kvp_file_info[pool].records;
180 struct kvp_record *readp;
181 int num_blocks = kvp_file_info[pool].num_blocks;
182 int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
183
184 kvp_acquire_lock(pool);
185
186 filep = fopen(kvp_file_info[pool].fname, "re");
187 if (!filep) {
188 syslog(LOG_ERR, "Failed to open file, pool: %d; error: %d %s", pool,
189 errno, strerror(errno));
190 kvp_release_lock(pool);
191 exit(EXIT_FAILURE);
192 }
193 for (;;) {
194 readp = &record[records_read];
195 records_read += fread(readp, sizeof(struct kvp_record),
196 ENTRIES_PER_BLOCK * num_blocks - records_read,
197 filep);
198
199 if (ferror(filep)) {
200 syslog(LOG_ERR,
201 "Failed to read file, pool: %d; error: %d %s",
202 pool, errno, strerror(errno));
203 kvp_release_lock(pool);
204 exit(EXIT_FAILURE);
205 }
206
207 if (!feof(filep)) {
208
209
210
211 num_blocks++;
212 record = realloc(record, alloc_unit * num_blocks);
213
214 if (record == NULL) {
215 syslog(LOG_ERR, "malloc failed");
216 kvp_release_lock(pool);
217 exit(EXIT_FAILURE);
218 }
219 continue;
220 }
221 break;
222 }
223
224 kvp_file_info[pool].num_blocks = num_blocks;
225 kvp_file_info[pool].records = record;
226 kvp_file_info[pool].num_records = records_read;
227
228 fclose(filep);
229 kvp_release_lock(pool);
230 }
231
232 static int kvp_file_init(void)
233 {
234 int fd;
235 char *fname;
236 int i;
237 int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
238
239 if (access(KVP_CONFIG_LOC, F_OK)) {
240 if (mkdir(KVP_CONFIG_LOC, 0755 )) {
241 syslog(LOG_ERR, "Failed to create '%s'; error: %d %s", KVP_CONFIG_LOC,
242 errno, strerror(errno));
243 exit(EXIT_FAILURE);
244 }
245 }
246
247 for (i = 0; i < KVP_POOL_COUNT; i++) {
248 fname = kvp_file_info[i].fname;
249 sprintf(fname, "%s/.kvp_pool_%d", KVP_CONFIG_LOC, i);
250 fd = open(fname, O_RDWR | O_CREAT | O_CLOEXEC, 0644 );
251
252 if (fd == -1)
253 return 1;
254
255 kvp_file_info[i].fd = fd;
256 kvp_file_info[i].num_blocks = 1;
257 kvp_file_info[i].records = malloc(alloc_unit);
258 if (kvp_file_info[i].records == NULL)
259 return 1;
260 kvp_file_info[i].num_records = 0;
261 kvp_update_mem_state(i);
262 }
263
264 return 0;
265 }
266
267 static int kvp_key_delete(int pool, const __u8 *key, int key_size)
268 {
269 int i;
270 int j, k;
271 int num_records;
272 struct kvp_record *record;
273
274
275
276
277 kvp_update_mem_state(pool);
278
279 num_records = kvp_file_info[pool].num_records;
280 record = kvp_file_info[pool].records;
281
282 for (i = 0; i < num_records; i++) {
283 if (memcmp(key, record[i].key, key_size))
284 continue;
285
286
287
288
289 if (i == (num_records - 1)) {
290 kvp_file_info[pool].num_records--;
291 kvp_update_file(pool);
292 return 0;
293 }
294
295 j = i;
296 k = j + 1;
297 for (; k < num_records; k++) {
298 strcpy(record[j].key, record[k].key);
299 strcpy(record[j].value, record[k].value);
300 j++;
301 }
302
303 kvp_file_info[pool].num_records--;
304 kvp_update_file(pool);
305 return 0;
306 }
307 return 1;
308 }
309
310 static int kvp_key_add_or_modify(int pool, const __u8 *key, int key_size,
311 const __u8 *value, int value_size)
312 {
313 int i;
314 int num_records;
315 struct kvp_record *record;
316 int num_blocks;
317
318 if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
319 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
320 return 1;
321
322
323
324
325 kvp_update_mem_state(pool);
326
327 num_records = kvp_file_info[pool].num_records;
328 record = kvp_file_info[pool].records;
329 num_blocks = kvp_file_info[pool].num_blocks;
330
331 for (i = 0; i < num_records; i++) {
332 if (memcmp(key, record[i].key, key_size))
333 continue;
334
335
336
337
338 memcpy(record[i].value, value, value_size);
339 kvp_update_file(pool);
340 return 0;
341 }
342
343
344
345
346 if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) {
347
348 record = realloc(record, sizeof(struct kvp_record) *
349 ENTRIES_PER_BLOCK * (num_blocks + 1));
350
351 if (record == NULL)
352 return 1;
353 kvp_file_info[pool].num_blocks++;
354
355 }
356 memcpy(record[i].value, value, value_size);
357 memcpy(record[i].key, key, key_size);
358 kvp_file_info[pool].records = record;
359 kvp_file_info[pool].num_records++;
360 kvp_update_file(pool);
361 return 0;
362 }
363
364 static int kvp_get_value(int pool, const __u8 *key, int key_size, __u8 *value,
365 int value_size)
366 {
367 int i;
368 int num_records;
369 struct kvp_record *record;
370
371 if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
372 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
373 return 1;
374
375
376
377
378 kvp_update_mem_state(pool);
379
380 num_records = kvp_file_info[pool].num_records;
381 record = kvp_file_info[pool].records;
382
383 for (i = 0; i < num_records; i++) {
384 if (memcmp(key, record[i].key, key_size))
385 continue;
386
387
388
389 memcpy(value, record[i].value, value_size);
390 return 0;
391 }
392
393 return 1;
394 }
395
396 static int kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size,
397 __u8 *value, int value_size)
398 {
399 struct kvp_record *record;
400
401
402
403
404 kvp_update_mem_state(pool);
405 record = kvp_file_info[pool].records;
406
407 if (index >= kvp_file_info[pool].num_records) {
408 return 1;
409 }
410
411 memcpy(key, record[index].key, key_size);
412 memcpy(value, record[index].value, value_size);
413 return 0;
414 }
415
416
417 void kvp_get_os_info(void)
418 {
419 FILE *file;
420 char *p, buf[512];
421
422 uname(&uts_buf);
423 os_version = uts_buf.release;
424 os_build = strdup(uts_buf.release);
425
426 os_name = uts_buf.sysname;
427 processor_arch = uts_buf.machine;
428
429
430
431
432
433
434 p = strchr(os_version, '-');
435 if (p)
436 *p = '\0';
437
438
439
440
441
442 file = fopen("/etc/os-release", "r");
443 if (file != NULL) {
444 while (fgets(buf, sizeof(buf), file)) {
445 char *value, *q;
446
447
448 if (buf[0] == '#')
449 continue;
450
451
452 p = strchr(buf, '=');
453 if (!p)
454 continue;
455 *p++ = 0;
456
457
458 value = p;
459 q = p;
460 while (*p) {
461 if (*p == '\\') {
462 ++p;
463 if (!*p)
464 break;
465 *q++ = *p++;
466 } else if (*p == '\'' || *p == '"' ||
467 *p == '\n') {
468 ++p;
469 } else {
470 *q++ = *p++;
471 }
472 }
473 *q = 0;
474
475 if (!strcmp(buf, "NAME")) {
476 p = strdup(value);
477 if (!p)
478 break;
479 os_name = p;
480 } else if (!strcmp(buf, "VERSION_ID")) {
481 p = strdup(value);
482 if (!p)
483 break;
484 os_major = p;
485 }
486 }
487 fclose(file);
488 return;
489 }
490
491
492 file = fopen("/etc/SuSE-release", "r");
493 if (file != NULL)
494 goto kvp_osinfo_found;
495 file = fopen("/etc/redhat-release", "r");
496 if (file != NULL)
497 goto kvp_osinfo_found;
498
499
500
501
502 return;
503
504 kvp_osinfo_found:
505
506 p = fgets(buf, sizeof(buf), file);
507 if (p) {
508 p = strchr(buf, '\n');
509 if (p)
510 *p = '\0';
511 p = strdup(buf);
512 if (!p)
513 goto done;
514 os_name = p;
515
516
517 p = fgets(buf, sizeof(buf), file);
518 if (p) {
519 p = strchr(buf, '\n');
520 if (p)
521 *p = '\0';
522 p = strdup(buf);
523 if (!p)
524 goto done;
525 os_major = p;
526
527
528 p = fgets(buf, sizeof(buf), file);
529 if (p) {
530 p = strchr(buf, '\n');
531 if (p)
532 *p = '\0';
533 p = strdup(buf);
534 if (p)
535 os_minor = p;
536 }
537 }
538 }
539
540 done:
541 fclose(file);
542 return;
543 }
544
545
546
547
548
549
550
551
552
553
554
555 static char *kvp_get_if_name(char *guid)
556 {
557 DIR *dir;
558 struct dirent *entry;
559 FILE *file;
560 char *p, *x;
561 char *if_name = NULL;
562 char buf[256];
563 char dev_id[PATH_MAX];
564
565 dir = opendir(KVP_NET_DIR);
566 if (dir == NULL)
567 return NULL;
568
569 while ((entry = readdir(dir)) != NULL) {
570
571
572
573 snprintf(dev_id, sizeof(dev_id), "%s%s/device/device_id",
574 KVP_NET_DIR, entry->d_name);
575
576 file = fopen(dev_id, "r");
577 if (file == NULL)
578 continue;
579
580 p = fgets(buf, sizeof(buf), file);
581 if (p) {
582 x = strchr(p, '\n');
583 if (x)
584 *x = '\0';
585
586 if (!strcmp(p, guid)) {
587
588
589
590
591 if_name = strdup(entry->d_name);
592 fclose(file);
593 break;
594 }
595 }
596 fclose(file);
597 }
598
599 closedir(dir);
600 return if_name;
601 }
602
603
604
605
606
607 static char *kvp_if_name_to_mac(char *if_name)
608 {
609 FILE *file;
610 char *p, *x;
611 char buf[256];
612 char addr_file[PATH_MAX];
613 unsigned int i;
614 char *mac_addr = NULL;
615
616 snprintf(addr_file, sizeof(addr_file), "%s%s%s", KVP_NET_DIR,
617 if_name, "/address");
618
619 file = fopen(addr_file, "r");
620 if (file == NULL)
621 return NULL;
622
623 p = fgets(buf, sizeof(buf), file);
624 if (p) {
625 x = strchr(p, '\n');
626 if (x)
627 *x = '\0';
628 for (i = 0; i < strlen(p); i++)
629 p[i] = toupper(p[i]);
630 mac_addr = strdup(p);
631 }
632
633 fclose(file);
634 return mac_addr;
635 }
636
637 static void kvp_process_ipconfig_file(char *cmd,
638 char *config_buf, unsigned int len,
639 int element_size, int offset)
640 {
641 char buf[256];
642 char *p;
643 char *x;
644 FILE *file;
645
646
647
648
649 file = popen(cmd, "r");
650 if (file == NULL)
651 return;
652
653 if (offset == 0)
654 memset(config_buf, 0, len);
655 while ((p = fgets(buf, sizeof(buf), file)) != NULL) {
656 if (len < strlen(config_buf) + element_size + 1)
657 break;
658
659 x = strchr(p, '\n');
660 if (x)
661 *x = '\0';
662
663 strcat(config_buf, p);
664 strcat(config_buf, ";");
665 }
666 pclose(file);
667 }
668
669 static void kvp_get_ipconfig_info(char *if_name,
670 struct hv_kvp_ipaddr_value *buffer)
671 {
672 char cmd[512];
673 char dhcp_info[128];
674 char *p;
675 FILE *file;
676
677
678
679
680 sprintf(cmd, "%s %s", "ip route show dev", if_name);
681 strcat(cmd, " | awk '/default/ {print $3 }'");
682
683
684
685
686 kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
687 (MAX_GATEWAY_SIZE * 2), INET_ADDRSTRLEN, 0);
688
689
690
691
692 sprintf(cmd, "%s %s", "ip -f inet6 route show dev", if_name);
693 strcat(cmd, " | awk '/default/ {print $3 }'");
694
695
696
697
698 kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
699 (MAX_GATEWAY_SIZE * 2), INET6_ADDRSTRLEN, 1);
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717 sprintf(cmd, KVP_SCRIPTS_PATH "%s", "hv_get_dns_info");
718
719
720
721
722 kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr,
723 (MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0);
724
725
726
727
728
729
730
731
732
733
734 sprintf(cmd, KVP_SCRIPTS_PATH "%s %s", "hv_get_dhcp_info", if_name);
735
736 file = popen(cmd, "r");
737 if (file == NULL)
738 return;
739
740 p = fgets(dhcp_info, sizeof(dhcp_info), file);
741 if (p == NULL) {
742 pclose(file);
743 return;
744 }
745
746 if (!strncmp(p, "Enabled", 7))
747 buffer->dhcp_enabled = 1;
748 else
749 buffer->dhcp_enabled = 0;
750
751 pclose(file);
752 }
753
754
755 static unsigned int hweight32(unsigned int *w)
756 {
757 unsigned int res = *w - ((*w >> 1) & 0x55555555);
758 res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
759 res = (res + (res >> 4)) & 0x0F0F0F0F;
760 res = res + (res >> 8);
761 return (res + (res >> 16)) & 0x000000FF;
762 }
763
764 static int kvp_process_ip_address(void *addrp,
765 int family, char *buffer,
766 int length, int *offset)
767 {
768 struct sockaddr_in *addr;
769 struct sockaddr_in6 *addr6;
770 int addr_length;
771 char tmp[50];
772 const char *str;
773
774 if (family == AF_INET) {
775 addr = (struct sockaddr_in *)addrp;
776 str = inet_ntop(family, &addr->sin_addr, tmp, 50);
777 addr_length = INET_ADDRSTRLEN;
778 } else {
779 addr6 = (struct sockaddr_in6 *)addrp;
780 str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50);
781 addr_length = INET6_ADDRSTRLEN;
782 }
783
784 if ((length - *offset) < addr_length + 2)
785 return HV_E_FAIL;
786 if (str == NULL) {
787 strcpy(buffer, "inet_ntop failed\n");
788 return HV_E_FAIL;
789 }
790 if (*offset == 0)
791 strcpy(buffer, tmp);
792 else {
793 strcat(buffer, ";");
794 strcat(buffer, tmp);
795 }
796
797 *offset += strlen(str) + 1;
798
799 return 0;
800 }
801
802 static int
803 kvp_get_ip_info(int family, char *if_name, int op,
804 void *out_buffer, unsigned int length)
805 {
806 struct ifaddrs *ifap;
807 struct ifaddrs *curp;
808 int offset = 0;
809 int sn_offset = 0;
810 int error = 0;
811 char *buffer;
812 struct hv_kvp_ipaddr_value *ip_buffer = NULL;
813 char cidr_mask[5];
814 int weight;
815 int i;
816 unsigned int *w;
817 char *sn_str;
818 struct sockaddr_in6 *addr6;
819
820 if (op == KVP_OP_ENUMERATE) {
821 buffer = out_buffer;
822 } else {
823 ip_buffer = out_buffer;
824 buffer = (char *)ip_buffer->ip_addr;
825 ip_buffer->addr_family = 0;
826 }
827
828
829
830
831
832 if (getifaddrs(&ifap)) {
833 strcpy(buffer, "getifaddrs failed\n");
834 return HV_E_FAIL;
835 }
836
837 curp = ifap;
838 while (curp != NULL) {
839 if (curp->ifa_addr == NULL) {
840 curp = curp->ifa_next;
841 continue;
842 }
843
844 if ((if_name != NULL) &&
845 (strncmp(curp->ifa_name, if_name, strlen(if_name)))) {
846
847
848
849
850 curp = curp->ifa_next;
851 continue;
852 }
853
854
855
856
857
858
859
860 if ((((family != 0) &&
861 (curp->ifa_addr->sa_family != family))) ||
862 (curp->ifa_flags & IFF_LOOPBACK)) {
863 curp = curp->ifa_next;
864 continue;
865 }
866 if ((curp->ifa_addr->sa_family != AF_INET) &&
867 (curp->ifa_addr->sa_family != AF_INET6)) {
868 curp = curp->ifa_next;
869 continue;
870 }
871
872 if (op == KVP_OP_GET_IP_INFO) {
873
874
875
876
877 if (curp->ifa_addr->sa_family == AF_INET) {
878 ip_buffer->addr_family |= ADDR_FAMILY_IPV4;
879
880
881
882 error = kvp_process_ip_address(
883 curp->ifa_netmask,
884 AF_INET,
885 (char *)
886 ip_buffer->sub_net,
887 length,
888 &sn_offset);
889 if (error)
890 goto gather_ipaddr;
891 } else {
892 ip_buffer->addr_family |= ADDR_FAMILY_IPV6;
893
894
895
896
897 weight = 0;
898 sn_str = (char *)ip_buffer->sub_net;
899 addr6 = (struct sockaddr_in6 *)
900 curp->ifa_netmask;
901 w = addr6->sin6_addr.s6_addr32;
902
903 for (i = 0; i < 4; i++)
904 weight += hweight32(&w[i]);
905
906 sprintf(cidr_mask, "/%d", weight);
907 if (length < sn_offset + strlen(cidr_mask) + 1)
908 goto gather_ipaddr;
909
910 if (sn_offset == 0)
911 strcpy(sn_str, cidr_mask);
912 else {
913 strcat((char *)ip_buffer->sub_net, ";");
914 strcat(sn_str, cidr_mask);
915 }
916 sn_offset += strlen(sn_str) + 1;
917 }
918
919
920
921
922
923 kvp_get_ipconfig_info(if_name, ip_buffer);
924 }
925
926 gather_ipaddr:
927 error = kvp_process_ip_address(curp->ifa_addr,
928 curp->ifa_addr->sa_family,
929 buffer,
930 length, &offset);
931 if (error)
932 goto getaddr_done;
933
934 curp = curp->ifa_next;
935 }
936
937 getaddr_done:
938 freeifaddrs(ifap);
939 return error;
940 }
941
942
943
944
945 static int kvp_mac_to_ip(struct hv_kvp_ipaddr_value *kvp_ip_val)
946 {
947 char *mac = (char *)kvp_ip_val->adapter_id;
948 DIR *dir;
949 struct dirent *entry;
950 FILE *file;
951 char *p, *x;
952 char *if_name = NULL;
953 char buf[256];
954 char dev_id[PATH_MAX];
955 unsigned int i;
956 int error = HV_E_FAIL;
957
958 dir = opendir(KVP_NET_DIR);
959 if (dir == NULL)
960 return HV_E_FAIL;
961
962 while ((entry = readdir(dir)) != NULL) {
963
964
965
966 snprintf(dev_id, sizeof(dev_id), "%s%s/address", KVP_NET_DIR,
967 entry->d_name);
968
969 file = fopen(dev_id, "r");
970 if (file == NULL)
971 continue;
972
973 p = fgets(buf, sizeof(buf), file);
974 fclose(file);
975 if (!p)
976 continue;
977
978 x = strchr(p, '\n');
979 if (x)
980 *x = '\0';
981
982 for (i = 0; i < strlen(p); i++)
983 p[i] = toupper(p[i]);
984
985 if (strcmp(p, mac))
986 continue;
987
988
989
990
991
992 if_name = entry->d_name;
993 if (!if_name)
994 continue;
995
996 error = kvp_get_ip_info(0, if_name, KVP_OP_GET_IP_INFO,
997 kvp_ip_val, MAX_IP_ADDR_SIZE * 2);
998
999 if (!error && strlen((char *)kvp_ip_val->ip_addr))
1000 break;
1001 }
1002
1003 closedir(dir);
1004 return error;
1005 }
1006
1007 static int expand_ipv6(char *addr, int type)
1008 {
1009 int ret;
1010 struct in6_addr v6_addr;
1011
1012 ret = inet_pton(AF_INET6, addr, &v6_addr);
1013
1014 if (ret != 1) {
1015 if (type == NETMASK)
1016 return 1;
1017 return 0;
1018 }
1019
1020 sprintf(addr, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
1021 "%02x%02x:%02x%02x:%02x%02x",
1022 (int)v6_addr.s6_addr[0], (int)v6_addr.s6_addr[1],
1023 (int)v6_addr.s6_addr[2], (int)v6_addr.s6_addr[3],
1024 (int)v6_addr.s6_addr[4], (int)v6_addr.s6_addr[5],
1025 (int)v6_addr.s6_addr[6], (int)v6_addr.s6_addr[7],
1026 (int)v6_addr.s6_addr[8], (int)v6_addr.s6_addr[9],
1027 (int)v6_addr.s6_addr[10], (int)v6_addr.s6_addr[11],
1028 (int)v6_addr.s6_addr[12], (int)v6_addr.s6_addr[13],
1029 (int)v6_addr.s6_addr[14], (int)v6_addr.s6_addr[15]);
1030
1031 return 1;
1032
1033 }
1034
1035 static int is_ipv4(char *addr)
1036 {
1037 int ret;
1038 struct in_addr ipv4_addr;
1039
1040 ret = inet_pton(AF_INET, addr, &ipv4_addr);
1041
1042 if (ret == 1)
1043 return 1;
1044 return 0;
1045 }
1046
1047 static int parse_ip_val_buffer(char *in_buf, int *offset,
1048 char *out_buf, int out_len)
1049 {
1050 char *x;
1051 char *start;
1052
1053
1054
1055
1056
1057
1058 start = in_buf + *offset;
1059
1060 x = strchr(start, ';');
1061 if (x)
1062 *x = 0;
1063 else
1064 x = start + strlen(start);
1065
1066 if (strlen(start) != 0) {
1067 int i = 0;
1068
1069
1070
1071 while (start[i] == ' ')
1072 i++;
1073
1074 if ((x - start) <= out_len) {
1075 strcpy(out_buf, (start + i));
1076 *offset += (x - start) + 1;
1077 return 1;
1078 }
1079 }
1080 return 0;
1081 }
1082
1083 static int kvp_write_file(FILE *f, char *s1, char *s2, char *s3)
1084 {
1085 int ret;
1086
1087 ret = fprintf(f, "%s%s%s%s\n", s1, s2, "=", s3);
1088
1089 if (ret < 0)
1090 return HV_E_FAIL;
1091
1092 return 0;
1093 }
1094
1095
1096 static int process_ip_string(FILE *f, char *ip_string, int type)
1097 {
1098 int error = 0;
1099 char addr[INET6_ADDRSTRLEN];
1100 int i = 0;
1101 int j = 0;
1102 char str[256];
1103 char sub_str[13];
1104 int offset = 0;
1105
1106 memset(addr, 0, sizeof(addr));
1107
1108 while (parse_ip_val_buffer(ip_string, &offset, addr,
1109 (MAX_IP_ADDR_SIZE * 2))) {
1110
1111 sub_str[0] = 0;
1112 if (is_ipv4(addr)) {
1113 switch (type) {
1114 case IPADDR:
1115 snprintf(str, sizeof(str), "%s", "IPADDR");
1116 break;
1117 case NETMASK:
1118 snprintf(str, sizeof(str), "%s", "NETMASK");
1119 break;
1120 case GATEWAY:
1121 snprintf(str, sizeof(str), "%s", "GATEWAY");
1122 break;
1123 case DNS:
1124 snprintf(str, sizeof(str), "%s", "DNS");
1125 break;
1126 }
1127
1128 if (type == DNS) {
1129 snprintf(sub_str, sizeof(sub_str), "%d", ++i);
1130 } else if (type == GATEWAY && i == 0) {
1131 ++i;
1132 } else {
1133 snprintf(sub_str, sizeof(sub_str), "%d", i++);
1134 }
1135
1136
1137 } else if (expand_ipv6(addr, type)) {
1138 switch (type) {
1139 case IPADDR:
1140 snprintf(str, sizeof(str), "%s", "IPV6ADDR");
1141 break;
1142 case NETMASK:
1143 snprintf(str, sizeof(str), "%s", "IPV6NETMASK");
1144 break;
1145 case GATEWAY:
1146 snprintf(str, sizeof(str), "%s",
1147 "IPV6_DEFAULTGW");
1148 break;
1149 case DNS:
1150 snprintf(str, sizeof(str), "%s", "DNS");
1151 break;
1152 }
1153
1154 if (type == DNS) {
1155 snprintf(sub_str, sizeof(sub_str), "%d", ++i);
1156 } else if (j == 0) {
1157 ++j;
1158 } else {
1159 snprintf(sub_str, sizeof(sub_str), "_%d", j++);
1160 }
1161 } else {
1162 return HV_INVALIDARG;
1163 }
1164
1165 error = kvp_write_file(f, str, sub_str, addr);
1166 if (error)
1167 return error;
1168 memset(addr, 0, sizeof(addr));
1169 }
1170
1171 return 0;
1172 }
1173
1174 static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
1175 {
1176 int error = 0;
1177 char if_file[PATH_MAX];
1178 FILE *file;
1179 char cmd[PATH_MAX];
1180 char *mac_addr;
1181 int str_len;
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230 snprintf(if_file, sizeof(if_file), "%s%s%s", KVP_CONFIG_LOC,
1231 "/ifcfg-", if_name);
1232
1233 file = fopen(if_file, "w");
1234
1235 if (file == NULL) {
1236 syslog(LOG_ERR, "Failed to open config file; error: %d %s",
1237 errno, strerror(errno));
1238 return HV_E_FAIL;
1239 }
1240
1241
1242
1243
1244
1245 mac_addr = kvp_if_name_to_mac(if_name);
1246 if (mac_addr == NULL) {
1247 error = HV_E_FAIL;
1248 goto setval_error;
1249 }
1250
1251 error = kvp_write_file(file, "HWADDR", "", mac_addr);
1252 free(mac_addr);
1253 if (error)
1254 goto setval_error;
1255
1256 error = kvp_write_file(file, "DEVICE", "", if_name);
1257 if (error)
1258 goto setval_error;
1259
1260
1261
1262
1263
1264
1265
1266 if (new_val->dhcp_enabled) {
1267 error = kvp_write_file(file, "BOOTPROTO", "", "dhcp");
1268 if (error)
1269 goto setval_error;
1270
1271 } else {
1272 error = kvp_write_file(file, "BOOTPROTO", "", "none");
1273 if (error)
1274 goto setval_error;
1275 }
1276
1277
1278
1279
1280
1281
1282 error = process_ip_string(file, (char *)new_val->ip_addr, IPADDR);
1283 if (error)
1284 goto setval_error;
1285
1286 error = process_ip_string(file, (char *)new_val->sub_net, NETMASK);
1287 if (error)
1288 goto setval_error;
1289
1290 error = process_ip_string(file, (char *)new_val->gate_way, GATEWAY);
1291 if (error)
1292 goto setval_error;
1293
1294 error = process_ip_string(file, (char *)new_val->dns_addr, DNS);
1295 if (error)
1296 goto setval_error;
1297
1298 fclose(file);
1299
1300
1301
1302
1303
1304
1305 str_len = snprintf(cmd, sizeof(cmd), KVP_SCRIPTS_PATH "%s %s",
1306 "hv_set_ifconfig", if_file);
1307
1308
1309
1310
1311 if (str_len <= 0 || (unsigned int)str_len >= sizeof(cmd)) {
1312 syslog(LOG_ERR, "Cmd '%s' (len=%d) may be too long",
1313 cmd, str_len);
1314 return HV_E_FAIL;
1315 }
1316
1317 if (system(cmd)) {
1318 syslog(LOG_ERR, "Failed to execute cmd '%s'; error: %d %s",
1319 cmd, errno, strerror(errno));
1320 return HV_E_FAIL;
1321 }
1322 return 0;
1323
1324 setval_error:
1325 syslog(LOG_ERR, "Failed to write config file");
1326 fclose(file);
1327 return error;
1328 }
1329
1330
1331 static void
1332 kvp_get_domain_name(char *buffer, int length)
1333 {
1334 struct addrinfo hints, *info ;
1335 int error = 0;
1336
1337 gethostname(buffer, length);
1338 memset(&hints, 0, sizeof(hints));
1339 hints.ai_family = AF_INET;
1340 hints.ai_socktype = SOCK_STREAM;
1341 hints.ai_flags = AI_CANONNAME;
1342
1343 error = getaddrinfo(buffer, NULL, &hints, &info);
1344 if (error != 0) {
1345 snprintf(buffer, length, "getaddrinfo failed: 0x%x %s",
1346 error, gai_strerror(error));
1347 return;
1348 }
1349 snprintf(buffer, length, "%s", info->ai_canonname);
1350 freeaddrinfo(info);
1351 }
1352
1353 void print_usage(char *argv[])
1354 {
1355 fprintf(stderr, "Usage: %s [options]\n"
1356 "Options are:\n"
1357 " -n, --no-daemon stay in foreground, don't daemonize\n"
1358 " -h, --help print this help\n", argv[0]);
1359 }
1360
1361 int main(int argc, char *argv[])
1362 {
1363 int kvp_fd, len;
1364 int error;
1365 struct pollfd pfd;
1366 char *p;
1367 struct hv_kvp_msg hv_msg[1];
1368 char *key_value;
1369 char *key_name;
1370 int op;
1371 int pool;
1372 char *if_name;
1373 struct hv_kvp_ipaddr_value *kvp_ip_val;
1374 int daemonize = 1, long_index = 0, opt;
1375
1376 static struct option long_options[] = {
1377 {"help", no_argument, 0, 'h' },
1378 {"no-daemon", no_argument, 0, 'n' },
1379 {0, 0, 0, 0 }
1380 };
1381
1382 while ((opt = getopt_long(argc, argv, "hn", long_options,
1383 &long_index)) != -1) {
1384 switch (opt) {
1385 case 'n':
1386 daemonize = 0;
1387 break;
1388 case 'h':
1389 print_usage(argv);
1390 exit(0);
1391 default:
1392 print_usage(argv);
1393 exit(EXIT_FAILURE);
1394 }
1395 }
1396
1397 if (daemonize && daemon(1, 0))
1398 return 1;
1399
1400 openlog("KVP", 0, LOG_USER);
1401 syslog(LOG_INFO, "KVP starting; pid is:%d", getpid());
1402
1403 kvp_fd = open("/dev/vmbus/hv_kvp", O_RDWR | O_CLOEXEC);
1404
1405 if (kvp_fd < 0) {
1406 syslog(LOG_ERR, "open /dev/vmbus/hv_kvp failed; error: %d %s",
1407 errno, strerror(errno));
1408 exit(EXIT_FAILURE);
1409 }
1410
1411
1412
1413
1414 kvp_get_os_info();
1415
1416
1417
1418
1419 kvp_get_domain_name(full_domain_name, sizeof(full_domain_name));
1420
1421 if (kvp_file_init()) {
1422 syslog(LOG_ERR, "Failed to initialize the pools");
1423 exit(EXIT_FAILURE);
1424 }
1425
1426
1427
1428
1429 hv_msg->kvp_hdr.operation = KVP_OP_REGISTER1;
1430 len = write(kvp_fd, hv_msg, sizeof(struct hv_kvp_msg));
1431 if (len != sizeof(struct hv_kvp_msg)) {
1432 syslog(LOG_ERR, "registration to kernel failed; error: %d %s",
1433 errno, strerror(errno));
1434 close(kvp_fd);
1435 exit(EXIT_FAILURE);
1436 }
1437
1438 pfd.fd = kvp_fd;
1439
1440 while (1) {
1441 pfd.events = POLLIN;
1442 pfd.revents = 0;
1443
1444 if (poll(&pfd, 1, -1) < 0) {
1445 syslog(LOG_ERR, "poll failed; error: %d %s", errno, strerror(errno));
1446 if (errno == EINVAL) {
1447 close(kvp_fd);
1448 exit(EXIT_FAILURE);
1449 }
1450 else
1451 continue;
1452 }
1453
1454 len = read(kvp_fd, hv_msg, sizeof(struct hv_kvp_msg));
1455
1456 if (len != sizeof(struct hv_kvp_msg)) {
1457 syslog(LOG_ERR, "read failed; error:%d %s",
1458 errno, strerror(errno));
1459
1460 close(kvp_fd);
1461 return EXIT_FAILURE;
1462 }
1463
1464
1465
1466
1467
1468
1469 op = hv_msg->kvp_hdr.operation;
1470 pool = hv_msg->kvp_hdr.pool;
1471 hv_msg->error = HV_S_OK;
1472
1473 if ((in_hand_shake) && (op == KVP_OP_REGISTER1)) {
1474
1475
1476
1477
1478 in_hand_shake = 0;
1479 p = (char *)hv_msg->body.kvp_register.version;
1480 lic_version = malloc(strlen(p) + 1);
1481 if (lic_version) {
1482 strcpy(lic_version, p);
1483 syslog(LOG_INFO, "KVP LIC Version: %s",
1484 lic_version);
1485 } else {
1486 syslog(LOG_ERR, "malloc failed");
1487 }
1488 continue;
1489 }
1490
1491 switch (op) {
1492 case KVP_OP_GET_IP_INFO:
1493 kvp_ip_val = &hv_msg->body.kvp_ip_val;
1494
1495 error = kvp_mac_to_ip(kvp_ip_val);
1496
1497 if (error)
1498 hv_msg->error = error;
1499
1500 break;
1501
1502 case KVP_OP_SET_IP_INFO:
1503 kvp_ip_val = &hv_msg->body.kvp_ip_val;
1504 if_name = kvp_get_if_name(
1505 (char *)kvp_ip_val->adapter_id);
1506 if (if_name == NULL) {
1507
1508
1509
1510
1511 hv_msg->error = HV_GUID_NOTFOUND;
1512 break;
1513 }
1514 error = kvp_set_ip_info(if_name, kvp_ip_val);
1515 if (error)
1516 hv_msg->error = error;
1517
1518 free(if_name);
1519 break;
1520
1521 case KVP_OP_SET:
1522 if (kvp_key_add_or_modify(pool,
1523 hv_msg->body.kvp_set.data.key,
1524 hv_msg->body.kvp_set.data.key_size,
1525 hv_msg->body.kvp_set.data.value,
1526 hv_msg->body.kvp_set.data.value_size))
1527 hv_msg->error = HV_S_CONT;
1528 break;
1529
1530 case KVP_OP_GET:
1531 if (kvp_get_value(pool,
1532 hv_msg->body.kvp_set.data.key,
1533 hv_msg->body.kvp_set.data.key_size,
1534 hv_msg->body.kvp_set.data.value,
1535 hv_msg->body.kvp_set.data.value_size))
1536 hv_msg->error = HV_S_CONT;
1537 break;
1538
1539 case KVP_OP_DELETE:
1540 if (kvp_key_delete(pool,
1541 hv_msg->body.kvp_delete.key,
1542 hv_msg->body.kvp_delete.key_size))
1543 hv_msg->error = HV_S_CONT;
1544 break;
1545
1546 default:
1547 break;
1548 }
1549
1550 if (op != KVP_OP_ENUMERATE)
1551 goto kvp_done;
1552
1553
1554
1555
1556
1557
1558 if (pool != KVP_POOL_AUTO) {
1559 if (kvp_pool_enumerate(pool,
1560 hv_msg->body.kvp_enum_data.index,
1561 hv_msg->body.kvp_enum_data.data.key,
1562 HV_KVP_EXCHANGE_MAX_KEY_SIZE,
1563 hv_msg->body.kvp_enum_data.data.value,
1564 HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
1565 hv_msg->error = HV_S_CONT;
1566 goto kvp_done;
1567 }
1568
1569 key_name = (char *)hv_msg->body.kvp_enum_data.data.key;
1570 key_value = (char *)hv_msg->body.kvp_enum_data.data.value;
1571
1572 switch (hv_msg->body.kvp_enum_data.index) {
1573 case FullyQualifiedDomainName:
1574 strcpy(key_value, full_domain_name);
1575 strcpy(key_name, "FullyQualifiedDomainName");
1576 break;
1577 case IntegrationServicesVersion:
1578 strcpy(key_name, "IntegrationServicesVersion");
1579 strcpy(key_value, lic_version);
1580 break;
1581 case NetworkAddressIPv4:
1582 kvp_get_ip_info(AF_INET, NULL, KVP_OP_ENUMERATE,
1583 key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1584 strcpy(key_name, "NetworkAddressIPv4");
1585 break;
1586 case NetworkAddressIPv6:
1587 kvp_get_ip_info(AF_INET6, NULL, KVP_OP_ENUMERATE,
1588 key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1589 strcpy(key_name, "NetworkAddressIPv6");
1590 break;
1591 case OSBuildNumber:
1592 strcpy(key_value, os_build);
1593 strcpy(key_name, "OSBuildNumber");
1594 break;
1595 case OSName:
1596 strcpy(key_value, os_name);
1597 strcpy(key_name, "OSName");
1598 break;
1599 case OSMajorVersion:
1600 strcpy(key_value, os_major);
1601 strcpy(key_name, "OSMajorVersion");
1602 break;
1603 case OSMinorVersion:
1604 strcpy(key_value, os_minor);
1605 strcpy(key_name, "OSMinorVersion");
1606 break;
1607 case OSVersion:
1608 strcpy(key_value, os_version);
1609 strcpy(key_name, "OSVersion");
1610 break;
1611 case ProcessorArchitecture:
1612 strcpy(key_value, processor_arch);
1613 strcpy(key_name, "ProcessorArchitecture");
1614 break;
1615 default:
1616 hv_msg->error = HV_S_CONT;
1617 break;
1618 }
1619
1620
1621 kvp_done:
1622 len = write(kvp_fd, hv_msg, sizeof(struct hv_kvp_msg));
1623 if (len != sizeof(struct hv_kvp_msg)) {
1624 syslog(LOG_ERR, "write failed; error: %d %s", errno,
1625 strerror(errno));
1626 exit(EXIT_FAILURE);
1627 }
1628 }
1629
1630 close(kvp_fd);
1631 exit(0);
1632 }