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