E-MailRelay

gprocess.h
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 gprocess.h
19///
20
21#ifndef G_PROCESS_H
22#define G_PROCESS_H
23
24#include "gdef.h"
25#include "gexception.h"
26#include "gidentity.h"
27#include "gpath.h"
28#include "gstr.h"
29#include "gstringarray.h"
30#include "gsignalsafe.h"
31#include <memory>
32#include <utility>
33#include <iostream>
34#include <limits>
35#include <type_traits>
36#include <string>
37#include <new>
38
39 namespace G
40{
41 class Process ;
42 class NewProcess ;
43}
44
45//| \class G::Process
46/// A static interface for doing things with processes.
47/// \see G::Identity
48///
49 class G::Process
50{
51 public:
52 G_EXCEPTION( CannotChangeDirectory , tx("cannot change directory") )
53 G_EXCEPTION( InvalidId , tx("invalid process-id string") )
54 G_EXCEPTION( UidError , tx("cannot set uid") )
55 G_EXCEPTION( GidError , tx("cannot set gid") )
56 G_EXCEPTION( GetCwdError , tx("cannot get current working directory") )
57 class Id ;
58 class Umask ;
59 class UmaskImp ;
60
61 static void closeFiles( bool keep_stderr = false ) ;
62 ///< Closes all open file descriptors and reopens stdin,
63 ///< stdout and possibly stderr to the null device.
64
65 static void closeStderr() ;
66 ///< Closes stderr and reopens it to the null device.
67
68 static void closeOtherFiles( int fd_keep = -1 ) ;
69 ///< Closes all open file descriptors except the three
70 ///< standard ones and optionally one other.
71
72 static void inheritStandardFiles() ;
73 ///< Makes sure that the standard file descriptors
74 ///< are inherited.
75
76 static void cd( const Path & dir ) ;
77 ///< Changes directory.
78
79 static bool cd( const Path & dir , std::nothrow_t ) ;
80 ///< Changes directory. Returns false on error.
81
82 static int errno_( const SignalSafe & = G::SignalSafe() ) noexcept ;
83 ///< Returns the process's current 'errno' value.
84 ///< (Beware of destructors of c++ temporaries disrupting
85 ///< the global errno value.)
86
87 static void errno_( int e_new ) noexcept ;
88 ///< Sets the process's 'errno' value.
89
90 static int errno_( const SignalSafe & , int e_new ) noexcept ;
91 ///< Sets the process's 'errno' value. Returns the old
92 ///< value. Typically used in signal handlers.
93
94 static std::string strerror( int errno_ ) ;
95 ///< Translates an 'errno' value into a meaningful diagnostic string.
96 ///< The returned string is non-empty, even for a zero errno.
97
98 static std::string errorMessage( DWORD error ) ;
99 ///< Translates a GetLastError() value into a meaningful diagnostic string.
100 ///< The returned string is non-empty, even for a zero error number.
101
102 static std::pair<Identity,Identity> beOrdinaryAtStartup( const std::string & nobody , bool change_group ) ;
103 ///< Revokes special privileges (root or suid) at startup, possibly
104 ///< including extra group membership, making the named user the
105 ///< effective identity. Returns the new effective identity and the
106 ///< original effective identity as a pair.
107 ///<
108 ///< \code
109 ///< auto pair = Process::beOrdinaryAtStartup( "daemon" , chgrp ) ;
110 ///< Process::beSpecial( pair.second , chgrp ) ;
111 ///< doPrivilegedStuff() ;
112 ///< Process::beOrdinary( pair.first , chgrp ) ;
113 ///< \endcode
114
115 static void beOrdinary( Identity ordinary_id , bool change_group ) ;
116 ///< Releases special privileges.
117 ///<
118 ///< If the real-id is root then the effective user-id is changed to
119 ///< whatever is passed in. Otherwise the effective user-id is changed
120 ///< to the real user-id (optionally including the group), and the
121 ///< identity parameter is ignored.
122 ///<
123 ///< Logs an error message and throws on failure, resulting in a call
124 ///< to std::terminate() when called from a destructor (see G::Root).
125 ///<
126 ///< (Note that the identity switch applies to all threads in the
127 ///< calling processes, so some run-time libraries engage in signal
128 ///< shenanigans to synchronise the change across threads, which can
129 ///< lead to surprising interruptions of sleep(), select() etc.)
130 ///<
131 ///< See also class G::Root.
132
133 static void beSpecial( Identity special_id , bool change_group = true ) ;
134 ///< Re-acquires special privileges (either root or suid). The
135 ///< parameter must have come from a previous call to
136 ///< beOrdinaryAtStartup() and use the same change_group value.
137 ///<
138 ///< See also class G::Root.
139
140 static void beSpecialForExit( SignalSafe , Identity special_id ) noexcept ;
141 ///< A signal-safe version of beSpecial() that should only be used
142 ///< just before process exit.
143
144 static void beOrdinaryForExec( Identity run_as_id ) noexcept ;
145 ///< Sets the real and effective user-id and group-ids to those
146 ///< given, on a best-effort basis. Errors are ignored.
147
148 static void setEffectiveUser( Identity ) ;
149 ///< Sets the effective user-id. Throws on error.
150
151 static void setEffectiveGroup( Identity ) ;
152 ///< Sets the effective group-id. Throws on error.
153
154 static Path cwd() ;
155 ///< Returns the current working directory. Throws on error.
156
157 static Path cwd( std::nothrow_t ) ;
158 ///< Returns the current working directory. Returns the
159 ///< empty path on error.
160
161 static Path exe() ;
162 ///< Returns the absolute path of the current executable,
163 ///< independent of the argv array passed to main(). Returns
164 ///< the empty path if unknown.
165
166 class Id /// Process-id class.
167 {
168 public:
169 Id() noexcept ;
170 explicit Id( const char * , const char * end ) noexcept ;
171 explicit Id( int ) noexcept ;
172 explicit Id( std::istream & ) ;
173 static Id invalid() noexcept ;
174 std::string str() const ;
175 bool operator==( const Id & ) const noexcept ;
176 bool operator!=( const Id & ) const noexcept ;
177 template <typename T> T value(
178 typename std::enable_if
179 <std::numeric_limits<T>::max() >= std::numeric_limits<pid_t>::max()>
180 ::type * = 0 ) const noexcept
181 {
182 static_assert( sizeof(T) >= sizeof(pid_t) , "" ) ;
183 return static_cast<T>( m_pid ) ;
184 }
185 template <typename T> T seed() const noexcept
186 {
187 return static_cast<T>( m_pid ) ;
188 }
189
190 private:
191 friend class NewProcess ;
192 friend class Process ;
193 pid_t m_pid{0} ;
194 } ;
195
196 class Umask /// Used to temporarily modify the process umask.
197 {
198 public:
199 enum class Mode
200 {
201 NoChange , // typically 0022
202 TightenOther , // -......---
203 LoosenGroup , // -...rwx...
204 Readable , // 0022 -rw-r--r-- for open(0666) and -rwxr-xr-x for mkdir(0777)
205 Tighter , // 0007 -rw-rw---- for open(0666) and -rwxrwx--- for mkdir(0777)
206 Tightest , // 0077 -rw------- for open(0666) and -rwx------ for mkdir(0777)
207 GroupOpen ,// 0002 -rw-rw-r-- for open(0666) and -rwxrwxr-x for mkdir(0777)
208 Open // 0000 -rw-rw-rw- for open(0666) and -rwxrwxrwx for mkdir(0777)
209 } ;
210 explicit Umask( Mode ) ;
211 ~Umask() ;
212 static void set( Mode ) ;
213 static void tightenOther() ; // deny "other" access, user and group unchanged
214 static void loosenGroup() ; // allow group access, user and "other" unchanged
215 Umask( const Umask & ) = delete ;
216 Umask( Umask && ) = delete ;
217 Umask & operator=( const Umask & ) = delete ;
218 Umask & operator=( Umask && ) = delete ;
219
220 private:
221 std::unique_ptr<UmaskImp> m_imp ;
222 } ;
223
224 public:
225 Process() = delete ;
226
227 private:
228 static Path cwdImp( bool ) ;
229} ;
230
231 inline G::Process::Id::Id( int n ) noexcept :
232 m_pid(static_cast<pid_t>(n))
233{
234}
235
236 inline G::Process::Id::Id( std::istream & stream )
237{
238 stream >> m_pid ;
239}
240
241 inline G::Process::Id::Id( const char * p , const char * end ) noexcept
242{
243 bool overflow = false ;
244 m_pid = G::Str::toUnsigned<pid_t>( p , end , overflow ) ;
245 if( overflow )
246 m_pid = static_cast<pid_t>(-1) ;
247}
248
249 inline G::Process::Id G::Process::Id::invalid() noexcept
250{
251 return Id(-1) ;
252}
253
254 namespace G
255{
256 inline
257 std::ostream & operator<<( std::ostream & stream , const G::Process::Id & id )
258 {
259 return stream << id.str() ;
260 }
261}
262
263#endif
G::Identity
A combination of user-id and group-id, with a very low-level interface to the get/set/e/uid/gid funct...
Definition: gidentity.h:45
G::NewProcess
A class for creating new processes.
Definition: gnewprocess.h:62
G::Path
A Path object represents a file system path.
Definition: gpath.h:82
G::Process::Id
Process-id class.
Definition: gprocess.h:167
G::Process::Umask
Used to temporarily modify the process umask.
Definition: gprocess.h:197
G::Process
A static interface for doing things with processes.
Definition: gprocess.h:50
G::Process::beSpecialForExit
static void beSpecialForExit(SignalSafe, Identity special_id) noexcept
A signal-safe version of beSpecial() that should only be used just before process exit.
Definition: gprocess_unix.cpp:162
G::Process::closeOtherFiles
static void closeOtherFiles(int fd_keep=-1)
Closes all open file descriptors except the three standard ones and optionally one other.
Definition: gprocess_unix.cpp:104
G::Process::cwd
static Path cwd()
Returns the current working directory. Throws on error.
Definition: gprocess_unix.cpp:210
G::Process::beOrdinaryAtStartup
static std::pair< Identity, Identity > beOrdinaryAtStartup(const std::string &nobody, bool change_group)
Revokes special privileges (root or suid) at startup, possibly including extra group membership,...
Definition: gprocess_unix.cpp:167
G::Process::beSpecial
static void beSpecial(Identity special_id, bool change_group=true)
Re-acquires special privileges (either root or suid).
Definition: gprocess_unix.cpp:157
G::Process::strerror
static std::string strerror(int errno_)
Translates an 'errno' value into a meaningful diagnostic string.
Definition: gprocess_unix.cpp:142
G::Process::beOrdinaryForExec
static void beOrdinaryForExec(Identity run_as_id) noexcept
Sets the real and effective user-id and group-ids to those given, on a best-effort basis.
Definition: gprocess_unix.cpp:191
G::Process::exe
static Path exe()
Returns the absolute path of the current executable, independent of the argv array passed to main().
Definition: gprocess_unix.cpp:265
G::Process::setEffectiveGroup
static void setEffectiveGroup(Identity)
Sets the effective group-id. Throws on error.
Definition: gprocess_unix.cpp:204
G::Process::closeStderr
static void closeStderr()
Closes stderr and reopens it to the null device.
Definition: gprocess_unix.cpp:85
G::Process::inheritStandardFiles
static void inheritStandardFiles()
Makes sure that the standard file descriptors are inherited.
Definition: gprocess_unix.cpp:118
G::Process::beOrdinary
static void beOrdinary(Identity ordinary_id, bool change_group)
Releases special privileges.
Definition: gprocess_unix.cpp:186
G::Process::errno_
static int errno_(const SignalSafe &=G::SignalSafe()) noexcept
Returns the process's current 'errno' value.
Definition: gprocess_unix.cpp:125
G::Process::setEffectiveUser
static void setEffectiveUser(Identity)
Sets the effective user-id. Throws on error.
Definition: gprocess_unix.cpp:197
G::Process::closeFiles
static void closeFiles(bool keep_stderr=false)
Closes all open file descriptors and reopens stdin, stdout and possibly stderr to the null device.
Definition: gprocess_unix.cpp:90
G::Process::cd
static void cd(const Path &dir)
Changes directory.
Definition: gprocess_unix.cpp:74
G::Process::errorMessage
static std::string errorMessage(DWORD error)
Translates a GetLastError() value into a meaningful diagnostic string.
Definition: gprocess_unix.cpp:151
G::SignalSafe
An empty structure that is used to indicate a signal-safe, reentrant implementation.
Definition: gsignalsafe.h:37
gexception.h
gidentity.h
gpath.h
gsignalsafe.h
gstr.h
gstringarray.h
G
Low-level classes.
Definition: garg.h:36
G::tx
constexpr const char * tx(const char *p) noexcept
A briefer alternative to G::gettext_noop().
Definition: ggettext.h:84