LCOV - code coverage report
Current view: top level - glib/glib/tests - unix.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 352 404 87.1 %
Date: 2024-04-16 05:15:53 Functions: 25 27 92.6 %
Branches: 31 72 43.1 %

           Branch data     Line data    Source code
       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                 :          0 : async_signal_safe_message (const char *message)
      41                 :            : {
      42         [ #  # ]:          0 :   if (write (2, message, strlen (message)) < 0 ||
      43                 :          0 :       write (2, "\n", 1) < 0)
      44                 :            :     {
      45                 :            :       /* ignore: not much we can do */
      46                 :            :     }
      47                 :          0 : }
      48                 :            : 
      49                 :            : static void
      50                 :          1 : test_closefrom (void)
      51                 :            : {
      52                 :            :   /* Enough file descriptors to be confident that we're operating on
      53                 :            :    * all of them */
      54                 :          1 :   const int N_FDS = 20;
      55                 :            :   int *fds;
      56                 :            :   int fd;
      57                 :            :   int i;
      58                 :            :   pid_t child;
      59                 :            :   int wait_status;
      60                 :            : 
      61                 :            :   /* The loop that populates @fds with pipes assumes this */
      62                 :          1 :   g_assert (N_FDS % 2 == 0);
      63                 :            : 
      64                 :          1 :   g_test_summary ("Test g_closefrom(), g_fdwalk_set_cloexec()");
      65                 :          1 :   g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/3247");
      66                 :            : 
      67         [ +  + ]:          4 :   for (fd = 0; fd <= 2; fd++)
      68                 :            :     {
      69                 :            :       int flags;
      70                 :            : 
      71                 :          3 :       g_assert_no_errno ((flags = fcntl (fd, F_GETFD)));
      72                 :          3 :       g_assert_no_errno (fcntl (fd, F_SETFD, flags & ~FD_CLOEXEC));
      73                 :            :     }
      74                 :            : 
      75                 :          1 :   fds = g_new0 (int, N_FDS);
      76                 :            : 
      77         [ +  + ]:         11 :   for (i = 0; i < N_FDS; i += 2)
      78                 :            :     {
      79                 :         10 :       GError *error = NULL;
      80                 :            :       int pipefd[2];
      81                 :            :       int res;
      82                 :            : 
      83                 :            :       /* Intentionally neither O_CLOEXEC nor FD_CLOEXEC */
      84                 :         10 :       res = g_unix_open_pipe (pipefd, 0, &error);
      85                 :         10 :       g_assert (res);
      86                 :         10 :       g_assert_no_error (error);
      87                 :         10 :       g_clear_error (&error);
      88                 :         10 :       fds[i] = pipefd[0];
      89                 :         10 :       fds[i + 1] = pipefd[1];
      90                 :            :     }
      91                 :            : 
      92                 :          1 :   child = fork ();
      93                 :            : 
      94                 :            :   /* Child process exits with status = 100 + the first wrong fd,
      95                 :            :    * or 0 if all were correct */
      96         [ -  + ]:          1 :   if (child == 0)
      97                 :            :     {
      98         [ #  # ]:          0 :       for (i = 0; i < N_FDS; i++)
      99                 :            :         {
     100                 :          0 :           int flags = fcntl (fds[i], F_GETFD);
     101                 :            : 
     102         [ #  # ]:          0 :           if (flags == -1)
     103                 :            :             {
     104                 :          0 :               async_signal_safe_message ("fd should not have been closed");
     105                 :          0 :               _exit (100 + fds[i]);
     106                 :            :             }
     107                 :            : 
     108         [ #  # ]:          0 :           if (flags & FD_CLOEXEC)
     109                 :            :             {
     110                 :          0 :               async_signal_safe_message ("fd should not have been close-on-exec yet");
     111                 :          0 :               _exit (100 + fds[i]);
     112                 :            :             }
     113                 :            :         }
     114                 :            : 
     115                 :          0 :       g_fdwalk_set_cloexec (3);
     116                 :            : 
     117         [ #  # ]:          0 :       for (i = 0; i < N_FDS; i++)
     118                 :            :         {
     119                 :          0 :           int flags = fcntl (fds[i], F_GETFD);
     120                 :            : 
     121         [ #  # ]:          0 :           if (flags == -1)
     122                 :            :             {
     123                 :          0 :               async_signal_safe_message ("fd should not have been closed");
     124                 :          0 :               _exit (100 + fds[i]);
     125                 :            :             }
     126                 :            : 
     127         [ #  # ]:          0 :           if (!(flags & FD_CLOEXEC))
     128                 :            :             {
     129                 :          0 :               async_signal_safe_message ("fd should have been close-on-exec");
     130                 :          0 :               _exit (100 + fds[i]);
     131                 :            :             }
     132                 :            :         }
     133                 :            : 
     134                 :          0 :       g_closefrom (3);
     135                 :            : 
     136         [ #  # ]:          0 :       for (fd = 0; fd <= 2; fd++)
     137                 :            :         {
     138                 :          0 :           int flags = fcntl (fd, F_GETFD);
     139                 :            : 
     140         [ #  # ]:          0 :           if (flags == -1)
     141                 :            :             {
     142                 :          0 :               async_signal_safe_message ("fd should not have been closed");
     143                 :          0 :               _exit (100 + fd);
     144                 :            :             }
     145                 :            : 
     146         [ #  # ]:          0 :           if (flags & FD_CLOEXEC)
     147                 :            :             {
     148                 :          0 :               async_signal_safe_message ("fd should not have been close-on-exec");
     149                 :          0 :               _exit (100 + fd);
     150                 :            :             }
     151                 :            :         }
     152                 :            : 
     153         [ #  # ]:          0 :       for (i = 0; i < N_FDS; i++)
     154                 :            :         {
     155   [ #  #  #  # ]:          0 :           if (fcntl (fds[i], F_GETFD) != -1 || errno != EBADF)
     156                 :            :             {
     157                 :          0 :               async_signal_safe_message ("fd should have been closed");
     158                 :          0 :               _exit (100 + fds[i]);
     159                 :            :             }
     160                 :            :         }
     161                 :            : 
     162                 :          0 :       _exit (0);
     163                 :            :     }
     164                 :            : 
     165                 :          1 :   g_assert_no_errno (waitpid (child, &wait_status, 0));
     166                 :            : 
     167         [ +  - ]:          1 :   if (WIFEXITED (wait_status))
     168                 :            :     {
     169                 :          1 :       int exit_status = WEXITSTATUS (wait_status);
     170                 :            : 
     171         [ -  + ]:          1 :       if (exit_status != 0)
     172                 :          0 :         g_test_fail_printf ("File descriptor %d in incorrect state", exit_status - 100);
     173                 :            :     }
     174                 :            :   else
     175                 :            :     {
     176                 :          0 :       g_test_fail_printf ("Unexpected wait status %d", wait_status);
     177                 :            :     }
     178                 :            : 
     179         [ +  + ]:         21 :   for (i = 0; i < N_FDS; i++)
     180                 :            :     {
     181                 :         20 :       GError *error = NULL;
     182                 :            : 
     183                 :         20 :       g_close (fds[i], &error);
     184                 :         20 :       g_assert_no_error (error);
     185                 :         20 :       g_clear_error (&error);
     186                 :            :     }
     187                 :            : 
     188                 :          1 :   g_free (fds);
     189                 :            : 
     190         [ +  - ]:          1 :   if (g_test_undefined ())
     191                 :            :     {
     192                 :          1 :       g_test_trap_subprocess ("/glib-unix/closefrom/subprocess/einval",
     193                 :            :                               0, G_TEST_SUBPROCESS_DEFAULT);
     194                 :          1 :       g_test_trap_assert_passed ();
     195                 :            :     }
     196                 :          1 : }
     197                 :            : 
     198                 :            : static void
     199                 :          1 : test_closefrom_subprocess_einval (void)
     200                 :            : {
     201                 :            :   int res;
     202                 :            :   int errsv;
     203                 :            : 
     204                 :          1 :   g_log_set_always_fatal (G_LOG_FATAL_MASK);
     205                 :          1 :   g_log_set_fatal_mask ("GLib", G_LOG_FATAL_MASK);
     206                 :            : 
     207                 :          1 :   errno = 0;
     208                 :          1 :   res = g_closefrom (-1);
     209                 :          1 :   errsv = errno;
     210                 :          1 :   g_assert_cmpint (res, ==, -1);
     211                 :          1 :   g_assert_cmpint (errsv, ==, EINVAL);
     212                 :            : 
     213                 :          1 :   errno = 0;
     214                 :          1 :   res = g_fdwalk_set_cloexec (-42);
     215                 :          1 :   errsv = errno;
     216                 :          1 :   g_assert_cmpint (res, ==, -1);
     217                 :          1 :   g_assert_cmpint (errsv, ==, EINVAL);
     218                 :          1 : }
     219                 :            : 
     220                 :            : static void
     221                 :          1 : test_pipe (void)
     222                 :            : {
     223                 :          1 :   GError *error = NULL;
     224                 :            :   int pipefd[2];
     225                 :            :   char buf[1024];
     226                 :            :   gssize bytes_read;
     227                 :            :   gboolean res;
     228                 :            : 
     229                 :          1 :   res = g_unix_open_pipe (pipefd, O_CLOEXEC, &error);
     230                 :          1 :   g_assert (res);
     231                 :          1 :   g_assert_no_error (error);
     232                 :            : 
     233                 :          1 :   g_assert_cmpint (write (pipefd[1], "hello", sizeof ("hello")), ==, sizeof ("hello"));
     234                 :          1 :   memset (buf, 0, sizeof (buf));
     235                 :          1 :   bytes_read = read (pipefd[0], buf, sizeof(buf) - 1);
     236                 :          1 :   g_assert_cmpint (bytes_read, >, 0);
     237                 :          1 :   buf[bytes_read] = '\0';
     238                 :            : 
     239                 :          1 :   close (pipefd[0]);
     240                 :          1 :   close (pipefd[1]);
     241                 :            : 
     242                 :          1 :   g_assert (g_str_has_prefix (buf, "hello"));
     243                 :          1 : }
     244                 :            : 
     245                 :            : static void
     246                 :          1 : test_pipe_fd_cloexec (void)
     247                 :            : {
     248                 :          1 :   GError *error = NULL;
     249                 :            :   int pipefd[2];
     250                 :            :   char buf[1024];
     251                 :            :   gssize bytes_read;
     252                 :            :   gboolean res;
     253                 :            : 
     254                 :          1 :   g_test_summary ("Test that FD_CLOEXEC is still accepted as an argument to g_unix_open_pipe()");
     255                 :          1 :   g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/merge_requests/3459");
     256                 :            : 
     257                 :          1 :   res = g_unix_open_pipe (pipefd, FD_CLOEXEC, &error);
     258                 :          1 :   g_assert (res);
     259                 :          1 :   g_assert_no_error (error);
     260                 :            : 
     261                 :          1 :   g_assert_cmpint (write (pipefd[1], "hello", sizeof ("hello")), ==, sizeof ("hello"));
     262                 :          1 :   memset (buf, 0, sizeof (buf));
     263                 :          1 :   bytes_read = read (pipefd[0], buf, sizeof(buf) - 1);
     264                 :          1 :   g_assert_cmpint (bytes_read, >, 0);
     265                 :          1 :   buf[bytes_read] = '\0';
     266                 :            : 
     267                 :          1 :   close (pipefd[0]);
     268                 :          1 :   close (pipefd[1]);
     269                 :            : 
     270                 :          1 :   g_assert_true (g_str_has_prefix (buf, "hello"));
     271                 :          1 : }
     272                 :            : 
     273                 :            : static void
     274                 :          1 : test_pipe_stdio_overwrite (void)
     275                 :            : {
     276                 :          1 :   GError *error = NULL;
     277                 :            :   int pipefd[2], ret;
     278                 :            :   gboolean res;
     279                 :            :   int stdin_fd;
     280                 :            : 
     281                 :            : 
     282                 :          1 :   g_test_summary ("Test that g_unix_open_pipe() will use the first available FD, even if it’s stdin/stdout/stderr");
     283                 :          1 :   g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2795");
     284                 :            : 
     285                 :          1 :   stdin_fd = dup (STDIN_FILENO);
     286                 :          1 :   g_assert_cmpint (stdin_fd, >, 0);
     287                 :            : 
     288                 :          1 :   g_close (STDIN_FILENO, &error);
     289                 :          1 :   g_assert_no_error (error);
     290                 :            : 
     291                 :          1 :   res = g_unix_open_pipe (pipefd, O_CLOEXEC, &error);
     292                 :          1 :   g_assert_no_error (error);
     293                 :          1 :   g_assert_true (res);
     294                 :            : 
     295                 :          1 :   g_assert_cmpint (pipefd[0], ==, STDIN_FILENO);
     296                 :            : 
     297                 :          1 :   g_close (pipefd[0], &error);
     298                 :          1 :   g_assert_no_error (error);
     299                 :            : 
     300                 :          1 :   g_close (pipefd[1], &error);
     301                 :          1 :   g_assert_no_error (error);
     302                 :            : 
     303                 :          1 :   ret = dup2 (stdin_fd, STDIN_FILENO);
     304                 :          1 :   g_assert_cmpint (ret, >=, 0);
     305                 :            : 
     306                 :          1 :   g_close (stdin_fd, &error);
     307                 :          1 :   g_assert_no_error (error);
     308                 :          1 : }
     309                 :            : 
     310                 :            : static void
     311                 :          1 : test_pipe_struct (void)
     312                 :            : {
     313                 :          1 :   GError *error = NULL;
     314                 :          1 :   GUnixPipe pair = G_UNIX_PIPE_INIT;
     315                 :            :   char buf[1024];
     316                 :            :   gssize bytes_read;
     317                 :            :   gboolean res;
     318                 :          1 :   int read_end = -1;    /* owned */
     319                 :          1 :   int write_end = -1;   /* unowned */
     320                 :            :   int errsv;
     321                 :            : 
     322                 :          1 :   g_test_summary ("Test GUnixPipe structure");
     323                 :            : 
     324                 :          1 :   res = g_unix_pipe_open (&pair, O_CLOEXEC, &error);
     325                 :          1 :   g_assert_no_error (error);
     326                 :          1 :   g_assert_true (res);
     327                 :            : 
     328                 :          1 :   read_end = g_unix_pipe_steal (&pair, G_UNIX_PIPE_END_READ);
     329                 :          1 :   g_assert_cmpint (read_end, >=, 0);
     330                 :          1 :   g_assert_cmpint (g_unix_pipe_steal (&pair, G_UNIX_PIPE_END_READ), ==, -1);
     331                 :          1 :   g_assert_cmpint (g_unix_pipe_get (&pair, G_UNIX_PIPE_END_READ), ==, -1);
     332                 :          1 :   write_end = g_unix_pipe_get (&pair, G_UNIX_PIPE_END_WRITE);
     333                 :          1 :   g_assert_cmpint (write_end, >=, 0);
     334                 :          1 :   g_assert_cmpint (g_unix_pipe_get (&pair, G_UNIX_PIPE_END_WRITE), ==, write_end);
     335                 :            : 
     336                 :          1 :   g_assert_cmpint (write (write_end, "hello", sizeof ("hello")), ==, sizeof ("hello"));
     337                 :          1 :   memset (buf, 0, sizeof (buf));
     338                 :          1 :   bytes_read = read (read_end, buf, sizeof(buf) - 1);
     339                 :          1 :   g_assert_cmpint (bytes_read, ==, sizeof ("hello"));
     340                 :          1 :   buf[bytes_read] = '\0';
     341                 :            : 
     342                 :            :   /* This is one of the few errno values guaranteed by Standard C.
     343                 :            :    * We set it here to check that g_unix_pipe_clear doesn't alter errno. */
     344                 :          1 :   errno = EILSEQ;
     345                 :            : 
     346                 :          1 :   g_unix_pipe_clear (&pair);
     347                 :          1 :   errsv = errno;
     348                 :          1 :   g_assert_cmpint (errsv, ==, EILSEQ);
     349                 :            : 
     350                 :          1 :   g_assert_cmpint (pair.fds[0], ==, -1);
     351                 :          1 :   g_assert_cmpint (pair.fds[1], ==, -1);
     352                 :            : 
     353                 :            :   /* The read end wasn't closed, because it was stolen first */
     354                 :          1 :   g_clear_fd (&read_end, &error);
     355                 :          1 :   g_assert_no_error (error);
     356                 :            : 
     357                 :            :   /* The write end was closed, because it wasn't stolen */
     358                 :          1 :   assert_fd_was_closed (write_end);
     359                 :            : 
     360                 :          1 :   g_assert_cmpstr (buf, ==, "hello");
     361                 :          1 : }
     362                 :            : 
     363                 :            : static void
     364                 :          1 : test_pipe_struct_auto (void)
     365                 :            : {
     366                 :            : #ifdef g_autofree
     367                 :            :   int i;
     368                 :            : 
     369                 :          1 :   g_test_summary ("Test g_auto(GUnixPipe)");
     370                 :            : 
     371                 :            :   /* Let g_auto close the read end, the write end, neither, or both */
     372         [ +  + ]:          5 :   for (i = 0; i < 4; i++)
     373                 :            :     {
     374                 :          4 :       int read_end = -1;    /* unowned */
     375                 :          4 :       int write_end = -1;   /* unowned */
     376                 :            :       int errsv;
     377                 :            : 
     378                 :            :         {
     379                 :          8 :           g_auto(GUnixPipe) pair = G_UNIX_PIPE_INIT;
     380                 :          4 :           GError *error = NULL;
     381                 :            :           gboolean res;
     382                 :            : 
     383                 :          4 :           res = g_unix_pipe_open (&pair, O_CLOEXEC, &error);
     384                 :          4 :           g_assert_no_error (error);
     385                 :          4 :           g_assert_true (res);
     386                 :            : 
     387                 :          4 :           read_end = pair.fds[G_UNIX_PIPE_END_READ];
     388                 :          4 :           g_assert_cmpint (read_end, >=, 0);
     389                 :          4 :           write_end = pair.fds[G_UNIX_PIPE_END_WRITE];
     390                 :          4 :           g_assert_cmpint (write_end, >=, 0);
     391                 :            : 
     392         [ +  + ]:          4 :           if (i & 1)
     393                 :            :             {
     394                 :            :               /* This also exercises g_unix_pipe_close() with error */
     395                 :          2 :               res = g_unix_pipe_close (&pair, G_UNIX_PIPE_END_READ, &error);
     396                 :          2 :               g_assert_no_error (error);
     397                 :          2 :               g_assert_true (res);
     398                 :            :             }
     399                 :            : 
     400                 :            :           /* This also exercises g_unix_pipe_close() without error */
     401         [ +  + ]:          4 :           if (i & 2)
     402                 :          2 :             g_unix_pipe_close (&pair, G_UNIX_PIPE_END_WRITE, NULL);
     403                 :            : 
     404                 :            :           /* This is one of the few errno values guaranteed by Standard C.
     405                 :            :            * We set it here to check that a g_auto(GUnixPipe) close doesn't
     406                 :            :            * alter errno. */
     407                 :          4 :           errno = EILSEQ;
     408                 :            :         }
     409                 :            : 
     410                 :          4 :       errsv = errno;
     411                 :          4 :       g_assert_cmpint (errsv, ==, EILSEQ);
     412                 :          4 :       assert_fd_was_closed (read_end);
     413                 :          4 :       assert_fd_was_closed (write_end);
     414                 :            :     }
     415                 :            : #else
     416                 :            :   g_test_skip ("g_auto not supported by compiler");
     417                 :            : #endif
     418                 :          1 : }
     419                 :            : 
     420                 :            : static void
     421                 :          1 : test_error (void)
     422                 :            : {
     423                 :          1 :   GError *error = NULL;
     424                 :            :   gboolean res;
     425                 :            : 
     426                 :          1 :   res = g_unix_set_fd_nonblocking (123456, TRUE, &error);
     427                 :          1 :   g_assert_cmpint (errno, ==, EBADF);
     428                 :          1 :   g_assert (!res);
     429                 :          1 :   g_assert_error (error, G_UNIX_ERROR, 0);
     430                 :          1 :   g_clear_error (&error);
     431                 :          1 : }
     432                 :            : 
     433                 :            : static void
     434                 :          1 : test_nonblocking (void)
     435                 :            : {
     436                 :          1 :   GError *error = NULL;
     437                 :            :   int pipefd[2];
     438                 :            :   gboolean res;
     439                 :            :   int flags;
     440                 :            : 
     441                 :          1 :   res = g_unix_open_pipe (pipefd, O_CLOEXEC, &error);
     442                 :          1 :   g_assert (res);
     443                 :          1 :   g_assert_no_error (error);
     444                 :            : 
     445                 :          1 :   res = g_unix_set_fd_nonblocking (pipefd[0], TRUE, &error);
     446                 :          1 :   g_assert (res);
     447                 :          1 :   g_assert_no_error (error);
     448                 :            :  
     449                 :          1 :   flags = fcntl (pipefd[0], F_GETFL);
     450                 :          1 :   g_assert_cmpint (flags, !=, -1);
     451                 :          1 :   g_assert (flags & O_NONBLOCK);
     452                 :            : 
     453                 :          1 :   res = g_unix_set_fd_nonblocking (pipefd[0], FALSE, &error);
     454                 :          1 :   g_assert (res);
     455                 :          1 :   g_assert_no_error (error);
     456                 :            :  
     457                 :          1 :   flags = fcntl (pipefd[0], F_GETFL);
     458                 :          1 :   g_assert_cmpint (flags, !=, -1);
     459                 :          1 :   g_assert (!(flags & O_NONBLOCK));
     460                 :            : 
     461                 :          1 :   close (pipefd[0]);
     462                 :          1 :   close (pipefd[1]);
     463                 :          1 : }
     464                 :            : 
     465                 :            : static gboolean sig_received = FALSE;
     466                 :            : static gboolean sig_timeout = FALSE;
     467                 :            : static int sig_counter = 0;
     468                 :            : 
     469                 :            : static gboolean
     470                 :          5 : on_sig_received (gpointer user_data)
     471                 :            : {
     472                 :          5 :   GMainLoop *loop = user_data;
     473                 :          5 :   g_main_loop_quit (loop);
     474                 :          5 :   sig_received = TRUE;
     475                 :          5 :   sig_counter ++;
     476                 :          5 :   return G_SOURCE_REMOVE;
     477                 :            : }
     478                 :            : 
     479                 :            : static gboolean
     480                 :          0 : on_sig_timeout (gpointer data)
     481                 :            : {
     482                 :          0 :   GMainLoop *loop = data;
     483                 :          0 :   g_main_loop_quit (loop);
     484                 :          0 :   sig_timeout = TRUE;
     485                 :          0 :   return G_SOURCE_REMOVE;
     486                 :            : }
     487                 :            : 
     488                 :            : static gboolean
     489                 :          3 : exit_mainloop (gpointer data)
     490                 :            : {
     491                 :          3 :   GMainLoop *loop = data;
     492                 :          3 :   g_main_loop_quit (loop);
     493                 :          3 :   return G_SOURCE_REMOVE;
     494                 :            : }
     495                 :            : 
     496                 :            : static gboolean
     497                 :          6 : on_sig_received_2 (gpointer data)
     498                 :            : {
     499                 :          6 :   GMainLoop *loop = data;
     500                 :            : 
     501                 :          6 :   sig_counter ++;
     502         [ +  + ]:          6 :   if (sig_counter == 2)
     503                 :          3 :     g_main_loop_quit (loop);
     504                 :          6 :   return G_SOURCE_REMOVE;
     505                 :            : }
     506                 :            : 
     507                 :            : static void
     508                 :          3 : test_signal (int signum)
     509                 :            : {
     510                 :            :   GMainLoop *mainloop;
     511                 :            :   int id;
     512                 :            : 
     513                 :          3 :   mainloop = g_main_loop_new (NULL, FALSE);
     514                 :            : 
     515                 :          3 :   sig_received = FALSE;
     516                 :          3 :   sig_counter = 0;
     517                 :          3 :   g_unix_signal_add (signum, on_sig_received, mainloop);
     518                 :          3 :   kill (getpid (), signum);
     519                 :          3 :   g_assert (!sig_received);
     520                 :          3 :   id = g_timeout_add (5000, on_sig_timeout, mainloop);
     521                 :          3 :   g_main_loop_run (mainloop);
     522                 :          3 :   g_assert (sig_received);
     523                 :          3 :   sig_received = FALSE;
     524                 :          3 :   g_source_remove (id);
     525                 :            : 
     526                 :            :   /* Ensure we don't get double delivery */
     527                 :          3 :   g_timeout_add (500, exit_mainloop, mainloop);
     528                 :          3 :   g_main_loop_run (mainloop);
     529                 :          3 :   g_assert (!sig_received);
     530                 :            : 
     531                 :            :   /* Ensure that two sources for the same signal get it */
     532                 :          3 :   sig_counter = 0;
     533                 :          3 :   g_unix_signal_add (signum, on_sig_received_2, mainloop);
     534                 :          3 :   g_unix_signal_add (signum, on_sig_received_2, mainloop);
     535                 :          3 :   id = g_timeout_add (5000, on_sig_timeout, mainloop);
     536                 :            : 
     537                 :          3 :   kill (getpid (), signum);
     538                 :          3 :   g_main_loop_run (mainloop);
     539                 :          3 :   g_assert_cmpint (sig_counter, ==, 2);
     540                 :          3 :   g_source_remove (id);
     541                 :            : 
     542                 :          3 :   g_main_loop_unref (mainloop);
     543                 :          3 : }
     544                 :            : 
     545                 :            : static void
     546                 :          2 : test_sighup (void)
     547                 :            : {
     548                 :          2 :   test_signal (SIGHUP);
     549                 :          2 : }
     550                 :            : 
     551                 :            : static void
     552                 :          1 : test_sigterm (void)
     553                 :            : {
     554                 :          1 :   test_signal (SIGTERM);
     555                 :          1 : }
     556                 :            : 
     557                 :            : static void
     558                 :          1 : test_sighup_add_remove (void)
     559                 :            : {
     560                 :            :   guint id;
     561                 :            :   struct sigaction action;
     562                 :            : 
     563                 :          1 :   sig_received = FALSE;
     564                 :          1 :   id = g_unix_signal_add (SIGHUP, on_sig_received, NULL);
     565                 :          1 :   g_source_remove (id);
     566                 :            : 
     567                 :          1 :   sigaction (SIGHUP, NULL, &action);
     568                 :          1 :   g_assert (action.sa_handler == SIG_DFL);
     569                 :          1 : }
     570                 :            : 
     571                 :            : static gboolean
     572                 :          1 : nested_idle (gpointer data)
     573                 :            : {
     574                 :            :   GMainLoop *nested;
     575                 :            :   GMainContext *context;
     576                 :            :   GSource *source;
     577                 :            : 
     578                 :          1 :   context = g_main_context_new ();
     579                 :          1 :   nested = g_main_loop_new (context, FALSE);
     580                 :            : 
     581                 :          1 :   source = g_unix_signal_source_new (SIGHUP);
     582                 :          1 :   g_source_set_callback (source, on_sig_received, nested, NULL);
     583                 :          1 :   g_source_attach (source, context);
     584                 :          1 :   g_source_unref (source);
     585                 :            : 
     586                 :          1 :   kill (getpid (), SIGHUP);
     587                 :          1 :   g_main_loop_run (nested);
     588                 :          1 :   g_assert_cmpint (sig_counter, ==, 1);
     589                 :            : 
     590                 :          1 :   g_main_loop_unref (nested);
     591                 :          1 :   g_main_context_unref (context);
     592                 :            : 
     593                 :          1 :   return G_SOURCE_REMOVE;
     594                 :            : }
     595                 :            : 
     596                 :            : static void
     597                 :          1 : test_sighup_nested (void)
     598                 :            : {
     599                 :            :   GMainLoop *mainloop;
     600                 :            : 
     601                 :          1 :   mainloop = g_main_loop_new (NULL, FALSE);
     602                 :            : 
     603                 :          1 :   sig_counter = 0;
     604                 :          1 :   sig_received = FALSE;
     605                 :          1 :   g_unix_signal_add (SIGHUP, on_sig_received, mainloop);
     606                 :          1 :   g_idle_add (nested_idle, mainloop);
     607                 :            : 
     608                 :          1 :   g_main_loop_run (mainloop);
     609                 :          1 :   g_assert_cmpint (sig_counter, ==, 2);
     610                 :            : 
     611                 :          1 :   g_main_loop_unref (mainloop);
     612                 :          1 : }
     613                 :            : 
     614                 :            : static gboolean
     615                 :          2 : on_sigwinch_received (gpointer data)
     616                 :            : {
     617                 :          2 :   GMainLoop *loop = (GMainLoop *) data;
     618                 :            : 
     619                 :          2 :   sig_counter ++;
     620                 :            : 
     621         [ +  + ]:          2 :   if (sig_counter == 1)
     622                 :          1 :     kill (getpid (), SIGWINCH);
     623         [ +  - ]:          1 :   else if (sig_counter == 2)
     624                 :          1 :     g_main_loop_quit (loop);
     625         [ #  # ]:          0 :   else if (sig_counter > 2)
     626                 :            :     g_assert_not_reached ();
     627                 :            : 
     628                 :            :   /* Increase the time window in which an issue could happen. */
     629                 :          2 :   g_usleep (G_USEC_PER_SEC);
     630                 :            : 
     631                 :          2 :   return G_SOURCE_CONTINUE;
     632                 :            : }
     633                 :            : 
     634                 :            : static void
     635                 :          1 : test_callback_after_signal (void)
     636                 :            : {
     637                 :            :   /* Checks that user signal callback is invoked *after* receiving a signal.
     638                 :            :    * In other words a new signal is never merged with the one being currently
     639                 :            :    * dispatched or whose dispatch had already finished. */
     640                 :            : 
     641                 :            :   GMainLoop *mainloop;
     642                 :            :   GMainContext *context;
     643                 :            :   GSource *source;
     644                 :            : 
     645                 :          1 :   sig_counter = 0;
     646                 :            : 
     647                 :          1 :   context = g_main_context_new ();
     648                 :          1 :   mainloop = g_main_loop_new (context, FALSE);
     649                 :            : 
     650                 :          1 :   source = g_unix_signal_source_new (SIGWINCH);
     651                 :          1 :   g_source_set_callback (source, on_sigwinch_received, mainloop, NULL);
     652                 :          1 :   g_source_attach (source, context);
     653                 :          1 :   g_source_unref (source);
     654                 :            : 
     655                 :          1 :   g_assert_cmpint (sig_counter, ==, 0);
     656                 :          1 :   kill (getpid (), SIGWINCH);
     657                 :          1 :   g_main_loop_run (mainloop);
     658                 :          1 :   g_assert_cmpint (sig_counter, ==, 2);
     659                 :            : 
     660                 :          1 :   g_main_loop_unref (mainloop);
     661                 :          1 :   g_main_context_unref (context);
     662                 :          1 : }
     663                 :            : 
     664                 :            : static void
     665                 :          1 : test_get_passwd_entry_root (void)
     666                 :            : {
     667                 :            :   struct passwd *pwd;
     668                 :          1 :   GError *local_error = NULL;
     669                 :            : 
     670                 :          1 :   g_test_summary ("Tests that g_unix_get_passwd_entry() works for a "
     671                 :            :                   "known-existing username.");
     672                 :            : 
     673                 :          1 :   pwd = g_unix_get_passwd_entry ("root", &local_error);
     674                 :          1 :   g_assert_no_error (local_error);
     675                 :            : 
     676                 :          1 :   g_assert_cmpstr (pwd->pw_name, ==, "root");
     677                 :          1 :   g_assert_cmpuint (pwd->pw_uid, ==, 0);
     678                 :            : 
     679                 :          1 :   g_free (pwd);
     680                 :          1 : }
     681                 :            : 
     682                 :            : static void
     683                 :          1 : test_get_passwd_entry_nonexistent (void)
     684                 :            : {
     685                 :            :   struct passwd *pwd;
     686                 :          1 :   GError *local_error = NULL;
     687                 :            : 
     688                 :          1 :   g_test_summary ("Tests that g_unix_get_passwd_entry() returns an error for a "
     689                 :            :                   "nonexistent username.");
     690                 :            : 
     691                 :          1 :   pwd = g_unix_get_passwd_entry ("thisusernamedoesntexist", &local_error);
     692                 :          1 :   g_assert_error (local_error, G_UNIX_ERROR, 0);
     693                 :          1 :   g_assert_null (pwd);
     694                 :            : 
     695                 :          1 :   g_clear_error (&local_error);
     696                 :          1 : }
     697                 :            : 
     698                 :            : static void
     699                 :          1 : _child_wait_watch_cb (GPid pid,
     700                 :            :                       gint wait_status,
     701                 :            :                       gpointer user_data)
     702                 :            : {
     703                 :          1 :   gboolean *p_got_callback = user_data;
     704                 :            : 
     705                 :          1 :   g_assert_nonnull (p_got_callback);
     706                 :          1 :   g_assert_false (*p_got_callback);
     707                 :          1 :   *p_got_callback = TRUE;
     708                 :          1 : }
     709                 :            : 
     710                 :            : static void
     711                 :          1 : test_child_wait (void)
     712                 :            : {
     713                 :            :   gboolean r;
     714                 :            :   GPid pid;
     715                 :            :   guint id;
     716                 :            :   pid_t pid2;
     717                 :            :   int wstatus;
     718                 :          1 :   gboolean got_callback = FALSE;
     719                 :          1 :   gboolean iterate_maincontext = g_test_rand_bit ();
     720                 :            :   char **argv;
     721                 :            :   int errsv;
     722                 :            : 
     723                 :            :   /* - We spawn a trivial child process that exits after a short time.
     724                 :            :    * - We schedule a g_child_watch_add()
     725                 :            :    * - we may iterate the GMainContext a bit. Randomly we either get the
     726                 :            :    *   child-watcher callback or not.
     727                 :            :    * - if we didn't get the callback, we g_source_remove() the child watcher.
     728                 :            :    *
     729                 :            :    * Afterwards, if the callback didn't fire, we check that we are able to waitpid()
     730                 :            :    * on the process ourselves. Of course, if the child watcher notified, the waitpid()
     731                 :            :    * will fail with ECHILD.
     732                 :            :    */
     733                 :            : 
     734         [ -  + ]:          1 :   argv = g_test_rand_bit () ? ((char *[]){ "/bin/sleep", "0.05", NULL }) : ((char *[]){ "/bin/true", NULL });
     735                 :            : 
     736                 :          1 :   r = g_spawn_async (NULL,
     737                 :            :                      argv,
     738                 :            :                      NULL,
     739                 :            :                      G_SPAWN_DO_NOT_REAP_CHILD,
     740                 :            :                      NULL,
     741                 :            :                      NULL,
     742                 :            :                      &pid,
     743                 :            :                      NULL);
     744         [ -  + ]:          1 :   if (!r)
     745                 :            :     {
     746                 :            :       /* Some odd system without /bin/sleep? Skip the test. */
     747                 :          0 :       g_test_skip ("failure to spawn test process in test_child_wait()");
     748                 :          0 :       return;
     749                 :            :     }
     750                 :            : 
     751                 :          1 :   g_assert_cmpint (pid, >=, 1);
     752                 :            : 
     753         [ -  + ]:          1 :   if (g_test_rand_bit ())
     754                 :          0 :     g_usleep (g_test_rand_int_range (0, (G_USEC_PER_SEC / 10)));
     755                 :            : 
     756                 :          1 :   id = g_child_watch_add (pid, _child_wait_watch_cb, &got_callback);
     757                 :            : 
     758         [ -  + ]:          1 :   if (g_test_rand_bit ())
     759                 :          0 :     g_usleep (g_test_rand_int_range (0, (G_USEC_PER_SEC / 10)));
     760                 :            : 
     761         [ +  - ]:          1 :   if (iterate_maincontext)
     762                 :            :     {
     763                 :          1 :       gint64 start_usec = g_get_monotonic_time ();
     764                 :          1 :       gint64 end_usec = start_usec + g_test_rand_int_range (0, (G_USEC_PER_SEC / 10));
     765                 :            : 
     766   [ +  +  +  - ]:        144 :       while (!got_callback && g_get_monotonic_time () < end_usec)
     767                 :        143 :         g_main_context_iteration (NULL, FALSE);
     768                 :            :     }
     769                 :            : 
     770         [ -  + ]:          1 :   if (!got_callback)
     771                 :          0 :     g_source_remove (id);
     772                 :            : 
     773                 :          1 :   errno = 0;
     774                 :          1 :   pid2 = waitpid (pid, &wstatus, 0);
     775                 :          1 :   errsv = errno;
     776         [ +  - ]:          1 :   if (got_callback)
     777                 :            :     {
     778                 :          1 :       g_assert_true (iterate_maincontext);
     779                 :          1 :       g_assert_cmpint (errsv, ==, ECHILD);
     780                 :          1 :       g_assert_cmpint (pid2, <, 0);
     781                 :            :     }
     782                 :            :   else
     783                 :            :     {
     784                 :          0 :       g_assert_cmpint (errsv, ==, 0);
     785                 :          0 :       g_assert_cmpint (pid2, ==, pid);
     786                 :          0 :       g_assert_true (WIFEXITED (wstatus));
     787                 :          0 :       g_assert_cmpint (WEXITSTATUS (wstatus), ==, 0);
     788                 :            :     }
     789                 :            : }
     790                 :            : 
     791                 :            : int
     792                 :          2 : main (int   argc,
     793                 :            :       char *argv[])
     794                 :            : {
     795                 :          2 :   g_test_init (&argc, &argv, NULL);
     796                 :            : 
     797                 :          2 :   g_test_add_func ("/glib-unix/closefrom", test_closefrom);
     798                 :          2 :   g_test_add_func ("/glib-unix/closefrom/subprocess/einval",
     799                 :            :                    test_closefrom_subprocess_einval);
     800                 :          2 :   g_test_add_func ("/glib-unix/pipe", test_pipe);
     801                 :          2 :   g_test_add_func ("/glib-unix/pipe/fd-cloexec", test_pipe_fd_cloexec);
     802                 :          2 :   g_test_add_func ("/glib-unix/pipe-stdio-overwrite", test_pipe_stdio_overwrite);
     803                 :          2 :   g_test_add_func ("/glib-unix/pipe-struct", test_pipe_struct);
     804                 :          2 :   g_test_add_func ("/glib-unix/pipe-struct-auto", test_pipe_struct_auto);
     805                 :          2 :   g_test_add_func ("/glib-unix/error", test_error);
     806                 :          2 :   g_test_add_func ("/glib-unix/nonblocking", test_nonblocking);
     807                 :          2 :   g_test_add_func ("/glib-unix/sighup", test_sighup);
     808                 :          2 :   g_test_add_func ("/glib-unix/sigterm", test_sigterm);
     809                 :          2 :   g_test_add_func ("/glib-unix/sighup_again", test_sighup);
     810                 :          2 :   g_test_add_func ("/glib-unix/sighup_add_remove", test_sighup_add_remove);
     811                 :          2 :   g_test_add_func ("/glib-unix/sighup_nested", test_sighup_nested);
     812                 :          2 :   g_test_add_func ("/glib-unix/callback_after_signal", test_callback_after_signal);
     813                 :          2 :   g_test_add_func ("/glib-unix/get-passwd-entry/root", test_get_passwd_entry_root);
     814                 :          2 :   g_test_add_func ("/glib-unix/get-passwd-entry/nonexistent", test_get_passwd_entry_nonexistent);
     815                 :          2 :   g_test_add_func ("/glib-unix/child-wait", test_child_wait);
     816                 :            : 
     817                 :          2 :   return g_test_run();
     818                 :            : }

Generated by: LCOV version 1.14