Ejemplo n.º 1
0
/* sigwait -- synchronously wait for a signal */
int __pthread_sigwait(const sigset_t * set, int * sig)
{
  __volatile__ pthread_descr self = thread_self();
  sigset_t mask;
  int s;
  sigjmp_buf jmpbuf;
  struct sigaction sa;

  /* Get ready to block all signals except those in set
     and the cancellation signal.
     Also check that handlers are installed on all signals in set,
     and if not, install our dummy handler.  This is conformant to
     POSIX: "The effect of sigwait() on the signal actions for the
     signals in set is unspecified." */
  __sigfillset(&mask);
  sigdelset(&mask, __pthread_sig_cancel);
  for (s = 1; s < NSIG; s++) {
    if (sigismember(set, s) &&
        s != __pthread_sig_restart &&
        s != __pthread_sig_cancel &&
        s != __pthread_sig_debug) {
      sigdelset(&mask, s);
      if (__sighandler[s].old == (arch_sighandler_t) SIG_ERR ||
          __sighandler[s].old == (arch_sighandler_t) SIG_DFL ||
          __sighandler[s].old == (arch_sighandler_t) SIG_IGN) {
        sa.sa_handler = __pthread_null_sighandler;
        __sigfillset(&sa.sa_mask);
        sa.sa_flags = 0;
        sigaction(s, &sa, NULL);
      }
    }
  }
  /* Test for cancellation */
  if (sigsetjmp(jmpbuf, 1) == 0) {
    THREAD_SETMEM(self, p_cancel_jmp, &jmpbuf);
    if (! (THREAD_GETMEM(self, p_canceled)
	   && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) {
      /* Reset the signal count */
      THREAD_SETMEM(self, p_signal, 0);
      /* Say we're in sigwait */
      THREAD_SETMEM(self, p_sigwaiting, 1);
      /* Unblock the signals and wait for them */
      sigsuspend(&mask);
    }
  }
  THREAD_SETMEM(self, p_cancel_jmp, NULL);
  /* The signals are now reblocked.  Check for cancellation */
  pthread_testcancel();
  /* We should have self->p_signal != 0 and equal to the signal received */
  *sig = THREAD_GETMEM(self, p_signal);
  return 0;
}
Ejemplo n.º 2
0
static int __NC(sigwait)(const sigset_t *set, int *sig)
{
  sigset_t tmp_mask;
  struct sigaction saved[NSIG];
  struct sigaction action;
  int save_errno;
  int this;

  /* Prepare set.  */
  __sigfillset (&tmp_mask);

  /* Unblock all signals in the SET and register our nice handler.  */
  action.sa_handler = ignore_signal;
  action.sa_flags = 0;
  __sigfillset (&action.sa_mask);       /* Block all signals for handler.  */

  /* Make sure we recognize error conditions by setting WAS_SIG to a
     value which does not describe a legal signal number.  */
  was_sig = -1;

  for (this = 1; this < NSIG; ++this)
    if (__sigismember (set, this))
      {
        /* Unblock this signal.  */
        __sigdelset (&tmp_mask, this);

        /* Register temporary action handler.  */
        /* In Linux (as of 2.6.25), fails only if sig is SIGKILL or SIGSTOP */
        /* (so, will it work correctly if set has, say, SIGSTOP?) */
        if (sigaction (this, &action, &saved[this]) != 0)
          goto restore_handler;
      }

  /* Now we can wait for signals.  */
  __NC(sigsuspend)(&tmp_mask);

 restore_handler:
  save_errno = errno;

  while (--this >= 1)
    if (__sigismember (set, this))
      /* We ignore errors here since we must restore all handlers.  */
      sigaction (this, &saved[this], NULL);

  __set_errno (save_errno);

  /* Store the result and return.  */
  *sig = was_sig;
  return was_sig == -1 ? -1 : 0;
}
Ejemplo n.º 3
0
/* Cause an abnormal program termination with core-dump.  */
void abort(void)
{
    sigset_t sigset;

      /* Make sure we acquire the lock before proceeding.  */
      LOCK;

    /* Unmask SIGABRT to be sure we can get it */
    if (__sigemptyset(&sigset) == 0 && __sigaddset(&sigset, SIGABRT) == 0) {
	sigprocmask(SIG_UNBLOCK, &sigset, (sigset_t *) NULL);
    }

    /* If we are using stdio, try to shut it down.  At the very least,
	 * this will attempt to commit all buffered writes.  It may also
	 * unbuffer all writable files, or close them outright.
	 * Check the stdio routines for details. */
    if (_stdio_term)
		_stdio_term();

    while (1) {
	/* Try to suicide with a SIGABRT.  */
	if (been_there_done_that == 0) {
	    been_there_done_that++;
	    UNLOCK;
	    raise(SIGABRT);
	    LOCK;
	}

	/* Still here?  Try to remove any signal handlers.  */
	if (been_there_done_that == 1) {
	    struct sigaction act;

	    been_there_done_that++;
	    memset (&act, '\0', sizeof (struct sigaction));
	    act.sa_handler = SIG_DFL;
	    __sigfillset (&act.sa_mask);
	    act.sa_flags = 0;
	    sigaction (SIGABRT, &act, NULL);
	}

	/* Still here?  Try to suicide with an illegal instruction */
	if (been_there_done_that == 2) {
	    been_there_done_that++;
	    ABORT_INSTRUCTION;
	}

	/* Still here?  Try to at least exit */
	if (been_there_done_that == 3) {
	    been_there_done_that++;
	    _exit (127);
	}

	/* Still here?  We're screwed.  Sleepy time.  Good night */
	while (1)
	    /* Try for ever and ever.  */
	    ABORT_INSTRUCTION;
    }
}
Ejemplo n.º 4
0
int
__profil (u_short *sample_buffer, size_t size, size_t offset, u_int scale)
{
  struct sigaction act;
  struct itimerval timer;
#ifndef IS_IN_rtld
  static struct sigaction oact;
  static struct itimerval otimer;
# define oact_ptr &oact
# define otimer_ptr &otimer

  if (sample_buffer == NULL)
    {
      /* Disable profiling.  */
      if (samples == NULL)
	/* Wasn't turned on.  */
	return 0;

      if (__setitimer (ITIMER_PROF, &otimer, NULL) < 0)
	return -1;
      samples = NULL;
      return __sigaction (SIGPROF, &oact, NULL);
    }

 if (samples)
    {
      /* Was already turned on.  Restore old timer and signal handler
	 first.  */
      if (__setitimer (ITIMER_PROF, &otimer, NULL) < 0
	  || __sigaction (SIGPROF, &oact, NULL) < 0)
	return -1;
    }
#else
 /* In ld.so profiling should never be disabled once it runs.  */
 //assert (sample_buffer != NULL);
# define oact_ptr NULL
# define otimer_ptr NULL
#endif

  samples = sample_buffer;
  nsamples = size / sizeof *samples;
  pc_offset = offset;
  pc_scale = scale;

  act.sa_handler = (sighandler_t) &profil_counter;
  act.sa_flags = SA_RESTART;
  __sigfillset (&act.sa_mask);
  if (__sigaction (SIGPROF, &act, oact_ptr) < 0)
    return -1;

  timer.it_value.tv_sec = 0;
  timer.it_value.tv_usec = 1000000 / __profile_frequency ();
  timer.it_interval = timer.it_value;
  return __setitimer (ITIMER_PROF, &timer, otimer_ptr);
}
Ejemplo n.º 5
0
/* Cause an abnormal program termination with core-dump.  */
void abort(void)
{
    sigset_t sigset;

      /* Make sure we acquire the lock before proceeding.  */
      LOCK;

    /* Unmask SIGABRT to be sure we can get it */
    if (__sigemptyset(&sigset) == 0 && __sigaddset(&sigset, SIGABRT) == 0) {
	sigprocmask(SIG_UNBLOCK, &sigset, (sigset_t *) NULL);
    }

    while (1) {
	/* Try to suicide with a SIGABRT.  */
	if (been_there_done_that == 0) {
	    been_there_done_that++;
	    UNLOCK;
	    raise(SIGABRT);
	    LOCK;
	}

	/* Still here?  Try to remove any signal handlers.  */
	if (been_there_done_that == 1) {
	    struct sigaction act;

	    been_there_done_that++;
	    memset (&act, '\0', sizeof (struct sigaction));
	    act.sa_handler = SIG_DFL;
	    __sigfillset (&act.sa_mask);
	    act.sa_flags = 0;
	    sigaction (SIGABRT, &act, NULL);
	}

	/* Still here?  Try to suicide with an illegal instruction */
	if (been_there_done_that == 2) {
	    been_there_done_that++;
	    ABORT_INSTRUCTION;
	}

	/* Still here?  Try to at least exit */
	if (been_there_done_that == 3) {
	    been_there_done_that++;
	    _exit (127);
	}

	/* Still here?  We're screwed.  Sleepy time.  Good night */
	while (1)
	    /* Try for ever and ever.  */
	    ABORT_INSTRUCTION;
    }
}
Ejemplo n.º 6
0
/* Set all signals in SET.  */
int
sigfillset (sigset_t *set)
{
#if 0 /* is it really required by standards?! */
  if (set == NULL)
    {
      __set_errno (EINVAL);
      return -1;
    }
#endif

  __sigfillset (set);

  /* If the implementation uses a cancellation signal don't set the bit.  */
#ifdef SIGCANCEL
  __sigdelset (set, SIGCANCEL);
#endif
  /* Likewise for the signal to implement setxid.  */
#ifdef SIGSETXID
  __sigdelset (set, SIGSETXID);
#endif

  return 0;
}
static inline void
__hardened_gentoo_fail(void)
{
#define MESSAGE_BUFSIZ 512
	static pid_t pid;
	static int plen, i, hlen;
	static char message[MESSAGE_BUFSIZ];
	/* <11> is LOG_USER|LOG_ERR. A dummy date for loggers to skip over. */
	static const char msg_header[] = "<11>" __DATE__ " " __TIME__ " glibc-gentoo-hardened-check: ";
	static const char msg_ssd[] = "*** " ERROR_MSG " detected ***: ";
	static const char msg_terminated[] = " terminated; ";
	static const char msg_report[] = "report to " REPORT_BUGS_TO "\n";
	static const char msg_unknown[] = "<unknown>";
	static int log_socket, connect_result;
	static struct sockaddr_un sock;
	static unsigned long int socketargs[4];

	/* Build socket address */
	sock.sun_family = AF_UNIX;
	i = 0;
	while (path_log[i] != '\0' && i < sizeof(sock.sun_path) - 1) {
		sock.sun_path[i] = path_log[i];
		++i;
	}
	sock.sun_path[i] = '\0';

	/* Try SOCK_DGRAM connection to syslog */
	connect_result = -1;
	DO_SOCKET(log_socket, AF_UNIX, SOCK_DGRAM, 0);
	if (log_socket != -1)
		DO_CONNECT(connect_result, log_socket, &sock, sizeof(sock));
	if (connect_result == -1) {
		if (log_socket != -1)
			INLINE_SYSCALL(close, 1, log_socket);
		/* Try SOCK_STREAM connection to syslog */
		DO_SOCKET(log_socket, AF_UNIX, SOCK_STREAM, 0);
		if (log_socket != -1)
			DO_CONNECT(connect_result, log_socket, &sock, sizeof(sock));
	}

	/* Build message.  Messages are generated both in the old style and new style,
	 * so that log watchers that are configured for the old-style message continue
	 * to work.
	 */
#define strconcat(str) \
	({ \
		i = 0; \
		while ((str[i] != '\0') && ((i + plen) < (MESSAGE_BUFSIZ - 1))) { \
			message[plen + i] = str[i]; \
			++i; \
		} \
		plen += i; \
	})

	/* Tersely log the failure */
	plen = 0;
	strconcat(msg_header);
	hlen = plen;
	strconcat(msg_ssd);
	if (__progname != NULL)
		strconcat(__progname);
	else
		strconcat(msg_unknown);
	strconcat(msg_terminated);
	strconcat(msg_report);

	/* Write out error message to STDERR, to syslog if open */
	INLINE_SYSCALL(write, 3, STDERR_FILENO, message + hlen, plen - hlen);
	if (connect_result != -1) {
		INLINE_SYSCALL(write, 3, log_socket, message, plen);
		INLINE_SYSCALL(close, 1, log_socket);
	}

	/* Time to kill self since we have no idea what is going on */
	pid = INLINE_SYSCALL(getpid, 0);

	if (ENABLE_SSP_SMASH_DUMPS_CORE) {
		/* Remove any user-supplied handler for SIGABRT, before using it. */
#if 0
		/*
		 * Note: Disabled because some programs catch & process their
		 * own crashes.  We've already enabled this code path which
		 * means we want to let core dumps happen.
		 */
		static struct sigaction default_abort_act;
		default_abort_act.sa_handler = SIG_DFL;
		default_abort_act.sa_sigaction = NULL;
		__sigfillset(&default_abort_act.sa_mask);
		default_abort_act.sa_flags = 0;
		if (DO_SIGACTION(SIGABRT, &default_abort_act, NULL) == 0)
			INLINE_SYSCALL(kill, 2, pid, SIGABRT);
#endif
		/* Use abort() directly. http://crbug.com/406598 */
		abort();
	}

	/* SIGKILL is only signal which cannot be caught */
	INLINE_SYSCALL(kill, 2, pid, SIGKILL);

	/* In case the kill didn't work, exit anyway.
	 * The loop prevents gcc thinking this routine returns.
	 */
	while (1)
		INLINE_SYSCALL(exit, 1, 137);
}
Ejemplo n.º 8
0
int attribute_noreturn __pthread_manager(void *arg)
{
  int reqfd = (int) (long int) arg;
#ifdef USE_SELECT
  struct timeval tv;
  fd_set fd;
#else
  struct pollfd ufd;
#endif
  sigset_t manager_mask;
  int n;
  struct pthread_request request;

  /* If we have special thread_self processing, initialize it.  */
#ifdef INIT_THREAD_SELF
  INIT_THREAD_SELF(&__pthread_manager_thread, 1);
#endif
  /* Set the error variable.  */
  __pthread_manager_thread.p_errnop = &__pthread_manager_thread.p_errno;
  __pthread_manager_thread.p_h_errnop = &__pthread_manager_thread.p_h_errno;

#ifdef __UCLIBC_HAS_XLOCALE__
  /* Initialize thread's locale to the global locale. */
  __pthread_manager_thread.locale = __global_locale;
#endif /* __UCLIBC_HAS_XLOCALE__ */

  /* Block all signals except __pthread_sig_cancel and SIGTRAP */
  __sigfillset(&manager_mask);
  sigdelset(&manager_mask, __pthread_sig_cancel); /* for thread termination */
  sigdelset(&manager_mask, SIGTRAP);            /* for debugging purposes */
  if (__pthread_threads_debug && __pthread_sig_debug > 0)
      sigdelset(&manager_mask, __pthread_sig_debug);
  sigprocmask(SIG_SETMASK, &manager_mask, NULL);
  /* Raise our priority to match that of main thread */
  __pthread_manager_adjust_prio(__pthread_main_thread->p_priority);
  /* Synchronize debugging of the thread manager */
  n = TEMP_FAILURE_RETRY(read(reqfd, (char *)&request,
				     sizeof(request)));
#ifndef USE_SELECT
  ufd.fd = reqfd;
  ufd.events = POLLIN;
#endif
  /* Enter server loop */
  while(1) {
#ifdef USE_SELECT
    tv.tv_sec = 2;
    tv.tv_usec = 0;
    FD_ZERO (&fd);
    FD_SET (reqfd, &fd);
    n = select (reqfd + 1, &fd, NULL, NULL, &tv);
#else
    PDEBUG("before poll\n");
    n = poll(&ufd, 1, 2000);
    PDEBUG("after poll\n");
#endif
    /* Check for termination of the main thread */
    if (getppid() == 1) {
      pthread_kill_all_threads(SIGKILL, 0);
      _exit(0);
    }
    /* Check for dead children */
    if (terminated_children) {
      terminated_children = 0;
      pthread_reap_children();
    }
    /* Read and execute request */
#ifdef USE_SELECT
    if (n == 1)
#else
    if (n == 1 && (ufd.revents & POLLIN))
#endif
    {

      PDEBUG("before read\n");
      n = read(reqfd, (char *)&request, sizeof(request));
      PDEBUG("after read, n=%d\n", n);
      switch(request.req_kind) {
      case REQ_CREATE:
        PDEBUG("got REQ_CREATE\n");
        request.req_thread->p_retcode =
          pthread_handle_create((pthread_t *) &request.req_thread->p_retval,
                                request.req_args.create.attr,
                                request.req_args.create.fn,
                                request.req_args.create.arg,
                                &request.req_args.create.mask,
                                request.req_thread->p_pid,
                                request.req_thread->p_report_events,
                                &request.req_thread->p_eventbuf.eventmask);
        PDEBUG("restarting %p\n", request.req_thread);
        restart(request.req_thread);
        break;
      case REQ_FREE:
        PDEBUG("got REQ_FREE\n");
        pthread_handle_free(request.req_args.free.thread_id);
        break;
      case REQ_PROCESS_EXIT:
        PDEBUG("got REQ_PROCESS_EXIT from %p, exit code = %d\n",
        request.req_thread, request.req_args.exit.code);
        pthread_handle_exit(request.req_thread,
                            request.req_args.exit.code);
        break;
      case REQ_MAIN_THREAD_EXIT:
        PDEBUG("got REQ_MAIN_THREAD_EXIT\n");
        main_thread_exiting = 1;
	/* Reap children in case all other threads died and the signal handler
	   went off before we set main_thread_exiting to 1, and therefore did
	   not do REQ_KICK. */
	pthread_reap_children();

        if (__pthread_main_thread->p_nextlive == __pthread_main_thread) {
          restart(__pthread_main_thread);
	  /* The main thread will now call exit() which will trigger an
	     __on_exit handler, which in turn will send REQ_PROCESS_EXIT
	     to the thread manager. In case you are wondering how the
	     manager terminates from its loop here. */
	}
        break;
      case REQ_POST:
        PDEBUG("got REQ_POST\n");
        sem_post(request.req_args.post);
        break;
      case REQ_DEBUG:
        PDEBUG("got REQ_DEBUG\n");
	/* Make gdb aware of new thread and gdb will restart the
	   new thread when it is ready to handle the new thread. */
	if (__pthread_threads_debug && __pthread_sig_debug > 0) {
	  PDEBUG("about to call raise(__pthread_sig_debug)\n");
	  raise(__pthread_sig_debug);
	}
      case REQ_KICK:
	/* This is just a prod to get the manager to reap some
	   threads right away, avoiding a potential delay at shutdown. */
	break;
      }
    }
  }
}
Ejemplo n.º 9
0
/* Cause an abnormal program termination with core-dump.  */
void
abort (void)
{
  struct sigaction act;
  sigset_t sigs;

  /* First acquire the lock.  */
  __libc_lock_lock_recursive (lock);

  /* Now it's for sure we are alone.  But recursive calls are possible.  */

  /* Unlock SIGABRT.  */
  if (stage == 0)
    {
      ++stage;
      if (__sigemptyset (&sigs) == 0 &&
	  __sigaddset (&sigs, SIGABRT) == 0)
	__sigprocmask (SIG_UNBLOCK, &sigs, (sigset_t *) NULL);
    }

  /* Flush all streams.  We cannot close them now because the user
     might have registered a handler for SIGABRT.  */
  if (stage == 1)
    {
      ++stage;
      fflush (NULL);
    }

  /* Send signal which possibly calls a user handler.  */
  if (stage == 2)
    {
      /* This stage is special: we must allow repeated calls of
	 `abort' when a user defined handler for SIGABRT is installed.
	 This is risky since the `raise' implementation might also
	 fail but I don't see another possibility.  */
      int save_stage = stage;

      stage = 0;
      __libc_lock_unlock_recursive (lock);

      raise (SIGABRT);

      __libc_lock_lock_recursive (lock);
      stage = save_stage + 1;
    }

  /* There was a handler installed.  Now remove it.  */
  if (stage == 3)
    {
      ++stage;
      memset (&act, '\0', sizeof (struct sigaction));
      act.sa_handler = SIG_DFL;
      __sigfillset (&act.sa_mask);
      act.sa_flags = 0;
      __sigaction (SIGABRT, &act, NULL);
    }

  /* Now close the streams which also flushes the output the user
     defined handler might has produced.  */
  if (stage == 4)
    {
      ++stage;
      __fcloseall ();
    }

  /* Try again.  */
  if (stage == 5)
    {
      ++stage;
      raise (SIGABRT);
    }

  /* Now try to abort using the system specific command.  */
  if (stage == 6)
    {
      ++stage;
      ABORT_INSTRUCTION;
    }

  /* If we can't signal ourselves and the abort instruction failed, exit.  */
  if (stage == 7)
    {
      ++stage;
      _exit (127);
    }

  /* If even this fails try to use the provided instruction to crash
     or otherwise make sure we never return.  */
  while (1)
    /* Try for ever and ever.  */
    ABORT_INSTRUCTION;
}
Ejemplo n.º 10
0
int
lckpwdf (void)
{
  sigset_t saved_set;			/* Saved set of caught signals.  */
  struct sigaction saved_act;		/* Saved signal action.  */
  sigset_t new_set;			/* New set of caught signals.  */
  struct sigaction new_act;		/* New signal action.  */
  struct flock fl;			/* Information struct for locking.  */
  int result;

  if (lock_fd != -1)
    /* Still locked by own process.  */
    return -1;

  /* Prevent problems caused by multiple threads.  */
  __UCLIBC_MUTEX_LOCK(mylock);

  lock_fd = open (_PATH_PASSWD, O_WRONLY | O_CLOEXEC);
  if (lock_fd == -1) {
    goto DONE;
  }
#ifndef __ASSUME_O_CLOEXEC
  /* Make sure file gets correctly closed when process finished.  */
  fcntl (lock_fd, F_SETFD, FD_CLOEXEC);
#endif

  /* Now we have to get exclusive write access.  Since multiple
     process could try this we won't stop when it first fails.
     Instead we set a timeout for the system call.  Once the timer
     expires it is likely that there are some problems which cannot be
     resolved by waiting. (sa_flags have no SA_RESTART. Thus SIGALRM
     will EINTR fcntl(F_SETLKW)

     It is important that we don't change the signal state.  We must
     restore the old signal behaviour.  */
  memset (&new_act, '\0', sizeof (new_act));
  new_act.sa_handler = noop_handler;
  __sigfillset (&new_act.sa_mask);

  /* Install new action handler for alarm and save old.
   * This never fails in Linux.  */
  sigaction (SIGALRM, &new_act, &saved_act);

  /* Now make sure the alarm signal is not blocked.  */
  __sigemptyset (&new_set);
  __sigaddset (&new_set, SIGALRM);
  sigprocmask (SIG_UNBLOCK, &new_set, &saved_set);

  /* Start timer.  If we cannot get the lock in the specified time we
     get a signal.  */
  alarm (TIMEOUT);

  /* Try to get the lock.  */
  memset (&fl, '\0', sizeof (fl));
  if (F_WRLCK)
    fl.l_type = F_WRLCK;
  if (SEEK_SET)
    fl.l_whence = SEEK_SET;
  result = fcntl (lock_fd, F_SETLKW, &fl);

  /* Clear alarm.  */
  alarm (0);

  sigprocmask (SIG_SETMASK, &saved_set, NULL);
  sigaction (SIGALRM, &saved_act, NULL);

  if (result < 0) {
    close(lock_fd);
    lock_fd = -1;
  }

DONE:
  __UCLIBC_MUTEX_UNLOCK(mylock);
  return 0; /* TODO: return result? */
}
Ejemplo n.º 11
0
int
__lckpwdf (void)
{
  int flags;
  sigset_t saved_set;			/* Saved set of caught signals.  */
  struct sigaction saved_act;		/* Saved signal action.  */
  sigset_t new_set;			/* New set of caught signals.  */
  struct sigaction new_act;		/* New signal action.  */
  struct flock fl;			/* Information struct for locking.  */
  int result;

  if (lock_fd != -1)
    /* Still locked by own process.  */
    return -1;

  /* Prevent problems caused by multiple threads.  */
  __libc_lock_lock (lock);

  int oflags = O_WRONLY | O_CREAT;
#ifdef O_CLOEXEC
  oflags |= O_CLOEXEC;
#endif
  lock_fd = __open (PWD_LOCKFILE, oflags, 0600);
  if (lock_fd == -1)
    /* Cannot create lock file.  */
    RETURN_CLOSE_FD (-1);

#ifndef __ASSUME_O_CLOEXEC
# ifdef O_CLOEXEC
  if (__have_o_cloexec <= 0)
# endif
    {
      /* Make sure file gets correctly closed when process finished.  */
      flags = __fcntl (lock_fd, F_GETFD, 0);
      if (flags == -1)
	/* Cannot get file flags.  */
	RETURN_CLOSE_FD (-1);
# ifdef O_CLOEXEC
      if (__have_o_cloexec == 0)
	__have_o_cloexec = (flags & FD_CLOEXEC) == 0 ? -1 : 1;
      if (__have_o_cloexec < 0)
# endif
	{
	  flags |= FD_CLOEXEC;		/* Close on exit.  */
	  if (__fcntl (lock_fd, F_SETFD, flags) < 0)
	    /* Cannot set new flags.  */
	    RETURN_CLOSE_FD (-1);
	}
    }
#endif

  /* Now we have to get exclusive write access.  Since multiple
     process could try this we won't stop when it first fails.
     Instead we set a timeout for the system call.  Once the timer
     expires it is likely that there are some problems which cannot be
     resolved by waiting.

     It is important that we don't change the signal state.  We must
     restore the old signal behaviour.  */
  memset (&new_act, '\0', sizeof (struct sigaction));
  new_act.sa_handler = noop_handler;
  __sigfillset (&new_act.sa_mask);
  new_act.sa_flags = 0ul;

  /* Install new action handler for alarm and save old.  */
  if (__sigaction (SIGALRM, &new_act, &saved_act) < 0)
    /* Cannot install signal handler.  */
    RETURN_CLOSE_FD (-1);

  /* Now make sure the alarm signal is not blocked.  */
  __sigemptyset (&new_set);
  __sigaddset (&new_set, SIGALRM);
  if (__sigprocmask (SIG_UNBLOCK, &new_set, &saved_set) < 0)
    RETURN_RESTORE_HANDLER (-1);

  /* Start timer.  If we cannot get the lock in the specified time we
     get a signal.  */
  alarm (TIMEOUT);

  /* Try to get the lock.  */
  memset (&fl, '\0', sizeof (struct flock));
  fl.l_type = F_WRLCK;
  fl.l_whence = SEEK_SET;
  result = __fcntl (lock_fd, F_SETLKW, &fl);

  RETURN_CLEAR_ALARM (result);
}