Hi --
I recently needed to wire up httpd's rotatelogs to a named pipe (a FIFO)
instead of to stdin. For context, we have a non-httpd server process
configured to write to the pipe instead of a log file; further, this
server likes to intermittently open, write to, and close its various
log files.
I wanted/needed to open the pipe in non-blocking mode, so rotatelogs
would start right away (we're using rotatelogs -cf) instead of blocking
until a writer process happened to open the pipe to write some log data.
My first attempt was to open the pipe as a regular file using
apr_file_open(), then extract the fd with apr_os_file_get(), use it
to create an APR pipe with apr_os_pipe_put(), and then set the
non-blocking status with apr_file_pipe_timeout_set(). That doesn't
work with APR 1.4.x, though, because the initial file open lacks
O_NONBLOCK.
With APR trunk I could use APR_FOPEN_NONBLOCK, but even so it's
a bit of a workaround for something which I thought would be simple.
At any rate, here's what I ended up with, an apr_file_namedpipe_open()
call which tries to align with the usage of the 1.4.x APR_*_BLOCK flags
in apr_file_pipe_create_ex(), although all that's really needed is
a simple Boolean -- but we don't have APR_FOPEN_NONBLOCK in 1.4.x.
Unlike the apr_file_open() trick I tried first, it won't let you
open a non-pipe by accident, and it will set the timeout and blocking
flags right away.
I'm sure others can improve on this (e.g., using APR_FOPEN_NONBLOCK
instead of the APR_*_BLOCK values), and/or see reasons not to include it
(I didn't try a Windows version, for example). But perhaps it'll help
the next person, at least. I'll post my rotatelogs patch over on
dev@httpd in a moment.
Chris.
===================================================================
--- include/apr_file_io.h.orig 2012-12-18 13:15:01.000000000 -0800
+++ include/apr_file_io.h 2012-12-18 13:17:48.000000000 -0800
@@ -741,6 +741,33 @@
apr_pool_t *pool);
/**
+ * Open a named pipe.
+ * @param file The opened file descriptor.
+ * @param fname The full path to the file (using / on all systems)
+ * @param flag Or'ed value of:
+ * <PRE>
+ * APR_READ open for reading
+ * APR_WRITE open for writing
+ * </PRE>
+ * @param blocking one of these values defined in apr_thread_proc.h:
+ * <pre>
+ * APR_FULL_BLOCK
+ * APR_READ_BLOCK
+ * APR_WRITE_BLOCK
+ * APR_FULL_NONBLOCK
+ * </pre>
+ * @param pool The pool to operate on.
+ * @remark By default, the returned file descriptors will be inherited
+ * by child processes created using apr_proc_create(). This can be
+ * changed using apr_file_inherit_unset().
+ */
+APR_DECLARE(apr_status_t) apr_file_namedpipe_open(apr_file_t **file,
+ const char *fname,
+ apr_int32_t flag,
+ apr_int32_t blocking,
+ apr_pool_t *pool);
+
+/**
* Create a named pipe.
* @param filename The filename of the named pipe
* @param perm The permissions for the newly created pipe.
===================================================================
--- file_io/unix/pipe.c.orig 2012-12-18 13:19:53.000000000 -0800
+++ file_io/unix/pipe.c 2012-12-18 13:17:33.000000000 -0800
@@ -249,6 +249,70 @@
return APR_SUCCESS;
}
+APR_DECLARE(apr_status_t) apr_file_namedpipe_open(apr_file_t **file,
+ const char *fname,
+ apr_int32_t flag,
+ apr_int32_t blocking,
+ apr_pool_t *pool)
+{
+ apr_os_file_t fd;
+ int oflags = 0;
+ int oblock = 0;
+ struct_stat info;
+
+ if ((flag & APR_FOPEN_READ) && (flag & APR_FOPEN_WRITE)) {
+ oflags = O_RDWR;
+ oblock = (blocking != APR_FULL_NONBLOCK);
+ }
+ else if (flag & APR_FOPEN_READ) {
+ oflags = O_RDONLY;
+ oblock = (blocking == APR_FULL_BLOCK || blocking == APR_READ_BLOCK);
+ }
+ else if (flag & APR_FOPEN_WRITE) {
+ oflags = O_WRONLY;
+ oblock = (blocking == APR_FULL_BLOCK || blocking == APR_WRITE_BLOCK);
+ }
+ else {
+ return APR_EACCES;
+ }
+
+ if (!oblock) {
+ oflags |= O_NONBLOCK;
+ }
+
+ fd = open(fname, oflags);
+ if (fd < 0) {
+ return errno;
+ }
+
+ if (fstat(fd, &info) != 0) {
+ apr_status_t rv = errno;
+
+ close(fd);
+ return rv;
+ }
+#if defined(S_IFFIFO)
+ if ((info.st_mode & S_IFMT) != S_IFFIFO) {
+#elif defined(S_ISFIFO)
+ if (!S_ISFIFO(info.st_mode)) {
+#else
+ {
+#endif
+ close(fd);
+ return EBADF;
+ }
+
+ apr_os_pipe_put_ex(file, &fd, 1, pool);
+
+ if (blocking) {
+ pipeblock(*file);
+ } else {
+ pipenonblock(*file);
+ }
+
+ return APR_SUCCESS;
+}
+
APR_DECLARE(apr_status_t) apr_file_namedpipe_create(const char *filename,
apr_fileperms_t perm, apr_pool_t *pool)
{
===================================================================
--
GPG Key ID: 088335A9
GPG Key Fingerprint: 86CD 3297 7493 75BC F820 6715 F54F E648 0883 35A9