about summary refs log tree commit diff
path: root/libgsystem/gsystem-console.c
diff options
context:
space:
mode:
Diffstat (limited to 'libgsystem/gsystem-console.c')
-rw-r--r--libgsystem/gsystem-console.c443
1 files changed, 0 insertions, 443 deletions
diff --git a/libgsystem/gsystem-console.c b/libgsystem/gsystem-console.c
deleted file mode 100644
index 35477eba..00000000
--- a/libgsystem/gsystem-console.c
+++ /dev/null
@@ -1,443 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2013 Colin Walters <walters@verbum.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include "config.h"
-
-#define _GSYSTEM_NO_LOCAL_ALLOC
-#include "libgsystem.h"
-
-/**
- * SECTION:gsconsole
- * @title: GSConsole
- * @short_description: Interact with standard input/output as well as terminal
- *
- * First, this class offers API to access the standard input and
- * output/error, streams as #GInputStream and #GOutputStream
- * respectively.
- *
- * In the case where the process is connected to a controlling
- * terminal, the gs_console_get() API is available, which exposes a
- * number of additional features such as no-echo password reading.
- *
- * Since: 2.36
- */
-
-#include "config.h"
-
-#include "gsystem-console.h"
-
-#include <string.h>
-#ifdef G_OS_UNIX
-#include <gio/gunixoutputstream.h>
-#include <gio/gfiledescriptorbased.h>
-#include <gio/gunixinputstream.h>
-#include <glib-unix.h>
-#include <unistd.h>
-#include <termios.h>
-#endif
-#include <fcntl.h>
-
-typedef GObjectClass GSConsoleClass;
-
-struct _GSConsole
-{
-  GObject parent;
-
-  gboolean in_status_line;
-  gssize last_line_written;
-};
-
-G_DEFINE_TYPE (GSConsole, gs_console, G_TYPE_OBJECT);
-
-static void
-gs_console_init (GSConsole  *self)
-{
-  self->last_line_written = -1;
-}
-
-static void
-gs_console_class_init (GSConsoleClass *class)
-{
-}
-
-/**
- * gs_console_get:
- *
- * If the current process has an interactive console, return the
- * singleton #GSConsole instance.  On Unix, this is equivalent to
- * isatty().  For all other cases, such as pipes, sockets, /dev/null,
- * this function will return %NULL.
- *
- * Returns: (transfer none): The console instance, or %NULL if not interactive
- *
- * Since: 2.36
- */
-GSConsole *
-gs_console_get (void)
-{
-  static gsize checked = 0;
-  static GSConsole *instance = NULL;
-
-  if (g_once_init_enter (&checked))
-    {
-#ifdef G_OS_UNIX
-      if (isatty (0) && isatty (1))
-        instance = g_object_new (GS_TYPE_CONSOLE, NULL);
-#endif
-      g_once_init_leave (&checked, 1);
-    }
-  
-  return (GSConsole*) instance;
-}
-
-/**
- * gs_console_get_stdin:
- *
- * Returns: (transfer none): The singleton stream connected to standard input
- */
-GInputStream *
-gs_console_get_stdin (void)
-{
-#ifdef G_OS_UNIX
-  static gsize instance = 0;
-
-  if (g_once_init_enter (&instance))
-    g_once_init_leave (&instance, (gsize) g_unix_input_stream_new (0, FALSE));
-  
-  return (GInputStream*) instance;
-#else
-  g_error ("not implemented");
-#endif
-}
-
-/**
- * gs_console_get_stdout:
- *
- * Returns: (transfer none): The singleton stream connected to standard output
- */
-GOutputStream *
-gs_console_get_stdout (void)
-{
-#ifdef G_OS_UNIX
-  static gsize instance = 0;
-
-  if (g_once_init_enter (&instance))
-    g_once_init_leave (&instance, (gsize) g_unix_output_stream_new (1, FALSE));
-  
-  return (GOutputStream*) instance;
-#else
-  g_error ("not implemented");
-#endif
-}
-
-/**
- * gs_console_get_stderr:
- *
- * Returns: (transfer none): The singleton stream connected to standard error
- */
-GOutputStream *
-gs_console_get_stderr (void)
-{
-#ifdef G_OS_UNIX
-  static gsize instance = 0;
-
-  if (g_once_init_enter (&instance))
-    g_once_init_leave (&instance, (gsize) g_unix_output_stream_new (2, FALSE));
-  
-  return (GOutputStream*) instance;
-#else
-  g_error ("not implemented");
-#endif
-}
-
-#ifdef G_OS_UNIX
-static inline void
-_set_error_from_errno (GError **error)
-{
-  int errsv = errno;
-  g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv),
-                       g_strerror (errsv));
-}
-#endif
-
-/**
- * gs_console_read_password:
- * @console: the #GSConsole
- * @prompt: A string to output before reading the password
- * @error: a #GError
- *
- * Write @prompt to standard output, then switch output echo off, read
- * a result string, then switch output echo back on.
- *
- * Returns: A string, or %NULL on error
- */
-char *
-gs_console_read_password (GSConsole     *console,
-                          const char    *prompt,
-                          GCancellable  *cancellable,
-                          GError       **error)
-{
-#ifdef G_OS_UNIX
-  gboolean ret = FALSE;
-  /* This code is modified from that found in
-   * polkit/src/polkittextagentlistener.c, reused under the LGPL v2.1
-   */
-  int res;
-  struct termios ts, ots;
-  GInputStream *in;
-  GOutputStream *out;
-  GString *str = NULL;
-  gsize bytes_written;
-  gboolean reset_terminal = FALSE;
-
-  in = gs_console_get_stdin ();
-  out = gs_console_get_stdout ();
-
-  if (!g_output_stream_write_all (out, prompt, strlen (prompt), &bytes_written,
-                                  cancellable, error))
-    goto out;
-  if (!g_output_stream_flush (out, cancellable, error))
-    goto out;
-
-  /* TODO: We really ought to block SIGINT and STGSTP (and probably
-   *       other signals too) so we can restore the terminal (since we
-   *       turn off echoing). See e.g. Advanced Programming in the
-   *       UNIX Environment 2nd edition (Steves and Rago) section
-   *       18.10, pg 660 where this is suggested. See also various
-   *       getpass(3) implementations
-   *
-   *       However, since we are a library routine the user could have
-   *       multiple threads - in fact, typical usage of
-   *       PolkitAgentTextListener is to run it in a thread. And
-   *       unfortunately threads and POSIX signals is a royal PITA.
-   *
-   *       Maybe we could fork(2) and ask for the password in the
-   *       child and send it back to the parent over a pipe? (we are
-   *       guaranteed that there is only one thread in the child
-   *       process).
-   *
-   *       (Side benefit of doing this in a child process is that we
-   *       could avoid blocking the thread where the
-   *       PolkitAgentTextListener object is being serviced from. But
-   *       since this class is normally used in a dedicated thread
-   *       it doesn't really matter *anyway*.)
-   *
-   *       Anyway, On modern Linux not doing this doesn't seem to be a
-   *       problem - looks like modern shells restore echoing anyway
-   *       on the first input. So maybe it's not even worth solving
-   *       the problem.
-   */
-
-  do
-    res = tcgetattr (1, &ts);
-  while (G_UNLIKELY (res == -1 && errno == EINTR));
-  if (res == -1)
-    {
-      _set_error_from_errno (error);
-      goto out;
-    }
-  ots = ts;
-  ts.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
-  do
-    res = tcsetattr (1, TCSAFLUSH, &ts);
-  while (G_UNLIKELY (res == -1 && errno == EINTR));
-  if (res == -1)
-    {
-      _set_error_from_errno (error);
-      goto out;
-    }
-
-  /* After this point, we'll need to clean up the terminal in case of
-   * error.
-   */
-  reset_terminal = TRUE;
-
-  str = g_string_new (NULL);
-  while (TRUE)
-    {
-      gssize bytes_read;
-      guint8 buf[1];
-
-      /* FIXME - we should probably be converting from the system
-       * codeset, in case it's not UTF-8.
-       */
-      bytes_read = g_input_stream_read (in, buf, sizeof (buf),
-                                        cancellable, error);
-      if (bytes_read < 0)
-        goto out;
-      else if (bytes_read == 0)
-        {
-          g_set_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED,
-                       "End of stream while reading password");
-          goto out;
-        }
-      else if (buf[0] == '\n')
-        {
-          break;
-        }
-      else
-        {
-          g_string_append_c (str, buf[0]);
-        }
-    }
-
-  ret = TRUE;
- out:
-  if (reset_terminal)
-    {
-      do
-        res = tcsetattr (1, TCSAFLUSH, &ots);
-      while (G_UNLIKELY (res == -1 && errno == EINTR));
-      if (res == -1)
-        {
-          _set_error_from_errno (error);
-          g_string_free (str, TRUE);
-          return NULL;
-        }
-    }
-
-  if (!ret)
-    {
-      g_string_free (str, TRUE);
-      return NULL;
-    }
-  else
-    {
-      return g_string_free (str, FALSE);
-    }
-#else
-  g_error ("not implemented");
-#endif
-}
-
-/**
- * gs_console_begin_status_line:
- * @console: the #GSConsole
- * @line: String to output
- *
- * The primary use case for this function is to output periodic
- * "status" or "progress" information.  The first time this function
- * is called, @line will be output normally.  Subsequent invocations
- * will overwrite the previous.
- *
- * You must invoke gs_console_end_status_line() to return the console
- * to normal mode.  In particular, concurrent use of this function and
- * the stream returned by gs_console_get_stdout() results in undefined
- * behavior.
- */
-gboolean
-gs_console_begin_status_line (GSConsole     *console,
-                              const char    *line,
-                              GCancellable  *cancellable,
-                              GError       **error)
-{
-#ifdef G_OS_UNIX
-  gboolean ret = FALSE;
-  gsize linelen;
-  GOutputStream *out;
-  gsize bytes_written;
-
-  out = gs_console_get_stdout ();
-
-  if (!console->in_status_line)
-    {
-      guint8 buf[3] = { (guint8)'\n', 0x1B, 0x37 };
-      if (!g_output_stream_write_all (out, buf, sizeof (buf), &bytes_written,
-                                      cancellable, error))
-        goto out;
-      console->in_status_line = TRUE;
-      console->last_line_written = -1;
-    }
-
-  {
-    guint8 buf[2] = { 0x1B, 0x38 };
-    if (!g_output_stream_write_all (out, buf, sizeof (buf), &bytes_written,
-                                    cancellable, error))
-      goto out;
-  }
-
-  linelen = strlen (line);
-  if (!g_output_stream_write_all (out, line, linelen, &bytes_written,
-                                  cancellable, error))
-    goto out;
-
-  /* Now we need to pad with spaces enough to overwrite our last line
-   */
-  if (console->last_line_written >= 0
-      && linelen < (gsize) console->last_line_written)
-    {
-      gsize towrite = console->last_line_written - linelen;
-      const char c = ' ';
-      while (towrite > 0)
-        {
-          if (!g_output_stream_write_all (out, &c, 1, &bytes_written,
-                                          cancellable, error))
-            goto out;
-          towrite--;
-        }
-    }
-  
-  console->last_line_written = linelen;
-  
-  ret = TRUE;
- out:
-  return ret;
-#else
-  g_error ("not implemented");
-#endif
-}
-
-/**
- * gs_console_end_status_line:
- * @console: the #GSConsole
- *
- * Complete a series of invocations of gs_console_begin_status_line(),
- * returning the stream to normal mode.  The last printed status line
- * remains on the console; if this is not desired, print an empty
- * string to clear it before invoking this function.
- */
-gboolean
-gs_console_end_status_line (GSConsole     *console,
-                            GCancellable  *cancellable,
-                            GError       **error)
-{
-#ifdef G_OS_UNIX  
-  gboolean ret = FALSE;
-  GOutputStream *out;
-  gsize bytes_written;
-  char c = '\n';
-
-  g_return_val_if_fail (console->in_status_line, FALSE);
-
-  out = gs_console_get_stdout ();
-
-  if (!g_output_stream_write_all (out, &c, 1, &bytes_written,
-                                  cancellable, error))
-    goto out;
-
-  console->in_status_line = FALSE;
-
-  ret = TRUE;
- out:
-  return ret;
-#else
-  g_error ("not implemented");
-#endif
-}