E-MailRelay
gpidfile.cpp
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2023 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#include <array>
32
33#ifndef G_LIB_SMALL
35= default;
36#endif
37
38G::PidFile::PidFile( const Path & path ) :
39 m_path((!path.empty()&&path.isRelative())?Path::join(Process::cwd(),path):path)
40{
41}
42
44{
45 if( !m_path.empty() )
46 {
47 bool done = cleanup( SignalSafe() , m_path.cstr() ) ;
48 if( !done )
49 {
50 Root::atExit() ;
51 cleanup( SignalSafe() , m_path.cstr() ) ;
52 }
53 }
54}
55
57{
58 if( !m_path.empty() )
59 File::mkdir( m_path.dirname() , std::nothrow ) ;
60}
61
62void G::PidFile::create( const Path & pid_file )
63{
64 if( !pid_file.empty() )
65 {
66 // (the effective user-id and umask is set by the caller)
67 std::ofstream file ;
68 File::open( file , pid_file , File::Text() ) ;
69 int e = G::Process::errno_() ;
70 if( !file.good() )
71 throw Error( "cannot create file" , pid_file.str() , G::Process::strerror(e) ) ;
72 Process::Id pid ;
73 file << pid.str() << std::endl ;
74 file.close() ;
75 if( file.fail() )
76 throw Error( "cannot write file" , pid_file.str() ) ;
77
78 // (leak only if necessary)
79 static constexpr std::size_t buffer_size = 60U ; // eg. "/var/run/whatever/whatever.pid"
80 static std::array<char,buffer_size> buffer {} ;
81 const char * cleanup_arg = &buffer[0] ;
82 if( buffer[0] == '\0' && pid_file.size() < buffer.size() )
83 G::Str::strncpy_s( &buffer[0] , buffer.size() , pid_file.cstr() , pid_file.size() ) ;
84 else
85 cleanup_arg = Cleanup::strdup( pid_file.str() ) ;
86
87 Cleanup::add( cleanup , cleanup_arg ) ;
88 }
89}
90
91G::Process::Id G::PidFile::read( SignalSafe , const char * path ) noexcept
92{
93 int fd = File::open( path , File::InOutAppend::In ) ;
94 if( fd < 0 )
95 return Process::Id::invalid() ;
96
97 constexpr std::size_t buffer_size = 11U ;
98 std::array<char,buffer_size> buffer {} ;
99 buffer[0U] = '\0' ;
100
101 ssize_t rc = File::read( fd , &buffer[0] , buffer_size-1U ) ;
102 File::close( fd ) ;
103 if( rc <= 0 )
104 return Process::Id::invalid() ;
105
106 return Process::Id( &buffer[0] , &buffer[0]+static_cast<std::size_t>(rc) ) ;
107}
108
109bool G::PidFile::cleanup( SignalSafe safe , const char * path ) noexcept
110{
111 try
112 {
113 if( path == nullptr || *path == '\0' )
114 return true ; // nothing to do
115
116 Process::Id this_pid ;
117 Process::Id file_pid = read( safe , path ) ;
118 if( this_pid != file_pid )
119 return false ; // try again in case we didnt have read permission
120
121 return 0 == std::remove( path ) ;
122 }
123 catch(...)
124 {
125 return false ;
126 }
127}
128
130{
131 if( !m_path.empty() )
132 {
133 create( m_path ) ;
134 m_committed = true ;
135 }
136}
137
139{
140 return m_committed ;
141}
142
144{
145 return m_path ;
146}
147
static const char * strdup(const char *)
A strdup() function that makes it clear in the stack trace that leaks are expected.
static void add(bool(*fn)(SignalSafe, const char *), const char *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:63
static void open(std::ofstream &, const Path &)
Calls open() on the given output file stream.
Definition: gfile_unix.cpp:55
static void close(int fd) noexcept
Calls ::close() or equivalent.
Definition: gfile_unix.cpp:149
static ssize_t read(int fd, char *, std::size_t) noexcept
Calls ::read() or equivalent.
Definition: gfile_unix.cpp:139
static bool mkdir(const Path &dir, std::nothrow_t)
Creates a directory.
Definition: gfile.cpp:245
A Path object represents a file system path.
Definition: gpath.h:73
const char * cstr() const noexcept
Returns the path string.
Definition: gpath.h:230
std::size_t size() const noexcept
Returns the length of the path string.
Definition: gpath.h:218
std::string str() const
Returns the path string.
Definition: gpath.h:224
bool empty() const noexcept
Returns true if size() is zero.
Definition: gpath.h:212
bool committed() const
Returns true if commit() has been called with a valid path().
Definition: gpidfile.cpp:138
void commit()
Creates the pid file if a path has been defined.
Definition: gpidfile.cpp:129
PidFile()
Default constructor.
~PidFile()
Destructor. Calls cleanup() to delete the file.
Definition: gpidfile.cpp:43
void mkdir()
Creates the directory if it does not already exist.
Definition: gpidfile.cpp:56
Path path() const
Returns the full path of the file.
Definition: gpidfile.cpp:143
static bool cleanup(SignalSafe, const char *path) noexcept
Deletes the specified pid file if it contains this process's id.
Definition: gpidfile.cpp:109
Process-id class.
Definition: gprocess.h:155
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
An empty structure that is used to indicate a signal-safe, reentrant implementation.
Definition: gsignalsafe.h:37
static errno_t strncpy_s(char *dst, std::size_t n_dst, const char *src, std::size_t count) noexcept
Does the same as windows strncpy_s().
Definition: gstr.cpp:1493