E-MailRelay
gpidfile.cpp
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2024 Graeme Walker <graeme_walker@users.sourceforge.net>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16// ===
17///
18/// \file gpidfile.cpp
19///
20
21#include "gdef.h"
22#include "gpidfile.h"
23#include "gprocess.h"
24#include "groot.h"
25#include "gstr.h"
26#include "gcleanup.h"
27#include "gfile.h"
28#include "glog.h"
29#include <fstream>
30#include <string>
31
32namespace G
33{
34 namespace PidFileImp
35 {
36 Process::Id read( SignalSafe , const char * path ) ;
37 bool cleanup( const Cleanup::Arg & ) noexcept ;
38 bool cleanup( const Path & ) noexcept ;
39 }
40}
41
42#ifndef G_LIB_SMALL
44= default;
45#endif
46
47G::PidFile::PidFile( const Path & path ) :
48 m_path((!path.empty()&&path.isRelative())?Path::join(Process::cwd(),path):path)
49{
50}
51
53{
54 static_assert( noexcept(m_path.cstr()) , "" ) ;
55 static_assert( noexcept(m_path.empty()) , "" ) ;
56 static_assert( noexcept(PidFileImp::cleanup(m_path)), "" ) ;
57 static_assert( noexcept(Root::atExit()) , "" ) ;
58 if( !m_path.empty() )
59 {
60 bool done = PidFileImp::cleanup( m_path ) ;
61 if( !done )
62 {
63 Root::atExit() ;
64 PidFileImp::cleanup( m_path ) ;
65 }
66 }
67}
68
70{
71 if( !m_path.empty() )
72 File::mkdir( m_path.dirname() , std::nothrow ) ;
73}
74
75void G::PidFile::create( const Path & pid_file )
76{
77 if( !pid_file.empty() )
78 {
79 // (the effective user-id and umask is set by the caller)
80 std::ofstream file ;
81 File::open( file , pid_file , File::Text() ) ;
82 int e = G::Process::errno_() ;
83 if( !file.good() )
84 throw Error( "cannot create file" , pid_file.str() , G::Process::strerror(e) ) ;
85 Process::Id pid ;
86 file << pid.str() << std::endl ;
87 file.close() ;
88 if( file.fail() )
89 throw Error( "cannot write file" , pid_file.str() ) ;
90
91 Cleanup::add( PidFileImp::cleanup , Cleanup::arg(pid_file) ) ;
92 }
93}
94
96{
97 if( !m_path.empty() )
98 {
99 create( m_path ) ;
100 m_committed = true ;
101 }
102}
103
105{
106 return m_committed ;
107}
108
110{
111 return m_path ;
112}
113
114// --
115
116bool G::PidFileImp::cleanup( const Path & path ) noexcept
117{
118 try
119 {
120 int fd = File::open( path , File::InOutAppend::In ) ;
121 if( fd < 0 )
122 return false ;
123
124 constexpr std::size_t buffer_size = 11U ;
125 std::array<char,buffer_size> buffer {} ;
126 buffer[0U] = '\0' ;
127
128 ssize_t rc = File::read( fd , buffer.data() , buffer_size-1U ) ;
129 File::close( fd ) ;
130 if( rc <= 0 )
131 return false ;
132
133 Process::Id file_pid( buffer.data() , buffer.data()+static_cast<std::size_t>(rc) ) ;
134
135 Process::Id this_pid ;
136 if( this_pid != file_pid )
137 return false ; // not our pid file -- false => try again
138
139 return File::remove( path , std::nothrow ) ;
140 }
141 catch(...)
142 {
143 return false ;
144 }
145}
146
147bool G::PidFileImp::cleanup( const Cleanup::Arg & arg ) noexcept
148{
149 try
150 {
151 return cleanup( Path(arg.str()) ) ;
152 }
153 catch(...)
154 {
155 return false ;
156 }
157}
158
static Arg arg(const char *)
Duplicates a c-string for add().
static void add(Fn, Arg arg)
Adds the given handler to the list of handlers that are to be called when the process terminates abno...
An overload discriminator for G::File::open().
Definition: gfile.h:64
static void open(std::ofstream &, const Path &)
Calls open() on the given output file stream.
Definition: gfile_unix.cpp:56
static void close(int fd) noexcept
Calls ::close() or equivalent.
Definition: gfile_unix.cpp:159
static bool remove(const Path &path, std::nothrow_t) noexcept
Deletes the file or directory. Returns false on error.
Definition: gfile_unix.cpp:177
static ssize_t read(int fd, char *, std::size_t) noexcept
Calls read() or equivalent.
Definition: gfile_unix.cpp:149
static bool mkdir(const Path &dir, std::nothrow_t)
Creates a directory.
Definition: gfile.cpp:235
A Path object represents a file system path.
Definition: gpath.h:82
std::string str() const
Returns the path string.
Definition: gpath.h:243
bool empty() const noexcept
Returns true if the path is empty.
Definition: gpath.h:237
bool committed() const
Returns true if commit() has been called with a valid path().
Definition: gpidfile.cpp:104
void commit()
Creates the pid file if a path has been defined.
Definition: gpidfile.cpp:95
PidFile()
Default constructor.
~PidFile()
Destructor. Deletes the file.
Definition: gpidfile.cpp:52
void mkdir()
Creates the directory if it does not already exist.
Definition: gpidfile.cpp:69
Path path() const
Returns the full path of the file.
Definition: gpidfile.cpp:109
Process-id class.
Definition: gprocess.h:167
A static interface for doing things with processes.
Definition: gprocess.h:50
static std::string strerror(int errno_)
Translates an 'errno' value into a meaningful diagnostic string.
static int errno_(const SignalSafe &=G::SignalSafe()) noexcept
Returns the process's current 'errno' value.
static void atExit() noexcept
Re-acquires special privileges just before process exit.
Definition: groot.cpp:68
Low-level classes.
Definition: garg.h:36