(root)/
glib-2.79.0/
glib/
tests/
unix.c
       1  /* 
       2   * Copyright (C) 2011 Red Hat, Inc.
       3   * Copyright 2023 Collabora Ltd.
       4   *
       5   * SPDX-License-Identifier: LicenseRef-old-glib-tests
       6   *
       7   * This work is provided "as is"; redistribution and modification
       8   * in whole or in part, in any medium, physical or electronic is
       9   * permitted without restriction.
      10   *
      11   * This work is distributed in the hope that it will be useful,
      12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
      14   *
      15   * In no event shall the authors or contributors be liable for any
      16   * direct, indirect, incidental, special, exemplary, or consequential
      17   * damages (including, but not limited to, procurement of substitute
      18   * goods or services; loss of use, data, or profits; or business
      19   * interruption) however caused and on any theory of liability, whether
      20   * in contract, strict liability, or tort (including negligence or
      21   * otherwise) arising in any way out of the use of this software, even
      22   * if advised of the possibility of such damage.
      23   *
      24   * Author: Colin Walters <walters@verbum.org> 
      25   */
      26  
      27  #include "config.h"
      28  
      29  #include "glib-private.h"
      30  #include "glib-unix.h"
      31  #include "gstdio.h"
      32  
      33  #include <string.h>
      34  #include <pwd.h>
      35  #include <unistd.h>
      36  
      37  #include "testutils.h"
      38  
      39  static void
      40  test_pipe (void)
      41  {
      42    GError *error = NULL;
      43    int pipefd[2];
      44    char buf[1024];
      45    gssize bytes_read;
      46    gboolean res;
      47  
      48    res = g_unix_open_pipe (pipefd, O_CLOEXEC, &error);
      49    g_assert (res);
      50    g_assert_no_error (error);
      51  
      52    g_assert_cmpint (write (pipefd[1], "hello", sizeof ("hello")), ==, sizeof ("hello"));
      53    memset (buf, 0, sizeof (buf));
      54    bytes_read = read (pipefd[0], buf, sizeof(buf) - 1);
      55    g_assert_cmpint (bytes_read, >, 0);
      56    buf[bytes_read] = '\0';
      57  
      58    close (pipefd[0]);
      59    close (pipefd[1]);
      60  
      61    g_assert (g_str_has_prefix (buf, "hello"));
      62  }
      63  
      64  static void
      65  test_pipe_fd_cloexec (void)
      66  {
      67    GError *error = NULL;
      68    int pipefd[2];
      69    char buf[1024];
      70    gssize bytes_read;
      71    gboolean res;
      72  
      73    g_test_summary ("Test that FD_CLOEXEC is still accepted as an argument to g_unix_open_pipe()");
      74    g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/merge_requests/3459");
      75  
      76    res = g_unix_open_pipe (pipefd, FD_CLOEXEC, &error);
      77    g_assert (res);
      78    g_assert_no_error (error);
      79  
      80    g_assert_cmpint (write (pipefd[1], "hello", sizeof ("hello")), ==, sizeof ("hello"));
      81    memset (buf, 0, sizeof (buf));
      82    bytes_read = read (pipefd[0], buf, sizeof(buf) - 1);
      83    g_assert_cmpint (bytes_read, >, 0);
      84    buf[bytes_read] = '\0';
      85  
      86    close (pipefd[0]);
      87    close (pipefd[1]);
      88  
      89    g_assert_true (g_str_has_prefix (buf, "hello"));
      90  }
      91  
      92  static void
      93  test_pipe_stdio_overwrite (void)
      94  {
      95    GError *error = NULL;
      96    int pipefd[2], ret;
      97    gboolean res;
      98    int stdin_fd;
      99  
     100  
     101    g_test_summary ("Test that g_unix_open_pipe() will use the first available FD, even if it’s stdin/stdout/stderr");
     102    g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2795");
     103  
     104    stdin_fd = dup (STDIN_FILENO);
     105    g_assert_cmpint (stdin_fd, >, 0);
     106  
     107    g_close (STDIN_FILENO, &error);
     108    g_assert_no_error (error);
     109  
     110    res = g_unix_open_pipe (pipefd, O_CLOEXEC, &error);
     111    g_assert_no_error (error);
     112    g_assert_true (res);
     113  
     114    g_assert_cmpint (pipefd[0], ==, STDIN_FILENO);
     115  
     116    g_close (pipefd[0], &error);
     117    g_assert_no_error (error);
     118  
     119    g_close (pipefd[1], &error);
     120    g_assert_no_error (error);
     121  
     122    ret = dup2 (stdin_fd, STDIN_FILENO);
     123    g_assert_cmpint (ret, >=, 0);
     124  
     125    g_close (stdin_fd, &error);
     126    g_assert_no_error (error);
     127  }
     128  
     129  static void
     130  test_pipe_struct (void)
     131  {
     132    GError *error = NULL;
     133    GUnixPipe pair = G_UNIX_PIPE_INIT;
     134    char buf[1024];
     135    gssize bytes_read;
     136    gboolean res;
     137    int read_end = -1;    /* owned */
     138    int write_end = -1;   /* unowned */
     139    int errsv;
     140  
     141    g_test_summary ("Test GUnixPipe structure");
     142  
     143    res = g_unix_pipe_open (&pair, FD_CLOEXEC, &error);
     144    g_assert_no_error (error);
     145    g_assert_true (res);
     146  
     147    read_end = g_unix_pipe_steal (&pair, G_UNIX_PIPE_END_READ);
     148    g_assert_cmpint (read_end, >=, 0);
     149    g_assert_cmpint (g_unix_pipe_steal (&pair, G_UNIX_PIPE_END_READ), ==, -1);
     150    g_assert_cmpint (g_unix_pipe_get (&pair, G_UNIX_PIPE_END_READ), ==, -1);
     151    write_end = g_unix_pipe_get (&pair, G_UNIX_PIPE_END_WRITE);
     152    g_assert_cmpint (write_end, >=, 0);
     153    g_assert_cmpint (g_unix_pipe_get (&pair, G_UNIX_PIPE_END_WRITE), ==, write_end);
     154  
     155    g_assert_cmpint (write (write_end, "hello", sizeof ("hello")), ==, sizeof ("hello"));
     156    memset (buf, 0, sizeof (buf));
     157    bytes_read = read (read_end, buf, sizeof(buf) - 1);
     158    g_assert_cmpint (bytes_read, ==, sizeof ("hello"));
     159    buf[bytes_read] = '\0';
     160  
     161    /* This is one of the few errno values guaranteed by Standard C.
     162     * We set it here to check that g_unix_pipe_clear doesn't alter errno. */
     163    errno = EILSEQ;
     164  
     165    g_unix_pipe_clear (&pair);
     166    errsv = errno;
     167    g_assert_cmpint (errsv, ==, EILSEQ);
     168  
     169    g_assert_cmpint (pair.fds[0], ==, -1);
     170    g_assert_cmpint (pair.fds[1], ==, -1);
     171  
     172    /* The read end wasn't closed, because it was stolen first */
     173    g_clear_fd (&read_end, &error);
     174    g_assert_no_error (error);
     175  
     176    /* The write end was closed, because it wasn't stolen */
     177    assert_fd_was_closed (write_end);
     178  
     179    g_assert_cmpstr (buf, ==, "hello");
     180  }
     181  
     182  static void
     183  test_pipe_struct_auto (void)
     184  {
     185  #ifdef g_autofree
     186    int i;
     187  
     188    g_test_summary ("Test g_auto(GUnixPipe)");
     189  
     190    /* Let g_auto close the read end, the write end, neither, or both */
     191    for (i = 0; i < 4; i++)
     192      {
     193        int read_end = -1;    /* unowned */
     194        int write_end = -1;   /* unowned */
     195        int errsv;
     196  
     197          {
     198            g_auto(GUnixPipe) pair = G_UNIX_PIPE_INIT;
     199            GError *error = NULL;
     200            gboolean res;
     201  
     202            res = g_unix_pipe_open (&pair, FD_CLOEXEC, &error);
     203            g_assert_no_error (error);
     204            g_assert_true (res);
     205  
     206            read_end = pair.fds[G_UNIX_PIPE_END_READ];
     207            g_assert_cmpint (read_end, >=, 0);
     208            write_end = pair.fds[G_UNIX_PIPE_END_WRITE];
     209            g_assert_cmpint (write_end, >=, 0);
     210  
     211            if (i & 1)
     212              {
     213                /* This also exercises g_unix_pipe_close() with error */
     214                res = g_unix_pipe_close (&pair, G_UNIX_PIPE_END_READ, &error);
     215                g_assert_no_error (error);
     216                g_assert_true (res);
     217              }
     218  
     219            /* This also exercises g_unix_pipe_close() without error */
     220            if (i & 2)
     221              g_unix_pipe_close (&pair, G_UNIX_PIPE_END_WRITE, NULL);
     222  
     223            /* This is one of the few errno values guaranteed by Standard C.
     224             * We set it here to check that a g_auto(GUnixPipe) close doesn't
     225             * alter errno. */
     226            errno = EILSEQ;
     227          }
     228  
     229        errsv = errno;
     230        g_assert_cmpint (errsv, ==, EILSEQ);
     231        assert_fd_was_closed (read_end);
     232        assert_fd_was_closed (write_end);
     233      }
     234  #else
     235    g_test_skip ("g_auto not supported by compiler");
     236  #endif
     237  }
     238  
     239  static void
     240  test_error (void)
     241  {
     242    GError *error = NULL;
     243    gboolean res;
     244  
     245    res = g_unix_set_fd_nonblocking (123456, TRUE, &error);
     246    g_assert_cmpint (errno, ==, EBADF);
     247    g_assert (!res);
     248    g_assert_error (error, G_UNIX_ERROR, 0);
     249    g_clear_error (&error);
     250  }
     251  
     252  static void
     253  test_nonblocking (void)
     254  {
     255    GError *error = NULL;
     256    int pipefd[2];
     257    gboolean res;
     258    int flags;
     259  
     260    res = g_unix_open_pipe (pipefd, O_CLOEXEC, &error);
     261    g_assert (res);
     262    g_assert_no_error (error);
     263  
     264    res = g_unix_set_fd_nonblocking (pipefd[0], TRUE, &error);
     265    g_assert (res);
     266    g_assert_no_error (error);
     267   
     268    flags = fcntl (pipefd[0], F_GETFL);
     269    g_assert_cmpint (flags, !=, -1);
     270    g_assert (flags & O_NONBLOCK);
     271  
     272    res = g_unix_set_fd_nonblocking (pipefd[0], FALSE, &error);
     273    g_assert (res);
     274    g_assert_no_error (error);
     275   
     276    flags = fcntl (pipefd[0], F_GETFL);
     277    g_assert_cmpint (flags, !=, -1);
     278    g_assert (!(flags & O_NONBLOCK));
     279  
     280    close (pipefd[0]);
     281    close (pipefd[1]);
     282  }
     283  
     284  static gboolean sig_received = FALSE;
     285  static gboolean sig_timeout = FALSE;
     286  static int sig_counter = 0;
     287  
     288  static gboolean
     289  on_sig_received (gpointer user_data)
     290  {
     291    GMainLoop *loop = user_data;
     292    g_main_loop_quit (loop);
     293    sig_received = TRUE;
     294    sig_counter ++;
     295    return G_SOURCE_REMOVE;
     296  }
     297  
     298  static gboolean
     299  on_sig_timeout (gpointer data)
     300  {
     301    GMainLoop *loop = data;
     302    g_main_loop_quit (loop);
     303    sig_timeout = TRUE;
     304    return G_SOURCE_REMOVE;
     305  }
     306  
     307  static gboolean
     308  exit_mainloop (gpointer data)
     309  {
     310    GMainLoop *loop = data;
     311    g_main_loop_quit (loop);
     312    return G_SOURCE_REMOVE;
     313  }
     314  
     315  static gboolean
     316  on_sig_received_2 (gpointer data)
     317  {
     318    GMainLoop *loop = data;
     319  
     320    sig_counter ++;
     321    if (sig_counter == 2)
     322      g_main_loop_quit (loop);
     323    return G_SOURCE_REMOVE;
     324  }
     325  
     326  static void
     327  test_signal (int signum)
     328  {
     329    GMainLoop *mainloop;
     330    int id;
     331  
     332    mainloop = g_main_loop_new (NULL, FALSE);
     333  
     334    sig_received = FALSE;
     335    sig_counter = 0;
     336    g_unix_signal_add (signum, on_sig_received, mainloop);
     337    kill (getpid (), signum);
     338    g_assert (!sig_received);
     339    id = g_timeout_add (5000, on_sig_timeout, mainloop);
     340    g_main_loop_run (mainloop);
     341    g_assert (sig_received);
     342    sig_received = FALSE;
     343    g_source_remove (id);
     344  
     345    /* Ensure we don't get double delivery */
     346    g_timeout_add (500, exit_mainloop, mainloop);
     347    g_main_loop_run (mainloop);
     348    g_assert (!sig_received);
     349  
     350    /* Ensure that two sources for the same signal get it */
     351    sig_counter = 0;
     352    g_unix_signal_add (signum, on_sig_received_2, mainloop);
     353    g_unix_signal_add (signum, on_sig_received_2, mainloop);
     354    id = g_timeout_add (5000, on_sig_timeout, mainloop);
     355  
     356    kill (getpid (), signum);
     357    g_main_loop_run (mainloop);
     358    g_assert_cmpint (sig_counter, ==, 2);
     359    g_source_remove (id);
     360  
     361    g_main_loop_unref (mainloop);
     362  }
     363  
     364  static void
     365  test_sighup (void)
     366  {
     367    test_signal (SIGHUP);
     368  }
     369  
     370  static void
     371  test_sigterm (void)
     372  {
     373    test_signal (SIGTERM);
     374  }
     375  
     376  static void
     377  test_sighup_add_remove (void)
     378  {
     379    guint id;
     380    struct sigaction action;
     381  
     382    sig_received = FALSE;
     383    id = g_unix_signal_add (SIGHUP, on_sig_received, NULL);
     384    g_source_remove (id);
     385  
     386    sigaction (SIGHUP, NULL, &action);
     387    g_assert (action.sa_handler == SIG_DFL);
     388  }
     389  
     390  static gboolean
     391  nested_idle (gpointer data)
     392  {
     393    GMainLoop *nested;
     394    GMainContext *context;
     395    GSource *source;
     396  
     397    context = g_main_context_new ();
     398    nested = g_main_loop_new (context, FALSE);
     399  
     400    source = g_unix_signal_source_new (SIGHUP);
     401    g_source_set_callback (source, on_sig_received, nested, NULL);
     402    g_source_attach (source, context);
     403    g_source_unref (source);
     404  
     405    kill (getpid (), SIGHUP);
     406    g_main_loop_run (nested);
     407    g_assert_cmpint (sig_counter, ==, 1);
     408  
     409    g_main_loop_unref (nested);
     410    g_main_context_unref (context);
     411  
     412    return G_SOURCE_REMOVE;
     413  }
     414  
     415  static void
     416  test_sighup_nested (void)
     417  {
     418    GMainLoop *mainloop;
     419  
     420    mainloop = g_main_loop_new (NULL, FALSE);
     421  
     422    sig_counter = 0;
     423    sig_received = FALSE;
     424    g_unix_signal_add (SIGHUP, on_sig_received, mainloop);
     425    g_idle_add (nested_idle, mainloop);
     426  
     427    g_main_loop_run (mainloop);
     428    g_assert_cmpint (sig_counter, ==, 2);
     429  
     430    g_main_loop_unref (mainloop);
     431  }
     432  
     433  static gboolean
     434  on_sigwinch_received (gpointer data)
     435  {
     436    GMainLoop *loop = (GMainLoop *) data;
     437  
     438    sig_counter ++;
     439  
     440    if (sig_counter == 1)
     441      kill (getpid (), SIGWINCH);
     442    else if (sig_counter == 2)
     443      g_main_loop_quit (loop);
     444    else if (sig_counter > 2)
     445      g_assert_not_reached ();
     446  
     447    /* Increase the time window in which an issue could happen. */
     448    g_usleep (G_USEC_PER_SEC);
     449  
     450    return G_SOURCE_CONTINUE;
     451  }
     452  
     453  static void
     454  test_callback_after_signal (void)
     455  {
     456    /* Checks that user signal callback is invoked *after* receiving a signal.
     457     * In other words a new signal is never merged with the one being currently
     458     * dispatched or whose dispatch had already finished. */
     459  
     460    GMainLoop *mainloop;
     461    GMainContext *context;
     462    GSource *source;
     463  
     464    sig_counter = 0;
     465  
     466    context = g_main_context_new ();
     467    mainloop = g_main_loop_new (context, FALSE);
     468  
     469    source = g_unix_signal_source_new (SIGWINCH);
     470    g_source_set_callback (source, on_sigwinch_received, mainloop, NULL);
     471    g_source_attach (source, context);
     472    g_source_unref (source);
     473  
     474    g_assert_cmpint (sig_counter, ==, 0);
     475    kill (getpid (), SIGWINCH);
     476    g_main_loop_run (mainloop);
     477    g_assert_cmpint (sig_counter, ==, 2);
     478  
     479    g_main_loop_unref (mainloop);
     480    g_main_context_unref (context);
     481  }
     482  
     483  static void
     484  test_get_passwd_entry_root (void)
     485  {
     486    struct passwd *pwd;
     487    GError *local_error = NULL;
     488  
     489    g_test_summary ("Tests that g_unix_get_passwd_entry() works for a "
     490                    "known-existing username.");
     491  
     492    pwd = g_unix_get_passwd_entry ("root", &local_error);
     493    g_assert_no_error (local_error);
     494  
     495    g_assert_cmpstr (pwd->pw_name, ==, "root");
     496    g_assert_cmpuint (pwd->pw_uid, ==, 0);
     497  
     498    g_free (pwd);
     499  }
     500  
     501  static void
     502  test_get_passwd_entry_nonexistent (void)
     503  {
     504    struct passwd *pwd;
     505    GError *local_error = NULL;
     506  
     507    g_test_summary ("Tests that g_unix_get_passwd_entry() returns an error for a "
     508                    "nonexistent username.");
     509  
     510    pwd = g_unix_get_passwd_entry ("thisusernamedoesntexist", &local_error);
     511    g_assert_error (local_error, G_UNIX_ERROR, 0);
     512    g_assert_null (pwd);
     513  
     514    g_clear_error (&local_error);
     515  }
     516  
     517  static void
     518  _child_wait_watch_cb (GPid pid,
     519                        gint wait_status,
     520                        gpointer user_data)
     521  {
     522    gboolean *p_got_callback = user_data;
     523  
     524    g_assert_nonnull (p_got_callback);
     525    g_assert_false (*p_got_callback);
     526    *p_got_callback = TRUE;
     527  }
     528  
     529  static void
     530  test_child_wait (void)
     531  {
     532    gboolean r;
     533    GPid pid;
     534    guint id;
     535    pid_t pid2;
     536    int wstatus;
     537    gboolean got_callback = FALSE;
     538    gboolean iterate_maincontext = g_test_rand_bit ();
     539    char **argv;
     540    int errsv;
     541  
     542    /* - We spawn a trivial child process that exits after a short time.
     543     * - We schedule a g_child_watch_add()
     544     * - we may iterate the GMainContext a bit. Randomly we either get the
     545     *   child-watcher callback or not.
     546     * - if we didn't get the callback, we g_source_remove() the child watcher.
     547     *
     548     * Afterwards, if the callback didn't fire, we check that we are able to waitpid()
     549     * on the process ourselves. Of course, if the child watcher notified, the waitpid()
     550     * will fail with ECHILD.
     551     */
     552  
     553    argv = g_test_rand_bit () ? ((char *[]){ "/bin/sleep", "0.05", NULL }) : ((char *[]){ "/bin/true", NULL });
     554  
     555    r = g_spawn_async (NULL,
     556                       argv,
     557                       NULL,
     558                       G_SPAWN_DO_NOT_REAP_CHILD,
     559                       NULL,
     560                       NULL,
     561                       &pid,
     562                       NULL);
     563    if (!r)
     564      {
     565        /* Some odd system without /bin/sleep? Skip the test. */
     566        g_test_skip ("failure to spawn test process in test_child_wait()");
     567        return;
     568      }
     569  
     570    g_assert_cmpint (pid, >=, 1);
     571  
     572    if (g_test_rand_bit ())
     573      g_usleep (g_test_rand_int_range (0, (G_USEC_PER_SEC / 10)));
     574  
     575    id = g_child_watch_add (pid, _child_wait_watch_cb, &got_callback);
     576  
     577    if (g_test_rand_bit ())
     578      g_usleep (g_test_rand_int_range (0, (G_USEC_PER_SEC / 10)));
     579  
     580    if (iterate_maincontext)
     581      {
     582        gint64 start_usec = g_get_monotonic_time ();
     583        gint64 end_usec = start_usec + g_test_rand_int_range (0, (G_USEC_PER_SEC / 10));
     584  
     585        while (!got_callback && g_get_monotonic_time () < end_usec)
     586          g_main_context_iteration (NULL, FALSE);
     587      }
     588  
     589    if (!got_callback)
     590      g_source_remove (id);
     591  
     592    errno = 0;
     593    pid2 = waitpid (pid, &wstatus, 0);
     594    errsv = errno;
     595    if (got_callback)
     596      {
     597        g_assert_true (iterate_maincontext);
     598        g_assert_cmpint (errsv, ==, ECHILD);
     599        g_assert_cmpint (pid2, <, 0);
     600      }
     601    else
     602      {
     603        g_assert_cmpint (errsv, ==, 0);
     604        g_assert_cmpint (pid2, ==, pid);
     605        g_assert_true (WIFEXITED (wstatus));
     606        g_assert_cmpint (WEXITSTATUS (wstatus), ==, 0);
     607      }
     608  }
     609  
     610  int
     611  main (int   argc,
     612        char *argv[])
     613  {
     614    g_test_init (&argc, &argv, NULL);
     615  
     616    g_test_add_func ("/glib-unix/pipe", test_pipe);
     617    g_test_add_func ("/glib-unix/pipe/fd-cloexec", test_pipe_fd_cloexec);
     618    g_test_add_func ("/glib-unix/pipe-stdio-overwrite", test_pipe_stdio_overwrite);
     619    g_test_add_func ("/glib-unix/pipe-struct", test_pipe_struct);
     620    g_test_add_func ("/glib-unix/pipe-struct-auto", test_pipe_struct_auto);
     621    g_test_add_func ("/glib-unix/error", test_error);
     622    g_test_add_func ("/glib-unix/nonblocking", test_nonblocking);
     623    g_test_add_func ("/glib-unix/sighup", test_sighup);
     624    g_test_add_func ("/glib-unix/sigterm", test_sigterm);
     625    g_test_add_func ("/glib-unix/sighup_again", test_sighup);
     626    g_test_add_func ("/glib-unix/sighup_add_remove", test_sighup_add_remove);
     627    g_test_add_func ("/glib-unix/sighup_nested", test_sighup_nested);
     628    g_test_add_func ("/glib-unix/callback_after_signal", test_callback_after_signal);
     629    g_test_add_func ("/glib-unix/get-passwd-entry/root", test_get_passwd_entry_root);
     630    g_test_add_func ("/glib-unix/get-passwd-entry/nonexistent", test_get_passwd_entry_nonexistent);
     631    g_test_add_func ("/glib-unix/child-wait", test_child_wait);
     632  
     633    return g_test_run();
     634  }