+ /* Also clean up utmp on normal exit. */
+ atexit(cleanup_utmp);
+ setup_utmp(pty_name, display);
+ }
+ }
+ }
+ } else {
+ close(pipefd[0]);
+ pty_utmp_helper_pid = pid;
+ pty_utmp_helper_pipe = pipefd[1];
+ signal(SIGCHLD, sigchld_handler);
+ }
+#endif
+
+ /* Drop privs. */
+ {
+ int gid = getgid(), uid = getuid();
+#ifndef HAVE_NO_SETRESUID
+ int setresgid(gid_t, gid_t, gid_t);
+ int setresuid(uid_t, uid_t, uid_t);
+ setresgid(gid, gid, gid);
+ setresuid(uid, uid, uid);
+#else
+ setgid(getgid());
+ setuid(getuid());
+#endif
+ }
+}
+
+/*
+ * Called to set up the pty.
+ *
+ * Returns an error message, or NULL on success.
+ *
+ * Also places the canonical host name into `realhost'. It must be
+ * freed by the caller.
+ */
+static char *pty_init(void *frontend, void **backend_handle,
+ char *host, int port, char **realhost, int nodelay)
+{
+ int slavefd;
+ pid_t pid, pgrp;
+
+ *backend_handle = NULL; /* we can't sensibly use this, sadly */
+
+ pty_term_width = cfg.width;
+ pty_term_height = cfg.height;
+
+ if (pty_master_fd < 0)
+ pty_open_master();
+
+ /*
+ * Set the backspace character to be whichever of ^H and ^? is
+ * specified by bksp_is_delete.
+ */
+ {
+ struct termios attrs;
+ tcgetattr(pty_master_fd, &attrs);
+ attrs.c_cc[VERASE] = cfg.bksp_is_delete ? '\177' : '\010';
+ tcsetattr(pty_master_fd, TCSANOW, &attrs);
+ }
+
+ /*
+ * Stamp utmp (that is, tell the utmp helper process to do so),
+ * or not.
+ */
+ if (!cfg.stamp_utmp)
+ close(pty_utmp_helper_pipe); /* just let the child process die */
+ else {
+ char *location = get_x_display();
+ int len = strlen(location)+1, pos = 0; /* +1 to include NUL */
+ while (pos < len) {
+ int ret = write(pty_utmp_helper_pipe, location+pos, len - pos);
+ if (ret < 0) {
+ perror("pterm: writing to utmp helper process");
+ close(pty_utmp_helper_pipe); /* arrgh, just give up */
+ break;
+ }
+ pos += ret;
+ }
+ }