lib: added FifoArgs API, for use in passing command line args without command line
[barry/progweb.git] / src / fifoargs.cc
blob0cd7781e6ab3627e5b166fdf573362afbfdb3ab2
1 ///
2 /// \file fifoargs.cc
3 /// Class for passing command line arguments via fifo instead
4 /// of command line.
5 ///
7 /*
8 Copyright (C) 2012, Net Direct Inc. (http://www.netdirect.ca/)
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License in the COPYING file at the
20 root directory of this project for more details.
23 #include "fifoargs.h"
24 #include "error.h"
25 #include "common.h"
26 #include <iostream>
27 #include <sstream>
28 #include <iomanip>
29 #include <string>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <errno.h>
36 using namespace std;
38 namespace Barry {
40 //////////////////////////////////////////////////////////////////////////////
41 // FifoArgs class
43 std::ostream& FifoArgs::Write(std::ostream &os) const
45 if( m_pin.Valid() )
46 os << "Pin " << m_pin.Str() << endl;
47 if( m_password.size() )
48 os << "Password " << m_password << endl;
49 if( m_log_filename.size() )
50 os << "LogFilename " << m_log_filename << endl;
51 if( m_use_serial_mode )
52 os << "UseSerialMode" << endl;
53 if( m_verbose )
54 os << "Verbose" << endl;
56 return os;
59 std::istream& FifoArgs::Read(std::istream &is)
61 string line, token, arg;
63 // start fresh
64 Clear();
66 while( getline(is, line) ) {
67 istringstream iss(line);
68 iss >> token >> ws;
70 if( token == "Pin" )
71 iss >> m_pin;
72 else if( token == "Password" )
73 getline(iss, m_password);
74 else if( token == "LogFilename" )
75 getline(iss, m_log_filename);
76 else if( token == "UseSerialMode" )
77 m_use_serial_mode = true;
78 else if( token == "Verbose" )
79 m_verbose = true;
82 return is;
85 void FifoArgs::Clear()
87 m_pin.Clear();
88 m_password.clear();
89 m_log_filename.clear();
90 m_use_serial_mode = false;
91 m_verbose = false;
95 //////////////////////////////////////////////////////////////////////////////
96 // FifoServer class
98 FifoServer::FifoServer(const FifoArgs &args)
99 : m_args(args)
100 , m_created(false)
102 int m_fifo = mkfifo(BARRY_FIFO_NAME, 0660);
103 if( m_fifo != 0 )
104 throw ErrnoError("Cannot open Barry argument fifo", errno);
105 m_created = true;
108 FifoServer::~FifoServer()
110 Cleanup();
113 bool FifoServer::Serve(int timeout_sec)
115 if( !m_created )
116 return false;
118 // man fifo(7) says that opening write-only in non-blocking mode
119 // will fail until the other side opens for read. So continue
120 // to attempt opens until out of time.
121 timeout_sec *= 4;
122 while( timeout_sec-- ) {
123 // attempt to open in non-blocking mode
124 int fd = open(BARRY_FIFO_NAME, O_WRONLY | O_NONBLOCK);
125 if( fd == -1 ) {
126 usleep(250000);
127 continue;
130 ostringstream oss;
131 m_args.Write(oss);
132 int written = write(fd, oss.str().data(), oss.str().size());
133 close(fd);
135 // only success if we wrote all the data
136 return written == (int)oss.str().size();
139 // timeout
140 return false;
143 void FifoServer::Cleanup()
145 if( m_created ) {
146 unlink(BARRY_FIFO_NAME);
147 m_created = false;
152 //////////////////////////////////////////////////////////////////////////////
153 // FifoClient class
155 FifoClient::FifoClient()
159 /// Tries to open the fifo and read the arguments from it.
160 /// If it fails in any way, or timeout, returns false.
161 bool FifoClient::Fetch(int timeout_sec)
163 // See man fifo(7). Should always succeed, as long as
164 // the file exists and permissions allow.
165 int fd = open(BARRY_FIFO_NAME, O_RDONLY | O_NONBLOCK);
166 if( fd == -1 )
167 return false;
169 string sbuf;
170 timeout_sec *= 4;
171 while( timeout_sec-- ) {
172 char buf[4096];
173 int r = read(fd, buf, sizeof(buf));
175 if( r == 0 ) {
176 // only consider this the end of file if
177 // we've already read something, otherwise we close
178 // before the server has a chance to speak up
179 if( sbuf.size() )
180 break;
181 else
182 usleep(250000);
184 else if( r < 0 ) {
185 usleep(250000);
186 continue;
188 else {
189 timeout_sec++;
190 sbuf.append(buf, r);
193 close(fd);
195 // parse
196 istringstream iss(sbuf);
197 m_args.Read(iss);
198 return true;
201 } // Barry namespace