| |
| /* |
| * Copyright 2009 Red Hat, Inc. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; see the file COPYING. If not, write to |
| * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
| * |
| */ |
| |
| #define _GNU_SOURCE |
| |
| #ifndef HAVE_CONFIG_H |
| #error Invalid or missing autoconf build environment |
| #endif |
| |
| #include "rng-tools-config.h" |
| |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <fcntl.h> |
| #include <string.h> |
| #include <errno.h> |
| |
| #include "rngd.h" |
| |
| int write_pid_file(const char *pid_fn) |
| { |
| char str[32], *s; |
| size_t bytes; |
| int fd; |
| struct flock lock; |
| int err; |
| |
| /* build file data */ |
| sprintf(str, "%u\n", (unsigned int) getpid()); |
| |
| /* open non-exclusively (works on NFS v2) */ |
| fd = open(pid_fn, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); |
| if (fd < 0) { |
| err = errno; |
| |
| message(LOG_DAEMON|LOG_ERR, "Cannot open PID file %s: %s", |
| pid_fn, strerror(err)); |
| return -err; |
| } |
| |
| /* lock */ |
| memset(&lock, 0, sizeof(lock)); |
| lock.l_type = F_WRLCK; |
| lock.l_whence = SEEK_SET; |
| if (fcntl(fd, F_SETLK, &lock) != 0) { |
| err = errno; |
| if (err == EAGAIN) { |
| message(LOG_DAEMON|LOG_ERR, "PID file %s is already locked", |
| pid_fn); |
| } else { |
| message(LOG_DAEMON|LOG_ERR, "Cannot lock PID file %s: %s", |
| pid_fn, strerror(err)); |
| } |
| close(fd); |
| return -err; |
| } |
| |
| /* write file data */ |
| bytes = strlen(str); |
| s = str; |
| while (bytes > 0) { |
| ssize_t rc = write(fd, s, bytes); |
| if (rc < 0) { |
| err = errno; |
| message(LOG_DAEMON|LOG_ERR, "PID number write failed: %s", |
| strerror(err)); |
| goto err_out; |
| } |
| |
| bytes -= rc; |
| s += rc; |
| } |
| |
| /* make sure file data is written to disk */ |
| if (fsync(fd) < 0) { |
| err = errno; |
| message(LOG_DAEMON|LOG_ERR, "PID file fsync failed: %s", strerror(err)); |
| goto err_out; |
| } |
| |
| return fd; |
| |
| err_out: |
| unlink(pid_fn); |
| close(fd); |
| return -err; |
| } |
| |