+ } else if (pid == 0) {
+ char display[128], buffer[128];
+ int dlen, ret;
+
+ close(pipefd[1]);
+ /*
+ * Now sit here until we receive a display name from the
+ * other end of the pipe, and then stamp utmp. Unstamp utmp
+ * again, and exit, when the pipe closes.
+ */
+
+ dlen = 0;
+ while (1) {
+
+ ret = read(pipefd[0], buffer, lenof(buffer));
+ if (ret <= 0) {
+ cleanup_utmp();
+ exit(0);
+ } else if (!pty_stamped_utmp) {
+ if (dlen < lenof(display))
+ memcpy(display+dlen, buffer,
+ min(ret, lenof(display)-dlen));
+ if (buffer[ret-1] == '\0') {
+ /*
+ * Now we have a display name. NUL-terminate
+ * it, and stamp utmp.
+ */
+ display[lenof(display)-1] = '\0';
+ /*
+ * Trap as many fatal signals as we can in the
+ * hope of having the best possible chance to
+ * clean up utmp before termination. We are
+ * unfortunately unprotected against SIGKILL,
+ * but that's life.
+ */
+ signal(SIGHUP, fatal_sig_handler);
+ signal(SIGINT, fatal_sig_handler);
+ signal(SIGQUIT, fatal_sig_handler);
+ signal(SIGILL, fatal_sig_handler);
+ signal(SIGABRT, fatal_sig_handler);
+ signal(SIGFPE, fatal_sig_handler);
+ signal(SIGPIPE, fatal_sig_handler);
+ signal(SIGALRM, fatal_sig_handler);
+ signal(SIGTERM, fatal_sig_handler);
+ signal(SIGSEGV, fatal_sig_handler);
+ signal(SIGUSR1, fatal_sig_handler);
+ signal(SIGUSR2, fatal_sig_handler);
+#ifdef SIGBUS
+ signal(SIGBUS, fatal_sig_handler);
+#endif
+#ifdef SIGPOLL
+ signal(SIGPOLL, fatal_sig_handler);
+#endif
+#ifdef SIGPROF
+ signal(SIGPROF, fatal_sig_handler);
+#endif
+#ifdef SIGSYS
+ signal(SIGSYS, fatal_sig_handler);
+#endif
+#ifdef SIGTRAP
+ signal(SIGTRAP, fatal_sig_handler);
+#endif
+#ifdef SIGVTALRM
+ signal(SIGVTALRM, fatal_sig_handler);
+#endif
+#ifdef SIGXCPU
+ signal(SIGXCPU, fatal_sig_handler);
+#endif
+#ifdef SIGXFSZ
+ signal(SIGXFSZ, fatal_sig_handler);
+#endif
+#ifdef SIGIO
+ signal(SIGIO, fatal_sig_handler);
+#endif
+ /* 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;
+
+ pty_frontend = frontend;
+ *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(pty_frontend);
+ 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;
+ }