From fffbde4e7b49d4c49f9f2d739572e51833c39d90 Mon Sep 17 00:00:00 2001 From: Thilo Boehm Date: Wed, 11 Sep 2013 16:45:37 +0200 Subject: [PATCH 17/60] libxkutil: Console Support Added data types for the representation of console devices and their source type specific properties. Further, implemented libvirt XML parsing and generation of console device XML. Signed-off-by: Thilo Boehm Signed-off-by: Viktor Mihajlovski Reviewed-by: Boris Fiuczynski Signed-off-by: John Ferlan --- libxkutil/device_parsing.c | 314 +++++++++++++++++++++++++++++++++++++++++++-- libxkutil/device_parsing.h | 43 ++++++- libxkutil/xmlgen.c | 191 ++++++++++++++++++++++++++- src/svpc_types.h | 5 +- 4 files changed, 541 insertions(+), 12 deletions(-) diff --git a/libxkutil/device_parsing.c b/libxkutil/device_parsing.c index f55061e..55c8d57 100644 --- a/libxkutil/device_parsing.c +++ b/libxkutil/device_parsing.c @@ -1,5 +1,5 @@ /* - * Copyright IBM Corp. 2007 + * Copyright IBM Corp. 2007, 2013 * * Authors: * Dan Smith @@ -41,6 +41,11 @@ #define NET_XPATH (xmlChar *)"/domain/devices/interface" #define EMU_XPATH (xmlChar *)"/domain/devices/emulator" #define MEM_XPATH (xmlChar *)"/domain/memory | /domain/currentMemory" +#define CONSOLE_XPATH (xmlChar *)"/domain/devices/console" +/* + * To be backward compatible, serial and console is + * still part of the graphics. + */ #define GRAPHICS_XPATH (xmlChar *)"/domain/devices/graphics | "\ "/domain/devices/console | /domain/devices/serial" #define INPUT_XPATH (xmlChar *)"/domain/devices/input" @@ -50,6 +55,11 @@ #define MAX(a,b) (((a)>(b))?(a):(b)) +#define DUP_FIELD(d, s, f) do { \ + if ((s)->f != NULL) \ + (d)->f = strdup((s)->f); \ + } while (0); + /* Device parse function */ typedef int (*dev_parse_func_t)(xmlNode *, struct virt_device **); @@ -135,6 +145,140 @@ static void cleanup_graphics_device(struct graphics_device *dev) free(dev->type); } +static void cleanup_path_device(struct path_device *dev) +{ + if (dev == NULL) + return; + + free(dev->path); + +} + +static void cleanup_unixsock_device(struct unixsock_device *dev) +{ + if (dev == NULL) + return; + + free(dev->path); + free(dev->mode); + +} + +static void cleanup_tcp_device(struct tcp_device *dev) +{ + if (dev == NULL) + return; + + free(dev->mode); + free(dev->protocol); + free(dev->host); + free(dev->service); + +} + +static void cleanup_udp_device(struct udp_device *dev) +{ + if (dev == NULL) + return; + + free(dev->bind_host); + free(dev->bind_service); + free(dev->connect_host); + free(dev->connect_service); +}; + +static void cleanup_console_device(struct console_device *dev) +{ + if (dev == NULL) + return; + + switch (dev->source_type) + { + case CIM_CHARDEV_SOURCE_TYPE_PTY: + cleanup_path_device(&dev->source_dev.pty); + break; + case CIM_CHARDEV_SOURCE_TYPE_DEV: + cleanup_path_device(&dev->source_dev.dev); + break; + case CIM_CHARDEV_SOURCE_TYPE_FILE: + cleanup_path_device(&dev->source_dev.file); + break; + case CIM_CHARDEV_SOURCE_TYPE_PIPE: + cleanup_path_device(&dev->source_dev.pipe); + break; + case CIM_CHARDEV_SOURCE_TYPE_UNIXSOCK: + cleanup_unixsock_device(&dev->source_dev.unixsock); + break; + case CIM_CHARDEV_SOURCE_TYPE_UDP: + cleanup_udp_device(&dev->source_dev.udp); + break; + case CIM_CHARDEV_SOURCE_TYPE_TCP: + cleanup_tcp_device(&dev->source_dev.tcp); + break; + default: + /* Nothing to do for : + CIM_CHARDEV_SOURCE_TYPE_STDIO + CIM_CHARDEV_SOURCE_TYPE_NULL + CIM_CHARDEV_SOURCE_TYPE_VC + CIM_CHARDEV_SOURCE_TYPE_SPICEVMC + */ + break; + } + + dev->source_type = 0; + free(dev->target_type); + memset(&dev->source_dev, 0, sizeof(dev->source_dev)); +}; + +static void console_device_dup(struct console_device *t, + struct console_device *s) +{ + cleanup_console_device(t); + + t->source_type = s->source_type; + DUP_FIELD(t, s, target_type); + + switch (s->source_type) + { + case CIM_CHARDEV_SOURCE_TYPE_PTY: + DUP_FIELD(t, s, source_dev.pty.path); + break; + case CIM_CHARDEV_SOURCE_TYPE_DEV: + DUP_FIELD(t, s, source_dev.dev.path); + break; + case CIM_CHARDEV_SOURCE_TYPE_FILE: + DUP_FIELD(t, s, source_dev.file.path); + break; + case CIM_CHARDEV_SOURCE_TYPE_PIPE: + DUP_FIELD(t, s, source_dev.pipe.path); + break; + case CIM_CHARDEV_SOURCE_TYPE_UNIXSOCK: + DUP_FIELD(t, s, source_dev.unixsock.path); + DUP_FIELD(t, s, source_dev.unixsock.mode); + break; + case CIM_CHARDEV_SOURCE_TYPE_UDP: + DUP_FIELD(t, s, source_dev.udp.bind_host); + DUP_FIELD(t, s, source_dev.udp.bind_service); + DUP_FIELD(t, s, source_dev.udp.connect_host); + DUP_FIELD(t, s, source_dev.udp.connect_service); + break; + case CIM_CHARDEV_SOURCE_TYPE_TCP: + DUP_FIELD(t, s, source_dev.tcp.mode); + DUP_FIELD(t, s, source_dev.tcp.protocol); + DUP_FIELD(t, s, source_dev.tcp.host); + DUP_FIELD(t, s, source_dev.tcp.service); + break; + default: + /* Nothing to do for : + CIM_CHARDEV_SOURCE_TYPE_STDIO + CIM_CHARDEV_SOURCE_TYPE_NULL + CIM_CHARDEV_SOURCE_TYPE_VC + CIM_CHARDEV_SOURCE_TYPE_SPICEVMC + */ + break; + } +} + static void cleanup_input_device(struct input_device *dev) { if (dev == NULL) @@ -159,6 +303,8 @@ void cleanup_virt_device(struct virt_device *dev) cleanup_graphics_device(&dev->dev.graphics); else if (dev->type == CIM_RES_TYPE_INPUT) cleanup_input_device(&dev->dev.input); + else if (dev->type == CIM_RES_TYPE_CONSOLE) + cleanup_console_device(&dev->dev.console); free(dev->id); @@ -616,6 +762,138 @@ static char *get_attr_value_default(xmlNode *node, char *attrname, return ret; } +static int parse_console_device(xmlNode *node, struct virt_device **vdevs) +{ + struct virt_device *vdev = NULL; + struct console_device *cdev = NULL; + char *source_type_str = NULL; + char *target_port_ID = NULL; + char *udp_source_mode = NULL; + + xmlNode *child = NULL; + + vdev = calloc(1, sizeof(*vdev)); + if (vdev == NULL) + goto err; + + cdev = &(vdev->dev.console); + + source_type_str = get_attr_value(node, "type"); + if (source_type_str == NULL) + goto err; + CU_DEBUG("console device type = %s", source_type_str ? : "NULL"); + + cdev->source_type = chardev_source_type_StrToID(source_type_str); + if (cdev->source_type == CIM_CHARDEV_SOURCE_TYPE_UNKNOWN) + goto err; + + CU_DEBUG("console device type ID = %d", cdev->source_type); + + for (child = node->children; child != NULL; child = child->next) { + if (XSTREQ(child->name, "target")) { + cdev->target_type = get_attr_value(child, "type"); + CU_DEBUG("Console device target type = '%s'", + cdev->target_type ? : "NULL"); + target_port_ID = get_attr_value(child, "port"); + if (target_port_ID == NULL) + goto err; + } + + if (XSTREQ(child->name, "source")) { + switch (cdev->source_type) + { + case CIM_CHARDEV_SOURCE_TYPE_PTY: + cdev->source_dev.pty.path = + get_attr_value(child, "path"); + break; + case CIM_CHARDEV_SOURCE_TYPE_DEV: + cdev->source_dev.dev.path = + get_attr_value(child, "path"); + break; + case CIM_CHARDEV_SOURCE_TYPE_FILE: + cdev->source_dev.file.path = + get_attr_value(child, "path"); + break; + case CIM_CHARDEV_SOURCE_TYPE_PIPE: + cdev->source_dev.pipe.path = + get_attr_value(child, "path"); + break; + case CIM_CHARDEV_SOURCE_TYPE_UNIXSOCK: + cdev->source_dev.unixsock.mode = + get_attr_value(child, "mode"); + cdev->source_dev.unixsock.path = + get_attr_value(child, "path"); + break; + case CIM_CHARDEV_SOURCE_TYPE_UDP: + udp_source_mode = get_attr_value(child, "mode"); + if (udp_source_mode == NULL) + goto err; + if (STREQC(udp_source_mode, "bind")) { + cdev->source_dev.udp.bind_host = + get_attr_value(child, "host"); + cdev->source_dev.udp.bind_service = + get_attr_value(child, "service"); + } else if (STREQC(udp_source_mode, "connect")) { + cdev->source_dev.udp.connect_host = + get_attr_value(child, "host"); + cdev->source_dev.udp.connect_service = + get_attr_value(child, "service"); + } else { + CU_DEBUG("unknown udp mode: %s", + udp_source_mode ? : "NULL"); + goto err; + } + break; + case CIM_CHARDEV_SOURCE_TYPE_TCP: + cdev->source_dev.tcp.mode = + get_attr_value(child, "mode"); + cdev->source_dev.tcp.host = + get_attr_value(child, "host"); + cdev->source_dev.tcp.service = + get_attr_value(child, "service"); + break; + + default: + /* Nothing to do for : + CIM_CHARDEV_SOURCE_TYPE_STDIO + CIM_CHARDEV_SOURCE_TYPE_NULL + CIM_CHARDEV_SOURCE_TYPE_VC + CIM_CHARDEV_SOURCE_TYPE_SPICEVMC + */ + break; + } + } + if ((cdev->source_type == CIM_CHARDEV_SOURCE_TYPE_TCP) + && XSTREQ(child->name, "protocol")) { + cdev->source_dev.tcp.protocol = + get_attr_value(child, "type"); + } + } + + vdev->type = CIM_RES_TYPE_CONSOLE; + + if (asprintf(&vdev->id, "charconsole:%s", target_port_ID) == -1) { + CU_DEBUG("Failed to create charconsole id string"); + goto err; + } + + *vdevs = vdev; + free(source_type_str); + free(target_port_ID); + free(udp_source_mode); + + return 1; + + err: + free(source_type_str); + free(target_port_ID); + free(udp_source_mode); + cleanup_console_device(cdev); + free(vdev); + + return 0; +} + static int parse_graphics_device(xmlNode *node, struct virt_device **vdevs) { struct virt_device *vdev = NULL; @@ -667,8 +945,20 @@ static int parse_graphics_device(xmlNode *node, struct virt_device **vdevs) child = child->next) { if (XSTREQ(child->name, "source")) gdev->dev.vnc.host = get_attr_value(child, "path"); - else if (XSTREQ(child->name, "target")) - gdev->dev.vnc.port = get_attr_value(child, "port"); + else if (XSTREQ(child->name, "target")) { + gdev->dev.vnc.port = + get_attr_value(child, "port"); + /* The graphics pty console can only be a + virtio console. If 'type' is not set in the + xml, the default of libvirt is virtio.*/ + char *t_type = get_attr_value(child, "type"); + if (t_type != NULL && !STREQC(t_type, "virtio")) { + CU_DEBUG("Not a pty-virtio graphics console"); + free(t_type); + goto err; + } + free(t_type); + } } } else { @@ -847,6 +1137,11 @@ static int parse_devices(const char *xml, struct virt_device **_list, int type) func = &parse_graphics_device; break; + case CIM_RES_TYPE_CONSOLE: + xpathstr = CONSOLE_XPATH; + func = &parse_console_device; + break; + case CIM_RES_TYPE_INPUT: xpathstr = INPUT_XPATH; func = &parse_input_device; @@ -882,11 +1177,6 @@ static int parse_devices(const char *xml, struct virt_device **_list, int type) return count; } -#define DUP_FIELD(d, s, f) do { \ - if ((s)->f != NULL) \ - (d)->f = strdup((s)->f); \ - } while (0); - struct virt_device *virt_device_dup(struct virt_device *_dev) { struct virt_device *dev; @@ -945,8 +1235,10 @@ struct virt_device *virt_device_dup(struct virt_device *_dev) } else if (dev->type == CIM_RES_TYPE_INPUT) { DUP_FIELD(dev, _dev, dev.input.type); DUP_FIELD(dev, _dev, dev.input.bus); + } else if (dev->type == CIM_RES_TYPE_CONSOLE) { + console_device_dup(&dev->dev.console, + &_dev->dev.console); } - return dev; } @@ -1307,6 +1599,9 @@ int get_dominfo_from_xml(const char *xml, struct domain **dominfo) (*dominfo)->dev_graphics_ct = parse_devices(xml, &(*dominfo)->dev_graphics, CIM_RES_TYPE_GRAPHICS); + (*dominfo)->dev_console_ct = parse_devices(xml, + &(*dominfo)->dev_console, + CIM_RES_TYPE_CONSOLE); (*dominfo)->dev_input_ct = parse_devices(xml, &(*dominfo)->dev_input, CIM_RES_TYPE_INPUT); @@ -1407,6 +1702,7 @@ void cleanup_dominfo(struct domain **dominfo) cleanup_virt_devices(&dom->dev_vcpu, dom->dev_vcpu_ct); cleanup_virt_devices(&dom->dev_graphics, dom->dev_graphics_ct); cleanup_virt_devices(&dom->dev_input, dom->dev_input_ct); + cleanup_virt_devices(&dom->dev_console, dom->dev_console_ct); free(dom); diff --git a/libxkutil/device_parsing.h b/libxkutil/device_parsing.h index 14e49b8..2803d6a 100644 --- a/libxkutil/device_parsing.h +++ b/libxkutil/device_parsing.h @@ -1,5 +1,5 @@ /* - * Copyright IBM Corp. 2007 + * Copyright IBM Corp. 2007, 2013 * * Authors: * Dan Smith @@ -111,6 +111,43 @@ struct graphics_device { } dev; }; +struct path_device { + char *path; +}; + +struct unixsock_device { + char *path; + char *mode; +}; + +struct tcp_device { + char *mode; + char *protocol; + char *host; + char *service; +}; + +struct udp_device { + char *bind_host; + char *bind_service; + char *connect_host; + char *connect_service; +}; + +struct console_device { + uint16_t source_type; + union { + struct path_device file; + struct path_device pty; + struct path_device dev; + struct path_device pipe; + struct unixsock_device unixsock; + struct tcp_device tcp; + struct udp_device udp; + } source_dev; + char *target_type; +}; + struct input_device { char *type; char *bus; @@ -125,6 +162,7 @@ struct virt_device { struct vcpu_device vcpu; struct emu_device emu; struct graphics_device graphics; + struct console_device console; struct input_device input; } dev; char *id; @@ -182,6 +220,9 @@ struct domain { struct virt_device *dev_graphics; int dev_graphics_ct; + struct virt_device *dev_console; + int dev_console_ct; + struct virt_device *dev_emu; struct virt_device *dev_input; diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c index 2ca2341..45bfb04 100644 --- a/libxkutil/xmlgen.c +++ b/libxkutil/xmlgen.c @@ -1,5 +1,5 @@ /* - * Copyright IBM Corp. 2007 + * Copyright IBM Corp. 2007, 2013 * * Authors: * Dan Smith @@ -42,6 +42,189 @@ typedef const char *(*devfn_t)(xmlNodePtr node, struct domain *dominfo); typedef const char *(*poolfn_t)(xmlNodePtr node, struct virt_pool *pool); typedef const char *(*resfn_t)(xmlNodePtr node, struct virt_pool_res *res); +static int _count_graphics_console_definitions(struct domain *dominfo) +{ + int i; + int num = 0; + + for (i = 0; i < dominfo->dev_graphics_ct; i++) { + struct virt_device *_dev = &dominfo->dev_graphics[i]; + if (_dev->type == CIM_RES_TYPE_UNKNOWN) + continue; + + struct graphics_device *dev = &_dev->dev.graphics; + + if (STREQC(dev->type, "console")) { + num++; + } + } + CU_DEBUG("Found %d console defintions in graphics devices.",num); + return num; + +} + +static const char *console_xml(xmlNodePtr root, struct domain *dominfo) +{ + int i; + xmlNodePtr console; + xmlNodePtr tmp; + int num_graphics_consol_def = 0; + int num_suppressed_console_def = 0; + + num_graphics_consol_def = _count_graphics_console_definitions(dominfo); + + for (i = 0; i < dominfo->dev_console_ct; i++) { + struct virt_device *_dev = &dominfo->dev_console[i]; + if (_dev->type == CIM_RES_TYPE_UNKNOWN) + continue; + + struct console_device *cdev = &_dev->dev.console; + + /* Due to backward compatibility, the graphics device handling + is still parsing consoles: + source = pty, target = virtio (which is the default target) + But the console device handling processes these kind of + consoles too. This would lead to a duplication of these + default consoles in the domain xml definition. + This code prevents the console handling of writing xml for + duplicate pty/virtio consoles which are written by the + graphics device handling. */ + if (cdev->source_type == CIM_CHARDEV_SOURCE_TYPE_PTY && + (cdev->target_type == NULL || + STREQC(cdev->target_type, "virtio"))) { + if (num_suppressed_console_def < + num_graphics_consol_def) { + num_suppressed_console_def++; + continue; + } + } + + console = xmlNewChild(root, NULL, BAD_CAST "console", NULL); + if (console == NULL) + return XML_ERROR; + + xmlNewProp(console, BAD_CAST "type", + BAD_CAST + chardev_source_type_IDToStr(cdev->source_type)); + + switch (cdev->source_type) { + case CIM_CHARDEV_SOURCE_TYPE_PTY: + /* The path property is not mandatory */ + if (cdev->source_dev.pty.path) { + tmp = xmlNewChild(console, NULL, + BAD_CAST "source", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "path", + BAD_CAST cdev->source_dev.pty.path); + } + break; + case CIM_CHARDEV_SOURCE_TYPE_DEV: + tmp = xmlNewChild(console, NULL, + BAD_CAST "source", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "path", + BAD_CAST cdev->source_dev.dev.path); + break; + case CIM_CHARDEV_SOURCE_TYPE_FILE: + tmp = xmlNewChild(console, NULL, + BAD_CAST "source", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "path", + BAD_CAST cdev->source_dev.file.path); + break; + case CIM_CHARDEV_SOURCE_TYPE_PIPE: + tmp = xmlNewChild(console, NULL, + BAD_CAST "source", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "path", + BAD_CAST cdev->source_dev.pipe.path); + break; + case CIM_CHARDEV_SOURCE_TYPE_UNIXSOCK: + tmp = xmlNewChild(console, NULL, + BAD_CAST "source", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "mode", + BAD_CAST cdev->source_dev.unixsock.mode); + xmlNewProp(tmp, BAD_CAST "path", + BAD_CAST cdev->source_dev.unixsock.path); + break; + case CIM_CHARDEV_SOURCE_TYPE_UDP: + tmp = xmlNewChild(console, NULL, + BAD_CAST "source", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "mode", BAD_CAST "bind"); + xmlNewProp(tmp, BAD_CAST "host", + BAD_CAST cdev->source_dev.udp.bind_host); + /* The service property is not mandatory */ + if (cdev->source_dev.udp.bind_service) + xmlNewProp(tmp, BAD_CAST "service", + BAD_CAST + cdev->source_dev.udp.bind_service); + + tmp = xmlNewChild(console, NULL, + BAD_CAST "source", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "mode", BAD_CAST "connect"); + xmlNewProp(tmp, BAD_CAST "host", + BAD_CAST cdev->source_dev.udp.connect_host); + /* The service property is not mandatory */ + if (cdev->source_dev.udp.connect_service) + xmlNewProp(tmp, BAD_CAST "service", + BAD_CAST + cdev->source_dev.udp.connect_service); + + break; + case CIM_CHARDEV_SOURCE_TYPE_TCP: + tmp = xmlNewChild(console, NULL, + BAD_CAST "source", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "mode", + BAD_CAST cdev->source_dev.tcp.mode); + xmlNewProp(tmp, BAD_CAST "host", + BAD_CAST cdev->source_dev.tcp.host); + if (cdev->source_dev.tcp.service) + xmlNewProp(tmp, BAD_CAST "service", + BAD_CAST + cdev->source_dev.tcp.service); + if (cdev->source_dev.tcp.protocol) { + tmp = xmlNewChild(console, NULL, + BAD_CAST "protocol", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "type", + BAD_CAST cdev->source_dev.tcp.protocol); + } + break; + default: + /* Nothing to do for : + CIM_CHARDEV_SOURCE_TYPE_STDIO + CIM_CHARDEV_SOURCE_TYPE_NULL + CIM_CHARDEV_SOURCE_TYPE_VC + CIM_CHARDEV_SOURCE_TYPE_SPICEVMC + */ + break; + } + + if (cdev->target_type) { + tmp = xmlNewChild(console, NULL, + BAD_CAST "target", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "type", + BAD_CAST cdev->target_type); + } + } + return NULL; +} + static char *disk_block_xml(xmlNodePtr root, struct disk_device *dev) { xmlNodePtr disk; @@ -977,6 +1160,11 @@ char *device_to_xml(struct virt_device *_dev) dominfo->dev_graphics_ct = 1; dominfo->dev_graphics = dev; break; + case CIM_RES_TYPE_CONSOLE: + func = console_xml; + dominfo->dev_console_ct = 1; + dominfo->dev_console = dev; + break; case CIM_RES_TYPE_INPUT: func = input_xml; dominfo->dev_input_ct = 1; @@ -1017,6 +1205,7 @@ char *system_to_xml(struct domain *dominfo) &disk_xml, &net_xml, &input_xml, + &console_xml, &graphics_xml, &emu_xml, NULL diff --git a/src/svpc_types.h b/src/svpc_types.h index 2e4d73f..0f46a86 100644 --- a/src/svpc_types.h +++ b/src/svpc_types.h @@ -25,6 +25,7 @@ #define CIM_OPERATIONAL_STATUS 2 #define CIM_RES_TYPE_ALL 0 +#define CIM_RES_TYPE_OTHER 1 #define CIM_RES_TYPE_PROC 3 #define CIM_RES_TYPE_MEM 4 #define CIM_RES_TYPE_NET 10 @@ -34,8 +35,9 @@ #define CIM_RES_TYPE_INPUT 13 #define CIM_RES_TYPE_UNKNOWN 1000 #define CIM_RES_TYPE_IMAGE 32768 +#define CIM_RES_TYPE_CONSOLE 32769 -#define CIM_RES_TYPE_COUNT 6 +#define CIM_RES_TYPE_COUNT 7 const static int cim_res_types[CIM_RES_TYPE_COUNT] = {CIM_RES_TYPE_NET, CIM_RES_TYPE_DISK, @@ -43,6 +45,7 @@ const static int cim_res_types[CIM_RES_TYPE_COUNT] = CIM_RES_TYPE_PROC, CIM_RES_TYPE_GRAPHICS, CIM_RES_TYPE_INPUT, + CIM_RES_TYPE_CONSOLE, }; #define CIM_VSSD_RECOVERY_NONE 2 -- 2.1.0