diff --git a/hyper-v.changes b/hyper-v.changes index 9ca2ea8..38aa81f 100644 --- a/hyper-v.changes +++ b/hyper-v.changes @@ -1,3 +1,15 @@ +------------------------------------------------------------------- +Thu Jan 23 17:00:54 CET 2014 - ohering@suse.de + +- Start daemons on demand via udev rules because the guest services + are optional. +- If systemd is used daemons live in libdir, they are not usercallable apps + +------------------------------------------------------------------- +Thu Jan 16 11:09:34 CET 2014 - ohering@suse.de + +- Add hv_fcopy_daemon for post 13.1 releases (fate#315887) + ------------------------------------------------------------------- Wed Dec 18 14:46:37 CET 2013 - ohering@suse.de diff --git a/hyper-v.include.linux.hyperv.h b/hyper-v.include.linux.hyperv.h index d120550..6e66087 100644 --- a/hyper-v.include.linux.hyperv.h +++ b/hyper-v.include.linux.hyperv.h @@ -26,6 +26,7 @@ #define _HYPERV_H #include +#include /* @@ -84,6 +85,52 @@ struct hv_vss_msg { }; } __attribute__((packed)); + +/* + * Implementation of a host to guest copy facility. + */ + +#define FCOPY_VERSION_0 0 +#define FCOPY_CURRENT_VERSION FCOPY_VERSION_0 +#define W_MAX_PATH 260 + +enum hv_fcopy_op { + START_FILE_COPY = 0, + WRITE_TO_FILE, + COMPLETE_FCOPY, + CANCEL_FCOPY, +}; + +struct hv_fcopy_hdr { + __u32 operation; + uuid_le service_id0; /* currently unused */ + uuid_le service_id1; /* currently unused */ +} __attribute__((packed)); + +#define OVER_WRITE 0x1 +#define CREATE_PATH 0x2 + +struct hv_start_fcopy { + struct hv_fcopy_hdr hdr; + __u16 file_name[W_MAX_PATH]; + __u16 path_name[W_MAX_PATH]; + __u32 copy_flags; + __u64 file_size; +} __attribute__((packed)); + +/* + * The file is chunked into fragments. + */ +#define DATA_FRAGMENT (6 * 1024) + +struct hv_do_fcopy { + struct hv_fcopy_hdr hdr; + __u64 offset; + __u32 size; + __u8 data[DATA_FRAGMENT]; +}; + + /* * An implementation of HyperV key value pair (KVP) functionality for Linux. * diff --git a/hyper-v.spec b/hyper-v.spec index d98e002..70af620 100644 --- a/hyper-v.spec +++ b/hyper-v.spec @@ -1,7 +1,7 @@ # # spec file for package hyper-v # -# Copyright (c) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2014 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 @@ -18,6 +18,7 @@ %define hv_kvp_daemon hv_kvp_daemon %define hv_vss_daemon hv_vss_daemon +%define hv_fcopy_daemon hv_fcopy_daemon %define helper_dir /usr/lib/%{name} Name: hyper-v @@ -50,6 +51,7 @@ 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 +Source14: hyper-v.tools.hv.hv_fcopy_daemon.c 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 @@ -65,10 +67,12 @@ 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 +cp -vL %{S:14} %{hv_fcopy_daemon}.c %build sed -i~ '/#include /d' %{hv_kvp_daemon}.c sed -i~ '/#include /d' %{hv_vss_daemon}.c +sed -i~ '/#include /d' %{hv_fcopy_daemon}.c gcc \ $RPM_OPT_FLAGS \ -Wno-unused-variable \ @@ -91,12 +95,28 @@ gcc \ -DCN_VSS_IDX=0xa \ -DCN_VSS_VAL=0x1 \ -o %{hv_vss_daemon} +gcc \ + $RPM_OPT_FLAGS \ + -Wno-unused-variable \ + -Wno-pointer-sign \ + -D_GNU_SOURCE \ + -g \ + %{hv_fcopy_daemon}.c \ + -include %{hv_kvp_daemon}.h \ + -o %{hv_fcopy_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 +%if %{use_systemd} +# It is not a callable app anyway, so move it out of the way +bindir=%{helper_dir}/bin +%else +bindir=/usr/sbin +%endif +mkdir -p $RPM_BUILD_ROOT${bindir} mkdir -p $RPM_BUILD_ROOT%{helper_dir}/bin +install -m755 %{hv_kvp_daemon} $RPM_BUILD_ROOT${bindir} +install -m755 %{hv_vss_daemon} $RPM_BUILD_ROOT${bindir} +install -m755 %{hv_fcopy_daemon} $RPM_BUILD_ROOT${bindir} cp -avL %{S:20} $RPM_BUILD_ROOT%{helper_dir}/bin/hv_get_dhcp_info cp -avL %{S:21} $RPM_BUILD_ROOT%{helper_dir}/bin/hv_get_dns_info cp -avL %{S:22} $RPM_BUILD_ROOT%{helper_dir}/bin/hv_set_ifconfig @@ -105,18 +125,19 @@ chmod 755 $RPM_BUILD_ROOT%{helper_dir}/bin/* d=$RPM_BUILD_ROOT%{_unitdir} mkdir -vp ${d} # -cat > ${d}/%{hv_kvp_daemon}.service <<'EOF' +cat > ${d}/%{hv_kvp_daemon}.service < ${d}/%{hv_vss_daemon}.service <<'EOF' +cat > ${d}/%{hv_vss_daemon}.service < ${d}/%{hv_fcopy_daemon}.service < ${d}/%{hv_kvp_daemon}.rules < ${d}/%{hv_vss_daemon}.rules < ${d}/%{hv_fcopy_daemon}.rules < + * + * 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 + +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; + + /* + * If possile append a path seperator to the path. + */ + if (strlen((char *)smsg->path_name) < (W_MAX_PATH - 2)) + strcat((char *)smsg->path_name, "/"); + + p = (char *)smsg->path_name; + snprintf(target_fname, sizeof(target_fname), "%s/%s", + (char *)smsg->path_name, 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) + goto done; + } + + target_fd = open(target_fname, O_RDWR | O_CREAT | 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; + +} + +int main(void) +{ + int fd, fcopy_fd, len; + int error = 0; + int version = FCOPY_CURRENT_VERSION; + char *buffer[4096 * 2]; + struct hv_fcopy_hdr *in_msg; + + if (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/hv_fcopy", O_RDWR); + + if (fcopy_fd < 0) { + syslog(LOG_ERR, "open /dev/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) { + if (!error) { + syslog(LOG_ERR, "Read error: %s", + strerror(errno)); + error = HV_E_FAIL; + } + continue; + } + 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); + } + } +}