(root)/
glibc-2.38/
rt/
tst-mqueue1.c
       1  /* Test message queue passing.
       2     Copyright (C) 2004-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <errno.h>
      20  #include <fcntl.h>
      21  #include <mqueue.h>
      22  #include <stdio.h>
      23  #include <stdlib.h>
      24  #include <string.h>
      25  #include <sys/wait.h>
      26  #include <time.h>
      27  #include <unistd.h>
      28  #include <stdint.h>
      29  #include <support/check.h>
      30  #include "tst-mqueue.h"
      31  
      32  static int
      33  intcmp (const void *a, const void *b)
      34  {
      35    if (*(unsigned char *)a < *(unsigned char *)b)
      36      return 1;
      37    if (*(unsigned char *)a > *(unsigned char *)b)
      38      return -1;
      39    return 0;
      40  }
      41  
      42  static int
      43  check_attrs (struct mq_attr *attr, int nonblock, long cnt)
      44  {
      45    int result = 0;
      46  
      47    if (attr->mq_maxmsg != 10 || attr->mq_msgsize != 1)
      48      {
      49        printf ("attributes don't match those passed to mq_open\n"
      50  	      "mq_maxmsg %jd, mq_msgsize %jd\n",
      51  	      (intmax_t) attr->mq_maxmsg, (intmax_t) attr->mq_msgsize);
      52        result = 1;
      53      }
      54  
      55    if ((attr->mq_flags & O_NONBLOCK) != nonblock)
      56      {
      57        printf ("mq_flags %jx != %x\n",
      58  	      (intmax_t) (attr->mq_flags & O_NONBLOCK), nonblock);
      59        result = 1;
      60      }
      61  
      62    if (attr->mq_curmsgs != cnt)
      63      {
      64        printf ("mq_curmsgs %jd != %ld\n", (intmax_t) attr->mq_curmsgs, cnt);
      65        result = 1;
      66      }
      67  
      68    return result;
      69  }
      70  
      71  static int
      72  do_one_test (mqd_t q, const char *name, int nonblock)
      73  {
      74    int result = 0;
      75  
      76    unsigned char v []
      77      = { 0x32, 0x62, 0x22, 0x31, 0x11, 0x73, 0x61, 0x21, 0x72, 0x71, 0x81 };
      78  
      79    struct mq_attr attr;
      80    memset (&attr, 0xaa, sizeof (attr));
      81    if (mq_getattr (q, &attr) != 0)
      82      {
      83        printf ("mq_getattr failed: %m\n");
      84        result = 1;
      85      }
      86    else
      87      result |= check_attrs (&attr, nonblock, 0);
      88  
      89    if (mq_receive (q, (char *) &v[0], 1, NULL) != -1)
      90      {
      91        puts ("mq_receive on O_WRONLY mqd_t unexpectedly succeeded");
      92        result = 1;
      93      }
      94    else if (errno != EBADF)
      95      {
      96        printf ("mq_receive on O_WRONLY mqd_t did not fail with EBADF: %m\n");
      97        result = 1;
      98      }
      99  
     100    struct timespec ts;
     101    if (clock_gettime (CLOCK_REALTIME, &ts) == 0)
     102      --ts.tv_sec;
     103    else
     104      {
     105        ts.tv_sec = time (NULL) - 1;
     106        ts.tv_nsec = 0;
     107      }
     108  
     109    int ret;
     110    for (int i = 0; i < 10; ++i)
     111      {
     112        if (i & 1)
     113  	ret = mq_send (q, (char *) &v[i], 1, v[i] >> 4);
     114        else
     115  	ret = mq_timedsend (q, (char *) &v[i], 1, v[i] >> 4, &ts);
     116  
     117        if (ret)
     118  	{
     119  	  printf ("mq_%ssend failed: %m\n", (i & 1) ? "" : "timed");
     120  	  result = 1;
     121  	}
     122      }
     123  
     124    ret = mq_timedsend (q, (char *) &v[10], 1, 8, &ts);
     125    if (ret != -1)
     126      {
     127        puts ("mq_timedsend on full queue did not fail");
     128        result = 1;
     129      }
     130    else if (errno != (nonblock ? EAGAIN : ETIMEDOUT))
     131      {
     132        printf ("mq_timedsend on full queue did not fail with %s: %m\n",
     133  	      nonblock ? "EAGAIN" : "ETIMEDOUT");
     134        result = 1;
     135      }
     136  
     137    if (nonblock)
     138      {
     139        ret = mq_send (q, (char *) &v[10], 1, 8);
     140        if (ret != -1)
     141  	{
     142  	  puts ("mq_send on full non-blocking queue did not fail");
     143  	  result = 1;
     144  	}
     145        else if (errno != EAGAIN)
     146  	{
     147  	  printf ("mq_send on full non-blocking queue did not fail"
     148  		  "with EAGAIN: %m\n");
     149  	  result = 1;
     150  	}
     151      }
     152  
     153    memset (&attr, 0xaa, sizeof (attr));
     154    if (mq_getattr (q, &attr) != 0)
     155      {
     156        printf ("mq_getattr failed: %m\n");
     157        result = 1;
     158      }
     159    else
     160      result |= check_attrs (&attr, nonblock, 10);
     161  
     162    pid_t pid = fork ();
     163    if (pid == -1)
     164      {
     165        printf ("fork failed: %m\n");
     166        result = 1;
     167      }
     168    else if (pid == 0)
     169      {
     170        result = 0;
     171  
     172        if (mq_close (q) != 0)
     173  	{
     174  	  printf ("mq_close in child failed: %m\n");
     175  	  result = 1;
     176  	}
     177  
     178        q = mq_open (name, O_RDONLY | nonblock);
     179        if (q == (mqd_t) -1)
     180          {
     181  	  printf ("mq_open in child failed: %m\n");
     182  	  exit (1);
     183          }
     184  
     185        memset (&attr, 0xaa, sizeof (attr));
     186        if (mq_getattr (q, &attr) != 0)
     187  	{
     188  	  printf ("mq_getattr failed: %m\n");
     189  	  result = 1;
     190  	}
     191        else
     192  	result |= check_attrs (&attr, nonblock, 10);
     193  
     194        unsigned char vr[11] = { };
     195        unsigned int prio;
     196        ssize_t rets;
     197  
     198        if (mq_send (q, (char *) &v[0], 1, 1) != -1)
     199  	{
     200  	  puts ("mq_send on O_RDONLY mqd_t unexpectedly succeeded");
     201  	  result = 1;
     202  	}
     203        else if (errno != EBADF)
     204  	{
     205  	  printf ("mq_send on O_WRONLY mqd_t did not fail with EBADF: %m\n");
     206  	  result = 1;
     207  	}
     208  
     209        for (int i = 0; i < 10; ++i)
     210  	{
     211  	  if (i & 1)
     212  	    rets = mq_receive (q, (char *) &vr[i], 1, &prio);
     213  	  else
     214  	    rets = mq_timedreceive (q, (char *) &vr[i], 1, &prio, &ts);
     215  
     216  	  if (rets != 1)
     217  	    {
     218  	      if (rets == -1)
     219  		printf ("mq_%sreceive failed: %m\n", (i & 1) ? "" : "timed");
     220  	      else
     221  		printf ("mq_%sreceive returned %zd != 1\n",
     222  			(i & 1) ? "" : "timed", rets);
     223  	      result = 1;
     224  	    }
     225  	  else if (prio != (unsigned int) vr[i] >> 4)
     226  	    {
     227  	      printf ("unexpected priority %x for value %02x\n", prio,
     228  		      vr[i]);
     229  	      result = 1;
     230  	    }
     231  	}
     232  
     233        qsort (v, 10, 1, intcmp);
     234        if (memcmp (v, vr, 10) != 0)
     235  	{
     236  	  puts ("messages not received in expected order");
     237  	  result = 1;
     238  	}
     239  
     240        rets = mq_timedreceive (q, (char *) &vr[10], 1, &prio, &ts);
     241        if (rets != -1)
     242  	{
     243  	  puts ("mq_timedreceive on empty queue did not fail");
     244  	  result = 1;
     245  	}
     246        else if (errno != (nonblock ? EAGAIN : ETIMEDOUT))
     247  	{
     248  	  printf ("mq_timedreceive on empty queue did not fail with %s: %m\n",
     249  		  nonblock ? "EAGAIN" : "ETIMEDOUT");
     250  	  result = 1;
     251  	}
     252  
     253        if (nonblock)
     254  	{
     255  	  ret = mq_receive (q, (char *) &vr[10], 1, &prio);
     256  	  if (ret != -1)
     257  	    {
     258  	      puts ("mq_receive on empty non-blocking queue did not fail");
     259  	      result = 1;
     260  	    }
     261  	  else if (errno != EAGAIN)
     262  	    {
     263  	      printf ("mq_receive on empty non-blocking queue did not fail"
     264  		      "with EAGAIN: %m\n");
     265  	      result = 1;
     266  	    }
     267  	}
     268  
     269        memset (&attr, 0xaa, sizeof (attr));
     270        if (mq_getattr (q, &attr) != 0)
     271  	{
     272  	  printf ("mq_getattr failed: %m\n");
     273  	  result = 1;
     274  	}
     275        else
     276  	result |= check_attrs (&attr, nonblock, 0);
     277  
     278        if (mq_close (q) != 0)
     279  	{
     280  	  printf ("mq_close in child failed: %m\n");
     281  	  result = 1;
     282  	}
     283  
     284        exit (result);
     285      }
     286  
     287    int status;
     288    if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
     289      {
     290        printf ("waitpid failed: %m\n");
     291        kill (pid, SIGKILL);
     292        result = 1;
     293      }
     294    else if (!WIFEXITED (status) || WEXITSTATUS (status))
     295      {
     296        printf ("child failed: %d\n", status);
     297        result = 1;
     298      }
     299  
     300    memset (&attr, 0xaa, sizeof (attr));
     301    if (mq_getattr (q, &attr) != 0)
     302      {
     303        printf ("mq_getattr failed: %m\n");
     304        result = 1;
     305      }
     306    else
     307      result |= check_attrs (&attr, nonblock, 0);
     308  
     309    return result;
     310  }
     311  
     312  #define TEST_FUNCTION do_test ()
     313  static int
     314  do_test (void)
     315  {
     316    int result = 0;
     317  
     318    char name[sizeof "/tst-mqueue1-" + sizeof (pid_t) * 3];
     319    snprintf (name, sizeof (name), "/tst-mqueue1-%u", getpid ());
     320  
     321    struct mq_attr attr = { .mq_maxmsg = 10, .mq_msgsize = 1 };
     322    mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_WRONLY, 0600, &attr);
     323  
     324    if (q == (mqd_t) -1)
     325      {
     326        if (errno == ENOSYS)
     327  	FAIL_UNSUPPORTED ("mq_open not supported");
     328  
     329        printf ("mq_open failed with: %m\n");
     330        return 1;
     331      }
     332  
     333    add_temp_mq (name);
     334  
     335    result |= do_one_test (q, name, 0);
     336  
     337    mqd_t q2 = mq_open (name, O_WRONLY | O_NONBLOCK);
     338    if (q2 == (mqd_t) -1)
     339      {
     340        printf ("mq_open failed with: %m\n");
     341        q2 = q;
     342        result = 1;
     343      }
     344    else
     345      {
     346        if (mq_close (q) != 0)
     347  	{
     348  	  printf ("mq_close in parent failed: %m\n");
     349  	  result = 1;
     350  	}
     351  
     352        q = q2;
     353        result |= do_one_test (q, name, O_NONBLOCK);
     354  
     355        if (mq_getattr (q, &attr) != 0)
     356  	{
     357  	  printf ("mq_getattr failed: %m\n");
     358  	  result = 1;
     359  	}
     360        else
     361  	{
     362  	  attr.mq_flags ^= O_NONBLOCK;
     363  
     364  	  struct mq_attr attr2;
     365  	  memset (&attr2, 0x55, sizeof (attr2));
     366  	  if (mq_setattr (q, &attr, &attr2) != 0)
     367  	    {
     368  	      printf ("mq_setattr failed: %m\n");
     369  	      result = 1;
     370  	    }
     371  	  else if (attr.mq_flags != (attr2.mq_flags ^ O_NONBLOCK)
     372  		   || attr.mq_maxmsg != attr2.mq_maxmsg
     373  		   || attr.mq_msgsize != attr2.mq_msgsize
     374  		   || attr.mq_curmsgs != 0
     375  		   || attr2.mq_curmsgs != 0)
     376  	    {
     377  	      puts ("mq_setattr returned unexpected values in *omqstat");
     378  	      result = 1;
     379  	    }
     380  	  else
     381  	    {
     382  	      result |= do_one_test (q, name, 0);
     383  
     384  	      if (mq_setattr (q, &attr2, NULL) != 0)
     385  		{
     386  		  printf ("mq_setattr failed: %m\n");
     387  		  result = 1;
     388  		}
     389  	      else
     390  		result |= do_one_test (q, name, O_NONBLOCK);
     391  	    }
     392  	}
     393      }
     394  
     395    if (mq_unlink (name) != 0)
     396      {
     397        printf ("mq_unlink failed: %m\n");
     398        result = 1;
     399      }
     400  
     401    if (mq_close (q) != 0)
     402      {
     403        printf ("mq_close in parent failed: %m\n");
     404        result = 1;
     405      }
     406  
     407    if (mq_close (q) != -1)
     408      {
     409        puts ("second mq_close did not fail");
     410        result = 1;
     411      }
     412    else if (errno != EBADF)
     413      {
     414        printf ("second mq_close did not fail with EBADF: %m\n");
     415        result = 1;
     416      }
     417  
     418    return result;
     419  }
     420  
     421  #include "../test-skeleton.c"