From 04cc92c36e9695088a441a6282c41558a30205834efc2ecd2cc5b8116c3b4b55 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Fri, 22 Mar 2013 15:49:02 +0000 Subject: [PATCH 1/7] - update hv_kvp_daemon Use CLOEXEC when opening kvp_pool files Fix permissions of created directory and files Fix /var subdirectory (move state files from /var/opt to /var/lib) Fix string types OBS-URL: https://build.opensuse.org/package/show/Virtualization/hyper-v?expand=0&rev=53 --- hyper-v.changes | 9 +++++++++ hyper-v.spec | 22 +++++++++++++++++++++- hyper-v.tools.hv.hv_kvp_daemon.c | 30 +++++++++++++++--------------- 3 files changed, 45 insertions(+), 16 deletions(-) diff --git a/hyper-v.changes b/hyper-v.changes index 884162e..3e66f33 100644 --- a/hyper-v.changes +++ b/hyper-v.changes @@ -1,3 +1,12 @@ +------------------------------------------------------------------- +Fri Mar 22 16:19:38 CET 2013 - ohering@suse.de + +- update hv_kvp_daemon + Use CLOEXEC when opening kvp_pool files + Fix permissions of created directory and files + Fix /var subdirectory (move state files from /var/opt to /var/lib) + Fix string types + ------------------------------------------------------------------- Tue Nov 27 11:19:32 CET 2012 - ohering@suse.de diff --git a/hyper-v.spec b/hyper-v.spec index d359cc8..f7ec428 100644 --- a/hyper-v.spec +++ b/hyper-v.spec @@ -1,7 +1,7 @@ # # spec file for package hyper-v # -# Copyright (c) 2012 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -21,6 +21,7 @@ Name: hyper-v ExclusiveArch: %ix86 x86_64 PreReq: %insserv_prereq +Requires(pre): coreutils Summary: Microsoft Hyper-V tools License: GPL-2.0 Group: System/Kernel @@ -81,6 +82,25 @@ ln -sfvbn ../../etc/init.d/%{hv_kvp_daemon} $RPM_BUILD_ROOT/usr/sbin/rc%{hv_kvp_ /usr/sbin/%{hv_kvp_daemon} /usr/lib/%{name} +%pre +# hv_kvp_daemon in SLES11 SP2 stored temporary state files in /var/opt +# move them to /var/lib and remove old directory, if possible. +if test -d /var/opt/hyperv +then + if mkdir -p -v -m 0755 /var/lib/hyperv && pushd /var/lib/hyperv > /dev/null + then + for oldfile in /var/opt/hyperv/ifcfg-* /var/opt/hyperv/.kvp_pool_* + do + if test -e "${oldfile}" + then + mv -vfb "${oldfile}" . || : + fi + done + popd > /dev/null + fi + rmdir -v /var/opt/hyperv || : +fi + %post board_vendor= product_name= diff --git a/hyper-v.tools.hv.hv_kvp_daemon.c b/hyper-v.tools.hv.hv_kvp_daemon.c index 7164441..272a3ea 100644 --- a/hyper-v.tools.hv.hv_kvp_daemon.c +++ b/hyper-v.tools.hv.hv_kvp_daemon.c @@ -97,7 +97,7 @@ static struct utsname uts_buf; * The location of the interface configuration file. */ -#define KVP_CONFIG_LOC "/var/opt/" +#define KVP_CONFIG_LOC "/var/lib/hyperv" #define MAX_FILE_NAME 100 #define ENTRIES_PER_BLOCK 50 @@ -151,7 +151,7 @@ static void kvp_update_file(int pool) */ kvp_acquire_lock(pool); - filep = fopen(kvp_file_info[pool].fname, "w"); + filep = fopen(kvp_file_info[pool].fname, "we"); if (!filep) { kvp_release_lock(pool); syslog(LOG_ERR, "Failed to open file, pool: %d", pool); @@ -182,7 +182,7 @@ static void kvp_update_mem_state(int pool) kvp_acquire_lock(pool); - filep = fopen(kvp_file_info[pool].fname, "r"); + filep = fopen(kvp_file_info[pool].fname, "re"); if (!filep) { kvp_release_lock(pool); syslog(LOG_ERR, "Failed to open file, pool: %d", pool); @@ -234,9 +234,9 @@ static int kvp_file_init(void) int i; int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK; - if (access("/var/opt/hyperv", F_OK)) { - if (mkdir("/var/opt/hyperv", S_IRUSR | S_IWUSR | S_IROTH)) { - syslog(LOG_ERR, " Failed to create /var/opt/hyperv"); + if (access(KVP_CONFIG_LOC, F_OK)) { + if (mkdir(KVP_CONFIG_LOC, 0755 /* rwxr-xr-x */)) { + syslog(LOG_ERR, " Failed to create %s", KVP_CONFIG_LOC); exit(EXIT_FAILURE); } } @@ -245,14 +245,14 @@ static int kvp_file_init(void) fname = kvp_file_info[i].fname; records_read = 0; num_blocks = 1; - sprintf(fname, "/var/opt/hyperv/.kvp_pool_%d", i); - fd = open(fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IROTH); + 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, "r"); + filep = fopen(fname, "re"); if (!filep) return 1; @@ -299,7 +299,7 @@ static int kvp_file_init(void) return 0; } -static int kvp_key_delete(int pool, __u8 *key, int key_size) +static int kvp_key_delete(int pool, const char *key, int key_size) { int i; int j, k; @@ -342,7 +342,7 @@ static int kvp_key_delete(int pool, __u8 *key, int key_size) return 1; } -static int kvp_key_add_or_modify(int pool, __u8 *key, int key_size, __u8 *value, +static int kvp_key_add_or_modify(int pool, const char *key, int key_size, const char *value, int value_size) { int i; @@ -396,7 +396,7 @@ static int kvp_key_add_or_modify(int pool, __u8 *key, int key_size, __u8 *value, return 0; } -static int kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value, +static int kvp_get_value(int pool, const char *key, int key_size, char *value, int value_size) { int i; @@ -428,8 +428,8 @@ static int kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value, return 1; } -static int kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size, - __u8 *value, int value_size) +static int kvp_pool_enumerate(int pool, int index, char *key, int key_size, + char *value, int value_size) { struct kvp_record *record; @@ -1271,7 +1271,7 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) */ snprintf(if_file, sizeof(if_file), "%s%s%s", KVP_CONFIG_LOC, - "hyperv/ifcfg-", if_name); + "/ifcfg-", if_name); file = fopen(if_file, "w"); From d6d5232591cf68f6971d6cde2d38b043f53e1f7f9174ecb05b577f18bb1ac9df Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Fri, 22 Mar 2013 15:58:18 +0000 Subject: [PATCH 2/7] - build hv_kvp_daemon with -D_GNU_SOURCE to get O_CLOEXEC OBS-URL: https://build.opensuse.org/package/show/Virtualization/hyper-v?expand=0&rev=54 --- hyper-v.changes | 5 +++++ hyper-v.spec | 1 + 2 files changed, 6 insertions(+) diff --git a/hyper-v.changes b/hyper-v.changes index 3e66f33..2bc1ec1 100644 --- a/hyper-v.changes +++ b/hyper-v.changes @@ -1,3 +1,8 @@ +------------------------------------------------------------------- +Fri Mar 22 16:56:57 CET 2013 - ohering@suse.de + +- build hv_kvp_daemon with -D_GNU_SOURCE to get O_CLOEXEC + ------------------------------------------------------------------- Fri Mar 22 16:19:38 CET 2013 - ohering@suse.de diff --git a/hyper-v.spec b/hyper-v.spec index f7ec428..ab63cd1 100644 --- a/hyper-v.spec +++ b/hyper-v.spec @@ -55,6 +55,7 @@ gcc \ $RPM_OPT_FLAGS \ -Wno-unused-variable \ -Wno-pointer-sign \ + -D_GNU_SOURCE \ -g \ %{hv_kvp_daemon}.c \ -include %{hv_kvp_daemon}.h \ From 906e78cd04145b8e4674ff555adef3befeeebfe7273c96091a8df50d259e2ee2 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Fri, 22 Mar 2013 16:24:55 +0000 Subject: [PATCH 3/7] - add hv_vss_daemon (fate#314921) helper to support host initiated backup OBS-URL: https://build.opensuse.org/package/show/Virtualization/hyper-v?expand=0&rev=55 --- hyper-v.changes | 6 + hyper-v.include.linux.hyperv.h | 57 ++++++++ hyper-v.init.vss.sh | 82 +++++++++++ hyper-v.spec | 27 +++- hyper-v.tools.hv.hv_vss_daemon.c | 225 +++++++++++++++++++++++++++++++ 5 files changed, 394 insertions(+), 3 deletions(-) create mode 100644 hyper-v.init.vss.sh create mode 100644 hyper-v.tools.hv.hv_vss_daemon.c diff --git a/hyper-v.changes b/hyper-v.changes index 2bc1ec1..900f544 100644 --- a/hyper-v.changes +++ b/hyper-v.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Fri Mar 22 17:23:36 CET 2013 - ohering@suse.de + +- add hv_vss_daemon (fate#314921) + helper to support host initiated backup + ------------------------------------------------------------------- Fri Mar 22 16:56:57 CET 2013 - ohering@suse.de diff --git a/hyper-v.include.linux.hyperv.h b/hyper-v.include.linux.hyperv.h index 2e9f44a..d120550 100644 --- a/hyper-v.include.linux.hyperv.h +++ b/hyper-v.include.linux.hyperv.h @@ -27,6 +27,63 @@ #include + +/* + * Implementation of host controlled snapshot of the guest. + */ + +#define VSS_OP_REGISTER 128 + +enum hv_vss_op { + VSS_OP_CREATE = 0, + VSS_OP_DELETE, + VSS_OP_HOT_BACKUP, + VSS_OP_GET_DM_INFO, + VSS_OP_BU_COMPLETE, + /* + * Following operations are only supported with IC version >= 5.0 + */ + VSS_OP_FREEZE, /* Freeze the file systems in the VM */ + VSS_OP_THAW, /* Unfreeze the file systems */ + VSS_OP_AUTO_RECOVER, + VSS_OP_COUNT /* Number of operations, must be last */ +}; + + +/* + * Header for all VSS messages. + */ +struct hv_vss_hdr { + __u8 operation; + __u8 reserved[7]; +} __attribute__((packed)); + + +/* + * Flag values for the hv_vss_check_feature. Linux supports only + * one value. + */ +#define VSS_HBU_NO_AUTO_RECOVERY 0x00000005 + +struct hv_vss_check_feature { + __u32 flags; +} __attribute__((packed)); + +struct hv_vss_check_dm_info { + __u32 flags; +} __attribute__((packed)); + +struct hv_vss_msg { + union { + struct hv_vss_hdr vss_hdr; + int error; + }; + union { + struct hv_vss_check_feature vss_cf; + struct hv_vss_check_dm_info dm_info; + }; +} __attribute__((packed)); + /* * An implementation of HyperV key value pair (KVP) functionality for Linux. * diff --git a/hyper-v.init.vss.sh b/hyper-v.init.vss.sh new file mode 100644 index 0000000..a714976 --- /dev/null +++ b/hyper-v.init.vss.sh @@ -0,0 +1,82 @@ +#!/bin/sh +# +# LSB compatible service control script; see http://www.linuxbase.org/spec/ +# +### BEGIN INIT INFO +# Provides: hv_vss_daemon +# Required-Start: $null +# Should-Start: $syslog $remote_fs $time +# Required-Stop: $null +# Should-Stop: $syslog $remote_fs $time +# Default-Start: 3 5 +# Default-Stop: 0 1 2 6 +# Short-Description: hv_vss_daemon assists with host initiated backup +# Description: Start hv_vss_daemon to allow the host to snapshot this guest +### END INIT INFO + +# Check for missing binaries (stale symlinks should not happen) +# Note: Special treatment of stop for LSB conformance +HV_VSS_BIN=/usr/sbin/hv_vss_daemon +test -x $HV_VSS_BIN || { echo "$HV_VSS_BIN not installed"; + if [ "$1" = "stop" ]; then exit 0; + else exit 5; fi; } + +. /etc/rc.status + +# Reset status of this service +rc_reset + +case "$1" in + start) + echo -n "Starting Hyper-V VSS daemon " + env PATH=/usr/lib/hyper-v/bin:$PATH \ + startproc $HV_VSS_BIN + rc_status -v + ;; + stop) + echo -n "Shutting down Hyper-V VSS daemon " + killproc -TERM $HV_VSS_BIN + rc_status -v + ;; + try-restart|condrestart) + if test "$1" = "condrestart"; then + echo "${attn} Use try-restart ${done}(LSB)${attn} rather than condrestart ${warn}(RH)${norm}" + fi + $0 status + if test $? = 0; then + $0 restart + else + rc_reset # Not running is not a failure. + fi + # Remember status and be quiet + rc_status + ;; + restart) + ## Stop the service and regardless of whether it was + ## running or not, start it again. + $0 stop + $0 start + + # Remember status and be quiet + rc_status + ;; + force-reload) + echo -n "Reload service Hyper-V VSS daemon " + $0 try-restart + rc_status + ;; + reload) + rc_failed 3 + rc_status -v + ;; + status) + echo -n "Checking for service Hyper-V VSS daemon " + checkproc $HV_VSS_BIN + rc_status -v + ;; + *) + echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload}" + exit 1 + ;; +esac +rc_exit diff --git a/hyper-v.spec b/hyper-v.spec index ab63cd1..f872518 100644 --- a/hyper-v.spec +++ b/hyper-v.spec @@ -17,6 +17,7 @@ %define hv_kvp_daemon hv_kvp_daemon +%define hv_vss_daemon hv_vss_daemon Name: hyper-v ExclusiveArch: %ix86 x86_64 @@ -34,6 +35,8 @@ Source5: hyper-v.kvptest.ps1.txt Source9: hyper-v.include.linux.hyperv.h Source10: hyper-v.tools.hv.hv_kvp_daemon.c Source11: hyper-v.init.sh +Source12: hyper-v.tools.hv.hv_vss_daemon.c +Source13: hyper-v.init.vss.sh Source20: hyper-v.tools.hv.hv_get_dhcp_info.sh Source21: hyper-v.tools.hv.hv_get_dns_info.sh Source22: hyper-v.tools.hv.hv_set_ifconfig.sh @@ -48,9 +51,11 @@ This package contains the Microsoft Hyper-V tools. cp -avL %{S:5} kvptest.ps1.txt cp -vL %{S:9} %{hv_kvp_daemon}.h cp -vL %{S:10} %{hv_kvp_daemon}.c +cp -vL %{S:12} %{hv_vss_daemon}.c %build sed -i~ '/#include /d' %{hv_kvp_daemon}.c +sed -i~ '/#include /d' %{hv_vss_daemon}.c gcc \ $RPM_OPT_FLAGS \ -Wno-unused-variable \ @@ -62,10 +67,22 @@ gcc \ -DCN_KVP_IDX=0x9 \ -DCN_KVP_VAL=0x1 \ -o %{hv_kvp_daemon} +gcc \ + $RPM_OPT_FLAGS \ + -Wno-unused-variable \ + -Wno-pointer-sign \ + -D_GNU_SOURCE \ + -g \ + %{hv_vss_daemon}.c \ + -include %{hv_kvp_daemon}.h \ + -DCN_VSS_IDX=0xa \ + -DCN_VSS_VAL=0x1 \ + -o %{hv_vss_daemon} %install mkdir -p $RPM_BUILD_ROOT/usr/sbin install -m755 %{hv_kvp_daemon} $RPM_BUILD_ROOT/usr/sbin +install -m755 %{hv_vss_daemon} $RPM_BUILD_ROOT/usr/sbin mkdir -p $RPM_BUILD_ROOT/usr/lib/%{name}/bin cp -avL %{S:20} $RPM_BUILD_ROOT/usr/lib/%{name}/bin/hv_get_dhcp_info cp -avL %{S:21} $RPM_BUILD_ROOT/usr/lib/%{name}/bin/hv_get_dns_info @@ -74,13 +91,14 @@ chmod 755 $RPM_BUILD_ROOT/usr/lib/%{name}/bin/* mkdir -p $RPM_BUILD_ROOT/etc/init.d install -m755 %{S:11} $RPM_BUILD_ROOT/etc/init.d/%{hv_kvp_daemon} ln -sfvbn ../../etc/init.d/%{hv_kvp_daemon} $RPM_BUILD_ROOT/usr/sbin/rc%{hv_kvp_daemon} +install -m755 %{S:13} $RPM_BUILD_ROOT/etc/init.d/%{hv_vss_daemon} +ln -sfvbn ../../etc/init.d/%{hv_vss_daemon} $RPM_BUILD_ROOT/usr/sbin/rc%{hv_vss_daemon} %files %defattr (-,root,root) %doc kvptest.ps1.txt -/etc/init.d/%{hv_kvp_daemon} -/usr/sbin/rc%{hv_kvp_daemon} -/usr/sbin/%{hv_kvp_daemon} +/etc/init.d/* +/usr/sbin/* /usr/lib/%{name} %pre @@ -121,10 +139,13 @@ if test "${board_vendor}" = "Microsoft Corporation" -a "${product_name}" = "Virt then echo "Enabling %{hv_kvp_daemon} on '${product_name}' from '${board_vendor}'" %{insserv_force_if_yast %{hv_kvp_daemon}} + echo "Enabling %{hv_vss_daemon} on '${product_name}' from '${board_vendor}'" + %{insserv_force_if_yast %{hv_vss_daemon}} fi %preun %stop_on_removal %{hv_kvp_daemon} +%stop_on_removal %{hv_vss_daemon} %postun # no restart on update because the daemon can not be restarted diff --git a/hyper-v.tools.hv.hv_vss_daemon.c b/hyper-v.tools.hv.hv_vss_daemon.c new file mode 100644 index 0000000..cd4f5c0 --- /dev/null +++ b/hyper-v.tools.hv.hv_vss_daemon.c @@ -0,0 +1,225 @@ +/* + * 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 + +static char vss_recv_buffer[4096]; +static char vss_send_buffer[4096]; +static struct sockaddr_nl addr; + +#ifndef SOL_NETLINK +#define SOL_NETLINK 270 +#endif + + +static int vss_operate(int operation) +{ + char *fs_op; + char cmd[512]; + char buf[512]; + FILE *file; + char *p; + char *x; + int error = -1; + + switch (operation) { + case VSS_OP_FREEZE: + fs_op = "-f "; + break; + case VSS_OP_THAW: + fs_op = "-u "; + break; + default: + goto out; + } + + file = popen("mount | awk '/^\\/dev\\// { print $3}'", "r"); + if (file == NULL) + goto out; + + while ((p = fgets(buf, sizeof(buf), file)) != NULL) { + x = strchr(p, '\n'); + *x = '\0'; + if (!strncmp(p, "/", sizeof("/"))) + continue; + + sprintf(cmd, "%s %s %s", "fsfreeze ", fs_op, p); + syslog(LOG_INFO, "VSS cmd is %s\n", cmd); + error = system(cmd); + } + pclose(file); + + sprintf(cmd, "%s %s %s", "fsfreeze ", fs_op, "/"); + syslog(LOG_INFO, "VSS cmd is %s\n", cmd); + error = system(cmd); + +out: + return error; +} + +static int netlink_send(int fd, struct cn_msg *msg) +{ + struct nlmsghdr *nlh; + unsigned int size; + struct msghdr message; + char buffer[64]; + struct iovec iov[2]; + + size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len); + + nlh = (struct nlmsghdr *)buffer; + nlh->nlmsg_seq = 0; + nlh->nlmsg_pid = getpid(); + nlh->nlmsg_type = NLMSG_DONE; + nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh)); + nlh->nlmsg_flags = 0; + + 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); +} + +int main(void) +{ + 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; + + if (daemon(1, 0)) + return 1; + + openlog("Hyper-V VSS", 0, LOG_USER); + syslog(LOG_INFO, "VSS starting; pid is:%d", getpid()); + + fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); + if (fd < 0) { + syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd); + 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", error); + close(fd); + exit(EXIT_FAILURE); + } + nl_group = CN_VSS_IDX; + setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &nl_group, sizeof(nl_group)); + /* + * Register ourselves with the kernel. + */ + message = (struct cn_msg *)vss_send_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", len); + 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; + poll(&pfd, 1, -1); + + len = recvfrom(fd, vss_recv_buffer, sizeof(vss_recv_buffer), 0, + addr_p, &addr_l); + + if (len < 0 || addr.nl_pid) { + syslog(LOG_ERR, "recvfrom failed; pid:%u error:%d %s", + addr.nl_pid, errno, strerror(errno)); + close(fd); + return -1; + } + + 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); + if (error) + error = HV_E_FAIL; + 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", len); + exit(EXIT_FAILURE); + } + } + +} From 8eff0a9f9ece2c62ba09b53661b4bcf908560abd44223478224f35700bd7f242 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Tue, 26 Mar 2013 17:06:22 +0000 Subject: [PATCH 4/7] - Update hv_vss_daemon (bnc#811033) OBS-URL: https://build.opensuse.org/package/show/Virtualization/hyper-v?expand=0&rev=56 --- hyper-v.changes | 5 +++ hyper-v.spec | 3 +- hyper-v.tools.hv.hv_vss_daemon.c | 73 ++++++++++++++++++++------------ 3 files changed, 54 insertions(+), 27 deletions(-) diff --git a/hyper-v.changes b/hyper-v.changes index 900f544..2fb697e 100644 --- a/hyper-v.changes +++ b/hyper-v.changes @@ -1,3 +1,8 @@ +------------------------------------------------------------------- +Tue Mar 26 18:03:47 CET 2013 - ohering@suse.de + +- Update hv_vss_daemon (bnc#811033) + ------------------------------------------------------------------- Fri Mar 22 17:23:36 CET 2013 - ohering@suse.de diff --git a/hyper-v.spec b/hyper-v.spec index f872518..fc7b7c3 100644 --- a/hyper-v.spec +++ b/hyper-v.spec @@ -29,7 +29,8 @@ Group: System/Kernel Supplements: modalias(dmi*:svn*MicrosoftCorporation*:pn*VirtualMachine*:rn*VirtualMachine*) Supplements: modalias(pci:v00001414d00005353sv*sd*bc*sc*i*) Url: http://www.kernel.org -Version: 4 +# Arbitrary version number +Version: 5 Release: 0 Source5: hyper-v.kvptest.ps1.txt Source9: hyper-v.include.linux.hyperv.h diff --git a/hyper-v.tools.hv.hv_vss_daemon.c b/hyper-v.tools.hv.hv_vss_daemon.c index cd4f5c0..5b36ea7 100644 --- a/hyper-v.tools.hv.hv_vss_daemon.c +++ b/hyper-v.tools.hv.hv_vss_daemon.c @@ -21,14 +21,18 @@ #include #include #include +#include #include +#include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -43,48 +47,59 @@ static struct sockaddr_nl addr; #endif +static int vss_do_freeze(char *dir, unsigned int cmd, char *fs_op) +{ + int ret, fd = open(dir, O_RDONLY); + + if (fd < 0) + return -1; + ret = ioctl(fd, cmd, 0); + syslog(LOG_INFO, "VSS: %s of %s: %s\n", fs_op, dir, strerror(errno)); + close(fd); + return !!ret; +} + static int vss_operate(int operation) { char *fs_op; - char cmd[512]; - char buf[512]; - FILE *file; - char *p; - char *x; - int error = -1; + char match[] = "/dev/"; + FILE *mounts; + struct mntent *ent; + unsigned int cmd; + int error = 0, root_seen = 0; switch (operation) { case VSS_OP_FREEZE: - fs_op = "-f "; + cmd = FIFREEZE; + fs_op = "freeze"; break; case VSS_OP_THAW: - fs_op = "-u "; + cmd = FITHAW; + fs_op = "thaw"; break; default: - goto out; + return -1; } - file = popen("mount | awk '/^\\/dev\\// { print $3}'", "r"); - if (file == NULL) - goto out; + mounts = setmntent("/proc/mounts", "r"); + if (mounts == NULL) + return -1; - while ((p = fgets(buf, sizeof(buf), file)) != NULL) { - x = strchr(p, '\n'); - *x = '\0'; - if (!strncmp(p, "/", sizeof("/"))) + while((ent = getmntent(mounts))) { + if (strncmp(ent->mnt_fsname, match, strlen(match))) continue; - - sprintf(cmd, "%s %s %s", "fsfreeze ", fs_op, p); - syslog(LOG_INFO, "VSS cmd is %s\n", cmd); - error = system(cmd); + if (strcmp(ent->mnt_dir, "/") == 0) { + root_seen = 1; + continue; + } + error |= vss_do_freeze(ent->mnt_dir, cmd, fs_op); } - pclose(file); + endmntent(mounts); - sprintf(cmd, "%s %s %s", "fsfreeze ", fs_op, "/"); - syslog(LOG_INFO, "VSS cmd is %s\n", cmd); - error = system(cmd); + if (root_seen) { + error |= vss_do_freeze("/", cmd, fs_op); + } -out: return error; } @@ -187,13 +202,19 @@ int main(void) len = recvfrom(fd, vss_recv_buffer, sizeof(vss_recv_buffer), 0, addr_p, &addr_l); - if (len < 0 || addr.nl_pid) { + 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) From 727d8197fcf3df2c6d18c7b71c0157ea75f8755d9c9b0ca01eeb0d89e4f65686 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Mon, 15 Jul 2013 10:04:35 +0000 Subject: [PATCH 5/7] - Fix a bug in IPV6 subnet enumeration (bnc#828714) OBS-URL: https://build.opensuse.org/package/show/Virtualization/hyper-v?expand=0&rev=57 --- hyper-v.changes | 5 +++++ hyper-v.tools.hv.hv_kvp_daemon.c | 5 +++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/hyper-v.changes b/hyper-v.changes index 2fb697e..42ec751 100644 --- a/hyper-v.changes +++ b/hyper-v.changes @@ -1,3 +1,8 @@ +------------------------------------------------------------------- +Mon Jul 15 12:04:05 CEST 2013 - ohering@suse.de + +- Fix a bug in IPV6 subnet enumeration (bnc#828714) + ------------------------------------------------------------------- Tue Mar 26 18:03:47 CET 2013 - ohering@suse.de diff --git a/hyper-v.tools.hv.hv_kvp_daemon.c b/hyper-v.tools.hv.hv_kvp_daemon.c index 272a3ea..bf5de4e 100644 --- a/hyper-v.tools.hv.hv_kvp_daemon.c +++ b/hyper-v.tools.hv.hv_kvp_daemon.c @@ -1012,9 +1012,10 @@ kvp_get_ip_info(int family, char *if_name, int op, if (sn_offset == 0) strcpy(sn_str, cidr_mask); - else + else { + strcat((char *)ip_buffer->sub_net, ";"); strcat(sn_str, cidr_mask); - strcat((char *)ip_buffer->sub_net, ";"); + } sn_offset += strlen(sn_str) + 1; } From 1051dacf7ebd41c6d94cb4d32bb7e8c73d0eefeafa88ee83a79fbb2c2dba9fdb Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Mon, 15 Jul 2013 14:11:35 +0000 Subject: [PATCH 6/7] - update hv_kvp_daemon (changes up to 3.11-rc1): Improve error logging in KVP daemon. Fix file descriptor leaks Check retrun value of strchr call Check return value of poll call Check return value of setsockopt call daemon should check type of received Netlink msg daemon setsockopt should use options macros daemon should subscribe only to CN_KVP_IDX group OBS-URL: https://build.opensuse.org/package/show/Virtualization/hyper-v?expand=0&rev=58 --- hyper-v.changes | 13 ++++++ hyper-v.tools.hv.hv_kvp_daemon.c | 72 ++++++++++++++++++++++++-------- 2 files changed, 67 insertions(+), 18 deletions(-) diff --git a/hyper-v.changes b/hyper-v.changes index 42ec751..36bd2d4 100644 --- a/hyper-v.changes +++ b/hyper-v.changes @@ -1,3 +1,16 @@ +------------------------------------------------------------------- +Mon Jul 15 15:24:00 CEST 2013 - ohering@suse.de + +- update hv_kvp_daemon (changes up to 3.11-rc1): + Improve error logging in KVP daemon. + Fix file descriptor leaks + Check retrun value of strchr call + Check return value of poll call + Check return value of setsockopt call + daemon should check type of received Netlink msg + daemon setsockopt should use options macros + daemon should subscribe only to CN_KVP_IDX group + ------------------------------------------------------------------- Mon Jul 15 12:04:05 CEST 2013 - ohering@suse.de diff --git a/hyper-v.tools.hv.hv_kvp_daemon.c b/hyper-v.tools.hv.hv_kvp_daemon.c index bf5de4e..2683322 100644 --- a/hyper-v.tools.hv.hv_kvp_daemon.c +++ b/hyper-v.tools.hv.hv_kvp_daemon.c @@ -102,6 +102,10 @@ static struct utsname uts_buf; #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]; @@ -123,7 +127,8 @@ static void kvp_acquire_lock(int pool) 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", pool); + syslog(LOG_ERR, "Failed to acquire the lock pool: %d; error: %d %s", pool, + errno, strerror(errno)); exit(EXIT_FAILURE); } } @@ -134,8 +139,8 @@ static void kvp_release_lock(int pool) fl.l_pid = getpid(); if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) { - perror("fcntl"); - syslog(LOG_ERR, "Failed to release the lock pool: %d", pool); + syslog(LOG_ERR, "Failed to release the lock pool: %d; error: %d %s", pool, + errno, strerror(errno)); exit(EXIT_FAILURE); } } @@ -153,8 +158,9 @@ static void kvp_update_file(int 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); - syslog(LOG_ERR, "Failed to open file, pool: %d", pool); exit(EXIT_FAILURE); } @@ -184,8 +190,9 @@ static void kvp_update_mem_state(int 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); - syslog(LOG_ERR, "Failed to open file, pool: %d", pool); exit(EXIT_FAILURE); } for (;;) { @@ -236,7 +243,8 @@ static int kvp_file_init(void) if (access(KVP_CONFIG_LOC, F_OK)) { if (mkdir(KVP_CONFIG_LOC, 0755 /* rwxr-xr-x */)) { - syslog(LOG_ERR, " Failed to create %s", KVP_CONFIG_LOC); + syslog(LOG_ERR, "Failed to create '%s'; error: %d %s", KVP_CONFIG_LOC, + errno, strerror(errno)); exit(EXIT_FAILURE); } } @@ -253,12 +261,15 @@ static int kvp_file_init(void) filep = fopen(fname, "re"); - if (!filep) + if (!filep) { + close(fd); return 1; + } record = malloc(alloc_unit * num_blocks); if (record == NULL) { fclose(filep); + close(fd); return 1; } for (;;) { @@ -282,6 +293,7 @@ static int kvp_file_init(void) num_blocks); if (record == NULL) { fclose(filep); + close(fd); return 1; } continue; @@ -761,7 +773,9 @@ static void kvp_process_ipconfig_file(char *cmd, break; x = strchr(p, '\n'); - *x = '\0'; + if (x) + *x = '\0'; + strcat(config_buf, p); strcat(config_buf, ";"); } @@ -1277,7 +1291,8 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) file = fopen(if_file, "w"); if (file == NULL) { - syslog(LOG_ERR, "Failed to open config file"); + syslog(LOG_ERR, "Failed to open config file; error: %d %s", + errno, strerror(errno)); return HV_E_FAIL; } @@ -1409,7 +1424,7 @@ netlink_send(int fd, struct cn_msg *msg) int main(void) { - int fd, len, sock_opt; + int fd, len, nl_group; int error; struct cn_msg *message; struct pollfd pfd; @@ -1439,23 +1454,30 @@ int main(void) fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); if (fd < 0) { - syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd); + 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 = CN_KVP_IDX; + addr.nl_groups = 0; error = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); if (error < 0) { - syslog(LOG_ERR, "bind failed; error:%d", error); + syslog(LOG_ERR, "bind failed; error: %d %s", errno, strerror(errno)); close(fd); exit(EXIT_FAILURE); } - sock_opt = addr.nl_groups; - setsockopt(fd, 270, 1, &sock_opt, sizeof(sock_opt)); + 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. */ @@ -1470,7 +1492,7 @@ int main(void) len = netlink_send(fd, message); if (len < 0) { - syslog(LOG_ERR, "netlink_send failed; error:%d", len); + syslog(LOG_ERR, "netlink_send failed; error: %d %s", errno, strerror(errno)); close(fd); exit(EXIT_FAILURE); } @@ -1482,7 +1504,16 @@ int main(void) socklen_t addr_l = sizeof(addr); pfd.events = POLLIN; pfd.revents = 0; - poll(&pfd, 1, -1); + + 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, sizeof(kvp_recv_buffer), 0, addr_p, &addr_l); @@ -1501,6 +1532,10 @@ int main(void) } 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; @@ -1689,7 +1724,8 @@ kvp_done: len = netlink_send(fd, incoming_cn_msg); if (len < 0) { - syslog(LOG_ERR, "net_link send failed; error:%d", len); + syslog(LOG_ERR, "net_link send failed; error: %d %s", errno, + strerror(errno)); exit(EXIT_FAILURE); } } From d58ac4b8e0e394b98f2936803cbf16657ef7bcdc11c9dcbcc7d218bf770befd3 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Mon, 15 Jul 2013 14:17:26 +0000 Subject: [PATCH 7/7] - update hv_kvp_daemon (merge 0783d72fa from v3.9-rc1) Fix how ifcfg-* file is created OBS-URL: https://build.opensuse.org/package/show/Virtualization/hyper-v?expand=0&rev=59 --- hyper-v.changes | 6 +++ hyper-v.tools.hv.hv_kvp_daemon.c | 59 ++++++++++++++--------------- hyper-v.tools.hv.hv_set_ifconfig.sh | 41 ++++++++++---------- 3 files changed, 56 insertions(+), 50 deletions(-) diff --git a/hyper-v.changes b/hyper-v.changes index 36bd2d4..104ad6f 100644 --- a/hyper-v.changes +++ b/hyper-v.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Mon Jul 15 16:16:06 CEST 2013 - ohering@suse.de + +- update hv_kvp_daemon (merge 0783d72fa from v3.9-rc1) + Fix how ifcfg-* file is created + ------------------------------------------------------------------- Mon Jul 15 15:24:00 CEST 2013 - ohering@suse.de diff --git a/hyper-v.tools.hv.hv_kvp_daemon.c b/hyper-v.tools.hv.hv_kvp_daemon.c index 2683322..d4fcafa 100644 --- a/hyper-v.tools.hv.hv_kvp_daemon.c +++ b/hyper-v.tools.hv.hv_kvp_daemon.c @@ -1177,16 +1177,13 @@ static int process_ip_string(FILE *f, char *ip_string, int type) snprintf(str, sizeof(str), "%s", "DNS"); break; } - if (i != 0) { - if (type != DNS) { - snprintf(sub_str, sizeof(sub_str), - "_%d", i++); - } else { - snprintf(sub_str, sizeof(sub_str), - "%d", ++i); - } - } else if (type == DNS) { + + 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++); } @@ -1206,17 +1203,13 @@ static int process_ip_string(FILE *f, char *ip_string, int type) snprintf(str, sizeof(str), "%s", "DNS"); break; } - if ((j != 0) || (type == DNS)) { - if (type != DNS) { - snprintf(sub_str, sizeof(sub_str), - "_%d", j++); - } else { - snprintf(sub_str, sizeof(sub_str), - "%d", ++i); - } - } else if (type == DNS) { - snprintf(sub_str, sizeof(sub_str), - "%d", ++i); + + 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; @@ -1259,18 +1252,19 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) * Here is the format of the ip configuration file: * * HWADDR=macaddr - * IF_NAME=interface name - * DHCP=yes (This is optional; if yes, DHCP is configured) + * DEVICE=interface name + * BOOTPROTO= (where is "dhcp" if DHCP is configured + * or "none" if no boot-time protocol should be used) * - * IPADDR=ipaddr1 - * IPADDR_1=ipaddr2 - * IPADDR_x=ipaddry (where y = x + 1) + * IPADDR0=ipaddr1 + * IPADDR1=ipaddr2 + * IPADDRx=ipaddry (where y = x + 1) * - * NETMASK=netmask1 - * NETMASK_x=netmasky (where y = x + 1) + * NETMASK0=netmask1 + * NETMASKx=netmasky (where y = x + 1) * * GATEWAY=ipaddr1 - * GATEWAY_x=ipaddry (where y = x + 1) + * GATEWAYx=ipaddry (where y = x + 1) * * DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc) * @@ -1310,12 +1304,12 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) if (error) goto setval_error; - error = kvp_write_file(file, "IF_NAME", "", if_name); + error = kvp_write_file(file, "DEVICE", "", if_name); if (error) goto setval_error; if (new_val->dhcp_enabled) { - error = kvp_write_file(file, "DHCP", "", "yes"); + error = kvp_write_file(file, "BOOTPROTO", "", "dhcp"); if (error) goto setval_error; @@ -1323,6 +1317,11 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) * We are done!. */ goto setval_done; + + } else { + error = kvp_write_file(file, "BOOTPROTO", "", "none"); + if (error) + goto setval_error; } /* diff --git a/hyper-v.tools.hv.hv_set_ifconfig.sh b/hyper-v.tools.hv.hv_set_ifconfig.sh index a776d43..695652f 100644 --- a/hyper-v.tools.hv.hv_set_ifconfig.sh +++ b/hyper-v.tools.hv.hv_set_ifconfig.sh @@ -10,18 +10,19 @@ # Here is the format of the ip configuration file: # # HWADDR=macaddr -# IF_NAME=interface name -# DHCP=yes (This is optional; if yes, DHCP is configured) +# DEVICE=interface name +# BOOTPROTO= (where is "dhcp" if DHCP is configured +# or "none" if no boot-time protocol should be used) # -# IPADDR=ipaddr1 -# IPADDR_1=ipaddr2 -# IPADDR_x=ipaddry (where y = x + 1) +# IPADDR0=ipaddr1 +# IPADDR1=ipaddr2 +# IPADDRx=ipaddry (where y = x + 1) # -# NETMASK=netmask1 -# NETMASK_x=netmasky (where y = x + 1) +# NETMASK0=netmask1 +# NETMASKx=netmasky (where y = x + 1) # # GATEWAY=ipaddr1 -# GATEWAY_x=ipaddry (where y = x + 1) +# GATEWAYx=ipaddry (where y = x + 1) # # DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc) # @@ -53,8 +54,8 @@ else fi # remove known config variables from environment unset HWADDR -unset DHCP -unset IF_NAME +unset BOOTPROTO +unset DEVICE unset ${!IPADDR*} unset ${!NETMASK*} unset ${!GATEWAY*} @@ -64,9 +65,9 @@ unset ${!IPV6_DEFAULTGW*} unset ${!DNS*} . "$1" # -if test -z "${IF_NAME}" +if test -z "${DEVICE}" then - echo "Missing IF_NAME= in ${cfg}" + echo "Missing DEVICE= in ${cfg}" exit 1 fi # @@ -91,7 +92,7 @@ fi : # ignore HWADDR, it just repeats the existing MAC value fi # - if test "${DHCP}" = "yes" + if test "${BOOTPROTO}" = "dhcp" then echo "BOOTPROTO=dhcp" fi @@ -145,11 +146,11 @@ fi ( if test -n "${GATEWAY}" then - echo "default $GATEWAY - $IF_NAME" + echo "default $GATEWAY - $DEVICE" fi if test -n "${IPV6_DEFAULTGW}" then - echo "default $IPV6_DEFAULTGW - $IF_NAME" + echo "default $IPV6_DEFAULTGW - $DEVICE" fi ) >> "${t_ifroute}" # Only a single default gateway is supported @@ -172,14 +173,14 @@ do fi done # -echo "$0: working on network interface ifcfg-${IF_NAME}" -cp -fb ${t_ifcfg} "/etc/sysconfig/network/ifcfg-${IF_NAME}" -cp -fb ${t_ifroute} "/etc/sysconfig/network/ifroute-${IF_NAME}" +echo "$0: working on network interface ifcfg-${DEVICE}" +cp -fb ${t_ifcfg} "/etc/sysconfig/network/ifcfg-${DEVICE}" +cp -fb ${t_ifroute} "/etc/sysconfig/network/ifroute-${DEVICE}" if test -w /etc/sysconfig/network/config then sed -i "s@^NETCONFIG_DNS_STATIC_SERVERS=.*@NETCONFIG_DNS_STATIC_SERVERS='$_DNS_'@" /etc/sysconfig/network/config netconfig update -m dns fi -ifdown "${IF_NAME}" -ifup "${IF_NAME}" +ifdown "${DEVICE}" +ifup "${DEVICE}" ) 2>&1 | logger -t "${0##*/}[$PPID / $$]"