flopen.c revision 169894
1169446Sdes/*- 2169446Sdes * Copyright (c) 2007 Dag-Erling Co�dan Sm�rgrav 3169446Sdes * All rights reserved. 4169446Sdes * 5169446Sdes * Redistribution and use in source and binary forms, with or without 6169446Sdes * modification, are permitted provided that the following conditions 7169446Sdes * are met: 8169446Sdes * 1. Redistributions of source code must retain the above copyright 9169446Sdes * notice, this list of conditions and the following disclaimer 10169446Sdes * in this position and unchanged. 11169446Sdes * 2. Redistributions in binary form must reproduce the above copyright 12169446Sdes * notice, this list of conditions and the following disclaimer in the 13169446Sdes * documentation and/or other materials provided with the distribution. 14169446Sdes * 15169446Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16169446Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17169446Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18169446Sdes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19169446Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20169446Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21169446Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22169446Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23169446Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24169446Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25169446Sdes * SUCH DAMAGE. 26169446Sdes */ 27169446Sdes 28169446Sdes#include <sys/cdefs.h> 29169446Sdes__FBSDID("$FreeBSD: head/lib/libutil/flopen.c 169894 2007-05-23 08:12:34Z des $"); 30169446Sdes 31169450Sdes#include <sys/file.h> 32169446Sdes#include <sys/stat.h> 33169446Sdes 34169446Sdes#include <errno.h> 35169446Sdes#include <fcntl.h> 36169446Sdes#include <stdarg.h> 37169450Sdes#include <unistd.h> 38169446Sdes 39169450Sdes#include <libutil.h> 40169450Sdes 41169446Sdesint 42169446Sdesflopen(const char *path, int flags, ...) 43169446Sdes{ 44169894Sdes int fd, operation, serrno, truncate; 45169446Sdes struct stat sb, fsb; 46169446Sdes mode_t mode; 47169446Sdes 48169446Sdes#ifdef O_EXLOCK 49169446Sdes flags &= ~O_EXLOCK; 50169446Sdes#endif 51169446Sdes 52169447Sdes mode = 0; 53169446Sdes if (flags & O_CREAT) { 54169446Sdes va_list ap; 55169446Sdes 56169446Sdes va_start(ap, flags); 57169446Sdes mode = va_arg(ap, int); /* mode_t promoted to int */ 58169446Sdes va_end(ap); 59169446Sdes } 60169446Sdes 61169447Sdes operation = LOCK_EX; 62169447Sdes if (flags & O_NONBLOCK) 63169447Sdes operation |= LOCK_NB; 64169447Sdes 65169894Sdes truncate = (flags & O_TRUNC); 66169894Sdes flags |= ~O_TRUNC; 67169894Sdes 68169446Sdes for (;;) { 69169446Sdes if ((fd = open(path, flags, mode)) == -1) 70169446Sdes /* non-existent or no access */ 71169446Sdes return (-1); 72169447Sdes if (flock(fd, operation) == -1) { 73169446Sdes /* unsupported or interrupted */ 74169446Sdes serrno = errno; 75169446Sdes close(fd); 76169446Sdes errno = serrno; 77169446Sdes return (-1); 78169446Sdes } 79169446Sdes if (stat(path, &sb) == -1) { 80169446Sdes /* disappeared from under our feet */ 81169446Sdes close(fd); 82169446Sdes continue; 83169446Sdes } 84169446Sdes if (fstat(fd, &fsb) == -1) { 85169446Sdes /* can't happen [tm] */ 86169446Sdes serrno = errno; 87169446Sdes close(fd); 88169446Sdes errno = serrno; 89169446Sdes return (-1); 90169446Sdes } 91169446Sdes if (sb.st_dev != fsb.st_dev || 92169446Sdes sb.st_ino != fsb.st_ino) { 93169446Sdes /* changed under our feet */ 94169446Sdes close(fd); 95169446Sdes continue; 96169446Sdes } 97169894Sdes if (truncate && ftruncate(fd, 0) != 0) { 98169894Sdes /* can't happen [tm] */ 99169894Sdes serrno = errno; 100169894Sdes close(fd); 101169894Sdes errno = serrno; 102169894Sdes return (-1); 103169894Sdes } 104169446Sdes return (fd); 105169446Sdes } 106169446Sdes} 107