(root)/
man-db-2.12.0/
src/
tests/
fspause.c
       1  /*
       2   * fspause.c: pause until a file timestamp updates
       3   *
       4   * Copyright (C) 2014 Colin Watson.
       5   *
       6   * This file is part of man-db.
       7   *
       8   * man-db is free software; you can redistribute it and/or modify it
       9   * under the terms of the GNU General Public License as published by
      10   * the Free Software Foundation; either version 2 of the License, or
      11   * (at your option) any later version.
      12   *
      13   * man-db is distributed in the hope that it will be useful, but
      14   * WITHOUT ANY WARRANTY; without even the implied warranty of
      15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16   * GNU General Public License for more details.
      17   *
      18   * You should have received a copy of the GNU General Public License
      19   * along with man-db; if not, write to the Free Software Foundation,
      20   * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
      21   */
      22  
      23  #ifdef HAVE_CONFIG_H
      24  #  include "config.h"
      25  #endif /* HAVE_CONFIG_H */
      26  
      27  #include <errno.h>
      28  #include <stdio.h>
      29  #include <stdlib.h>
      30  #include <sys/types.h>
      31  #include <sys/stat.h>
      32  #include <time.h>
      33  #include <unistd.h>
      34  
      35  #include "attribute.h"
      36  #include "progname.h"
      37  #include "stat-time.h"
      38  #include "timespec.h"
      39  #include "xalloc.h"
      40  
      41  #include "manconfig.h"
      42  
      43  static char *filename;
      44  static int fd = -1;
      45  
      46  #define MUST(name, cond) \
      47  	do { \
      48  		if (!(cond)) { \
      49  			fprintf (stderr, "fspause: " name " failed\n"); \
      50  			abort (); \
      51  		} \
      52  	} while (0)
      53  
      54  static void unlink_tempfile (void)
      55  {
      56  	if (fd >= 0) {
      57  		MUST ("close", close (fd) >= 0);
      58  		MUST ("unlink", unlink (filename) >= 0);
      59  	}
      60  }
      61  
      62  static void delay (int delay_ns)
      63  {
      64  	struct timespec delay_ts;
      65  
      66  	delay_ts.tv_sec = delay_ns / 1000000000;
      67  	delay_ts.tv_nsec = delay_ns % 1000000000;
      68  	for (;;) {
      69  		errno = 0;
      70  		if (nanosleep (&delay_ts, NULL) == 0)
      71  			break;
      72  		MUST ("nanosleep", errno == 0 || errno == EINTR);
      73  	}
      74  }
      75  
      76  static int try_delay (struct stat *st, int delay_ns)
      77  {
      78  	struct timespec start_ts, end_ts;
      79  
      80  	start_ts = get_stat_mtime (st);
      81  	delay (delay_ns);
      82  	MUST ("write", write (fd, "\n", 1) == 1);
      83  	MUST ("fstat", fstat (fd, st) >= 0);
      84  	end_ts = get_stat_mtime (st);
      85  	return timespec_cmp (start_ts, end_ts) != 0;
      86  }
      87  
      88  int main (int argc MAYBE_UNUSED, char **argv)
      89  {
      90  	struct stat st;
      91  	int delay_ns;
      92  
      93  	set_program_name (argv[0]);
      94  
      95  	filename = xstrdup ("fspause.tmp.XXXXXX");
      96  	MUST ("mkstemp", (fd = mkstemp (filename)) >= 0);
      97  	atexit (unlink_tempfile);
      98  	MUST ("fstat", fstat (fd, &st) >= 0);
      99  
     100  	/* 0x40000000 nanoseconds is just over a second.  The effective
     101  	 * maximum delay we will allow is thus about two seconds.  This
     102  	 * saves us having to keep track of anything more complicated than a
     103  	 * single signed 32-bit int.
     104  	 */
     105  	for (delay_ns = 1; delay_ns < 0x40000000; delay_ns *= 2) {
     106  		if (try_delay (&st, delay_ns))
     107  			return 0;
     108  	}
     109  
     110  	fprintf (stderr,
     111  		 "fspause: temporary file timestamp refuses to change!\n");
     112  	return 1;
     113  }