[pty] Use ptysvc to get new pty servers

Bug: 33204
Change-Id: I4e915e4003b92fab1530c13b2e2ab9e571d4cb1e
diff --git a/sshpty.c b/sshpty.c
index 4a40a4a..aa84a6e 100644
--- a/sshpty.c
+++ b/sshpty.c
@@ -57,7 +57,52 @@
 
 #ifdef __Fuchsia__
 #include <fuchsia/hardware/pty/c/fidl.h>
+#include <lib/fdio/directory.h>
+#include <lib/fdio/fd.h>
 #include <lib/fdio/unsafe.h>
+#include <zircon/status.h>
+#include <zircon/syscalls.h>
+#endif  // __Fuchsia__
+
+#ifdef __Fuchsia__
+static int fuchsia_get_new_pty_server(void) {
+  zx_handle_t local, remote;
+  zx_status_t status = zx_channel_create(0, &local, &remote);
+  int fd = -1;
+  if (status != ZX_OK) {
+    error("channel create failed: %s", zx_status_get_string(status));
+    goto bail;
+  }
+  status = fdio_service_connect("/svc/fuchsia.hardware.pty.Device", remote);
+  remote = ZX_HANDLE_INVALID;
+  if (status != ZX_OK) {
+    error("fdio_service_connect failed: %s", zx_status_get_string(status));
+    goto bail;
+  }
+
+  status = fdio_fd_create(local, &fd);
+  local = ZX_HANDLE_INVALID;
+  if (status != ZX_OK) {
+    error("fdio_service_connect failed: %s", zx_status_get_string(status));
+    goto bail;
+  }
+  int flags = fcntl(fd, F_GETFL);
+  if (flags < 0) {
+    error("fcntl(F_GETFL): %s", strerror(errno));
+    goto bail;
+  }
+  if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
+    error("fcntl(F_SETFL): %s", strerror(errno));
+    goto bail;
+  }
+  return fd;
+
+bail:
+  zx_handle_close(local);
+  zx_handle_close(remote);
+  close(fd);
+  return -1;
+}
 #endif  // __Fuchsia__
 
 /*
@@ -71,9 +116,8 @@
 pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, size_t namebuflen)
 {
 #ifdef __Fuchsia__
-  *ptyfd = open("/dev/misc/ptmx", O_RDWR | O_NONBLOCK);
+  *ptyfd = fuchsia_get_new_pty_server();
   if (*ptyfd < 0) {
-    error("open /dev/misc/ptmx: %s", strerror(errno));
     return 0;
   }
   *ttyfd = fuchsia_open_pty_client(*ptyfd, 0);