1151497Sru/* Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc. 2114402Sru Written by Werner Lemberg (wl@gnu.org) 3114402Sru 4114402SruThis file is part of groff. 5114402Sru 6114402Srugroff is free software; you can redistribute it and/or modify it under 7114402Sruthe terms of the GNU General Public License as published by the Free 8114402SruSoftware Foundation; either version 2, or (at your option) any later 9114402Sruversion. 10114402Sru 11114402Srugroff is distributed in the hope that it will be useful, but WITHOUT ANY 12114402SruWARRANTY; without even the implied warranty of MERCHANTABILITY or 13114402SruFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14114402Srufor more details. 15114402Sru 16114402SruYou should have received a copy of the GNU General Public License along 17114402Sruwith groff; see the file COPYING. If not, write to the Free Software 18151497SruFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */ 19114402Sru 20114402Sru 21114402Sru/* This file is heavily based on the function __gen_tempname() in the 22114402Sru file tempname.c which is part of the fileutils package. */ 23114402Sru 24114402Sru 25114402Sru#include "lib.h" 26114402Sru 27114402Sru#include <stddef.h> 28114402Sru#include <stdlib.h> 29114402Sru#include <errno.h> 30114402Sru#include <time.h> 31114402Sru 32114402Sru#include "posix.h" 33114402Sru#include "nonposix.h" 34114402Sru 35114402Sru#ifndef TMP_MAX 36114402Sru# define TMP_MAX 238328 37114402Sru#endif 38114402Sru 39114402Sru#if HAVE_SYS_TIME_H 40114402Sru# include <sys/time.h> 41114402Sru#endif 42114402Sru 43114402Sru#ifdef HAVE_GETTIMEOFDAY 44114402Sru#ifdef NEED_DECLARATION_GETTIMEOFDAY 45114402Sruextern "C" { 46114402Sru int gettimeofday(struct timeval *, void *); 47114402Sru} 48114402Sru#endif 49114402Sru#endif 50114402Sru 51151497Sru#if HAVE_CC_INTTYPES_H 52151497Sru# include <inttypes.h> 53114402Sru#endif 54114402Sru 55114402Sru/* Use the widest available unsigned type if uint64_t is not 56114402Sru available. The algorithm below extracts a number less than 62**6 57114402Sru (approximately 2**35.725) from uint64_t, so ancient hosts where 58114402Sru uintmax_t is only 32 bits lose about 3.725 bits of randomness, 59114402Sru which is better than not having mkstemp at all. */ 60114402Sru#if !defined UINT64_MAX && !defined uint64_t 61114402Sru# define uint64_t uintmax_t 62114402Sru#endif 63114402Sru 64114402Sru/* These are the characters used in temporary filenames. */ 65114402Srustatic const char letters[] = 66114402Sru"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; 67114402Sru 68114402Sruint gen_tempname(char *tmpl, int dir) 69114402Sru{ 70114402Sru static uint64_t value; 71114402Sru 72114402Sru size_t len = strlen(tmpl); 73114402Sru if (len < 6 || strcmp(&tmpl[len - 6], "XXXXXX")) 74114402Sru return -1; /* EINVAL */ 75114402Sru 76114402Sru /* This is where the Xs start. */ 77114402Sru char *XXXXXX = &tmpl[len - 6]; 78114402Sru 79114402Sru /* Get some more or less random data. */ 80114402Sru#if HAVE_GETTIMEOFDAY 81114402Sru timeval tv; 82114402Sru gettimeofday(&tv, NULL); 83114402Sru uint64_t random_time_bits = ((uint64_t)tv.tv_usec << 16) ^ tv.tv_sec; 84114402Sru#else 85114402Sru uint64_t random_time_bits = time(NULL); 86114402Sru#endif 87114402Sru value += random_time_bits ^ getpid(); 88114402Sru 89114402Sru for (int count = 0; count < TMP_MAX; value += 7777, ++count) { 90114402Sru uint64_t v = value; 91114402Sru 92114402Sru /* Fill in the random bits. */ 93114402Sru XXXXXX[0] = letters[v % 62]; 94114402Sru v /= 62; 95114402Sru XXXXXX[1] = letters[v % 62]; 96114402Sru v /= 62; 97114402Sru XXXXXX[2] = letters[v % 62]; 98114402Sru v /= 62; 99114402Sru XXXXXX[3] = letters[v % 62]; 100114402Sru v /= 62; 101114402Sru XXXXXX[4] = letters[v % 62]; 102114402Sru v /= 62; 103114402Sru XXXXXX[5] = letters[v % 62]; 104114402Sru 105114402Sru int fd = dir ? mkdir(tmpl, S_IRUSR | S_IWUSR | S_IXUSR) 106114402Sru : open(tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); 107114402Sru 108114402Sru if (fd >= 0) 109114402Sru return fd; 110114402Sru else if (errno != EEXIST) 111114402Sru return -1; 112114402Sru } 113114402Sru 114114402Sru /* We got out of the loop because we ran out of combinations to try. */ 115114402Sru return -1; /* EEXIST */ 116114402Sru} 117