Ejemplo n.º 1
0
static void *
tf_read  (void *arg)
{
  int fd;

  if (arg == NULL)
    fd = fds[0];
  else
    {
      char fname[] = "/tmp/tst-cancel4-fd-XXXXXX";
      tempfd = fd = mkstemp (fname);
      if (fd == -1)
	FAIL_EXIT1 ("mkstemp failed: %m");
      unlink (fname);

      xpthread_barrier_wait (&b2);
    }

  xpthread_barrier_wait (&b2);

  ssize_t s;
  pthread_cleanup_push (cl, NULL);

  char buf[100];
  s = read (fd, buf, sizeof (buf));

  pthread_cleanup_pop (0);

  FAIL_EXIT1 ("read returns with %zd", s);
}
Ejemplo n.º 2
0
/* Limit the size of the process, so that memory allocation in
   allocate_thread will eventually fail, without impacting the entire
   system.  By default, a dynamic limit which leaves room for 2 MiB is
   activated.  The TEST_RLIMIT_AS environment variable overrides
   it.  */
static void
reduce_rlimit_as (void)
{
  struct rlimit limit;
  if (getrlimit (RLIMIT_AS, &limit) != 0)
    FAIL_EXIT1 ("getrlimit (RLIMIT_AS) failed: %m");

  /* Use the TEST_RLIMIT_AS setting if available.  */
  {
    long target = 0;
    const char *variable = "TEST_RLIMIT_AS";
    const char *target_str = getenv (variable);
    if (target_str != NULL)
      {
        target = atoi (target_str);
        if (target <= 0)
          FAIL_EXIT1 ("invalid %s value: \"%s\"", variable, target_str);
        printf ("info: setting RLIMIT_AS to %ld MiB\n", target);
        target *= 1024 * 1024;      /* Convert to megabytes.  */
        limit.rlim_cur = target;
        xsetrlimit_as (&limit);
        return;
      }
  }

  /* Otherwise, try to find the limit with a binary search.  */
  unsigned long low = 1 << 20;
  limit.rlim_cur = low;
  xsetrlimit_as (&limit);

  /* Find working upper limit.  */
  unsigned long high = 1 << 30;
  while (true)
    {
      limit.rlim_cur = high;
      xsetrlimit_as (&limit);
      if (mmap_works ())
        break;
      if (2 * high < high)
        FAIL_EXIT1 ("cannot find upper AS limit");
      high *= 2;
    }

  /* Perform binary search.  */
  while ((high - low) > 128 * 1024)
    {
      unsigned long middle = (low + high) / 2;
      limit.rlim_cur = middle;
      xsetrlimit_as (&limit);
      if (mmap_works ())
        high = middle;
      else
        low = middle;
    }

  unsigned long target = high + as_limit_reserve;
  limit.rlim_cur = target;
  xsetrlimit_as (&limit);
  printf ("info: RLIMIT_AS limit: %lu bytes\n", target);
}
Ejemplo n.º 3
0
static void
run_script (const char *script, char *const argv[])
{
  for (size_t i = 0; i < 5; i++)
    {
      pid_t pid = vfork ();
      if (pid < 0)
	FAIL_EXIT1 ("vfork failed: %m");
      else if (pid == 0)
	{
	  execvp (script, argv);
	  _exit (errno);
	}

      int status;
      if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
	FAIL_EXIT1 ("waitpid failed");
      else if (status != 0)
	{
	  if (WIFEXITED (status))
	    FAIL_EXIT1 ("%s failed with status %d\n", script,
			WEXITSTATUS (status));
	  else
	    FAIL_EXIT1 ("%s killed by signal %d\n", script,
			WTERMSIG (status));
	}
    }
}
Ejemplo n.º 4
0
static int
do_test (void)
{
  /* Setting an invalid key should return an error.  */
  if (tss_set (key, TSS_VALUE) == thrd_success)
    FAIL_EXIT1 ("tss_set succeed where it should have failed");

  if (tss_create (&key, NULL) != thrd_success)
    FAIL_EXIT1 ("tss_create failed");

  thrd_t id;
  if (thrd_create (&id, tss_thrd, NULL) != thrd_success)
    FAIL_EXIT1 ("thrd_create failed");

  if (thrd_join (id, NULL) != thrd_success)
    FAIL_EXIT1 ("thrd failed");

  /* The value set in tss_thrd should not be visible here.  */
  void *value = tss_get (key);
  if (value != 0)
    FAIL_EXIT1 ("tss_get succeed where it should have failed");

  tss_delete (key);

  return 0;
}
Ejemplo n.º 5
0
static void
do_prepare (void)
{
  size_t len = strlen (test_dir) + sizeof ("/tst-vfork3.XXXXXX");
  tmpdirname = malloc (len);
  if (tmpdirname == NULL)
    FAIL_EXIT1 ("out of memory");
  strcpy (stpcpy (tmpdirname, test_dir), "/tst-vfork3.XXXXXX");

  tmpdirname = mkdtemp (tmpdirname);
  if (tmpdirname == NULL)
    FAIL_EXIT1 ("could not create temporary directory");

  char script0[len + sizeof "/script0.sh"];
  char script1[len + sizeof "/script1.sh"];
  char script2[len + sizeof "/script2.sh"];

  strcpy (stpcpy (script0, tmpdirname), "/script0.sh");
  strcpy (stpcpy (script1, tmpdirname), "/script1.sh");
  strcpy (stpcpy (script2, tmpdirname), "/script2.sh");

  add_temp_file (tmpdirname);
  add_temp_file (script0);
  add_temp_file (script1);
  add_temp_file (script2);

  const char content0[] = "#!/bin/sh\necho empty\n";
  create_script (script0, content0, sizeof content0);

  const char content1[] = "#!/bin/sh\necho script $1\n";
  create_script (script1, content1, sizeof content1);

  const char content2[] = "echo script $1\n";
  create_script (script2, content2, sizeof content2);
}
Ejemplo n.º 6
0
static int
do_test (void)
{
  if (signal (SIGUSR1, sigusr1_handler) == SIG_ERR)
    FAIL_EXIT1 ("signal (SIGUSR1): %m\n");

  sigset_t sigs;
  sigemptyset (&sigs);
  sigaddset (&sigs, SIGUSR2);
  if (sigprocmask (SIG_BLOCK, &sigs, NULL) != 0)
    FAIL_EXIT1 ("sigprocmask (SIGBLOCK, SIGUSR2): %m");
  pid_t pid = signal_sender ();
  int signo = 0;
  int ret = sigwait (&sigs, &signo);
  if (ret != 0)
    {
      support_record_failure ();
      errno = ret;
      printf ("error: sigwait failed: %m (%d)\n", ret);
    }
  TEST_VERIFY (signo == SIGUSR2);

  int status;
  xwaitpid (pid, &status, 0);
  TEST_VERIFY (status == 0);

  return 0;
}
Ejemplo n.º 7
0
static int
do_test (void)
{
  atexit (remove_msq);

  key_t key = ftok (name, 'G');
  if (key == -1)
    FAIL_EXIT1 ("ftok failed");

  msqid = msgget (key, MSGQ_MODE | IPC_CREAT);
  if (msqid == -1)
    {
      if (errno == ENOSYS)
	FAIL_UNSUPPORTED ("msgget not supported");
      FAIL_EXIT1 ("msgget failed (errno=%d)", errno);
    }

  /* Get message queue kernel information and do some sanity checks.  */
  struct msqid_ds msginfo;
  if (msgctl (msqid, IPC_STAT, &msginfo) == -1)
    FAIL_EXIT1 ("msgctl with IPC_STAT failed (errno=%d)", errno);

  if (msginfo.msg_perm.__key != key)
    FAIL_EXIT1 ("msgid_ds::msg_perm::key (%d) != %d",
		(int) msginfo.msg_perm.__key, (int) key);
  if (msginfo.msg_perm.mode != MSGQ_MODE)
    FAIL_EXIT1 ("msgid_ds::msg_perm::mode (%o) != %o",
		msginfo.msg_perm.mode, MSGQ_MODE);
  if (msginfo.msg_qnum != 0)
    FAIL_EXIT1 ("msgid_ds::msg_qnum (%lu) != 0",
		(long unsigned) msginfo.msg_qnum);

  /* Check if last argument (IPC_NOWAIT) is correctly handled.  */
  struct msgbuf_t msg2rcv = { 0 };
  if (msgrcv (msqid, &msg2rcv, sizeof (msg2rcv.buf), MSGTYPE,
	      IPC_NOWAIT) == -1
      && errno != ENOMSG)
    FAIL_EXIT1 ("msgrcv failed (errno=%d)", errno);

  struct msgbuf_t msg2snd = { MSGTYPE, MSGDATA };
  if (msgsnd (msqid, &msg2snd, sizeof (msg2snd.buf), 0) == -1)
    FAIL_EXIT1 ("msgsnd failed (errno=%d)", errno);

  if (msgrcv (msqid, &msg2rcv, sizeof (msg2rcv.buf), MSGTYPE, 0) == -1)
    FAIL_EXIT1 ("msgrcv failed (errno=%d)", errno);

  int ret = 0;
  if (strncmp (msg2snd.buf, msg2rcv.buf, TEXTSIZE) != 0)
    ret = 1;

  if (msgctl (msqid, IPC_RMID, NULL) == -1)
    FAIL_EXIT1 ("msgctl failed");

  return ret;
}
Ejemplo n.º 8
0
static void
do_prepare (int argc, char *argv[])
{
  int fd = create_temp_file ("tst-sysvmsg.", &name);
  if (fd == -1)
    FAIL_EXIT1 ("cannot create temporary file (errno=%d)", errno);
}
Ejemplo n.º 9
0
static void
one_test (const char *message, int error_code, const wchar_t *expected)
{
  wchar_t *buffer = NULL;
  size_t length = 0;
  FILE *fp = open_wmemstream (&buffer, &length);
  TEST_VERIFY_EXIT (fp != NULL);
  FILE *old_stderr = stderr;
  stderr = fp;
  errno = error_code;
  switch (error_code)
    {
    case E2BIG:
      warn ("%s with padding " PADDING, message);
      break;
    case EAGAIN:
      warn ("%s", message);
      break;
    case -1:
      warnx ("%s", message);
      break;
    case -2:
      warnx ("%s with padding " PADDING, message);
      break;
    }
  stderr = old_stderr;
  TEST_VERIFY_EXIT (!ferror (fp));
  TEST_COMPARE (fclose (fp), 0);
  if (wcscmp (buffer, expected) != 0)
    FAIL_EXIT1 ("unexpected output: %ls", buffer);
  free (buffer);
}
Ejemplo n.º 10
0
static void *
tf_readv  (void *arg)
{
  int fd;

  if (arg == NULL)
    fd = fds[0];
  else
    {
      char fname[] = "/tmp/tst-cancel4-fd-XXXXXX";
      tempfd = fd = mkstemp (fname);
      if (fd == -1)
	FAIL_EXIT1 ("mkstemp failed: %m");
      unlink (fname);

      xpthread_barrier_wait (&b2);
    }

  xpthread_barrier_wait (&b2);

  ssize_t s;
  pthread_cleanup_push (cl, NULL);

  char buf[100];
  struct iovec iov[1] = { [0] = { .iov_base = buf, .iov_len = sizeof (buf) } };
Ejemplo n.º 11
0
static void
do_prepare (int argc, char **argv)
{
  temp_fd = create_temp_file ("tst-fallocate.", &temp_filename);
  if (temp_fd == -1)
    FAIL_EXIT1 ("cannot create temporary file: %m");
}
Ejemplo n.º 12
0
/* Set the RLIMIT_AS limit to the value in *LIMIT.  */
static void
xsetrlimit_as (const struct rlimit *limit)
{
  if (setrlimit (RLIMIT_AS, limit) != 0)
    FAIL_EXIT1 ("setrlimit (RLIMIT_AS, %lu): %m",
                (unsigned long) limit->rlim_cur);
}
Ejemplo n.º 13
0
static void
response (const struct resolv_response_context *ctx,
          struct resolv_response_builder *b,
          const char *qname, uint16_t qclass, uint16_t qtype)
{
  /* The tests are not supposed send any DNS queries.  */
  FAIL_EXIT1 ("unexpected DNS query for %s/%d/%d", qname, qclass, qtype);
}
Ejemplo n.º 14
0
static int
tss_thrd (void *arg)
{
  if (tss_create (&key, NULL) != thrd_success)
    FAIL_EXIT1 ("tss_create failed");

  if (tss_set (key, TSS_VALUE))
    FAIL_EXIT1 ("tss_set failed");

  void *value = tss_get (key);
  if (value == 0)
    FAIL_EXIT1 ("tss_get failed");
  if (value != TSS_VALUE)
    FAIL_EXIT1 ("tss_get returned %p, expected %p", value, TSS_VALUE);

  thrd_exit (thrd_success);
}
Ejemplo n.º 15
0
int
xpoll (struct pollfd *fds, nfds_t nfds, int timeout)
{
  int ret = poll (fds, nfds, timeout);
  if (ret < 0)
    FAIL_EXIT1 ("poll: %m");
  return ret;
}
Ejemplo n.º 16
0
void
xwrite (int fd, const void *buffer, size_t length)
{
  const char *p = buffer;
  const char *end = p + length;
  while (p < end)
    {
      ssize_t ret = write (fd, p, end - p);
      if (ret < 0)
        FAIL_EXIT1 ("write of %zu bytes failed after %td: %m",
                    length, p - (const char *) buffer);
      if (ret == 0)
        FAIL_EXIT1 ("write return 0 after writing %td bytes of %zu",
                    p - (const char *) buffer, length);
      p += ret;
    }
}
Ejemplo n.º 17
0
int
xaccept (int fd, struct sockaddr *sa, socklen_t *salen)
{
  int clientfd = accept (fd, sa, salen);
  if (clientfd < 0)
    FAIL_EXIT1 ("accept (%d): %m", fd);
  return clientfd;
}
Ejemplo n.º 18
0
void *
xmmap (void *addr, size_t length, int prot, int flags, int fd)
{
  void *result = mmap (addr, length, prot, flags, fd, 0);
  if (result == MAP_FAILED)
    FAIL_EXIT1 ("mmap of %zu bytes, prot=0x%x, flags=0x%x: %m",
                length, prot, flags);
  return result;
}
Ejemplo n.º 19
0
void
xpthread_check_return (const char *function, int value)
{
  if (value != 0)
    {
      errno = value;
      FAIL_EXIT1 ("%s: %m", function);
    }
}
Ejemplo n.º 20
0
size_t
xrecvfrom (int fd, void *buf, size_t buflen, int flags,
           struct sockaddr *sa, socklen_t *salen)
{
  ssize_t ret = recvfrom (fd, buf, buflen, flags, sa, salen);
  if (ret < 0)
    FAIL_EXIT1 ("error: recvfrom (%d), %zu bytes buffer: %m", fd, buflen);
  return ret;
}
Ejemplo n.º 21
0
static void
create_script (const char *script, const char *contents, size_t size)
{
  int fd = open (script, O_WRONLY | O_CREAT, 0700);
  if (fd < 0
      || TEMP_FAILURE_RETRY (write (fd, contents, size)) != size
      || fchmod (fd, S_IRUSR | S_IXUSR) < 0)
    FAIL_EXIT1 ("could not write %s\n", script);
  close (fd);
}
Ejemplo n.º 22
0
/* Spawn a subprocess to send two signals: First SIGUSR1, then
   SIGUSR2.  Return the PID of the process.  */
static pid_t
signal_sender (void)
{
  pid_t pid = xfork ();
  if (pid == 0)
    {
      static const struct timespec delay = { 1, };
      if (nanosleep (&delay, NULL) != 0)
        FAIL_EXIT1 ("nanosleep: %m");
      if (kill (getppid (), SIGUSR1) != 0)
        FAIL_EXIT1 ("kill (SIGUSR1): %m");
      if (nanosleep (&delay, NULL) != 0)
        FAIL_EXIT1 ("nanosleep: %m");
      if (kill (getppid (), SIGUSR2) != 0)
        FAIL_EXIT1 ("kill (SIGUSR2): %m");
      _exit (0);
    }
  return pid;
}
Ejemplo n.º 23
0
static int
do_test (void)
{
  size_t cnt;
  for (cnt = 0; cnt < sizeof (kind) / sizeof (kind[0]); ++cnt)
    {
      pthread_rwlock_t r;
      pthread_rwlockattr_t a;

      if (pthread_rwlockattr_init (&a) != 0)
        FAIL_EXIT1 ("round %Zu: rwlockattr_t failed\n", cnt);

      if (pthread_rwlockattr_setkind_np (&a, kind[cnt]) != 0)
        FAIL_EXIT1 ("round %Zu: rwlockattr_setkind failed\n", cnt);

      if (pthread_rwlock_init (&r, &a) != 0)
        FAIL_EXIT1 ("round %Zu: rwlock_init failed\n", cnt);

      if (pthread_rwlockattr_destroy (&a) != 0)
        FAIL_EXIT1 ("round %Zu: rwlockattr_destroy failed\n", cnt);

      struct timespec ts;
      xclock_gettime (CLOCK_REALTIME, &ts);

      ++ts.tv_sec;

      /* Get a read lock.  */
      if (pthread_rwlock_timedrdlock (&r, &ts) != 0)
        FAIL_EXIT1 ("round %Zu: rwlock_timedrdlock failed\n", cnt);

      printf ("%zu: got timedrdlock\n", cnt);

      pthread_t th;
      if (pthread_create (&th, NULL, tf, &r) != 0)
        FAIL_EXIT1 ("round %Zu: create failed\n", cnt);

      void *status;
      if (pthread_join (th, &status) != 0)
        FAIL_EXIT1 ("round %Zu: join failed\n", cnt);
      if (status != NULL)
        FAIL_EXIT1 ("failure in round %Zu\n", cnt);

      if (pthread_rwlock_destroy (&r) != 0)
        FAIL_EXIT1 ("round %Zu: rwlock_destroy failed\n", cnt);
    }

  return 0;
}
Ejemplo n.º 24
0
static int
do_test (void)
{
  activate_test_gconv_modules ();

  TEST_VERIFY (iconv_open ("UTF-8", "tst-gconv-init-failure//")
               == (iconv_t) -1);
  if (errno != ENOMEM)
    FAIL_EXIT1 ("unexpected iconv_open error: %m");

  return 0;
}
Ejemplo n.º 25
0
static int
do_test (void)
{
  void *ref = (void *) 0;
  void *ptr;

  ptr = get_absolute ();
  if (ptr != ref)
    FAIL_EXIT1 ("Got %p, expected %p\n", ptr, ref);

  return 0;
}
Ejemplo n.º 26
0
static int
do_test_with_offset (off_t offset)
{
  int ret;
  struct stat finfo;
#define BLK_SIZE 1024
  char bwrite[BLK_SIZE] = { 0xf0 };
  char bread[BLK_SIZE];

  /* It tries to fallocate 1024 bytes from 'offset' and then write 1024 bytes.
     After both operation rewind the file descriptor and read 1024 bytes
     and check if both buffer have the same contents.  */
  ret = fallocate (temp_fd, 0, offset, BLK_SIZE);
  if (ret == -1)
    {
      /* fallocate might not be fully supported by underlying filesystem (for
	 instance some NFS versions).   */
      if (errno == EOPNOTSUPP)
	FAIL_EXIT (77, "fallocate not supported");
      FAIL_EXIT1 ("fallocate failed");
    }

  ret = fstat (temp_fd, &finfo);
  if (ret == -1)
    FAIL_EXIT1 ("fstat failed");

  if (finfo.st_size < (offset + BLK_SIZE))
    FAIL_EXIT1 ("size of first fallocate less than expected (%llu)",
		(long long unsigned int)offset + BLK_SIZE);

  if (lseek (temp_fd, offset, SEEK_SET) == (off_t) -1)
    FAIL_EXIT1 ("fseek (0, SEEK_SET) failed");

  if (write (temp_fd, bwrite, BLK_SIZE) != BLK_SIZE)
    FAIL_EXIT1 ("fail trying to write " XSTR (BLK_SIZE) " bytes");

  if (lseek (temp_fd, offset, SEEK_SET) == (off_t) -1)
    FAIL_EXIT1 ("fseek (0, SEEK_SET) failed");

  if (read (temp_fd, bread, BLK_SIZE) != BLK_SIZE)
    FAIL_EXIT1 ("fail trying to read " XSTR (BLK_SIZE) " bytes");

  if (memcmp (bwrite, bread, BLK_SIZE) != 0)
    FAIL_EXIT1 ("buffer written different than buffer readed");

  return 0;
}
Ejemplo n.º 27
0
static int
do_test (void)
{
  void *handle = dlopen (LIBIDN2_SONAME, RTLD_LAZY);
  if (handle == NULL)
    FAIL_UNSUPPORTED ("libidn2 not installed");

  if (setlocale (LC_CTYPE, "en_US.ISO-8859-1") == NULL)
    FAIL_EXIT1 ("setlocale: %m");

  struct resolv_test *aux = resolv_test_start
    ((struct resolv_redirect_config)
     {
       .response_callback = response,
     });
Ejemplo n.º 28
0
static void
do_test_setsid (bool test_setsid)
{
  pid_t sid, child_sid;
  int res;

  /* Current session ID.  */
  sid = getsid(0);
  if (sid == (pid_t) -1)
    FAIL_EXIT1 ("getsid (0): %m");

  posix_spawnattr_t attrp;
  /* posix_spawnattr_init should not fail (it basically memset the
     attribute).  */
  posix_spawnattr_init (&attrp);
  if (test_setsid)
    {
      res = posix_spawnattr_setflags (&attrp, POSIX_SPAWN_SETSID);
      if (res != 0)
	{
	  errno = res;
	  FAIL_EXIT1 ("posix_spawnattr_setflags: %m");
	}
    }

  /* Program to run.  */
  char *args[2] = { (char *) "true", NULL };
  pid_t child;

  res = posix_spawnp (&child, "true", NULL, &attrp, args, environ);
  /* posix_spawnattr_destroy is noop.  */
  posix_spawnattr_destroy (&attrp);

  if (res != 0)
    {
      errno = res;
      FAIL_EXIT1 ("posix_spawnp: %m");
    }

  /* Child should have a different session ID than parent.  */
  child_sid = getsid (child);

  if (child_sid == (pid_t) -1)
    FAIL_EXIT1 ("getsid (%i): %m", child);

  if (test_setsid)
    {
      if (child_sid == sid)
	FAIL_EXIT1 ("child session ID matched parent one");
    }
  else
    {
      if (child_sid != sid)
	FAIL_EXIT1 ("child session ID did not match parent one");
    }
}
Ejemplo n.º 29
0
static int
do_test_with_offset (off_t offset)
{
  struct stat st;

  if (posix_fallocate (temp_fd, offset, 768) != 0)
    FAIL_EXIT1 ("1st posix_fallocate call failed");

  if (fstat (temp_fd, &st) != 0)
    FAIL_EXIT1 ("2nd fstat failed");

  if (st.st_size != (offset + 768))
    FAIL_EXIT1 ("file size after first posix_fallocate call is %lu, "
		"expected %lu",
		(unsigned long int) st.st_size, 512lu + 768lu);

  if (posix_fallocate (temp_fd, 0, 1024) != 0)
    FAIL_EXIT1 ("2nd posix_fallocate call failed");

  if (fstat (temp_fd, &st) != 0)
    FAIL_EXIT1 ("3rd fstat failed");

  if (st.st_size != (offset) + 768)
    FAIL_EXIT1 ("file size changed in second posix_fallocate");

  offset += 2048;
  if (posix_fallocate (temp_fd, offset, 64) != 0)
    FAIL_EXIT1 ("3rd posix_fallocate call failed");

  if (fstat (temp_fd, &st) != 0)
    FAIL_EXIT1 ("4th fstat failed");

  if (st.st_size != (offset + 64))
    FAIL_EXIT1 ("file size after first posix_fallocate call is %llu, "
		"expected %u",
		(unsigned long long int) st.st_size, 2048u + 64u);

  return 0;
}
Ejemplo n.º 30
0
static int
do_test (void)
{
  char *dir = support_create_temp_directory ("tst-xreadlink-");
  char *symlink_name = xasprintf ("%s/symlink", dir);
  add_temp_file (symlink_name);

  /* The limit 10000 is arbitrary and simply there to prevent an
     attempt to exhaust all available disk space.  */
  for (int size = 1; size < 10000; ++size)
    {
      char *contents = xmalloc (size + 1);
      for (int i = 0; i < size; ++i)
        contents[i] = 'a' + (rand () % 26);
      contents[size] = '\0';
      if (symlink (contents, symlink_name) != 0)
        {
          if (errno == ENAMETOOLONG)
            {
              printf ("info: ENAMETOOLONG failure at %d bytes\n", size);
              free (contents);
              break;
            }
          FAIL_EXIT1 ("symlink (%d bytes): %m", size);
        }

      char *readlink_result = xreadlink (symlink_name);
      TEST_VERIFY (strcmp (readlink_result, contents) == 0);
      free (readlink_result);
      xunlink (symlink_name);
      free (contents);
    }

  /* Create an empty file to suppress the temporary file deletion
     warning.  */
  xclose (xopen (symlink_name, O_WRONLY | O_CREAT, 0));

  free (symlink_name);
  free (dir);

  return 0;
}