示例#1
0
static int
do_test (void)
{
  int result = 0;

  char tmpfname[] = "/tmp/tst-mqueue5-barrier.XXXXXX";
  int fd = mkstemp (tmpfname);
  if (fd == -1)
    {
      printf ("cannot open temporary file: %m\n");
      return 1;
    }

  /* Make sure it is always removed.  */
  unlink (tmpfname);

  /* Create one page of data.  */
  size_t ps = sysconf (_SC_PAGESIZE);
  char data[ps];
  memset (data, '\0', ps);

  /* Write the data to the file.  */
  if (write (fd, data, ps) != (ssize_t) ps)
    {
      puts ("short write");
      return 1;
    }

  void *mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  if (mem == MAP_FAILED)
    {
      printf ("mmap failed: %m\n");
      return 1;
    }

  pthread_barrier_t *b2;
  b2 = (pthread_barrier_t *) (((uintptr_t) mem + __alignof (pthread_barrier_t))
			      & ~(__alignof (pthread_barrier_t) - 1));

  pthread_barrier_t *b3;
  b3 = b2 + 1;

  pthread_barrierattr_t a;
  if (pthread_barrierattr_init (&a) != 0)
    {
      puts ("barrierattr_init failed");
      return 1;
    }

  if (pthread_barrierattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0)
    {
      puts ("barrierattr_setpshared failed, could not test");
      return 0;
    }

  if (pthread_barrier_init (b2, &a, 2) != 0)
    {
      puts ("barrier_init failed");
      return 1;
    }

  if (pthread_barrier_init (b3, &a, 3) != 0)
    {
      puts ("barrier_init failed");
      return 1;
    }

  if (pthread_barrierattr_destroy (&a) != 0)
    {
      puts ("barrierattr_destroy failed");
      return 1;
    }

  char name[sizeof "/tst-mqueue5-" + sizeof (pid_t) * 3];
  snprintf (name, sizeof (name), "/tst-mqueue5-%u", getpid ());

  struct mq_attr attr = { .mq_maxmsg = 1, .mq_msgsize = 1 };
  mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr);

  if (q == (mqd_t) -1)
    {
      printf ("mq_open failed with: %m\n");
      return result;
    }
  else
    add_temp_mq (name);

  struct sigevent ev;
  memset (&ev, 0xaa, sizeof (ev));
  ev.sigev_notify = SIGEV_NONE;
  if (mq_notify (q, &ev) != 0)
    {
      printf ("mq_notify (q, { SIGEV_NONE }) failed with: %m\n");
      result = 1;
    }

  if (mq_notify (q, &ev) == 0)
    {
      puts ("second mq_notify (q, { SIGEV_NONE }) unexpectedly succeeded");
      result = 1;
    }
  else if (errno != EBUSY)
    {
      printf ("second mq_notify (q, { SIGEV_NONE }) failed with: %m\n");
      result = 1;
    }

  result |= mqsend (q);

  if (mq_notify (q, &ev) != 0)
    {
      printf ("third mq_notify (q, { SIGEV_NONE }) failed with: %m\n");
      result = 1;
    }

  result |= mqrecv (q);

  if (mq_notify (q, NULL) != 0)
    {
      printf ("mq_notify (q, NULL) failed with: %m\n");
      result = 1;
    }

  if (mq_notify (q, NULL) != 0)
    {
      /* Implementation-defined behaviour, so don't fail,
	 just inform.  */
      printf ("second mq_notify (q, NULL) failed with: %m\n");
    }

  struct sigaction sa = { .sa_sigaction = rtmin_handler,
			  .sa_flags = SA_SIGINFO };
  sigemptyset (&sa.sa_mask);
  sigaction (SIGRTMIN, &sa, NULL);

  memset (&ev, 0x55, sizeof (ev));
  ev.sigev_notify = SIGEV_SIGNAL;
  ev.sigev_signo = SIGRTMIN;
  ev.sigev_value.sival_int = 26;
  if (mq_notify (q, &ev) != 0)
    {
      printf ("mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n");
      result = 1;
    }

  ev.sigev_value.sival_ptr = &ev;
  if (mq_notify (q, &ev) == 0)
    {
      puts ("second mq_notify (q, { SIGEV_SIGNAL }) unexpectedly succeeded");
      result = 1;
    }
  else if (errno != EBUSY)
    {
      printf ("second mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n");
      result = 1;
    }

  if (rtmin_cnt != 0)
    {
      puts ("SIGRTMIN signal caught too early");
      result = 1;
    }

  result |= mqsend (q);

  if (rtmin_cnt != 1)
    {
      puts ("SIGRTMIN signal did not arrive");
      result = 1;
    }
  else if (rtmin_pid != getpid ()
	   || rtmin_uid != getuid ()
	   || rtmin_code != SI_MESGQ
	   || rtmin_sigval.sival_int != 26)
    {
      printf ("unexpected siginfo_t fields: pid %u (%u), uid %u (%u), code %d (%d), si_int %d (26)\n",
	      rtmin_pid, getpid (), rtmin_uid, getuid (),
	      rtmin_code, SI_MESGQ, rtmin_sigval.sival_int);
      result = 1;
    }

  ev.sigev_value.sival_int = 75;
  if (mq_notify (q, &ev) != 0)
    {
      printf ("third mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n");
      result = 1;
    }

  result |= mqrecv (q);

  if (mq_notify (q, NULL) != 0)
    {
      printf ("mq_notify (q, NULL) failed with: %m\n");
      result = 1;
    }

  memset (&ev, 0x33, sizeof (ev));
  ev.sigev_notify = SIGEV_NONE;
  if (mq_notify (q, &ev) != 0)
    {
      printf ("fourth mq_notify (q, { SIGEV_NONE }) failed with: %m\n");
      result = 1;
    }

  pid_t pid = fork ();
  if (pid == -1)
    {
      printf ("fork () failed: %m\n");
      mq_unlink (name);
      return 1;
    }

  if (pid == 0)
    do_child (name, b2, b3, q);

  /* Child unsuccessfully attempts to mq_notify.  */

  (void) pthread_barrier_wait (b2);

  result |= mqsend (q);

  (void) pthread_barrier_wait (b2);

  /* Child successfully calls mq_notify SIGEV_SIGNAL now.  */

  result |= mqrecv (q);

  (void) pthread_barrier_wait (b2);

  memset (&ev, 0xbb, sizeof (ev));
  ev.sigev_notify = SIGEV_SIGNAL;
  ev.sigev_signo = SIGRTMIN;
  ev.sigev_value.sival_int = 15;
  if (mq_notify (q, &ev) == 0)
    {
      puts ("fourth mq_notify (q, { SIGEV_SIGNAL }) unexpectedly succeeded");
      result = 1;
    }
  else if (errno != EBUSY)
    {
      printf ("fourth mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n");
      result = 1;
    }

  result |= mqsend (q);

  if (mq_notify (q, &ev) != 0)
    {
      printf ("fifth mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n");
      result = 1;
    }

  if (rtmin_cnt != 1)
    {
      puts ("SIGRTMIN signal caught too early");
      result = 1;
    }

  result |= mqrecv (q);

  (void) pthread_barrier_wait (b2);

  /* Child verifies caught SIGRTMIN signal.  */
  /* Child calls mq_send (q) which triggers SIGRTMIN signal here.  */

  (void) pthread_barrier_wait (b2);

  /* Child mq_open's another mqd_t for the same queue (q2).  */

  if (rtmin_cnt != 2)
    {
      puts ("SIGRTMIN signal did not arrive");
      result = 1;
    }
  else if (rtmin_pid != pid
	   || rtmin_uid != getuid ()
	   || rtmin_code != SI_MESGQ
	   || rtmin_sigval.sival_int != 15)
    {
      printf ("unexpected siginfo_t fields: pid %u (%u), uid %u (%u), code %d (%d), si_int %d (15)\n",
	      rtmin_pid, pid, rtmin_uid, getuid (),
	      rtmin_code, SI_MESGQ, rtmin_sigval.sival_int);
      result = 1;
    }

  result |= mqrecv (q);

  (void) pthread_barrier_wait (b2);

  /* Child successfully calls mq_notify { SIGEV_SIGNAL } on q2.  */

  (void) pthread_barrier_wait (b2);

  memset (&ev, 0xbb, sizeof (ev));
  ev.sigev_notify = SIGEV_NONE;
  if (mq_notify (q, &ev) == 0)
    {
      puts ("fifth mq_notify (q, { SIGEV_NONE }) unexpectedly succeeded");
      result = 1;
    }
  else if (errno != EBUSY)
    {
      printf ("fifth mq_notify (q, { SIGEV_NONE }) failed with: %m\n");
      result = 1;
    }

  (void) pthread_barrier_wait (b2);

  /* Child calls mq_close on q2, which makes the queue available again for
     notification.  */

  mqd_t q3 = mq_open (name, O_RDWR);
  if (q3 == (mqd_t) -1)
    {
      printf ("mq_open q3 in parent failed with: %m\n");
      result = 1;
    }

  (void) pthread_barrier_wait (b2);

  memset (&ev, 0x12, sizeof (ev));
  ev.sigev_notify = SIGEV_NONE;
  if (mq_notify (q3, &ev) != 0)
    {
      printf ("mq_notify (q3, { SIGEV_NONE }) failed with: %m\n");
      result = 1;
    }

  (void) pthread_barrier_wait (b2);

  /* Child unsuccessfully attempts to mq_notify { SIGEV_SIGNAL } on q.  */

  (void) pthread_barrier_wait (b2);

  if (mq_close (q3) != 0)
    {
      printf ("mq_close failed: %m\n");
      result = 1;
    }

  (void) pthread_barrier_wait (b2);

  /* Child successfully calls mq_notify { SIGEV_NONE } on q.  */
  /* Child successfully calls mq_notify NULL on q.  */

  (void) pthread_barrier_wait (b2);

  /* Child creates new thread.  */
  /* Thread blocks on mqrecv (q).  */
  /* Child sleeps for 1sec so that thread has time to reach that point.  */
  /* Child successfully calls mq_notify { SIGEV_SIGNAL } on q.  */

  (void) pthread_barrier_wait (b2);

  result |= mqsend (q);

  (void) pthread_barrier_wait (b3);

  /* Child verifies SIGRTMIN has not been sent.  */

  (void) pthread_barrier_wait (b3);

  result |= mqsend (q);

  (void) pthread_barrier_wait (b3);

  /* Thread verifies SIGRTMIN has been caught.  */
  /* Thread calls mq_notify (q, { SIGEV_NONE }) to verify notification is now
     available for registration.  */
  /* Thread calls mq_notify (q, NULL).  */

  (void) pthread_barrier_wait (b3);

  /* Child calls mq_notify (q, { SIGEV_SIGNAL }).  */

  (void) pthread_barrier_wait (b3);

  /* Thread calls mq_notify (q, NULL). */

  (void) pthread_barrier_wait (b3);

  result |= mqsend (q);
  result |= mqrecv (q);

  (void) pthread_barrier_wait (b3);

  /* Child verifies SIGRTMIN has not been sent.  */
  /* Child calls mq_notify (q, { SIGEV_SIGNAL }).  */

  (void) pthread_barrier_wait (b3);

  /* Thread opens a new O_RDONLY mqd_t (q4).  */
  /* Thread calls mq_notify (q4, NULL). */
  /* Thread calls mq_close (q4).  */

  (void) pthread_barrier_wait (b3);

  result |= mqsend (q);
  result |= mqrecv (q);

  (void) pthread_barrier_wait (b3);

  /* Child verifies SIGRTMIN has not been sent.  */
  /* Child calls mq_notify (q, { SIGEV_SIGNAL }).  */

  (void) pthread_barrier_wait (b3);

  /* Thread opens a new O_WRONLY mqd_t (q5).  */
  /* Thread calls mq_notify (q5, NULL). */
  /* Thread calls mq_close (q5).  */

  (void) pthread_barrier_wait (b3);

  result |= mqsend (q);
  result |= mqrecv (q);

  (void) pthread_barrier_wait (b3);

  /* Child verifies SIGRTMIN has not been sent.  */

  int status;
  if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
    {
      puts ("waitpid failed");
      kill (pid, SIGKILL);
      result = 1;
    }
  else if (!WIFEXITED (status) || WEXITSTATUS (status))
    {
      printf ("child failed with status %d\n", status);
      result = 1;
    }

  if (mq_unlink (name) != 0)
    {
      printf ("mq_unlink failed: %m\n");
      result = 1;
    }

  if (mq_close (q) != 0)
    {
      printf ("mq_close failed: %m\n");
      result = 1;
    }

  if (mq_notify (q, NULL) == 0)
    {
      puts ("mq_notify on closed mqd_t unexpectedly succeeded");
      result = 1;
    }
  else if (errno != EBADF)
    {
      printf ("mq_notify on closed mqd_t did not fail with EBADF: %m\n");
      result = 1;
    }

  memset (&ev, 0x55, sizeof (ev));
  ev.sigev_notify = SIGEV_NONE;
  if (mq_notify (q, &ev) == 0)
    {
      puts ("mq_notify on closed mqd_t unexpectedly succeeded");
      result = 1;
    }
  else if (errno != EBADF)
    {
      printf ("mq_notify on closed mqd_t did not fail with EBADF: %m\n");
      result = 1;
    }

  return result;
}
示例#2
0
static int
do_test (void)
{
  if (geteuid () != 0)
    {
      puts ("this test requires root");
      return 0;
    }

  char name[sizeof "/tst-mqueue9-" + sizeof (pid_t) * 3];
  snprintf (name, sizeof (name), "/tst-mqueue9-%u", getpid ());

  struct mq_attr attr = { .mq_maxmsg = 1, .mq_msgsize = 1 };
  mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr);

  if (q == (mqd_t) -1)
    {
      printf ("mq_open failed with: %m\n");
      return 0;
    }
  else
    add_temp_mq (name);

  if (seteuid (1) != 0)
    {
      printf ("failed to seteuid (1): %m\n");
      mq_unlink (name);
      return 0;
    }

  int result = 0;
  if (mq_unlink (name) == 0)
    {
      puts ("mq_unlink unexpectedly succeeded");
      result = 1;
    }
  else if (errno != EACCES)
    {
      printf ("mq_unlink did not fail with EACCES: %m\n");
      result = 1;;
    }

  if (seteuid (0) != 0)
    {
      printf ("failed to seteuid (0): %m\n");
      result = 1;
    }

  if (mq_unlink (name) != 0)
    {
      printf ("mq_unlink failed with: %m\n");
      result = 1;
    }

  if (mq_close (q) != 0)
    {
      printf ("mq_close failed with: %m\n");
      result = 1;
    }

  return result;
}
示例#3
0
static int
do_test (void)
{
  int result = 0;

  char name[sizeof "/tst-mqueue6-" + sizeof (pid_t) * 3];
  snprintf (name, sizeof (name), "/tst-mqueue6-%u", getpid ());

  struct mq_attr attr = { .mq_maxmsg = 1, .mq_msgsize = 1 };
  mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr);

  if (q == (mqd_t) -1)
    {
      printf ("mq_open failed with: %m\n");
      return result;
    }
  else
    add_temp_mq (name);

  pthread_attr_t nattr;
  if (pthread_attr_init (&nattr)
      || pthread_attr_setguardsize (&nattr, 0))
    {
      puts ("pthread_attr_t setup failed");
      result = 1;
    }

  fct_guardsize = 1;

  struct sigevent ev;
  memset (&ev, 0xaa, sizeof (ev));
  ev.sigev_notify = SIGEV_THREAD;
  ev.sigev_notify_function = fct;
  ev.sigev_notify_attributes = &nattr;
  ev.sigev_value.sival_ptr = &q;
  if (mq_notify (q, &ev) != 0)
    {
      printf ("mq_notify (q, { SIGEV_THREAD }) failed with: %m\n");
      result = 1;
    }

  size_t ps = sysconf (_SC_PAGESIZE);
  if (pthread_attr_setguardsize (&nattr, 32 * ps))
    {
      puts ("pthread_attr_t setup failed");
      result = 1;
    }

  if (mq_notify (q, &ev) == 0)
    {
      puts ("second mq_notify (q, { SIGEV_NONE }) unexpectedly succeeded");
      result = 1;
    }
  else if (errno != EBUSY)
    {
      printf ("second mq_notify (q, { SIGEV_NONE }) failed with: %m\n");
      result = 1;
    }

  if (fct_cnt != 0)
    {
      printf ("fct called too early (%d on %d)\n", fct_cnt, __LINE__);
      result = 1;
    }

  result |= mqsend (q);

  result |= mqrecv (q);
  result |= mqrecv (q);

  if (fct_cnt != 1)
    {
      printf ("fct not called (%d on %d)\n", fct_cnt, __LINE__);
      result = 1;
    }
  else if (fct_guardsize != 0)
    {
      printf ("fct_guardsize %zd != 0\n", fct_guardsize);
      result = 1;
    }

  if (mq_notify (q, &ev) != 0)
    {
      printf ("third mq_notify (q, { SIGEV_NONE }) failed with: %m\n");
      result = 1;
    }

  if (mq_notify (q, NULL) != 0)
    {
      printf ("mq_notify (q, NULL) failed with: %m\n");
      result = 1;
    }

  memset (&ev, 0x11, sizeof (ev));
  ev.sigev_notify = SIGEV_THREAD;
  ev.sigev_notify_function = fct;
  ev.sigev_notify_attributes = &nattr;
  ev.sigev_value.sival_ptr = &q;
  if (mq_notify (q, &ev) != 0)
    {
      printf ("mq_notify (q, { SIGEV_THREAD }) failed with: %m\n");
      result = 1;
    }

  if (pthread_attr_setguardsize (&nattr, 0))
    {
      puts ("pthread_attr_t setup failed");
      result = 1;
    }

  if (mq_notify (q, &ev) == 0)
    {
      puts ("second mq_notify (q, { SIGEV_NONE }) unexpectedly succeeded");
      result = 1;
    }
  else if (errno != EBUSY)
    {
      printf ("second mq_notify (q, { SIGEV_NONE }) failed with: %m\n");
      result = 1;
    }

  if (fct_cnt != 1)
    {
      printf ("fct called too early (%d on %d)\n", fct_cnt, __LINE__);
      result = 1;
    }

  result |= mqsend (q);

  result |= mqrecv (q);
  result |= mqrecv (q);

  if (fct_cnt != 2)
    {
      printf ("fct not called (%d on %d)\n", fct_cnt, __LINE__);
      result = 1;
    }
  else if (fct_guardsize != 32 * ps)
    {
      printf ("fct_guardsize %zd != %zd\n", fct_guardsize, 32 * ps);
      result = 1;
    }

  if (mq_notify (q, &ev) != 0)
    {
      printf ("third mq_notify (q, { SIGEV_NONE }) failed with: %m\n");
      result = 1;
    }

  if (mq_notify (q, NULL) != 0)
    {
      printf ("mq_notify (q, NULL) failed with: %m\n");
      result = 1;
    }

  if (pthread_attr_destroy (&nattr) != 0)
    {
      puts ("pthread_attr_destroy failed");
      result = 1;
    }

  if (mq_unlink (name) != 0)
    {
      printf ("mq_unlink failed: %m\n");
      result = 1;
    }

  if (mq_close (q) != 0)
    {
      printf ("mq_close failed: %m\n");
      result = 1;
    }

  memset (&ev, 0x55, sizeof (ev));
  ev.sigev_notify = SIGEV_THREAD;
  ev.sigev_notify_function = fct;
  ev.sigev_notify_attributes = NULL;
  ev.sigev_value.sival_int = 0;
  if (mq_notify (q, &ev) == 0)
    {
      puts ("mq_notify on closed mqd_t unexpectedly succeeded");
      result = 1;
    }
  else if (errno != EBADF)
    {
      printf ("mq_notify on closed mqd_t did not fail with EBADF: %m\n");
      result = 1;
    }

  if (fct_err)
    result = 1;
  return result;
}
示例#4
0
static int
do_test (void)
{
  int result = 0;

  char name[sizeof "/tst-mqueue4-" + sizeof (pid_t) * 3 + NAME_MAX];
  char *p;
  p = name + snprintf (name, sizeof (name), "/tst-mqueue4-%u", getpid ());
  struct mq_attr attr = { .mq_maxmsg = 2, .mq_msgsize = 2 };
  mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr);

  if (q == (mqd_t) -1)
    {
      printf ("mq_open failed with: %m\n");
      return result;
    }
  else
    add_temp_mq (name);

  *p = '.';
  memset (p + 1, 'x', NAME_MAX + 1 - (p - name));
  name[NAME_MAX + 1] = '\0';

  mqd_t q2 = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr);
  if (q2 == (mqd_t) -1)
    {
      printf ("mq_open with NAME_MAX long name compoment failed with: %m\n");
      result = 1;
    }

  if (mq_unlink (name) != 0)
    {
      printf ("mq_unlink failed: %m\n");
      result = 1;
    }

  if (mq_close (q2) != 0)
    {
      printf ("mq_close failed: %m\n");
      result = 1;
    }

  name[NAME_MAX + 1] = 'x';
  name[NAME_MAX + 2] = '\0';
  q2 = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr);
  if (q2 != (mqd_t) -1)
    {
      puts ("mq_open with too long name component unexpectedly succeeded");
      mq_unlink (name);
      mq_close (q2);
      result = 1;
    }
  else if (errno != ENAMETOOLONG)
    {
      printf ("mq_open with too long name component did not fail with "
	      "ENAMETOOLONG: %m\n");
      result = 1;
    }

  if (mq_unlink (name) == 0)
    {
      puts ("mq_unlink with too long name component unexpectedly succeeded");
      result = 1;
    }
  else if (errno != ENAMETOOLONG)
    {
      printf ("mq_unlink with too long name component did not fail with "
	      "ENAMETOOLONG: %m\n");
      result = 1;
    }

  *p = '\0';
  attr.mq_maxmsg = 1;
  attr.mq_msgsize = 3;
  q2 = mq_open (name, O_CREAT | O_RDWR, 0600, &attr);
  if (q2 == (mqd_t) -1)
    {
      printf ("mq_open without O_EXCL failed with %m\n");
      result = 1;
    }

  char buf[3];
  strcpy (buf, "jk");
  if (mq_send (q, buf, 2, 4) != 0)
    {
      printf ("mq_send failed: %m\n");
      result = 1;
    }

  if (mq_send (q, buf + 1, 1, 5) != 0)
    {
      printf ("mq_send failed: %m\n");
      result = 1;
    }

  if (mq_getattr (q2, &attr) != 0)
    {
      printf ("mq_getattr failed: %m\n");
      result = 1;
    }

  if ((attr.mq_flags & O_NONBLOCK)
      || attr.mq_maxmsg != 2
      || attr.mq_msgsize != 2
      || attr.mq_curmsgs != 2)
    {
      printf ("mq_getattr returned unexpected { .mq_flags = %jd,\n"
	      ".mq_maxmsg = %jd, .mq_msgsize = %jd, .mq_curmsgs = %jd }\n",
	      (intmax_t) attr.mq_flags, (intmax_t) attr.mq_maxmsg,
	      (intmax_t) attr.mq_msgsize, (intmax_t) attr.mq_curmsgs);
      result = 1;
    }

  struct timespec ts;
  if (clock_gettime (CLOCK_REALTIME, &ts) == 0)
    ++ts.tv_sec;
  else
    {
      ts.tv_sec = time (NULL) + 1;
      ts.tv_nsec = 0;
    }

  if (mq_timedsend (q2, buf, 1, 1, &ts) == 0)
    {
      puts ("mq_timedsend unexpectedly succeeded");
      result = 1;
    }
  else if (errno != ETIMEDOUT)
    {
      printf ("mq_timedsend did not fail with ETIMEDOUT: %m\n");
      result = 1;
    }

  if (mq_close (q2) != 0)
    {
      printf ("mq_close failed: %m\n");
      result = 1;
    }

  q2 = mq_open (name, O_RDONLY, 0600);
  if (q2 == (mqd_t) -1)
    {
      printf ("mq_open without O_CREAT failed with %m\n");
      result = 1;
    }

  mqd_t q3 = mq_open (name, O_RDONLY, 0600);
  if (q3 == (mqd_t) -1)
    {
      printf ("mq_open without O_CREAT failed with %m\n");
      result = 1;
    }

  memset (buf, ' ', sizeof (buf));

  unsigned int prio;
  ssize_t rets = mq_receive (q2, buf, 2, &prio);
  if (rets != 1)
    {
      if (rets == -1)
	printf ("mq_receive failed with: %m\n");
      else
	printf ("mq_receive returned %zd != 1\n", rets);
      result = 1;
    }
  else if (prio != 5 || memcmp (buf, "k  ", 3) != 0)
    {
      printf ("mq_receive returned prio %u (2) buf \"%c%c%c\" (\"k  \")\n",
	      prio, buf[0], buf[1], buf[2]);
      result = 1;
    }

  if (mq_getattr (q3, &attr) != 0)
    {
      printf ("mq_getattr failed: %m\n");
      result = 1;
    }

  if ((attr.mq_flags & O_NONBLOCK)
      || attr.mq_maxmsg != 2
      || attr.mq_msgsize != 2
      || attr.mq_curmsgs != 1)
    {
      printf ("mq_getattr returned unexpected { .mq_flags = %jd,\n"
	      ".mq_maxmsg = %jd, .mq_msgsize = %jd, .mq_curmsgs = %jd }\n",
	      (intmax_t) attr.mq_flags, (intmax_t) attr.mq_maxmsg,
	      (intmax_t) attr.mq_msgsize, (intmax_t) attr.mq_curmsgs);
      result = 1;
    }

  rets = mq_receive (q3, buf, 2, NULL);
  if (rets != 2)
    {
      if (rets == -1)
	printf ("mq_receive failed with: %m\n");
      else
	printf ("mq_receive returned %zd != 2\n", rets);
      result = 1;
    }
  else if (memcmp (buf, "jk ", 3) != 0)
    {
      printf ("mq_receive returned buf \"%c%c%c\" != \"jk \"\n",
	      buf[0], buf[1], buf[2]);
      result = 1;
    }

  if (clock_gettime (CLOCK_REALTIME, &ts) == 0)
    ++ts.tv_sec;
  else
    {
      ts.tv_sec = time (NULL) + 1;
      ts.tv_nsec = 0;
    }

  if (mq_timedreceive (q2, buf, 2, NULL, &ts) != -1)
    {
      puts ("mq_timedreceive on empty queue unexpectedly succeeded");
      result = 1;
    }
  else if (errno != ETIMEDOUT)
    {
      printf ("mq_timedreceive on empty queue did not fail with "
	      "ETIMEDOUT: %m\n");
      result = 1;
    }

  if (mq_unlink (name) != 0)
    {
      printf ("mq_unlink failed: %m\n");
      result = 1;
    }

  if (mq_close (q) != 0)
    {
      printf ("mq_close failed: %m\n");
      result = 1;
    }

  if (mq_close (q2) != 0)
    {
      printf ("mq_close failed: %m\n");
      result = 1;
    }

  if (mq_close (q3) != 0)
    {
      printf ("mq_close failed: %m\n");
      result = 1;
    }

  return result;
}
static int
do_test (void)
{
  int result = 0;

  char name[sizeof "/tst-mqueue2-" + sizeof (pid_t) * 3];
  snprintf (name, sizeof (name), "/tst-mqueue2-%u", getpid ());

  struct mq_attr attr = { .mq_maxmsg = 2, .mq_msgsize = 2 };
  mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr);

  if (q == (mqd_t) -1)
    {
      printf ("mq_open failed with: %m\n");
      return result;
    }
  else
    add_temp_mq (name);

  mqd_t q2 = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr);
  if (q2 != (mqd_t) -1)
    {
      puts ("mq_open with O_EXCL unexpectedly succeeded");
      result = 1;
    }
  else if (errno != EEXIST)
    {
      printf ("mq_open did not fail with EEXIST: %m\n");
      result = 1;
    }

  char name2[sizeof "/tst-mqueue2-2-" + sizeof (pid_t) * 3];
  snprintf (name2, sizeof (name2), "/tst-mqueue2-2-%u", getpid ());

  attr.mq_maxmsg = -2;
  q2 = mq_open (name2, O_CREAT | O_EXCL | O_RDWR, 0600, &attr);
  if (q2 != (mqd_t) -1)
    {
      puts ("mq_open with invalid mq_maxmsg unexpectedly succeeded");
      add_temp_mq (name2);
      result = 1;
    }
  else if (errno != EINVAL)
    {
      printf ("mq_open with invalid mq_maxmsg did not fail with "
	      "EINVAL: %m\n");
      result = 1;
    }

  attr.mq_maxmsg = 2;
  attr.mq_msgsize = -56;
  q2 = mq_open (name2, O_CREAT | O_EXCL | O_RDWR, 0600, &attr);
  if (q2 != (mqd_t) -1)
    {
      puts ("mq_open with invalid mq_msgsize unexpectedly succeeded");
      add_temp_mq (name2);
      result = 1;
    }
  else if (errno != EINVAL)
    {
      printf ("mq_open with invalid mq_msgsize did not fail with "
	      "EINVAL: %m\n");
      result = 1;
    }

  char buf[3];
  struct timespec ts;
  if (clock_gettime (CLOCK_REALTIME, &ts) == 0)
    ts.tv_sec += 10;
  else
    {
      ts.tv_sec = time (NULL) + 10;
      ts.tv_nsec = 0;
    }

  if (mq_timedreceive (q, buf, 1, NULL, &ts) == 0)
    {
      puts ("mq_timedreceive with too small msg_len did not fail");
      result = 1;
    }
  else if (errno != EMSGSIZE)
    {
      printf ("mq_timedreceive with too small msg_len did not fail with "
	      "EMSGSIZE: %m\n");
      result = 1;
    }

  ts.tv_nsec = -1;
  if (mq_timedreceive (q, buf, 2, NULL, &ts) == 0)
    {
      puts ("mq_timedreceive with negative tv_nsec did not fail");
      result = 1;
    }
  else if (errno != EINVAL)
    {
      printf ("mq_timedreceive with negative tv_nsec did not fail with "
	      "EINVAL: %m\n");
      result = 1;
    }

  ts.tv_nsec = 1000000000;
  if (mq_timedreceive (q, buf, 2, NULL, &ts) == 0)
    {
      puts ("mq_timedreceive with tv_nsec >= 1000000000 did not fail");
      result = 1;
    }
  else if (errno != EINVAL)
    {
      printf ("mq_timedreceive with tv_nsec >= 1000000000 did not fail with "
	      "EINVAL: %m\n");
      result = 1;
    }

  struct sigaction sa = { .sa_handler = alrm_handler, .sa_flags = 0 };
  sigemptyset (&sa.sa_mask);
  sigaction (SIGALRM, &sa, NULL);

  struct itimerval it = { .it_value = { .tv_sec = 1 } };
  setitimer (ITIMER_REAL, &it, NULL);

  if (mq_receive (q, buf, 2, NULL) == 0)
    {
      puts ("mq_receive on empty queue did not block");
      result = 1;
    }
  else if (errno != EINTR)
    {
      printf ("mq_receive on empty queue did not fail with EINTR: %m\n");
      result = 1;
    }

  setitimer (ITIMER_REAL, &it, NULL);

  ts.tv_nsec = 0;
  if (mq_timedreceive (q, buf, 2, NULL, &ts) == 0)
    {
      puts ("mq_timedreceive on empty queue did not block");
      result = 1;
    }
  else if (errno != EINTR)
    {
      printf ("mq_timedreceive on empty queue did not fail with EINTR: %m\n");
      result = 1;
    }

  buf[0] = '6';
  buf[1] = '7';
  if (mq_send (q, buf, 2, 3) != 0
      || (buf[0] = '8', mq_send (q, buf, 1, 4) != 0))
    {
      printf ("mq_send failed: %m\n");
      result = 1;
    }

  memset (buf, ' ', sizeof (buf));

  unsigned int prio;
  ssize_t rets = mq_receive (q, buf, 3, &prio);
  if (rets != 1)
    {
      if (rets == -1)
	printf ("mq_receive failed: %m\n");
      else
	printf ("mq_receive returned %zd != 1\n", rets);
      result = 1;
    }
  else if (prio != 4 || memcmp (buf, "8  ", 3) != 0)
    {
      printf ("mq_receive prio %u (4) buf \"%c%c%c\" (\"8  \")\n",
	      prio, buf[0], buf[1], buf[2]);
      result = 1;
    }

  rets = mq_receive (q, buf, 2, NULL);
  if (rets != 2)
    {
      if (rets == -1)
	printf ("mq_receive failed: %m\n");
      else
	printf ("mq_receive returned %zd != 2\n", rets);
      result = 1;
    }
  else if (memcmp (buf, "67 ", 3) != 0)
    {
      printf ("mq_receive buf \"%c%c%c\" != \"67 \"\n",
	      buf[0], buf[1], buf[2]);
      result = 1;
    }

  buf[0] = '2';
  buf[1] = '1';
  if (clock_gettime (CLOCK_REALTIME, &ts) != 0)
    ts.tv_sec = time (NULL);
  ts.tv_nsec = -1000000001;
  if ((mq_timedsend (q, buf, 2, 5, &ts) != 0
       && (errno != EINVAL || mq_send (q, buf, 2, 5) != 0))
      || (buf[0] = '3', ts.tv_nsec = -ts.tv_nsec,
	  (mq_timedsend (q, buf, 1, 4, &ts) != 0
	   && (errno != EINVAL || mq_send (q, buf, 1, 4) != 0))))
    {
      printf ("mq_timedsend failed: %m\n");
      result = 1;
    }

  buf[0] = '-';
  ts.tv_nsec = 1000000001;
  if (mq_timedsend (q, buf, 1, 6, &ts) == 0)
    {
      puts ("mq_timedsend with tv_nsec >= 1000000000 did not fail");
      result = 1;
    }
  else if (errno != EINVAL)
    {
      printf ("mq_timedsend with tv_nsec >= 1000000000 did not fail with "
	      "EINVAL: %m\n");
      result = 1;
    }

  ts.tv_nsec = -2;
  if (mq_timedsend (q, buf, 1, 6, &ts) == 0)
    {
      puts ("mq_timedsend with negative tv_nsec did not fail");
      result = 1;
    }
  else if (errno != EINVAL)
    {
      printf ("mq_timedsend with megatove tv_nsec did not fail with "
	      "EINVAL: %m\n");
      result = 1;
    }

  setitimer (ITIMER_REAL, &it, NULL);

  if (mq_send (q, buf, 2, 8) == 0)
    {
      puts ("mq_send on full queue did not block");
      result = 1;
    }
  else if (errno != EINTR)
    {
      printf ("mq_send on full queue did not fail with EINTR: %m\n");
      result = 1;
    }

  setitimer (ITIMER_REAL, &it, NULL);

  ts.tv_sec += 10;
  ts.tv_nsec = 0;
  if (mq_timedsend (q, buf, 2, 7, &ts) == 0)
    {
      puts ("mq_timedsend on full queue did not block");
      result = 1;
    }
  else if (errno != EINTR)
    {
      printf ("mq_timedsend on full queue did not fail with EINTR: %m\n");
      result = 1;
    }

  memset (buf, ' ', sizeof (buf));

  if (clock_gettime (CLOCK_REALTIME, &ts) != 0)
    ts.tv_sec = time (NULL);
  ts.tv_nsec = -1000000001;
  rets = mq_timedreceive (q, buf, 2, &prio, &ts);
  if (rets == -1 && errno == EINVAL)
    rets = mq_receive (q, buf, 2, &prio);
  if (rets != 2)
    {
      if (rets == -1)
	printf ("mq_timedreceive failed: %m\n");
      else
	printf ("mq_timedreceive returned %zd != 2\n", rets);
      result = 1;
    }
  else if (prio != 5 || memcmp (buf, "21 ", 3) != 0)
    {
      printf ("mq_timedreceive prio %u (5) buf \"%c%c%c\" (\"21 \")\n",
	      prio, buf[0], buf[1], buf[2]);
      result = 1;
    }

  if (mq_receive (q, buf, 1, NULL) == 0)
    {
      puts ("mq_receive with too small msg_len did not fail");
      result = 1;
    }
  else if (errno != EMSGSIZE)
    {
      printf ("mq_receive with too small msg_len did not fail with "
	      "EMSGSIZE: %m\n");
      result = 1;
    }

  ts.tv_nsec = -ts.tv_nsec;
  rets = mq_timedreceive (q, buf, 2, NULL, &ts);
  if (rets == -1 && errno == EINVAL)
    rets = mq_receive (q, buf, 2, NULL);
  if (rets != 1)
    {
      if (rets == -1)
	printf ("mq_timedreceive failed: %m\n");
      else
	printf ("mq_timedreceive returned %zd != 1\n", rets);
      result = 1;
    }
  else if (memcmp (buf, "31 ", 3) != 0)
    {
      printf ("mq_timedreceive buf \"%c%c%c\" != \"31 \"\n",
	      buf[0], buf[1], buf[2]);
      result = 1;
    }

  if (mq_send (q, "", 0, 2) != 0)
    {
      printf ("mq_send with msg_len 0 failed: %m\n");
      result = 1;
    }

  rets = mq_receive (q, buf, 2, &prio);
  if (rets)
    {
      if (rets == -1)
	printf ("mq_receive failed: %m\n");
      else
	printf ("mq_receive returned %zd != 0\n", rets);
      result = 1;
    }

  long mq_prio_max = sysconf (_SC_MQ_PRIO_MAX);
  if (mq_prio_max > 0 && (unsigned int) mq_prio_max == mq_prio_max)
    {
      if (mq_send (q, buf, 1, mq_prio_max) == 0)
	{
	  puts ("mq_send with MQ_PRIO_MAX priority unpexpectedly succeeded");
	  result = 1;
	}
      else if (errno != EINVAL)
	{
	  printf ("mq_send with MQ_PRIO_MAX priority did not fail with "
		  "EINVAL: %m\n");
	  result = 1;
	}

      if (mq_send (q, buf, 1, mq_prio_max - 1) != 0)
	{
	  printf ("mq_send with MQ_PRIO_MAX-1 priority failed: %m\n");
	  result = 1;
	}
    }

  if (mq_unlink (name) != 0)
    {
      printf ("mq_unlink failed: %m\n");
      result = 1;
    }

  q2 = mq_open (name, O_RDWR);
  if (q2 != (mqd_t) -1)
    {
      printf ("mq_open of unlinked %s without O_CREAT unexpectedly"
	      "succeeded\n", name);
      result = 1;
    }
  else if (errno != ENOENT)
    {
      printf ("mq_open of unlinked %s without O_CREAT did not fail with "
	      "ENOENT: %m\n", name);
      result = 1;
    }

  if (mq_close (q) != 0)
    {
      printf ("mq_close in parent failed: %m\n");
      result = 1;
    }

  if (mq_receive (q, buf, 2, NULL) == 0)
    {
      puts ("mq_receive on invalid mqd_t did not fail");
      result = 1;
    }
  else if (errno != EBADF)
    {
      printf ("mq_receive on invalid mqd_t did not fail with EBADF: %m\n");
      result = 1;
    }

  if (mq_send (q, buf, 1, 2) == 0)
    {
      puts ("mq_send on invalid mqd_t did not fail");
      result = 1;
    }
  else if (errno != EBADF)
    {
      printf ("mq_send on invalid mqd_t did not fail with EBADF: %m\n");
      result = 1;
    }

  if (mq_getattr (q, &attr) == 0)
    {
      puts ("mq_getattr on invalid mqd_t did not fail");
      result = 1;
    }
  else if (errno != EBADF)
    {
      printf ("mq_getattr on invalid mqd_t did not fail with EBADF: %m\n");
      result = 1;
    }

  memset (&attr, 0, sizeof (attr));
  if (mq_setattr (q, &attr, NULL) == 0)
    {
      puts ("mq_setattr on invalid mqd_t did not fail");
      result = 1;
    }
  else if (errno != EBADF)
    {
      printf ("mq_setattr on invalid mqd_t did not fail with EBADF: %m\n");
      result = 1;
    }

  if (mq_unlink ("/tst-mqueue2-which-should-never-exist") != -1)
    {
      puts ("mq_unlink of non-existant message queue unexpectedly succeeded");
      result = 1;
    }
  else if (errno != ENOENT)
    {
      printf ("mq_unlink of non-existant message queue did not fail with "
	      "ENOENT: %m\n");
      result = 1;
    }
  return result;
}