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 }