From c9594c5a02a0d96ed294be96d5130f5fa2383737 Mon Sep 17 00:00:00 2001 From: Rolf Neugebauer Date: Tue, 20 Sep 2016 15:39:36 +0100 Subject: [PATCH] packages: remove hvtools Signed-off-by: Rolf Neugebauer --- alpine/Makefile | 1 - alpine/packages/Makefile | 2 +- alpine/packages/hvtools/.gitignore | 2 - alpine/packages/hvtools/Dockerfile | 8 - alpine/packages/hvtools/Makefile | 14 - alpine/packages/hvtools/README.md | 3 - .../packages/hvtools/etc/init.d/hv_kvp_daemon | 42 - .../packages/hvtools/etc/init.d/hv_vss_daemon | 37 - alpine/packages/hvtools/sbin/hv_get_dhcp_info | 30 - alpine/packages/hvtools/sbin/hv_get_dns_info | 13 - alpine/packages/hvtools/sbin/hv_set_ifconfig | 93 - alpine/packages/hvtools/src/Makefile | 13 - alpine/packages/hvtools/src/hv_fcopy_daemon.c | 221 -- .../packages/hvtools/src/hv_get_dhcp_info.sh | 28 - .../packages/hvtools/src/hv_get_dns_info.sh | 13 - alpine/packages/hvtools/src/hv_kvp_daemon.c | 1967 ----------------- .../packages/hvtools/src/hv_set_ifconfig.sh | 64 - alpine/packages/hvtools/src/hv_vss_daemon.c | 342 --- alpine/packages/hvtools/src/lsvmbus | 101 - 19 files changed, 1 insertion(+), 2993 deletions(-) delete mode 100644 alpine/packages/hvtools/.gitignore delete mode 100644 alpine/packages/hvtools/Dockerfile delete mode 100644 alpine/packages/hvtools/Makefile delete mode 100644 alpine/packages/hvtools/README.md delete mode 100755 alpine/packages/hvtools/etc/init.d/hv_kvp_daemon delete mode 100755 alpine/packages/hvtools/etc/init.d/hv_vss_daemon delete mode 100755 alpine/packages/hvtools/sbin/hv_get_dhcp_info delete mode 100755 alpine/packages/hvtools/sbin/hv_get_dns_info delete mode 100755 alpine/packages/hvtools/sbin/hv_set_ifconfig delete mode 100644 alpine/packages/hvtools/src/Makefile delete mode 100644 alpine/packages/hvtools/src/hv_fcopy_daemon.c delete mode 100755 alpine/packages/hvtools/src/hv_get_dhcp_info.sh delete mode 100755 alpine/packages/hvtools/src/hv_get_dns_info.sh delete mode 100644 alpine/packages/hvtools/src/hv_kvp_daemon.c delete mode 100755 alpine/packages/hvtools/src/hv_set_ifconfig.sh delete mode 100644 alpine/packages/hvtools/src/hv_vss_daemon.c delete mode 100755 alpine/packages/hvtools/src/lsvmbus diff --git a/alpine/Makefile b/alpine/Makefile index 06523409d..84a47dc66 100644 --- a/alpine/Makefile +++ b/alpine/Makefile @@ -16,7 +16,6 @@ initrd.img: Dockerfile mkinitrd.sh init $(ETCFILES) -C packages/automount etc -C ../.. \ -C packages/binfmt_misc etc -C ../.. \ -C packages/hostsettings etc -C ../.. \ - -C packages/hvtools sbin etc usr -C ../.. \ -C packages/chronyd etc -C ../.. \ -C packages/userns etc -C ../.. \ -C packages/nc-vsock usr -C ../.. \ diff --git a/alpine/packages/Makefile b/alpine/packages/Makefile index 4af716eca..b2166e303 100644 --- a/alpine/packages/Makefile +++ b/alpine/packages/Makefile @@ -1,4 +1,4 @@ -DEPS=proxy diagnostics transfused tap-vsockd hvtools docker nc-vsock vsudd 9pmount-vsock iptables +DEPS=proxy diagnostics transfused tap-vsockd docker nc-vsock vsudd 9pmount-vsock iptables .PHONY: clean $(DEPS) default: $(DEPS) diff --git a/alpine/packages/hvtools/.gitignore b/alpine/packages/hvtools/.gitignore deleted file mode 100644 index cf40cde3b..000000000 --- a/alpine/packages/hvtools/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -sbin/ -usr/ diff --git a/alpine/packages/hvtools/Dockerfile b/alpine/packages/hvtools/Dockerfile deleted file mode 100644 index 49e8a932a..000000000 --- a/alpine/packages/hvtools/Dockerfile +++ /dev/null @@ -1,8 +0,0 @@ -FROM mobylinux/alpine-build-c:1ea690a7438cdd8a5965eaa034e0a0c521d9cb40 - -COPY src /hvtools/ - -WORKDIR /hvtools -RUN make - -CMD ["tar", "cf", "-", "hv_fcopy_daemon", "hv_kvp_daemon", "hv_vss_daemon"] diff --git a/alpine/packages/hvtools/Makefile b/alpine/packages/hvtools/Makefile deleted file mode 100644 index 936858ccb..000000000 --- a/alpine/packages/hvtools/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -all: sbin/hv_fcopy_daemon usr/share/src/hvtools.tar.gz - -sbin/hv_fcopy_daemon: Dockerfile src/* - tar cf - Dockerfile src | docker build -t hvtools:build - - docker run --rm --net=none hvtools:build | tar xf - -C sbin - -usr/share/src/hvtools.tar.gz: src/* - mkdir -p usr/share/src/ - tar czf usr/share/src/hvtools.tar.gz src - -clean: - rm -rf usr sbin/hv_fcopy_daemon sbin/hv_kvp_daemon sbin/hv_vss_daemon - -.DELETE_ON_ERROR: diff --git a/alpine/packages/hvtools/README.md b/alpine/packages/hvtools/README.md deleted file mode 100644 index 5cbafcadd..000000000 --- a/alpine/packages/hvtools/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Hyper-V guest tools and daemons - -This package contains a copy of the ./tools/hv directory of the matching Linux kernel source in ./src. At the top level directory are customised versions of the various scripts used by the daemons. diff --git a/alpine/packages/hvtools/etc/init.d/hv_kvp_daemon b/alpine/packages/hvtools/etc/init.d/hv_kvp_daemon deleted file mode 100755 index 952bca4d2..000000000 --- a/alpine/packages/hvtools/etc/init.d/hv_kvp_daemon +++ /dev/null @@ -1,42 +0,0 @@ -#!/sbin/openrc-run - -HV_DAEMON=hv_kvp_daemon - -depend() -{ - after dev - need networking - before docker proxy vsudd diagnostics -} - -start() -{ - [ "$(mobyplatform)" != "windows" ] && exit 0 - - ebegin "Starting Hyper-V Daemon: ${HV_DAEMON}" - - # Delete the existing store - rm -rf /var/lib/hyperv - - [ -n "${PIDFILE}" ] || PIDFILE=/var/run/${HV_DAEMON}.pid - - start-stop-daemon --start --quiet \ - --background \ - --exec /sbin/${HV_DAEMON} \ - --make-pidfile --pidfile ${PIDFILE} \ - -- - eend 0 -} - -stop() -{ - [ "$(mobyplatform)" != "windows" ] && exit 0 - - ebegin "Stopping Hyper-V Daemon: ${HV_DAEMON}" - - [ -n "${PIDFILE}" ] || PIDFILE=/var/run/${HV_DAEMON}.pid - - start-stop-daemon --stop --quiet --pidfile ${PIDFILE} - - eend $? "Failed to stop ${HV_DAEMON}" -} diff --git a/alpine/packages/hvtools/etc/init.d/hv_vss_daemon b/alpine/packages/hvtools/etc/init.d/hv_vss_daemon deleted file mode 100755 index 609c83cf0..000000000 --- a/alpine/packages/hvtools/etc/init.d/hv_vss_daemon +++ /dev/null @@ -1,37 +0,0 @@ -#!/sbin/openrc-run - -HV_DAEMON=hv_vss_daemon - -depend() -{ - after dev -} - -start() -{ - [ "$(mobyplatform)" != "windows" ] && exit 0 - - ebegin "Starting Hyper-V Daemon: ${HV_DAEMON}" - - [ -n "${PIDFILE}" ] || PIDFILE=/var/run/${HV_DAEMON}.pid - - start-stop-daemon --start --quiet \ - --background \ - --exec /sbin/${HV_DAEMON} \ - --make-pidfile --pidfile ${PIDFILE} \ - -- - eend 0 -} - -stop() -{ - [ "$(mobyplatform)" != "windows" ] && exit 0 - - ebegin "Stopping Hyper-V Daemon: ${HV_DAEMON}" - - [ -n "${PIDFILE}" ] || PIDFILE=/var/run/${HV_DAEMON}.pid - - start-stop-daemon --stop --quiet --pidfile ${PIDFILE} - - eend $? "Failed to stop ${HV_DAEMON}" -} diff --git a/alpine/packages/hvtools/sbin/hv_get_dhcp_info b/alpine/packages/hvtools/sbin/hv_get_dhcp_info deleted file mode 100755 index 65ce927e0..000000000 --- a/alpine/packages/hvtools/sbin/hv_get_dhcp_info +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash - -# Adjusted for Alpine - -# This example script retrieves the DHCP state of a given interface. -# In the interest of keeping the KVP daemon code free of distro specific -# information; the kvp daemon code invokes this external script to gather -# DHCP setting for the specific interface. -# -# Input: Name of the interface -# -# Output: The script prints the string "Enabled" to stdout to indicate -# that DHCP is enabled on the interface. If DHCP is not enabled, -# the script prints the string "Disabled" to stdout. -# -# Each Distro is expected to implement this script in a distro specific -# fashion. For instance on Distros that ship with Network Manager enabled, -# this script can be based on the Network Manager APIs for retrieving DHCP -# information. - -if_file="/etc/network/interfaces" - -dhcp=$(grep "$1.*dhcp" $if_file 2>/dev/null) - -if [ "$dhcp" != "" ]; -then -echo "Enabled" -else -echo "Disabled" -fi diff --git a/alpine/packages/hvtools/sbin/hv_get_dns_info b/alpine/packages/hvtools/sbin/hv_get_dns_info deleted file mode 100755 index 058c17b46..000000000 --- a/alpine/packages/hvtools/sbin/hv_get_dns_info +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -# This example script parses /etc/resolv.conf to retrive DNS information. -# In the interest of keeping the KVP daemon code free of distro specific -# information; the kvp daemon code invokes this external script to gather -# DNS information. -# This script is expected to print the nameserver values to stdout. -# Each Distro is expected to implement this script in a distro specific -# fashion. For instance on Distros that ship with Network Manager enabled, -# this script can be based on the Network Manager APIs for retrieving DNS -# entries. - -cat /etc/resolv.conf 2>/dev/null | awk '/^nameserver/ { print $2 }' diff --git a/alpine/packages/hvtools/sbin/hv_set_ifconfig b/alpine/packages/hvtools/sbin/hv_set_ifconfig deleted file mode 100755 index e6a115371..000000000 --- a/alpine/packages/hvtools/sbin/hv_set_ifconfig +++ /dev/null @@ -1,93 +0,0 @@ -#!/bin/sh - -# This example script activates an interface based on the specified -# configuration. -# -# In the interest of keeping the KVP daemon code free of distro specific -# information; the kvp daemon code invokes this external script to configure -# the interface. -# -# The only argument to this script is the configuration file that is to -# be used to configure the interface. -# -# Each Distro is expected to implement this script in a distro specific -# fashion. For instance on Distros that ship with Network Manager enabled, -# this script can be based on the Network Manager APIs for configuring the -# interface. -# -# This example script is based on a RHEL environment. -# -# Here is the format of the ip configuration file: -# -# HWADDR=macaddr -# DEVICE=interface name -# BOOTPROTO= (where is "dhcp" if DHCP is configured -# or "none" if no boot-time protocol should be used) -# -# IPADDR0=ipaddr1 -# IPADDR1=ipaddr2 -# IPADDRx=ipaddry (where y = x + 1) -# -# NETMASK0=netmask1 -# NETMASKx=netmasky (where y = x + 1) -# -# GATEWAY=ipaddr1 -# GATEWAYx=ipaddry (where y = x + 1) -# -# DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc) -# -# IPV6 addresses will be tagged as IPV6ADDR, IPV6 gateway will be -# tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as -# IPV6NETMASK. -# -# The host can specify multiple ipv4 and ipv6 addresses to be -# configured for the interface. Furthermore, the configuration -# needs to be persistent. A subsequent GET call on the interface -# is expected to return the configuration that is set via the SET -# call. -# - - -## -## XXX This is really hacky. We just whack the existing -## /etc/network/interfaces and also only configure IPv4. This will -## break with multiple network interfaces etc. -## - - -# Stash away a copy of the config we got -cp $1 /etc/network/hv_config - -# Source it -. $1 - -# Down the interface -ifdown -f $DEVICE - -# create a new interfaces file -outf=/etc/network/interfaces -echo "auto lo" > $outf -echo "iface lo inet loopback" >> $outf -echo "" >> $outf -echo "auto $DEVICE" >> $outf - -if [ "$BOOTPROTO" = "dhcp" ]; then - echo "iface $DEVICE inet dhcp" >> $outf -else - echo "iface $DEVICE inet static" >> $outf - echo " address $IPADDR0" >> $outf - echo " netmask $NETMASK0" >> $outf - echo " gateway $GATEWAY" >> $outf -fi - -echo " hwaddress ether $HWADDR" >> $outf - -# create a new resolve.conf file -outf=/etc/resolv.conf -[ -n "$DNS1" ] && echo "nameserver $DNS1" > $outf -[ -n "$DNS2" ] && echo "nameserver $DNS2" >> $outf -[ -n "$DNS3" ] && echo "nameserver $DNS3" >> $outf -[ -n "$DNS4" ] && echo "nameserver $DNS4" >> $outf - -# Up the interface -ifup $DEVICE diff --git a/alpine/packages/hvtools/src/Makefile b/alpine/packages/hvtools/src/Makefile deleted file mode 100644 index a8ab79556..000000000 --- a/alpine/packages/hvtools/src/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# Makefile for Hyper-V tools - -CC = $(CROSS_COMPILE)gcc -PTHREAD_LIBS = -lpthread -WARNINGS = -Wall -Wextra -CFLAGS = $(WARNINGS) -g $(PTHREAD_LIBS) $(shell getconf LFS_CFLAGS) - -all: hv_kvp_daemon hv_vss_daemon hv_fcopy_daemon -%: %.c - $(CC) $(CFLAGS) -o $@ $^ - -clean: - $(RM) hv_kvp_daemon hv_vss_daemon hv_fcopy_daemon diff --git a/alpine/packages/hvtools/src/hv_fcopy_daemon.c b/alpine/packages/hvtools/src/hv_fcopy_daemon.c deleted file mode 100644 index 9445d8f26..000000000 --- a/alpine/packages/hvtools/src/hv_fcopy_daemon.c +++ /dev/null @@ -1,221 +0,0 @@ -/* - * An implementation of host to guest copy functionality for Linux. - * - * Copyright (C) 2014, Microsoft, Inc. - * - * Author : K. Y. Srinivasan - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int target_fd; -static char target_fname[W_MAX_PATH]; - -static int hv_start_fcopy(struct hv_start_fcopy *smsg) -{ - int error = HV_E_FAIL; - char *q, *p; - - p = (char *)smsg->path_name; - snprintf(target_fname, sizeof(target_fname), "%s/%s", - (char *)smsg->path_name, (char *)smsg->file_name); - - syslog(LOG_INFO, "Target file name: %s", target_fname); - /* - * Check to see if the path is already in place; if not, - * create if required. - */ - while ((q = strchr(p, '/')) != NULL) { - if (q == p) { - p++; - continue; - } - *q = '\0'; - if (access((char *)smsg->path_name, F_OK)) { - if (smsg->copy_flags & CREATE_PATH) { - if (mkdir((char *)smsg->path_name, 0755)) { - syslog(LOG_ERR, "Failed to create %s", - (char *)smsg->path_name); - goto done; - } - } else { - syslog(LOG_ERR, "Invalid path: %s", - (char *)smsg->path_name); - goto done; - } - } - p = q + 1; - *q = '/'; - } - - if (!access(target_fname, F_OK)) { - syslog(LOG_INFO, "File: %s exists", target_fname); - if (!(smsg->copy_flags & OVER_WRITE)) { - error = HV_ERROR_ALREADY_EXISTS; - goto done; - } - } - - target_fd = open(target_fname, - O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0744); - if (target_fd == -1) { - syslog(LOG_INFO, "Open Failed: %s", strerror(errno)); - goto done; - } - - error = 0; -done: - return error; -} - -static int hv_copy_data(struct hv_do_fcopy *cpmsg) -{ - ssize_t bytes_written; - - bytes_written = pwrite(target_fd, cpmsg->data, cpmsg->size, - cpmsg->offset); - - if (bytes_written != cpmsg->size) - return HV_E_FAIL; - - return 0; -} - -static int hv_copy_finished(void) -{ - close(target_fd); - return 0; -} -static int hv_copy_cancel(void) -{ - close(target_fd); - unlink(target_fname); - return 0; - -} - -void print_usage(char *argv[]) -{ - fprintf(stderr, "Usage: %s [options]\n" - "Options are:\n" - " -n, --no-daemon stay in foreground, don't daemonize\n" - " -h, --help print this help\n", argv[0]); -} - -int main(int argc, char *argv[]) -{ - int fcopy_fd, len; - int error; - int daemonize = 1, long_index = 0, opt; - int version = FCOPY_CURRENT_VERSION; - char *buffer[4096 * 2]; - struct hv_fcopy_hdr *in_msg; - - static struct option long_options[] = { - {"help", no_argument, 0, 'h' }, - {"no-daemon", no_argument, 0, 'n' }, - {0, 0, 0, 0 } - }; - - while ((opt = getopt_long(argc, argv, "hn", long_options, - &long_index)) != -1) { - switch (opt) { - case 'n': - daemonize = 0; - break; - case 'h': - default: - print_usage(argv); - exit(EXIT_FAILURE); - } - } - - if (daemonize && daemon(1, 0)) { - syslog(LOG_ERR, "daemon() failed; error: %s", strerror(errno)); - exit(EXIT_FAILURE); - } - - openlog("HV_FCOPY", 0, LOG_USER); - syslog(LOG_INFO, "HV_FCOPY starting; pid is:%d", getpid()); - - fcopy_fd = open("/dev/vmbus/hv_fcopy", O_RDWR); - - if (fcopy_fd < 0) { - syslog(LOG_ERR, "open /dev/vmbus/hv_fcopy failed; error: %d %s", - errno, strerror(errno)); - exit(EXIT_FAILURE); - } - - /* - * Register with the kernel. - */ - if ((write(fcopy_fd, &version, sizeof(int))) != sizeof(int)) { - syslog(LOG_ERR, "Registration failed: %s", strerror(errno)); - exit(EXIT_FAILURE); - } - - while (1) { - /* - * In this loop we process fcopy messages after the - * handshake is complete. - */ - len = pread(fcopy_fd, buffer, (4096 * 2), 0); - if (len < 0) { - syslog(LOG_ERR, "pread failed: %s", strerror(errno)); - exit(EXIT_FAILURE); - } - in_msg = (struct hv_fcopy_hdr *)buffer; - - switch (in_msg->operation) { - case START_FILE_COPY: - error = hv_start_fcopy((struct hv_start_fcopy *)in_msg); - break; - case WRITE_TO_FILE: - error = hv_copy_data((struct hv_do_fcopy *)in_msg); - break; - case COMPLETE_FCOPY: - error = hv_copy_finished(); - break; - case CANCEL_FCOPY: - error = hv_copy_cancel(); - break; - - default: - syslog(LOG_ERR, "Unknown operation: %d", - in_msg->operation); - - } - - if (pwrite(fcopy_fd, &error, sizeof(int), 0) != sizeof(int)) { - syslog(LOG_ERR, "pwrite failed: %s", strerror(errno)); - exit(EXIT_FAILURE); - } - } -} diff --git a/alpine/packages/hvtools/src/hv_get_dhcp_info.sh b/alpine/packages/hvtools/src/hv_get_dhcp_info.sh deleted file mode 100755 index ccd3e9532..000000000 --- a/alpine/packages/hvtools/src/hv_get_dhcp_info.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash - -# This example script retrieves the DHCP state of a given interface. -# In the interest of keeping the KVP daemon code free of distro specific -# information; the kvp daemon code invokes this external script to gather -# DHCP setting for the specific interface. -# -# Input: Name of the interface -# -# Output: The script prints the string "Enabled" to stdout to indicate -# that DHCP is enabled on the interface. If DHCP is not enabled, -# the script prints the string "Disabled" to stdout. -# -# Each Distro is expected to implement this script in a distro specific -# fashion. For instance on Distros that ship with Network Manager enabled, -# this script can be based on the Network Manager APIs for retrieving DHCP -# information. - -if_file="/etc/sysconfig/network-scripts/ifcfg-"$1 - -dhcp=$(grep "dhcp" $if_file 2>/dev/null) - -if [ "$dhcp" != "" ]; -then -echo "Enabled" -else -echo "Disabled" -fi diff --git a/alpine/packages/hvtools/src/hv_get_dns_info.sh b/alpine/packages/hvtools/src/hv_get_dns_info.sh deleted file mode 100755 index 058c17b46..000000000 --- a/alpine/packages/hvtools/src/hv_get_dns_info.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -# This example script parses /etc/resolv.conf to retrive DNS information. -# In the interest of keeping the KVP daemon code free of distro specific -# information; the kvp daemon code invokes this external script to gather -# DNS information. -# This script is expected to print the nameserver values to stdout. -# Each Distro is expected to implement this script in a distro specific -# fashion. For instance on Distros that ship with Network Manager enabled, -# this script can be based on the Network Manager APIs for retrieving DNS -# entries. - -cat /etc/resolv.conf 2>/dev/null | awk '/^nameserver/ { print $2 }' diff --git a/alpine/packages/hvtools/src/hv_kvp_daemon.c b/alpine/packages/hvtools/src/hv_kvp_daemon.c deleted file mode 100644 index 2ec9aca30..000000000 --- a/alpine/packages/hvtools/src/hv_kvp_daemon.c +++ /dev/null @@ -1,1967 +0,0 @@ -/* - * An implementation of key value pair (KVP) functionality for Linux. - * - * - * Copyright (C) 2010, Novell, Inc. - * Author : K. Y. Srinivasan - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * KVP protocol: The user mode component first registers with the - * the kernel component. Subsequently, the kernel component requests, data - * for the specified keys. In response to this message the user mode component - * fills in the value corresponding to the specified key. We overload the - * sequence field in the cn_msg header to define our KVP message types. - * - * We use this infrastructure for also supporting queries from user mode - * application for state that may be maintained in the KVP kernel component. - * - */ - - -enum key_index { - FullyQualifiedDomainName = 0, - IntegrationServicesVersion, /*This key is serviced in the kernel*/ - NetworkAddressIPv4, - NetworkAddressIPv6, - OSBuildNumber, - OSName, - OSMajorVersion, - OSMinorVersion, - OSVersion, - ProcessorArchitecture -}; - - -enum { - IPADDR = 0, - NETMASK, - GATEWAY, - DNS -}; - -static struct sockaddr_nl addr; -static int in_hand_shake = 1; - -static char *os_name = ""; -static char *os_major = ""; -static char *os_minor = ""; -static char *processor_arch; -static char *os_build; -static char *os_version; -static char *lic_version = "Unknown version"; -static char full_domain_name[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; -static struct utsname uts_buf; - -/* - * The location of the interface configuration file. - */ - -#define KVP_CONFIG_LOC "/var/lib/hyperv" - -#define MAX_FILE_NAME 100 -#define ENTRIES_PER_BLOCK 50 - -#ifndef SOL_NETLINK -#define SOL_NETLINK 270 -#endif - -struct kvp_record { - char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; - char value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; -}; - -struct kvp_file_state { - int fd; - int num_blocks; - struct kvp_record *records; - int num_records; - char fname[MAX_FILE_NAME]; -}; - -static struct kvp_file_state kvp_file_info[KVP_POOL_COUNT]; - - -static void kvp_process_ipconfig_file(char *cmd, - char *config_buf, unsigned int len, - int element_size, int offset); - - -static void kvp_acquire_lock(int pool) -{ - struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0}; - fl.l_pid = getpid(); - - if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) { - syslog(LOG_ERR, "Failed to acquire the lock pool: %d; error: %d %s", pool, - errno, strerror(errno)); - exit(EXIT_FAILURE); - } -} - -static void kvp_release_lock(int pool) -{ - struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0}; - fl.l_pid = getpid(); - - if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) { - syslog(LOG_ERR, "Failed to release the lock pool: %d; error: %d %s", pool, - errno, strerror(errno)); - exit(EXIT_FAILURE); - } -} - -static void kvp_update_file(int pool) -{ - FILE *filep; - - /* - * We are going to write our in-memory registry out to - * disk; acquire the lock first. - */ - kvp_acquire_lock(pool); - - filep = fopen(kvp_file_info[pool].fname, "we"); - if (!filep) { - syslog(LOG_ERR, "Failed to open file, pool: %d; error: %d %s", pool, - errno, strerror(errno)); - kvp_release_lock(pool); - exit(EXIT_FAILURE); - } - - fwrite(kvp_file_info[pool].records, sizeof(struct kvp_record), - kvp_file_info[pool].num_records, filep); - - if (ferror(filep) || fclose(filep)) { - kvp_release_lock(pool); - syslog(LOG_ERR, "Failed to write file, pool: %d", pool); - exit(EXIT_FAILURE); - } - - kvp_release_lock(pool); -} - -static void kvp_update_mem_state(int pool) -{ - FILE *filep; - size_t records_read = 0; - struct kvp_record *record = kvp_file_info[pool].records; - struct kvp_record *readp; - int num_blocks = kvp_file_info[pool].num_blocks; - int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK; - - kvp_acquire_lock(pool); - - filep = fopen(kvp_file_info[pool].fname, "re"); - if (!filep) { - syslog(LOG_ERR, "Failed to open file, pool: %d; error: %d %s", pool, - errno, strerror(errno)); - kvp_release_lock(pool); - exit(EXIT_FAILURE); - } - for (;;) { - readp = &record[records_read]; - records_read += fread(readp, sizeof(struct kvp_record), - ENTRIES_PER_BLOCK * num_blocks, - filep); - - if (ferror(filep)) { - syslog(LOG_ERR, "Failed to read file, pool: %d", pool); - exit(EXIT_FAILURE); - } - - if (!feof(filep)) { - /* - * We have more data to read. - */ - num_blocks++; - record = realloc(record, alloc_unit * num_blocks); - - if (record == NULL) { - syslog(LOG_ERR, "malloc failed"); - exit(EXIT_FAILURE); - } - continue; - } - break; - } - - kvp_file_info[pool].num_blocks = num_blocks; - kvp_file_info[pool].records = record; - kvp_file_info[pool].num_records = records_read; - - fclose(filep); - kvp_release_lock(pool); -} -static int kvp_file_init(void) -{ - int fd; - FILE *filep; - size_t records_read; - char *fname; - struct kvp_record *record; - struct kvp_record *readp; - int num_blocks; - int i; - int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK; - - if (access(KVP_CONFIG_LOC, F_OK)) { - if (mkdir(KVP_CONFIG_LOC, 0755 /* rwxr-xr-x */)) { - syslog(LOG_ERR, "Failed to create '%s'; error: %d %s", KVP_CONFIG_LOC, - errno, strerror(errno)); - exit(EXIT_FAILURE); - } - } - - for (i = 0; i < KVP_POOL_COUNT; i++) { - fname = kvp_file_info[i].fname; - records_read = 0; - num_blocks = 1; - sprintf(fname, "%s/.kvp_pool_%d", KVP_CONFIG_LOC, i); - fd = open(fname, O_RDWR | O_CREAT | O_CLOEXEC, 0644 /* rw-r--r-- */); - - if (fd == -1) - return 1; - - - filep = fopen(fname, "re"); - if (!filep) { - close(fd); - return 1; - } - - record = malloc(alloc_unit * num_blocks); - if (record == NULL) { - fclose(filep); - close(fd); - return 1; - } - for (;;) { - readp = &record[records_read]; - records_read += fread(readp, sizeof(struct kvp_record), - ENTRIES_PER_BLOCK, - filep); - - if (ferror(filep)) { - syslog(LOG_ERR, "Failed to read file, pool: %d", - i); - exit(EXIT_FAILURE); - } - - if (!feof(filep)) { - /* - * We have more data to read. - */ - num_blocks++; - record = realloc(record, alloc_unit * - num_blocks); - if (record == NULL) { - fclose(filep); - close(fd); - return 1; - } - continue; - } - break; - } - kvp_file_info[i].fd = fd; - kvp_file_info[i].num_blocks = num_blocks; - kvp_file_info[i].records = record; - kvp_file_info[i].num_records = records_read; - fclose(filep); - - } - - return 0; -} - -static int kvp_key_delete(int pool, const __u8 *key, int key_size) -{ - int i; - int j, k; - int num_records; - struct kvp_record *record; - - /* - * First update the in-memory state. - */ - kvp_update_mem_state(pool); - - num_records = kvp_file_info[pool].num_records; - record = kvp_file_info[pool].records; - - for (i = 0; i < num_records; i++) { - if (memcmp(key, record[i].key, key_size)) - continue; - /* - * Found a match; just move the remaining - * entries up. - */ - if (i == num_records) { - kvp_file_info[pool].num_records--; - kvp_update_file(pool); - return 0; - } - - j = i; - k = j + 1; - for (; k < num_records; k++) { - strcpy(record[j].key, record[k].key); - strcpy(record[j].value, record[k].value); - j++; - } - - kvp_file_info[pool].num_records--; - kvp_update_file(pool); - return 0; - } - return 1; -} - -/* - * CFIS/SMB mount a directory from the host. - * - * The format of the value is "\n\n\n\n", where options are either - * "" or - * "domain=,". - */ -static int kvp_cifs_mount(const char *value) -{ - char val[1024]; - char mntcmd[2048]; - char *mntpoint; - char *bindpoint; - char *username; - char *password; - char *options; - char *t; - - char gw[256]; - char gwcmd[] = "ip route show | grep 'eth0' | awk '/default/ {print $3 }'"; - char credname[] = "/tmp/credXXXXXX"; - int fd; - FILE *fp; - - int ret, i, count; - - if (strlen(value) >= sizeof(val)) { - syslog(LOG_ERR, "mount: value is too long"); - return -1; - } - - /* Always mount from the gateway */ - kvp_process_ipconfig_file(gwcmd, gw, sizeof(gw), - INET_ADDRSTRLEN, 0); - - /* The above adds a ';' at the end, whack it */ - gw[strlen(gw) - 1] = '\0'; - - - /* Parse the value: - * Make sure we have the right number of '\n'. Makes the code - * below simpler: no check for strchr() return value required. */ - for (i = 0, count = 0; value[i]; i++) - count += (value[i] == '\n'); - if (count != 4) { - syslog(LOG_ERR, "mount: Malformed value. %d lines", count); - return -1; - } - - (void)strncpy(val, value, sizeof(val)); - mntpoint = val; - t = strchr(mntpoint, '\n'); - *t = '\0'; - - bindpoint = t + 1; - t = strchr(bindpoint, '\n'); - *t = '\0'; - - username = t + 1; - t = strchr(username, '\n'); - *t = '\0'; - - password = t + 1; - t = strchr(password, '\n'); - *t = '\0'; - - options = t + 1; - - /* Write credentials file */ - fd = mkstemp(credname); - if (fd < 0) { - syslog(LOG_ERR, "mount: failed to create cred file. %d %s", - errno, strerror(errno)); - return -1; - } - fp = fdopen(fd, "w"); - if (!fp) { - syslog(LOG_ERR, "mount: failed to open cred stream. %d %s", - errno, strerror(errno)); - ret = -1; - close(fd); - goto err_unlink; - } - ret = fprintf(fp, "username=%s\n", username); - if (ret < 0) { - syslog(LOG_ERR, "mount: failed to add username. %d %s", - errno, strerror(errno)); - fclose(fp); - goto err_unlink; - } - fprintf(fp, "password=%s\n", password); - if (ret < 0) { - syslog(LOG_ERR, "mount: failed to add password. %d %s", - errno, strerror(errno)); - fclose(fp); - goto err_unlink; - } - fclose(fp); - - /* Execute the mount */ - syslog(LOG_INFO, "mount: cifs //%s%s to %s and %s", - gw, mntpoint, mntpoint, bindpoint); - - snprintf(mntcmd, sizeof(mntcmd), - "mkdir -p %s && " - "mkdir -p %s && " - "mount.cifs //%s%s %s -o %s,credentials=%s && " - "mount --bind %s %s", - mntpoint, bindpoint, - gw, mntpoint, mntpoint, options, credname, - mntpoint, bindpoint); - - ret = system(mntcmd); - if (ret) - syslog(LOG_ERR, "mount: error: %d %s", errno, strerror(errno)); - -err_unlink: - unlink(credname); - return ret; -} - -/* - * CFIS/SMB un-mount a directory from the host. - * - * Value has the format: "\n". - */ -static int kvp_cifs_umount(const char *value) -{ - char val[1024]; - char umntcmd[2048]; - char *mntpoint; - char *bindpoint; - - if (strlen(value) >= sizeof(val)) { - syslog(LOG_ERR, "umount: value is too long"); - return -1; - } - - (void)strncpy(val, value, sizeof(val)); - - bindpoint = strchr(val, '\n'); - if (!bindpoint) { - syslog(LOG_ERR, "umount: Malformed value. %s", value); - return -1; - } - - mntpoint = val; - *bindpoint = '\0'; - bindpoint++; - - syslog(LOG_INFO, "umount: %s and %s", mntpoint, bindpoint); - - snprintf(umntcmd, sizeof(umntcmd), - "umount %s && " - "umount %s && " - "rmdir %s && " - "rmdir %s", - mntpoint, bindpoint, mntpoint, bindpoint); - - if (system(umntcmd)) { - syslog(LOG_ERR, "umount: error: %d %s", errno, strerror(errno)); - return 1; - } - return 0; -} - - -static int kvp_key_add_or_modify(int pool, const __u8 *key, int key_size, - const __u8 *value, int value_size) -{ - int i; - int num_records; - struct kvp_record *record; - int num_blocks; - - if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) || - (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) - return 1; - - /* Check for special keys. These are not stored in the store */ - if (strncmp((char *)key, "cifsmount", key_size) == 0) - return kvp_cifs_mount((const char *)value); - else if (strncmp((char *)key, "cifsumount", key_size) == 0) - return kvp_cifs_umount((const char *)value); - - - syslog(LOG_INFO, "KVP Add or Mod key=%s val=%s", key, value); - - /* - * First update the in-memory state. - */ - kvp_update_mem_state(pool); - - num_records = kvp_file_info[pool].num_records; - record = kvp_file_info[pool].records; - num_blocks = kvp_file_info[pool].num_blocks; - - for (i = 0; i < num_records; i++) { - if (memcmp(key, record[i].key, key_size)) - continue; - /* - * Found a match; just update the value - - * this is the modify case. - */ - memcpy(record[i].value, value, value_size); - kvp_update_file(pool); - return 0; - } - - /* - * Need to add a new entry; - */ - if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) { - /* Need to allocate a larger array for reg entries. */ - record = realloc(record, sizeof(struct kvp_record) * - ENTRIES_PER_BLOCK * (num_blocks + 1)); - - if (record == NULL) - return 1; - - kvp_file_info[pool].num_blocks++; - } - - memcpy(record[i].value, value, value_size); - memcpy(record[i].key, key, key_size); - kvp_file_info[pool].records = record; - kvp_file_info[pool].num_records++; - kvp_update_file(pool); - return 0; -} - -static int kvp_get_value(int pool, const __u8 *key, int key_size, __u8 *value, - int value_size) -{ - int i; - int num_records; - struct kvp_record *record; - - if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) || - (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) - return 1; - - /* - * First update the in-memory state. - */ - kvp_update_mem_state(pool); - - num_records = kvp_file_info[pool].num_records; - record = kvp_file_info[pool].records; - - for (i = 0; i < num_records; i++) { - if (memcmp(key, record[i].key, key_size)) - continue; - /* - * Found a match; just copy the value out. - */ - memcpy(value, record[i].value, value_size); - return 0; - } - - return 1; -} - -static int kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size, - __u8 *value, int value_size) -{ - struct kvp_record *record; - - /* - * First update our in-memory database. - */ - kvp_update_mem_state(pool); - record = kvp_file_info[pool].records; - - if (index >= kvp_file_info[pool].num_records) { - return 1; - } - - memcpy(key, record[index].key, key_size); - memcpy(value, record[index].value, value_size); - return 0; -} - - -void kvp_get_os_info(void) -{ - FILE *file; - char *p, buf[512]; - - uname(&uts_buf); - os_version = uts_buf.release; - os_build = strdup(uts_buf.release); - - os_name = uts_buf.sysname; - processor_arch = uts_buf.machine; - - /* - * The current windows host (win7) expects the build - * string to be of the form: x.y.z - * Strip additional information we may have. - */ - p = strchr(os_version, '-'); - if (p) - *p = '\0'; - - /* - * Parse the /etc/os-release file if present: - * http://www.freedesktop.org/software/systemd/man/os-release.html - */ - file = fopen("/etc/os-release", "r"); - if (file != NULL) { - while (fgets(buf, sizeof(buf), file)) { - char *value, *q; - - /* Ignore comments */ - if (buf[0] == '#') - continue; - - /* Split into name=value */ - p = strchr(buf, '='); - if (!p) - continue; - *p++ = 0; - - /* Remove quotes and newline; un-escape */ - value = p; - q = p; - while (*p) { - if (*p == '\\') { - ++p; - if (!*p) - break; - *q++ = *p++; - } else if (*p == '\'' || *p == '"' || - *p == '\n') { - ++p; - } else { - *q++ = *p++; - } - } - *q = 0; - - if (!strcmp(buf, "NAME")) { - p = strdup(value); - if (!p) - break; - os_name = p; - } else if (!strcmp(buf, "VERSION_ID")) { - p = strdup(value); - if (!p) - break; - os_major = p; - } - } - fclose(file); - return; - } - - /* Fallback for older RH/SUSE releases */ - file = fopen("/etc/SuSE-release", "r"); - if (file != NULL) - goto kvp_osinfo_found; - file = fopen("/etc/redhat-release", "r"); - if (file != NULL) - goto kvp_osinfo_found; - - /* - * We don't have information about the os. - */ - return; - -kvp_osinfo_found: - /* up to three lines */ - p = fgets(buf, sizeof(buf), file); - if (p) { - p = strchr(buf, '\n'); - if (p) - *p = '\0'; - p = strdup(buf); - if (!p) - goto done; - os_name = p; - - /* second line */ - p = fgets(buf, sizeof(buf), file); - if (p) { - p = strchr(buf, '\n'); - if (p) - *p = '\0'; - p = strdup(buf); - if (!p) - goto done; - os_major = p; - - /* third line */ - p = fgets(buf, sizeof(buf), file); - if (p) { - p = strchr(buf, '\n'); - if (p) - *p = '\0'; - p = strdup(buf); - if (p) - os_minor = p; - } - } - } - -done: - fclose(file); - return; -} - - - -/* - * Retrieve an interface name corresponding to the specified guid. - * If there is a match, the function returns a pointer - * to the interface name and if not, a NULL is returned. - * If a match is found, the caller is responsible for - * freeing the memory. - */ - -static char *kvp_get_if_name(char *guid) -{ - DIR *dir; - struct dirent *entry; - FILE *file; - char *p, *q, *x; - char *if_name = NULL; - char buf[256]; - char *kvp_net_dir = "/sys/class/net/"; - char dev_id[256]; - - dir = opendir(kvp_net_dir); - if (dir == NULL) - return NULL; - - snprintf(dev_id, sizeof(dev_id), "%s", kvp_net_dir); - q = dev_id + strlen(kvp_net_dir); - - while ((entry = readdir(dir)) != NULL) { - /* - * Set the state for the next pass. - */ - *q = '\0'; - strcat(dev_id, entry->d_name); - strcat(dev_id, "/device/device_id"); - - file = fopen(dev_id, "r"); - if (file == NULL) - continue; - - p = fgets(buf, sizeof(buf), file); - if (p) { - x = strchr(p, '\n'); - if (x) - *x = '\0'; - - if (!strcmp(p, guid)) { - /* - * Found the guid match; return the interface - * name. The caller will free the memory. - */ - if_name = strdup(entry->d_name); - fclose(file); - break; - } - } - fclose(file); - } - - closedir(dir); - return if_name; -} - -/* - * Retrieve the MAC address given the interface name. - */ - -static char *kvp_if_name_to_mac(char *if_name) -{ - FILE *file; - char *p, *x; - char buf[256]; - char addr_file[256]; - unsigned int i; - char *mac_addr = NULL; - - snprintf(addr_file, sizeof(addr_file), "%s%s%s", "/sys/class/net/", - if_name, "/address"); - - file = fopen(addr_file, "r"); - if (file == NULL) - return NULL; - - p = fgets(buf, sizeof(buf), file); - if (p) { - x = strchr(p, '\n'); - if (x) - *x = '\0'; - for (i = 0; i < strlen(p); i++) - p[i] = toupper(p[i]); - mac_addr = strdup(p); - } - - fclose(file); - return mac_addr; -} - - -/* - * Retrieve the interface name given tha MAC address. - */ - -static char *kvp_mac_to_if_name(char *mac) -{ - DIR *dir; - struct dirent *entry; - FILE *file; - char *p, *q, *x; - char *if_name = NULL; - char buf[256]; - char *kvp_net_dir = "/sys/class/net/"; - char dev_id[256]; - unsigned int i; - - dir = opendir(kvp_net_dir); - if (dir == NULL) - return NULL; - - snprintf(dev_id, sizeof(dev_id), kvp_net_dir); - q = dev_id + strlen(kvp_net_dir); - - while ((entry = readdir(dir)) != NULL) { - /* - * Set the state for the next pass. - */ - *q = '\0'; - - strcat(dev_id, entry->d_name); - strcat(dev_id, "/address"); - - file = fopen(dev_id, "r"); - if (file == NULL) - continue; - - p = fgets(buf, sizeof(buf), file); - if (p) { - x = strchr(p, '\n'); - if (x) - *x = '\0'; - - for (i = 0; i < strlen(p); i++) - p[i] = toupper(p[i]); - - if (!strcmp(p, mac)) { - /* - * Found the MAC match; return the interface - * name. The caller will free the memory. - */ - if_name = strdup(entry->d_name); - fclose(file); - break; - } - } - fclose(file); - } - - closedir(dir); - return if_name; -} - - -static void kvp_process_ipconfig_file(char *cmd, - char *config_buf, unsigned int len, - int element_size, int offset) -{ - char buf[256]; - char *p; - char *x; - FILE *file; - - /* - * First execute the command. - */ - file = popen(cmd, "r"); - if (file == NULL) - return; - - if (offset == 0) - memset(config_buf, 0, len); - while ((p = fgets(buf, sizeof(buf), file)) != NULL) { - if (len < strlen(config_buf) + element_size + 1) - break; - - x = strchr(p, '\n'); - if (x) - *x = '\0'; - - strcat(config_buf, p); - strcat(config_buf, ";"); - } - pclose(file); -} - -static void kvp_get_ipconfig_info(char *if_name, - struct hv_kvp_ipaddr_value *buffer) -{ - char cmd[512]; - char dhcp_info[128]; - char *p; - FILE *file; - - /* - * Get the address of default gateway (ipv4). - */ - sprintf(cmd, "%s %s", "ip route show dev", if_name); - strcat(cmd, " | awk '/default/ {print $3 }'"); - - /* - * Execute the command to gather gateway info. - */ - kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way, - (MAX_GATEWAY_SIZE * 2), INET_ADDRSTRLEN, 0); - - /* - * Get the address of default gateway (ipv6). - */ - sprintf(cmd, "%s %s", "ip -f inet6 route show dev", if_name); - strcat(cmd, " | awk '/default/ {print $3 }'"); - - /* - * Execute the command to gather gateway info (ipv6). - */ - kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way, - (MAX_GATEWAY_SIZE * 2), INET6_ADDRSTRLEN, 1); - - - /* - * Gather the DNS state. - * Since there is no standard way to get this information - * across various distributions of interest; we just invoke - * an external script that needs to be ported across distros - * of interest. - * - * Following is the expected format of the information from the script: - * - * ipaddr1 (nameserver1) - * ipaddr2 (nameserver2) - * . - * . - */ - - sprintf(cmd, "%s", "hv_get_dns_info"); - - /* - * Execute the command to gather DNS info. - */ - kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr, - (MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0); - - /* - * Gather the DHCP state. - * We will gather this state by invoking an external script. - * The parameter to the script is the interface name. - * Here is the expected output: - * - * Enabled: DHCP enabled. - */ - - sprintf(cmd, "%s %s", "hv_get_dhcp_info", if_name); - - file = popen(cmd, "r"); - if (file == NULL) - return; - - p = fgets(dhcp_info, sizeof(dhcp_info), file); - if (p == NULL) { - pclose(file); - return; - } - - if (!strncmp(p, "Enabled", 7)) - buffer->dhcp_enabled = 1; - else - buffer->dhcp_enabled = 0; - - pclose(file); -} - - -static unsigned int hweight32(unsigned int *w) -{ - unsigned int res = *w - ((*w >> 1) & 0x55555555); - res = (res & 0x33333333) + ((res >> 2) & 0x33333333); - res = (res + (res >> 4)) & 0x0F0F0F0F; - res = res + (res >> 8); - return (res + (res >> 16)) & 0x000000FF; -} - -static int kvp_process_ip_address(void *addrp, - int family, char *buffer, - int length, int *offset) -{ - struct sockaddr_in *addr; - struct sockaddr_in6 *addr6; - int addr_length; - char tmp[50]; - const char *str; - - if (family == AF_INET) { - addr = (struct sockaddr_in *)addrp; - str = inet_ntop(family, &addr->sin_addr, tmp, 50); - addr_length = INET_ADDRSTRLEN; - } else { - addr6 = (struct sockaddr_in6 *)addrp; - str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50); - addr_length = INET6_ADDRSTRLEN; - } - - if ((length - *offset) < addr_length + 2) - return HV_E_FAIL; - if (str == NULL) { - strcpy(buffer, "inet_ntop failed\n"); - return HV_E_FAIL; - } - if (*offset == 0) - strcpy(buffer, tmp); - else { - strcat(buffer, ";"); - strcat(buffer, tmp); - } - - *offset += strlen(str) + 1; - - return 0; -} - -static int -kvp_get_ip_info(int family, char *if_name, int op, - void *out_buffer, unsigned int length) -{ - struct ifaddrs *ifap; - struct ifaddrs *curp; - int offset = 0; - int sn_offset = 0; - int error = 0; - char *buffer; - struct hv_kvp_ipaddr_value *ip_buffer; - char cidr_mask[5]; /* /xyz */ - int weight; - int i; - unsigned int *w; - char *sn_str; - struct sockaddr_in6 *addr6; - - if (op == KVP_OP_ENUMERATE) { - buffer = out_buffer; - } else { - ip_buffer = out_buffer; - buffer = (char *)ip_buffer->ip_addr; - ip_buffer->addr_family = 0; - } - /* - * On entry into this function, the buffer is capable of holding the - * maximum key value. - */ - - if (getifaddrs(&ifap)) { - strcpy(buffer, "getifaddrs failed\n"); - return HV_E_FAIL; - } - - curp = ifap; - while (curp != NULL) { - if (curp->ifa_addr == NULL) { - curp = curp->ifa_next; - continue; - } - - if ((if_name != NULL) && - (strncmp(curp->ifa_name, if_name, strlen(if_name)))) { - /* - * We want info about a specific interface; - * just continue. - */ - curp = curp->ifa_next; - continue; - } - - /* - * We only support two address families: AF_INET and AF_INET6. - * If a family value of 0 is specified, we collect both - * supported address families; if not we gather info on - * the specified address family. - */ - if ((((family != 0) && - (curp->ifa_addr->sa_family != family))) || - (curp->ifa_flags & IFF_LOOPBACK)) { - curp = curp->ifa_next; - continue; - } - if ((curp->ifa_addr->sa_family != AF_INET) && - (curp->ifa_addr->sa_family != AF_INET6)) { - curp = curp->ifa_next; - continue; - } - - if (op == KVP_OP_GET_IP_INFO) { - /* - * Gather info other than the IP address. - * IP address info will be gathered later. - */ - if (curp->ifa_addr->sa_family == AF_INET) { - ip_buffer->addr_family |= ADDR_FAMILY_IPV4; - /* - * Get subnet info. - */ - error = kvp_process_ip_address( - curp->ifa_netmask, - AF_INET, - (char *) - ip_buffer->sub_net, - length, - &sn_offset); - if (error) - goto gather_ipaddr; - } else { - ip_buffer->addr_family |= ADDR_FAMILY_IPV6; - - /* - * Get subnet info in CIDR format. - */ - weight = 0; - sn_str = (char *)ip_buffer->sub_net; - addr6 = (struct sockaddr_in6 *) - curp->ifa_netmask; - w = addr6->sin6_addr.s6_addr32; - - for (i = 0; i < 4; i++) - weight += hweight32(&w[i]); - - sprintf(cidr_mask, "/%d", weight); - if (length < sn_offset + strlen(cidr_mask) + 1) - goto gather_ipaddr; - - if (sn_offset == 0) - strcpy(sn_str, cidr_mask); - else { - strcat((char *)ip_buffer->sub_net, ";"); - strcat(sn_str, cidr_mask); - } - sn_offset += strlen(sn_str) + 1; - } - - /* - * Collect other ip related configuration info. - */ - - kvp_get_ipconfig_info(if_name, ip_buffer); - } - -gather_ipaddr: - error = kvp_process_ip_address(curp->ifa_addr, - curp->ifa_addr->sa_family, - buffer, - length, &offset); - if (error) - goto getaddr_done; - - curp = curp->ifa_next; - } - -getaddr_done: - freeifaddrs(ifap); - return error; -} - - -static int expand_ipv6(char *addr, int type) -{ - int ret; - struct in6_addr v6_addr; - - ret = inet_pton(AF_INET6, addr, &v6_addr); - - if (ret != 1) { - if (type == NETMASK) - return 1; - return 0; - } - - sprintf(addr, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:" - "%02x%02x:%02x%02x:%02x%02x", - (int)v6_addr.s6_addr[0], (int)v6_addr.s6_addr[1], - (int)v6_addr.s6_addr[2], (int)v6_addr.s6_addr[3], - (int)v6_addr.s6_addr[4], (int)v6_addr.s6_addr[5], - (int)v6_addr.s6_addr[6], (int)v6_addr.s6_addr[7], - (int)v6_addr.s6_addr[8], (int)v6_addr.s6_addr[9], - (int)v6_addr.s6_addr[10], (int)v6_addr.s6_addr[11], - (int)v6_addr.s6_addr[12], (int)v6_addr.s6_addr[13], - (int)v6_addr.s6_addr[14], (int)v6_addr.s6_addr[15]); - - return 1; - -} - -static int is_ipv4(char *addr) -{ - int ret; - struct in_addr ipv4_addr; - - ret = inet_pton(AF_INET, addr, &ipv4_addr); - - if (ret == 1) - return 1; - return 0; -} - -static int parse_ip_val_buffer(char *in_buf, int *offset, - char *out_buf, int out_len) -{ - char *x; - char *start; - - /* - * in_buf has sequence of characters that are seperated by - * the character ';'. The last sequence does not have the - * terminating ";" character. - */ - start = in_buf + *offset; - - x = strchr(start, ';'); - if (x) - *x = 0; - else - x = start + strlen(start); - - if (strlen(start) != 0) { - int i = 0; - /* - * Get rid of leading spaces. - */ - while (start[i] == ' ') - i++; - - if ((x - start) <= out_len) { - strcpy(out_buf, (start + i)); - *offset += (x - start) + 1; - return 1; - } - } - return 0; -} - -static int kvp_write_file(FILE *f, char *s1, char *s2, char *s3) -{ - int ret; - - ret = fprintf(f, "%s%s%s%s\n", s1, s2, "=", s3); - - if (ret < 0) - return HV_E_FAIL; - - return 0; -} - - -static int process_ip_string(FILE *f, char *ip_string, int type) -{ - int error = 0; - char addr[INET6_ADDRSTRLEN]; - int i = 0; - int j = 0; - char str[256]; - char sub_str[10]; - int offset = 0; - - memset(addr, 0, sizeof(addr)); - - while (parse_ip_val_buffer(ip_string, &offset, addr, - (MAX_IP_ADDR_SIZE * 2))) { - - sub_str[0] = 0; - if (is_ipv4(addr)) { - switch (type) { - case IPADDR: - snprintf(str, sizeof(str), "%s", "IPADDR"); - break; - case NETMASK: - snprintf(str, sizeof(str), "%s", "NETMASK"); - break; - case GATEWAY: - snprintf(str, sizeof(str), "%s", "GATEWAY"); - break; - case DNS: - snprintf(str, sizeof(str), "%s", "DNS"); - break; - } - - if (type == DNS) { - snprintf(sub_str, sizeof(sub_str), "%d", ++i); - } else if (type == GATEWAY && i == 0) { - ++i; - } else { - snprintf(sub_str, sizeof(sub_str), "%d", i++); - } - - - } else if (expand_ipv6(addr, type)) { - switch (type) { - case IPADDR: - snprintf(str, sizeof(str), "%s", "IPV6ADDR"); - break; - case NETMASK: - snprintf(str, sizeof(str), "%s", "IPV6NETMASK"); - break; - case GATEWAY: - snprintf(str, sizeof(str), "%s", - "IPV6_DEFAULTGW"); - break; - case DNS: - snprintf(str, sizeof(str), "%s", "DNS"); - break; - } - - if (type == DNS) { - snprintf(sub_str, sizeof(sub_str), "%d", ++i); - } else if (j == 0) { - ++j; - } else { - snprintf(sub_str, sizeof(sub_str), "_%d", j++); - } - } else { - return HV_INVALIDARG; - } - - error = kvp_write_file(f, str, sub_str, addr); - if (error) - return error; - memset(addr, 0, sizeof(addr)); - } - - return 0; -} - -static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) -{ - int error = 0; - char if_file[128]; - FILE *file; - char cmd[512]; - char *mac_addr; - - /* - * Set the configuration for the specified interface with - * the information provided. Since there is no standard - * way to configure an interface, we will have an external - * script that does the job of configuring the interface and - * flushing the configuration. - * - * The parameters passed to this external script are: - * 1. A configuration file that has the specified configuration. - * - * We will embed the name of the interface in the configuration - * file: ifcfg-ethx (where ethx is the interface name). - * - * The information provided here may be more than what is needed - * in a given distro to configure the interface and so are free - * ignore information that may not be relevant. - * - * Here is the format of the ip configuration file: - * - * HWADDR=macaddr - * DEVICE=interface name - * BOOTPROTO= (where is "dhcp" if DHCP is configured - * or "none" if no boot-time protocol should be used) - * - * IPADDR0=ipaddr1 - * IPADDR1=ipaddr2 - * IPADDRx=ipaddry (where y = x + 1) - * - * NETMASK0=netmask1 - * NETMASKx=netmasky (where y = x + 1) - * - * GATEWAY=ipaddr1 - * GATEWAYx=ipaddry (where y = x + 1) - * - * DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc) - * - * IPV6 addresses will be tagged as IPV6ADDR, IPV6 gateway will be - * tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as - * IPV6NETMASK. - * - * The host can specify multiple ipv4 and ipv6 addresses to be - * configured for the interface. Furthermore, the configuration - * needs to be persistent. A subsequent GET call on the interface - * is expected to return the configuration that is set via the SET - * call. - */ - - snprintf(if_file, sizeof(if_file), "%s%s%s", KVP_CONFIG_LOC, - "/ifcfg-", if_name); - - file = fopen(if_file, "w"); - - if (file == NULL) { - syslog(LOG_ERR, "Failed to open config file; error: %d %s", - errno, strerror(errno)); - return HV_E_FAIL; - } - - /* - * First write out the MAC address. - */ - - mac_addr = kvp_if_name_to_mac(if_name); - if (mac_addr == NULL) { - error = HV_E_FAIL; - goto setval_error; - } - - error = kvp_write_file(file, "HWADDR", "", mac_addr); - free(mac_addr); - if (error) - goto setval_error; - - error = kvp_write_file(file, "DEVICE", "", if_name); - if (error) - goto setval_error; - - /* - * The dhcp_enabled flag is only for IPv4. In the case the host only - * injects an IPv6 address, the flag is true, but we still need to - * proceed to parse and pass the IPv6 information to the - * disto-specific script hv_set_ifconfig. - */ - if (new_val->dhcp_enabled) { - error = kvp_write_file(file, "BOOTPROTO", "", "dhcp"); - if (error) - goto setval_error; - - } else { - error = kvp_write_file(file, "BOOTPROTO", "", "none"); - if (error) - goto setval_error; - } - - /* - * Write the configuration for ipaddress, netmask, gateway and - * name servers. - */ - - error = process_ip_string(file, (char *)new_val->ip_addr, IPADDR); - if (error) - goto setval_error; - - error = process_ip_string(file, (char *)new_val->sub_net, NETMASK); - if (error) - goto setval_error; - - error = process_ip_string(file, (char *)new_val->gate_way, GATEWAY); - if (error) - goto setval_error; - - error = process_ip_string(file, (char *)new_val->dns_addr, DNS); - if (error) - goto setval_error; - - fclose(file); - - /* - * Now that we have populated the configuration file, - * invoke the external script to do its magic. - */ - - snprintf(cmd, sizeof(cmd), "%s %s", "hv_set_ifconfig", if_file); - if (system(cmd)) { - syslog(LOG_ERR, "Failed to execute cmd '%s'; error: %d %s", - cmd, errno, strerror(errno)); - return HV_E_FAIL; - } - return 0; - -setval_error: - syslog(LOG_ERR, "Failed to write config file"); - fclose(file); - return error; -} - - -static void -kvp_get_domain_name(char *buffer, int length) -{ - struct addrinfo hints, *info ; - int error = 0; - - gethostname(buffer, length); - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; /*Get only ipv4 addrinfo. */ - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_CANONNAME; - - error = getaddrinfo(buffer, NULL, &hints, &info); - if (error != 0) { - snprintf(buffer, length, "getaddrinfo failed: 0x%x %s", - error, gai_strerror(error)); - return; - } - snprintf(buffer, length, "%s", info->ai_canonname); - freeaddrinfo(info); -} - -static int -netlink_send(int fd, struct cn_msg *msg) -{ - struct nlmsghdr nlh = { .nlmsg_type = NLMSG_DONE }; - unsigned int size; - struct msghdr message; - struct iovec iov[2]; - - size = sizeof(struct cn_msg) + msg->len; - - nlh.nlmsg_pid = getpid(); - nlh.nlmsg_len = NLMSG_LENGTH(size); - - iov[0].iov_base = &nlh; - iov[0].iov_len = sizeof(nlh); - - iov[1].iov_base = msg; - iov[1].iov_len = size; - - memset(&message, 0, sizeof(message)); - message.msg_name = &addr; - message.msg_namelen = sizeof(addr); - message.msg_iov = iov; - message.msg_iovlen = 2; - - return sendmsg(fd, &message, 0); -} - -void print_usage(char *argv[]) -{ - fprintf(stderr, "Usage: %s [options]\n" - "Options are:\n" - " -n, --no-daemon stay in foreground, don't daemonize\n" - " -h, --help print this help\n", argv[0]); -} - -int main(int argc, char *argv[]) -{ - int fd, len, nl_group; - int error; - struct cn_msg *message; - struct pollfd pfd; - struct nlmsghdr *incoming_msg; - struct cn_msg *incoming_cn_msg; - struct hv_kvp_msg *hv_msg; - char *p; - char *key_value; - char *key_name; - int op; - int pool; - char *if_name; - struct hv_kvp_ipaddr_value *kvp_ip_val; - char *kvp_recv_buffer; - size_t kvp_recv_buffer_len; - int daemonize = 1, long_index = 0, opt; - - static struct option long_options[] = { - {"help", no_argument, 0, 'h' }, - {"no-daemon", no_argument, 0, 'n' }, - {0, 0, 0, 0 } - }; - - while ((opt = getopt_long(argc, argv, "hn", long_options, - &long_index)) != -1) { - switch (opt) { - case 'n': - daemonize = 0; - break; - case 'h': - default: - print_usage(argv); - exit(EXIT_FAILURE); - } - } - - if (daemonize && daemon(1, 0)) - return 1; - - openlog("KVP", 0, LOG_USER); - syslog(LOG_INFO, "KVP starting; pid is:%d", getpid()); - - kvp_recv_buffer_len = NLMSG_LENGTH(0) + sizeof(struct cn_msg) + sizeof(struct hv_kvp_msg); - kvp_recv_buffer = calloc(1, kvp_recv_buffer_len); - if (!kvp_recv_buffer) { - syslog(LOG_ERR, "Failed to allocate netlink buffer"); - exit(EXIT_FAILURE); - } - /* - * Retrieve OS release information. - */ - kvp_get_os_info(); - /* - * Cache Fully Qualified Domain Name because getaddrinfo takes an - * unpredictable amount of time to finish. - */ - kvp_get_domain_name(full_domain_name, sizeof(full_domain_name)); - - if (kvp_file_init()) { - syslog(LOG_ERR, "Failed to initialize the pools"); - exit(EXIT_FAILURE); - } - - fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); - if (fd < 0) { - syslog(LOG_ERR, "netlink socket creation failed; error: %d %s", errno, - strerror(errno)); - exit(EXIT_FAILURE); - } - addr.nl_family = AF_NETLINK; - addr.nl_pad = 0; - addr.nl_pid = 0; - addr.nl_groups = 0; - - - error = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); - if (error < 0) { - syslog(LOG_ERR, "bind failed; error: %d %s", errno, strerror(errno)); - close(fd); - exit(EXIT_FAILURE); - } - nl_group = CN_KVP_IDX; - - if (setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &nl_group, sizeof(nl_group)) < 0) { - syslog(LOG_ERR, "setsockopt failed; error: %d %s", errno, strerror(errno)); - close(fd); - exit(EXIT_FAILURE); - } - - /* - * Register ourselves with the kernel. - */ - message = (struct cn_msg *)kvp_recv_buffer; - message->id.idx = CN_KVP_IDX; - message->id.val = CN_KVP_VAL; - - hv_msg = (struct hv_kvp_msg *)message->data; - hv_msg->kvp_hdr.operation = KVP_OP_REGISTER1; - message->ack = 0; - message->len = sizeof(struct hv_kvp_msg); - - len = netlink_send(fd, message); - if (len < 0) { - syslog(LOG_ERR, "netlink_send failed; error: %d %s", errno, strerror(errno)); - close(fd); - exit(EXIT_FAILURE); - } - - pfd.fd = fd; - - while (1) { - struct sockaddr *addr_p = (struct sockaddr *) &addr; - socklen_t addr_l = sizeof(addr); - pfd.events = POLLIN; - pfd.revents = 0; - - if (poll(&pfd, 1, -1) < 0) { - syslog(LOG_ERR, "poll failed; error: %d %s", errno, strerror(errno)); - if (errno == EINVAL) { - close(fd); - exit(EXIT_FAILURE); - } - else - continue; - } - - len = recvfrom(fd, kvp_recv_buffer, kvp_recv_buffer_len, 0, - addr_p, &addr_l); - - if (len < 0) { - int saved_errno = errno; - syslog(LOG_ERR, "recvfrom failed; pid:%u error:%d %s", - addr.nl_pid, errno, strerror(errno)); - - if (saved_errno == ENOBUFS) { - syslog(LOG_ERR, "receive error: ignored"); - continue; - } - - close(fd); - return -1; - } - - if (addr.nl_pid) { - syslog(LOG_WARNING, "Received packet from untrusted pid:%u", - addr.nl_pid); - continue; - } - - incoming_msg = (struct nlmsghdr *)kvp_recv_buffer; - - if (incoming_msg->nlmsg_type != NLMSG_DONE) - continue; - - incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg); - hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data; - - /* - * We will use the KVP header information to pass back - * the error from this daemon. So, first copy the state - * and set the error code to success. - */ - op = hv_msg->kvp_hdr.operation; - pool = hv_msg->kvp_hdr.pool; - hv_msg->error = HV_S_OK; - - if ((in_hand_shake) && (op == KVP_OP_REGISTER1)) { - /* - * Driver is registering with us; stash away the version - * information. - */ - in_hand_shake = 0; - p = (char *)hv_msg->body.kvp_register.version; - lic_version = malloc(strlen(p) + 1); - if (lic_version) { - strcpy(lic_version, p); - syslog(LOG_INFO, "KVP LIC Version: %s", - lic_version); - } else { - syslog(LOG_ERR, "malloc failed"); - } - continue; - } - - switch (op) { - case KVP_OP_GET_IP_INFO: - kvp_ip_val = &hv_msg->body.kvp_ip_val; - if_name = - kvp_mac_to_if_name((char *)kvp_ip_val->adapter_id); - - if (if_name == NULL) { - /* - * We could not map the mac address to an - * interface name; return error. - */ - hv_msg->error = HV_E_FAIL; - break; - } - error = kvp_get_ip_info( - 0, if_name, KVP_OP_GET_IP_INFO, - kvp_ip_val, - (MAX_IP_ADDR_SIZE * 2)); - - if (error) - hv_msg->error = error; - - free(if_name); - break; - - case KVP_OP_SET_IP_INFO: - kvp_ip_val = &hv_msg->body.kvp_ip_val; - if_name = kvp_get_if_name( - (char *)kvp_ip_val->adapter_id); - if (if_name == NULL) { - /* - * We could not map the guid to an - * interface name; return error. - */ - hv_msg->error = HV_GUID_NOTFOUND; - break; - } - error = kvp_set_ip_info(if_name, kvp_ip_val); - if (error) - hv_msg->error = error; - - free(if_name); - break; - - case KVP_OP_SET: - if (kvp_key_add_or_modify(pool, - hv_msg->body.kvp_set.data.key, - hv_msg->body.kvp_set.data.key_size, - hv_msg->body.kvp_set.data.value, - hv_msg->body.kvp_set.data.value_size)) - hv_msg->error = HV_S_CONT; - break; - - case KVP_OP_GET: - if (kvp_get_value(pool, - hv_msg->body.kvp_set.data.key, - hv_msg->body.kvp_set.data.key_size, - hv_msg->body.kvp_set.data.value, - hv_msg->body.kvp_set.data.value_size)) - hv_msg->error = HV_S_CONT; - break; - - case KVP_OP_DELETE: - if (kvp_key_delete(pool, - hv_msg->body.kvp_delete.key, - hv_msg->body.kvp_delete.key_size)) - hv_msg->error = HV_S_CONT; - break; - - default: - break; - } - - if (op != KVP_OP_ENUMERATE) - goto kvp_done; - - /* - * If the pool is KVP_POOL_AUTO, dynamically generate - * both the key and the value; if not read from the - * appropriate pool. - */ - if (pool != KVP_POOL_AUTO) { - if (kvp_pool_enumerate(pool, - hv_msg->body.kvp_enum_data.index, - hv_msg->body.kvp_enum_data.data.key, - HV_KVP_EXCHANGE_MAX_KEY_SIZE, - hv_msg->body.kvp_enum_data.data.value, - HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) - hv_msg->error = HV_S_CONT; - goto kvp_done; - } - - hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data; - key_name = (char *)hv_msg->body.kvp_enum_data.data.key; - key_value = (char *)hv_msg->body.kvp_enum_data.data.value; - - switch (hv_msg->body.kvp_enum_data.index) { - case FullyQualifiedDomainName: - strcpy(key_value, full_domain_name); - strcpy(key_name, "FullyQualifiedDomainName"); - break; - case IntegrationServicesVersion: - strcpy(key_name, "IntegrationServicesVersion"); - strcpy(key_value, lic_version); - break; - case NetworkAddressIPv4: - kvp_get_ip_info(AF_INET, NULL, KVP_OP_ENUMERATE, - key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); - strcpy(key_name, "NetworkAddressIPv4"); - break; - case NetworkAddressIPv6: - kvp_get_ip_info(AF_INET6, NULL, KVP_OP_ENUMERATE, - key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); - strcpy(key_name, "NetworkAddressIPv6"); - break; - case OSBuildNumber: - strcpy(key_value, os_build); - strcpy(key_name, "OSBuildNumber"); - break; - case OSName: - strcpy(key_value, os_name); - strcpy(key_name, "OSName"); - break; - case OSMajorVersion: - strcpy(key_value, os_major); - strcpy(key_name, "OSMajorVersion"); - break; - case OSMinorVersion: - strcpy(key_value, os_minor); - strcpy(key_name, "OSMinorVersion"); - break; - case OSVersion: - strcpy(key_value, os_version); - strcpy(key_name, "OSVersion"); - break; - case ProcessorArchitecture: - strcpy(key_value, processor_arch); - strcpy(key_name, "ProcessorArchitecture"); - break; - default: - hv_msg->error = HV_S_CONT; - break; - } - /* - * Send the value back to the kernel. The response is - * already in the receive buffer. Update the cn_msg header to - * reflect the key value that has been added to the message - */ -kvp_done: - - incoming_cn_msg->id.idx = CN_KVP_IDX; - incoming_cn_msg->id.val = CN_KVP_VAL; - incoming_cn_msg->ack = 0; - incoming_cn_msg->len = sizeof(struct hv_kvp_msg); - - len = netlink_send(fd, incoming_cn_msg); - if (len < 0) { - int saved_errno = errno; - syslog(LOG_ERR, "net_link send failed; error: %d %s", errno, - strerror(errno)); - - if (saved_errno == ENOMEM || saved_errno == ENOBUFS) { - syslog(LOG_ERR, "send error: ignored"); - continue; - } - - exit(EXIT_FAILURE); - } - } - -} diff --git a/alpine/packages/hvtools/src/hv_set_ifconfig.sh b/alpine/packages/hvtools/src/hv_set_ifconfig.sh deleted file mode 100755 index 735aafd64..000000000 --- a/alpine/packages/hvtools/src/hv_set_ifconfig.sh +++ /dev/null @@ -1,64 +0,0 @@ -#!/bin/bash - -# This example script activates an interface based on the specified -# configuration. -# -# In the interest of keeping the KVP daemon code free of distro specific -# information; the kvp daemon code invokes this external script to configure -# the interface. -# -# The only argument to this script is the configuration file that is to -# be used to configure the interface. -# -# Each Distro is expected to implement this script in a distro specific -# fashion. For instance on Distros that ship with Network Manager enabled, -# this script can be based on the Network Manager APIs for configuring the -# interface. -# -# This example script is based on a RHEL environment. -# -# Here is the format of the ip configuration file: -# -# HWADDR=macaddr -# DEVICE=interface name -# BOOTPROTO= (where is "dhcp" if DHCP is configured -# or "none" if no boot-time protocol should be used) -# -# IPADDR0=ipaddr1 -# IPADDR1=ipaddr2 -# IPADDRx=ipaddry (where y = x + 1) -# -# NETMASK0=netmask1 -# NETMASKx=netmasky (where y = x + 1) -# -# GATEWAY=ipaddr1 -# GATEWAYx=ipaddry (where y = x + 1) -# -# DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc) -# -# IPV6 addresses will be tagged as IPV6ADDR, IPV6 gateway will be -# tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as -# IPV6NETMASK. -# -# The host can specify multiple ipv4 and ipv6 addresses to be -# configured for the interface. Furthermore, the configuration -# needs to be persistent. A subsequent GET call on the interface -# is expected to return the configuration that is set via the SET -# call. -# - - - -echo "IPV6INIT=yes" >> $1 -echo "NM_CONTROLLED=no" >> $1 -echo "PEERDNS=yes" >> $1 -echo "ONBOOT=yes" >> $1 - - -cp $1 /etc/sysconfig/network-scripts/ - - -interface=$(echo $1 | awk -F - '{ print $2 }') - -/sbin/ifdown $interface 2>/dev/null -/sbin/ifup $interface 2>/dev/null diff --git a/alpine/packages/hvtools/src/hv_vss_daemon.c b/alpine/packages/hvtools/src/hv_vss_daemon.c deleted file mode 100644 index 506dd0148..000000000 --- a/alpine/packages/hvtools/src/hv_vss_daemon.c +++ /dev/null @@ -1,342 +0,0 @@ -/* - * An implementation of the host initiated guest snapshot for Hyper-V. - * - * - * Copyright (C) 2013, Microsoft, Inc. - * Author : K. Y. Srinivasan - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct sockaddr_nl addr; - -#ifndef SOL_NETLINK -#define SOL_NETLINK 270 -#endif - - -/* Don't use syslog() in the function since that can cause write to disk */ -static int vss_do_freeze(char *dir, unsigned int cmd) -{ - int ret, fd = open(dir, O_RDONLY); - - if (fd < 0) - return 1; - - ret = ioctl(fd, cmd, 0); - - /* - * If a partition is mounted more than once, only the first - * FREEZE/THAW can succeed and the later ones will get - * EBUSY/EINVAL respectively: there could be 2 cases: - * 1) a user may mount the same partition to differnt directories - * by mistake or on purpose; - * 2) The subvolume of btrfs appears to have the same partition - * mounted more than once. - */ - if (ret) { - if ((cmd == FIFREEZE && errno == EBUSY) || - (cmd == FITHAW && errno == EINVAL)) { - close(fd); - return 0; - } - } - - close(fd); - return !!ret; -} - -static int vss_operate(int operation) -{ - char match[] = "/dev/"; - FILE *mounts; - struct mntent *ent; - char errdir[1024] = {0}; - unsigned int cmd; - int error = 0, root_seen = 0, save_errno = 0; - - switch (operation) { - case VSS_OP_FREEZE: - cmd = FIFREEZE; - break; - case VSS_OP_THAW: - cmd = FITHAW; - break; - default: - return -1; - } - - mounts = setmntent("/proc/mounts", "r"); - if (mounts == NULL) - return -1; - - while ((ent = getmntent(mounts))) { - if (strncmp(ent->mnt_fsname, match, strlen(match))) - continue; - if (hasmntopt(ent, MNTOPT_RO) != NULL) - continue; - if (strcmp(ent->mnt_type, "vfat") == 0) - continue; - if (strcmp(ent->mnt_dir, "/") == 0) { - root_seen = 1; - continue; - } - error |= vss_do_freeze(ent->mnt_dir, cmd); - if (error && operation == VSS_OP_FREEZE) - goto err; - } - - endmntent(mounts); - - if (root_seen) { - error |= vss_do_freeze("/", cmd); - if (error && operation == VSS_OP_FREEZE) - goto err; - } - - goto out; -err: - save_errno = errno; - if (ent) { - strncpy(errdir, ent->mnt_dir, sizeof(errdir)-1); - endmntent(mounts); - } - vss_operate(VSS_OP_THAW); - /* Call syslog after we thaw all filesystems */ - if (ent) - syslog(LOG_ERR, "FREEZE of %s failed; error:%d %s", - errdir, save_errno, strerror(save_errno)); - else - syslog(LOG_ERR, "FREEZE of / failed; error:%d %s", save_errno, - strerror(save_errno)); -out: - return error; -} - -static int netlink_send(int fd, struct cn_msg *msg) -{ - struct nlmsghdr nlh = { .nlmsg_type = NLMSG_DONE }; - unsigned int size; - struct msghdr message; - struct iovec iov[2]; - - size = sizeof(struct cn_msg) + msg->len; - - nlh.nlmsg_pid = getpid(); - nlh.nlmsg_len = NLMSG_LENGTH(size); - - iov[0].iov_base = &nlh; - iov[0].iov_len = sizeof(nlh); - - iov[1].iov_base = msg; - iov[1].iov_len = size; - - memset(&message, 0, sizeof(message)); - message.msg_name = &addr; - message.msg_namelen = sizeof(addr); - message.msg_iov = iov; - message.msg_iovlen = 2; - - return sendmsg(fd, &message, 0); -} - -void print_usage(char *argv[]) -{ - fprintf(stderr, "Usage: %s [options]\n" - "Options are:\n" - " -n, --no-daemon stay in foreground, don't daemonize\n" - " -h, --help print this help\n", argv[0]); -} - -int main(int argc, char *argv[]) -{ - int fd, len, nl_group; - int error; - struct cn_msg *message; - struct pollfd pfd; - struct nlmsghdr *incoming_msg; - struct cn_msg *incoming_cn_msg; - int op; - struct hv_vss_msg *vss_msg; - char *vss_recv_buffer; - size_t vss_recv_buffer_len; - int daemonize = 1, long_index = 0, opt; - - static struct option long_options[] = { - {"help", no_argument, 0, 'h' }, - {"no-daemon", no_argument, 0, 'n' }, - {0, 0, 0, 0 } - }; - - while ((opt = getopt_long(argc, argv, "hn", long_options, - &long_index)) != -1) { - switch (opt) { - case 'n': - daemonize = 0; - break; - case 'h': - default: - print_usage(argv); - exit(EXIT_FAILURE); - } - } - - if (daemonize && daemon(1, 0)) - return 1; - - openlog("Hyper-V VSS", 0, LOG_USER); - syslog(LOG_INFO, "VSS starting; pid is:%d", getpid()); - - vss_recv_buffer_len = NLMSG_LENGTH(0) + sizeof(struct cn_msg) + sizeof(struct hv_vss_msg); - vss_recv_buffer = calloc(1, vss_recv_buffer_len); - if (!vss_recv_buffer) { - syslog(LOG_ERR, "Failed to allocate netlink buffers"); - exit(EXIT_FAILURE); - } - - fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); - if (fd < 0) { - syslog(LOG_ERR, "netlink socket creation failed; error:%d %s", - errno, strerror(errno)); - exit(EXIT_FAILURE); - } - addr.nl_family = AF_NETLINK; - addr.nl_pad = 0; - addr.nl_pid = 0; - addr.nl_groups = 0; - - - error = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); - if (error < 0) { - syslog(LOG_ERR, "bind failed; error:%d %s", errno, strerror(errno)); - close(fd); - exit(EXIT_FAILURE); - } - nl_group = CN_VSS_IDX; - if (setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &nl_group, sizeof(nl_group)) < 0) { - syslog(LOG_ERR, "setsockopt failed; error:%d %s", errno, strerror(errno)); - close(fd); - exit(EXIT_FAILURE); - } - /* - * Register ourselves with the kernel. - */ - message = (struct cn_msg *)vss_recv_buffer; - message->id.idx = CN_VSS_IDX; - message->id.val = CN_VSS_VAL; - message->ack = 0; - vss_msg = (struct hv_vss_msg *)message->data; - vss_msg->vss_hdr.operation = VSS_OP_REGISTER; - - message->len = sizeof(struct hv_vss_msg); - - len = netlink_send(fd, message); - if (len < 0) { - syslog(LOG_ERR, "netlink_send failed; error:%d %s", errno, strerror(errno)); - close(fd); - exit(EXIT_FAILURE); - } - - pfd.fd = fd; - - while (1) { - struct sockaddr *addr_p = (struct sockaddr *) &addr; - socklen_t addr_l = sizeof(addr); - pfd.events = POLLIN; - pfd.revents = 0; - - if (poll(&pfd, 1, -1) < 0) { - syslog(LOG_ERR, "poll failed; error:%d %s", errno, strerror(errno)); - if (errno == EINVAL) { - close(fd); - exit(EXIT_FAILURE); - } - else - continue; - } - - len = recvfrom(fd, vss_recv_buffer, vss_recv_buffer_len, 0, - addr_p, &addr_l); - - if (len < 0) { - syslog(LOG_ERR, "recvfrom failed; pid:%u error:%d %s", - addr.nl_pid, errno, strerror(errno)); - close(fd); - return -1; - } - - if (addr.nl_pid) { - syslog(LOG_WARNING, - "Received packet from untrusted pid:%u", - addr.nl_pid); - continue; - } - - incoming_msg = (struct nlmsghdr *)vss_recv_buffer; - - if (incoming_msg->nlmsg_type != NLMSG_DONE) - continue; - - incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg); - vss_msg = (struct hv_vss_msg *)incoming_cn_msg->data; - op = vss_msg->vss_hdr.operation; - error = HV_S_OK; - - switch (op) { - case VSS_OP_FREEZE: - case VSS_OP_THAW: - error = vss_operate(op); - syslog(LOG_INFO, "VSS: op=%s: %s\n", - op == VSS_OP_FREEZE ? "FREEZE" : "THAW", - error ? "failed" : "succeeded"); - - if (error) { - error = HV_E_FAIL; - syslog(LOG_ERR, "op=%d failed!", op); - syslog(LOG_ERR, "report it with these files:"); - syslog(LOG_ERR, "/etc/fstab and /proc/mounts"); - } - break; - default: - syslog(LOG_ERR, "Illegal op:%d\n", op); - } - vss_msg->error = error; - len = netlink_send(fd, incoming_cn_msg); - if (len < 0) { - syslog(LOG_ERR, "net_link send failed; error:%d %s", - errno, strerror(errno)); - exit(EXIT_FAILURE); - } - } - -} diff --git a/alpine/packages/hvtools/src/lsvmbus b/alpine/packages/hvtools/src/lsvmbus deleted file mode 100755 index 162a3784d..000000000 --- a/alpine/packages/hvtools/src/lsvmbus +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/env python - -import os -from optparse import OptionParser - -parser = OptionParser() -parser.add_option("-v", "--verbose", dest="verbose", - help="print verbose messages. Try -vv, -vvv for \ - more verbose messages", action="count") - -(options, args) = parser.parse_args() - -verbose = 0 -if options.verbose is not None: - verbose = options.verbose - -vmbus_sys_path = '/sys/bus/vmbus/devices' -if not os.path.isdir(vmbus_sys_path): - print "%s doesn't exist: exiting..." % vmbus_sys_path - exit(-1) - -vmbus_dev_dict = { - '{0e0b6031-5213-4934-818b-38d90ced39db}' : '[Operating system shutdown]', - '{9527e630-d0ae-497b-adce-e80ab0175caf}' : '[Time Synchronization]', - '{57164f39-9115-4e78-ab55-382f3bd5422d}' : '[Heartbeat]', - '{a9a0f4e7-5a45-4d96-b827-8a841e8c03e6}' : '[Data Exchange]', - '{35fa2e29-ea23-4236-96ae-3a6ebacba440}' : '[Backup (volume checkpoint)]', - '{34d14be3-dee4-41c8-9ae7-6b174977c192}' : '[Guest services]', - '{525074dc-8985-46e2-8057-a307dc18a502}' : '[Dynamic Memory]', - '{cfa8b69e-5b4a-4cc0-b98b-8ba1a1f3f95a}' : 'Synthetic mouse', - '{f912ad6d-2b17-48ea-bd65-f927a61c7684}' : 'Synthetic keyboard', - '{da0a7802-e377-4aac-8e77-0558eb1073f8}' : 'Synthetic framebuffer adapter', - '{f8615163-df3e-46c5-913f-f2d2f965ed0e}' : 'Synthetic network adapter', - '{32412632-86cb-44a2-9b5c-50d1417354f5}' : 'Synthetic IDE Controller', - '{ba6163d9-04a1-4d29-b605-72e2ffb1dc7f}' : 'Synthetic SCSI Controller', - '{2f9bcc4a-0069-4af3-b76b-6fd0be528cda}' : 'Synthetic fiber channel adapter', - '{8c2eaf3d-32a7-4b09-ab99-bd1f1c86b501}' : 'Synthetic RDMA adapter', - '{276aacf4-ac15-426c-98dd-7521ad3f01fe}' : '[Reserved system device]', - '{f8e65716-3cb3-4a06-9a60-1889c5cccab5}' : '[Reserved system device]', - '{3375baf4-9e15-4b30-b765-67acb10d607b}' : '[Reserved system device]', -} - -def get_vmbus_dev_attr(dev_name, attr): - try: - f = open('%s/%s/%s' % (vmbus_sys_path, dev_name, attr), 'r') - lines = f.readlines() - f.close() - except IOError: - lines = [] - - return lines - -class VMBus_Dev: - pass - - -vmbus_dev_list = [] - -for f in os.listdir(vmbus_sys_path): - vmbus_id = get_vmbus_dev_attr(f, 'id')[0].strip() - class_id = get_vmbus_dev_attr(f, 'class_id')[0].strip() - device_id = get_vmbus_dev_attr(f, 'device_id')[0].strip() - dev_desc = vmbus_dev_dict.get(class_id, 'Unknown') - - chn_vp_mapping = get_vmbus_dev_attr(f, 'channel_vp_mapping') - chn_vp_mapping = [c.strip() for c in chn_vp_mapping] - chn_vp_mapping = sorted(chn_vp_mapping, - key = lambda c : int(c.split(':')[0])) - - chn_vp_mapping = ['\tRel_ID=%s, target_cpu=%s' % - (c.split(':')[0], c.split(':')[1]) - for c in chn_vp_mapping] - d = VMBus_Dev() - d.sysfs_path = '%s/%s' % (vmbus_sys_path, f) - d.vmbus_id = vmbus_id - d.class_id = class_id - d.device_id = device_id - d.dev_desc = dev_desc - d.chn_vp_mapping = '\n'.join(chn_vp_mapping) - if d.chn_vp_mapping: - d.chn_vp_mapping += '\n' - - vmbus_dev_list.append(d) - - -vmbus_dev_list = sorted(vmbus_dev_list, key = lambda d : int(d.vmbus_id)) - -format0 = '%2s: %s' -format1 = '%2s: Class_ID = %s - %s\n%s' -format2 = '%2s: Class_ID = %s - %s\n\tDevice_ID = %s\n\tSysfs path: %s\n%s' - -for d in vmbus_dev_list: - if verbose == 0: - print ('VMBUS ID ' + format0) % (d.vmbus_id, d.dev_desc) - elif verbose == 1: - print ('VMBUS ID ' + format1) % \ - (d.vmbus_id, d.class_id, d.dev_desc, d.chn_vp_mapping) - else: - print ('VMBUS ID ' + format2) % \ - (d.vmbus_id, d.class_id, d.dev_desc, \ - d.device_id, d.sysfs_path, d.chn_vp_mapping)