@@ -295,3 +295,57 @@ void ga_channel_free(GAChannel *c)
}
g_free(c);
}
+
+static bool is_serial_present(GAChannelMethod method, const gchar *path,
+ int *error_code)
+{
+ int fd = -1;
+ bool ret = true;
+
+ assert(error_code);
+ *error_code = 0;
+
+ switch (method) {
+ case GA_CHANNEL_VIRTIO_SERIAL:
+ fd = qemu_open(path, O_RDWR | O_NONBLOCK
+#ifndef CONFIG_SOLARIS
+ | O_ASYNC
+#endif
+ );
+ break;
+ case GA_CHANNEL_ISA_SERIAL:
+ fd = qemu_open(path, O_RDWR | O_NOCTTY | O_NONBLOCK);
+ break;
+ default:
+ ret = false;
+ }
+ if (fd < 0) {
+ *error_code = errno;
+ ret = false;
+ } else {
+ close(fd);
+ }
+ return ret;
+}
+
+bool ga_channel_serial_is_present(GAChannelMethod method, const gchar *path)
+{
+ int error_code = 0;
+ return is_serial_present(method, path, &error_code) ||
+ error_code == EBUSY;
+}
+
+bool ga_channel_was_serial_attached(GAChannelMethod method, const gchar *path,
+ bool is_serial_attached)
+{
+ int error_code = 0;
+ return !is_serial_attached &&
+ is_serial_present(method, path, &error_code);
+}
+bool ga_channel_was_serial_detached(GAChannelMethod method, const gchar *path,
+ bool is_serial_attached)
+{
+ int error_code = 0;
+ return is_serial_attached && !is_serial_present(method, path, &error_code)
+ && error_code == ENOENT;
+}
@@ -354,3 +354,63 @@ void ga_channel_free(GAChannel *c)
g_free(c->rstate.buf);
g_free(c);
}
+
+static bool is_serial_present(GAChannelMethod method, const gchar *path,
+ DWORD *err)
+{
+ gchar newpath[MAXPATHLEN] = { 0 };
+ bool ret = false;
+
+ assert(err);
+
+ if (method != GA_CHANNEL_VIRTIO_SERIAL && method != GA_CHANNEL_ISA_SERIAL) {
+ g_critical("unsupported communication method");
+ return false;
+ }
+
+ if (method == GA_CHANNEL_ISA_SERIAL) {
+ snprintf(newpath, sizeof(newpath), "\\\\.\\%s", path);
+ } else {
+ g_strlcpy(newpath, path, sizeof(newpath));
+ }
+
+ HANDLE handle = CreateFile(newpath, GENERIC_READ | GENERIC_WRITE, 0, NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ *err = GetLastError();
+ ret = false;
+ } else {
+ ret = true;
+ }
+
+ CloseHandle(handle);
+ return ret;
+}
+
+bool ga_channel_serial_is_present(GAChannelMethod method, const gchar *path)
+{
+ DWORD err_code;
+ return is_serial_present(method, path, &err_code) ||
+ err_code == ERROR_ACCESS_DENIED;
+}
+
+bool ga_channel_was_serial_attached(GAChannelMethod method, const gchar *path,
+ bool is_serial_attached)
+{
+ DWORD err_code;
+ return !is_serial_attached && is_serial_present(method, path, &err_code);
+}
+
+bool ga_channel_was_serial_detached(GAChannelMethod method, const gchar *path,
+ bool is_serial_attached)
+{
+ DWORD err_code = NO_ERROR;
+ /* In order to make sure the serial that qemu-ga uses is the one that
+ * was detached. We'll get the error ERROR_FILE_NOT_FOUND when
+ * attempting to call CreateFile with the serial path.
+ */
+ return is_serial_attached && !is_serial_present(method, path, &err_code)
+ && err_code == ERROR_FILE_NOT_FOUND;
+}
@@ -12,6 +12,10 @@
#ifndef QGA_CHANNEL_H
#define QGA_CHANNEL_H
+#ifndef _WIN32
+#define SUBSYSTEM_VIRTIO_SERIAL "virtio-ports";
+#define SUBSYSTEM_ISA_SERIAL "isa-serial";
+#endif
typedef struct GAChannel GAChannel;
@@ -30,5 +34,10 @@ GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path,
void ga_channel_free(GAChannel *c);
GIOStatus ga_channel_read(GAChannel *c, gchar *buf, gsize size, gsize *count);
GIOStatus ga_channel_write_all(GAChannel *c, const gchar *buf, gsize size);
+bool ga_channel_serial_is_present(GAChannelMethod method, const gchar *path);
+bool ga_channel_was_serial_attached(GAChannelMethod method, const gchar *path,
+ bool is_serial_attached);
+bool ga_channel_was_serial_detached(GAChannelMethod method, const gchar *path,
+ bool is_serial_attached);
#endif