00001 /* 00002 Copyright 2003 by Marc J. Rochkind. All rights reserved. 00003 May be copied only for purposes and under conditions described 00004 on the Web page www.basepath.com/aup/copyright.htm. 00005 00006 The Example Files are provided "as is," without any warranty; 00007 without even the implied warranty of merchantability or fitness 00008 for a particular purpose. The author and his publisher are not 00009 responsible for any damages, direct or incidental, resulting 00010 from the use or non-use of these Example Files. 00011 00012 The Example Files may contain defects, and some contain deliberate 00013 coding mistakes that were included for educational reasons. 00014 You are responsible for determining if and how the Example Files 00015 are to be used. 00016 00017 */ 00018 #ifdef SOLARIS 00019 // needed for setegid and seteuid 00020 #define __EXTENSIONS__ 00021 #endif 00022 00023 /* 00024 Need to prevent GNU from using the wrong prototype for functions declared in 00025 sys/resource.h (see comment there). As sys/wait.h (included by defs.h) brings 00026 in this include (on GNU systems, anyway), there is a special symbol (AUP2_SKIP_WAIT) 00027 used in defs.h to suppress that include. Also, we should not have to undef __USE_GNU 00028 (I think), we seem to have to do that as well. 00029 00030 (It would have been much better if the GNU folks had not tried to improve things!) 00031 */ 00032 00033 #define AUP2_SKIP_WAIT 00034 #include "defs.h" 00035 00036 #ifdef _GNU_SOURCE 00037 #define _GNU_SOURCE_WAS_DEFINED 00038 #undef _GNU_SOURCE 00039 #undef __USE_GNU 00040 #endif 00041 #include <sys/resource.h> 00042 #ifdef _GNU_SOURCE_WAS_DEFINED 00043 #define _GNU_SOURCE 00044 #undef _GNU_SOURCE_WAS_DEFINED 00045 #endif 00046 00047 #include <sys/wait.h> // now it is OK to bring it in 00048 #include "ux.hpp" // and now everything else can come in 00049 00050 using namespace Ux; 00051 00052 /** 00053 Calls ::atexit. 00054 */ 00055 /* static */ void Process::atexit(void (*fcn)(void)) 00056 { 00057 errno = 0; // SUS doesn't say it's set on error 00058 if (::atexit(fcn) != 0) 00059 throw Error(errno); 00060 } 00061 00062 /** 00063 Calls ::chdir. 00064 */ 00065 /* static */ void Process::chdir(const char *path) 00066 { 00067 if (::chdir(path) == -1) 00068 throw Error(errno); 00069 } 00070 00071 /** 00072 Calls ::fchdir. 00073 */ 00074 /* static */ void Process::chdir(int fd) 00075 { 00076 if (::fchdir(fd) == -1) 00077 throw Error(errno); 00078 } 00079 00080 /** 00081 Calls ::chroot. 00082 */ 00083 /* static */ void Process::chroot(const char *path) 00084 { 00085 if (::chroot(path) == -1) 00086 throw Error(errno); 00087 } 00088 00089 /** 00090 Calls ::clock. 00091 */ 00092 /* static */ clock_t Process::clock(void) 00093 { 00094 clock_t c; 00095 00096 errno = 0; 00097 if ((c = ::clock()) == -1) { 00098 if (errno == 0) 00099 throw Error(EINVAL); 00100 else 00101 throw Error(errno); 00102 } 00103 return c; 00104 } 00105 00106 /** 00107 Calls ::execvp after building a vector from the arguments. (Not feasible to call ::execlp, 00108 as there's no portable way to pass it the arguments as a list.) 00109 */ 00110 /* static */ void Process::execlp(const char *file, const char *arg0, ...) 00111 { 00112 va_list ap; 00113 int count; 00114 00115 va_start(ap, arg0); 00116 for (count = 1; va_arg(ap, char *) != NULL; count++) 00117 ; 00118 va_end(ap); 00119 char **argv = new char*[count + 1]; 00120 if (argv == NULL) 00121 throw Error(ENOMEM); 00122 va_start(ap, arg0); 00123 argv[0] = (char *)arg0; 00124 for (count = 1; (argv[count] = va_arg(ap, char *)) != NULL; count++) 00125 ; 00126 va_end(ap); 00127 (void)::execvp(file, argv); 00128 delete [] argv; 00129 throw Error(errno); 00130 } 00131 00132 00133 /** 00134 Calls ::execvp, first setting the global environ to the argument if it's non-NULL. 00135 environ is restored if the call fails. Not thread safe, as setting and re-setting of 00136 environ isn't protected with a mutex. (It's not that important for an exec call to be 00137 thread safe, since calling it with more than one thread active is not good practice anyway.) 00138 */ 00139 /* static */ void Process::execvpe(const char *file, char *const argv[], char *const *envv = NULL) 00140 { 00141 extern char **environ; 00142 00143 char **environ_save = environ; 00144 if (envv != NULL) 00145 environ = (char **)envv; 00146 (void)execvp(file, argv); 00147 environ = environ_save; 00148 throw Error(errno); 00149 } 00150 00151 /** 00152 Calls ::fork. Returns a Process, which is automatically converted to a pid_t if necessary. 00153 */ 00154 /* static */ Process Process::fork(void) 00155 { 00156 pid_t rtn_pid; 00157 00158 if ((rtn_pid = ::fork()) == -1) 00159 throw Error(errno); 00160 return Process(rtn_pid); 00161 } 00162 00163 /** 00164 Calls ::getcwd. Dir argument must have space allocated with File::alloc, 00165 or at least the size and path members set properly. 00166 */ 00167 /* static */ void Process::getcwd(Dir& d) 00168 { 00169 if (d.get_size() < 0) 00170 throw Error(ENOMEM); 00171 // overriding const -- user better have supplied buffer! 00172 if (::getcwd((char *)(const char *)d, d.get_size()) == NULL) 00173 throw(errno); 00174 } 00175 00176 /** 00177 Calls ::getenv. Does not throw error; returns NULL if not found. 00178 */ 00179 /* static */ char* Process::getenv(const char *var) 00180 { 00181 return ::getenv(var); 00182 } 00183 00184 /** 00185 Calls ::getpgid. 00186 */ 00187 /* static */ pid_t Process::getpgid(pid_t pid) 00188 { 00189 pid_t rtn_pid; 00190 00191 if ((rtn_pid = ::getpgid(pid)) == -1) 00192 throw Error(errno); 00193 return rtn_pid; 00194 } 00195 00196 /** 00197 Calls ::getrlimit. 00198 */ 00199 /* static */ void Process::getrlimit(int resource, struct rlimit *rlp) 00200 { 00201 if (::getrlimit(resource, rlp) == -1) 00202 throw Error(errno); 00203 } 00204 00205 /** 00206 Calls ::getrusage. 00207 */ 00208 /* static */ void Process::getrusage(int who, struct rusage *r_usage) 00209 { 00210 if (::getrusage(who, r_usage) == -1) 00211 throw Error(errno); 00212 } 00213 00214 /** 00215 Calls ::getsid, for this process. getsid(0) (getsid of calling process) not 00216 implemented and not needed, since a Process is initialized to the calling process 00217 by default. 00218 */ 00219 pid_t Process::getsid(void) 00220 { 00221 pid_t rtn_pid; 00222 00223 if ((rtn_pid = ::getsid(pid)) == -1) 00224 throw Error(errno); 00225 return rtn_pid; 00226 } 00227 00228 /** 00229 Calls ::kill. 00230 */ 00231 /* static */ void Process::kill(pid_t pid, int signum) 00232 { 00233 if (::kill(pid, signum) == -1) 00234 throw Error(errno); 00235 } 00236 00237 /** 00238 Calls ::nice. 00239 */ 00240 /* static */ void Process::nice(int incr) 00241 { 00242 if (::nice(incr) == -1) 00243 throw Error(errno); 00244 } 00245 00246 /** 00247 Calls ::pause. 00248 */ 00249 /* static */ void Process::pause(void) 00250 { 00251 if (::pause() == -1 && errno != EINTR) 00252 throw Error(errno); 00253 } 00254 00255 /** 00256 Calls ::putenv. 00257 */ 00258 /* static */ void Process::putenv(char *string) 00259 { 00260 if (::putenv(string) != 0) 00261 throw Error(errno); 00262 } 00263 00264 /** 00265 Calls ::setegid. 00266 */ 00267 /* static */ void Process::setegid(gid_t gid) 00268 { 00269 if (::setegid(gid) == -1) 00270 throw Error(errno); 00271 } 00272 00273 /** 00274 Calls ::setenv. 00275 */ 00276 /* static */ void Process::setenv(const char *var, const char *val, int overwrite) 00277 { 00278 #if _XOPEN_VERSION >= 600 || defined(FREEBSD) || defined(LINUX) 00279 if (::setenv(var, val, overwrite) == -1) 00280 throw Error(errno); 00281 #else 00282 throw Error(ENOSYS); 00283 #endif 00284 } 00285 00286 /** 00287 Calls ::seteuid. 00288 */ 00289 /* static */ void Process::seteuid(uid_t uid) 00290 { 00291 if (::seteuid(uid) == -1) 00292 throw Error(errno); 00293 } 00294 00295 /** 00296 Calls ::setgid. 00297 */ 00298 /* static */ void Process::setgid(gid_t gid) 00299 { 00300 if (::setgid(gid) == -1) 00301 throw Error(errno); 00302 } 00303 00304 /** 00305 Calls ::setpgid. 00306 */ 00307 /* static */ void Process::setpgid(pid_t pid, pid_t pgid) 00308 { 00309 if (::setpgid(pid, pgid) == -1) 00310 throw Error(errno); 00311 } 00312 00313 /** 00314 Calls ::setrlimit. 00315 */ 00316 /* static */ void Process::setrlimit(int resource, const struct rlimit *rlp) 00317 { 00318 if (::setrlimit(resource, rlp) == -1) 00319 throw Error(errno); 00320 } 00321 00322 /** 00323 Calls ::setsid. 00324 */ 00325 /* static */ pid_t Process::setsid(void) 00326 { 00327 pid_t rtn_pid; 00328 00329 if ((rtn_pid = ::setsid()) == -1) 00330 throw Error(errno); 00331 return rtn_pid; 00332 } 00333 00334 /** 00335 Calls ::setuid. 00336 */ 00337 /* static */ void Process::setuid(uid_t uid) 00338 { 00339 if (::setuid(uid) == -1) 00340 throw Error(errno); 00341 } 00342 00343 /** 00344 Calls ::sigaction. 00345 */ 00346 /* static */ void Process::sigaction(int signum, const struct sigaction *act, struct sigaction *oact) 00347 { 00348 if (::sigaction(signum, act, oact) == -1) 00349 throw Error(errno); 00350 } 00351 00352 /** 00353 Calls ::sigaltstack. 00354 */ 00355 /* static */ void Process::sigaltstack(const stack_t *stack, stack_t *ostack) 00356 { 00357 if (::sigaltstack(stack, ostack) == -1) 00358 throw Error(errno); 00359 } 00360 00361 /** 00362 Calls ::siginterrupt. 00363 */ 00364 /* static */ void Process::siginterrupt(int signum, int on) 00365 { 00366 if (::siginterrupt(signum, on) == -1) 00367 throw Error(errno); 00368 } 00369 00370 /** 00371 Calls ::sigprocmask. 00372 */ 00373 /* static */ void Process::sigprocmask(int how, const sigset_t *set, sigset_t *oset) 00374 { 00375 if (::sigprocmask(how, set, oset) == -1) 00376 throw Error(errno); 00377 } 00378 00379 /** 00380 Calls ::sigqueue. 00381 */ 00382 void Process::sigqueue(int signum, const union sigval value) 00383 { 00384 #ifdef _POSIX_REALTIME_SIGNALS 00385 if (::sigqueue(pid, signum, value) == -1) 00386 throw Error(errno); 00387 #else 00388 throw Error(ENOSYS); 00389 #endif 00390 } 00391 00392 /** 00393 Calls ::sigsuspend. 00394 */ 00395 /* static */ void Process::sigsuspend(const sigset_t *sigmask) 00396 { 00397 if (::sigsuspend(sigmask) == -1) 00398 throw Error(errno); 00399 } 00400 /* Returns -1 on error, always (sets errno) */ 00401 00402 /** 00403 Calls ::sigtimedwait. 00404 */ 00405 /* static */ int Process::sigtimedwait(const sigset_t *set, siginfo_t *info, const struct timespec *ts) 00406 { 00407 #ifdef _POSIX_REALTIME_SIGNALS 00408 int r; 00409 00410 if ((r = ::sigtimedwait(set, info, ts)) == -1) 00411 throw Error(errno); 00412 return r; 00413 #else 00414 throw Error(ENOSYS); 00415 #endif 00416 } 00417 /* Returns signal number or -1 on error (sets errno) */ 00418 00419 /** 00420 Calls ::sigwait. 00421 */ 00422 /* static */ void Process::sigwait(const sigset_t *set, int *signum) 00423 { 00424 #if _XOPEN_VERSION >= 500 00425 if (::sigwait(set, signum) == -1) 00426 throw Error(errno); 00427 #else 00428 throw Error(ENOSYS); 00429 #endif 00430 } 00431 /* Returns 0 on success or error number on error */ 00432 00433 /** 00434 Calls ::sigwaitinfo. 00435 */ 00436 /* static */ int Process::sigwaitinfo(const sigset_t *set, siginfo_t *info) 00437 { 00438 #ifdef _POSIX_REALTIME_SIGNALS 00439 int r; 00440 00441 if ((r = ::sigwaitinfo(set, info)) == -1) 00442 throw Error(errno); 00443 return r; 00444 #else 00445 throw Error(ENOSYS); 00446 #endif 00447 } 00448 /* Returns signal number or -1 on error (sets errno) */ 00449 00450 /** 00451 Calls ::system. 00452 */ 00453 /* static */ int Process::system(const char *command) 00454 { 00455 int n; 00456 00457 if ((n = ::system(command)) == -1) 00458 throw Error(errno); 00459 return n; 00460 } 00461 00462 /** 00463 Calls ::times. 00464 */ 00465 /* static */ clock_t Process::times(struct tms *buffer) 00466 { 00467 clock_t c; 00468 00469 if ((c = ::times(buffer)) == -1) 00470 throw Error(errno); 00471 return c; 00472 } 00473 00474 /** 00475 Calls ::unsetenv. 00476 */ 00477 /* static */ void Process::unsetenv(const char *var) 00478 { 00479 #if _XOPEN_VERSION >= 600 00480 if (::unsetenv(var) == -1) 00481 throw Error(errno); 00482 #elif defined(FREEBSD) || defined(LINUX) 00483 ::unsetenv(var); 00484 #else 00485 throw Error(ENOSYS); 00486 #endif 00487 } 00488 00489 /** 00490 Calls ::waitid if it's supported. Otherwise throws ENOSYS. 00491 */ 00492 /* static */ void Process::waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options) 00493 { 00494 #ifdef _XOPEN_UNIX 00495 if (::waitid(idtype, id, infop, options) == -1) 00496 throw Error(errno); 00497 #else 00498 throw Error(ENOSYS); 00499 #endif 00500 } 00501 00502 /** 00503 Calls ::waitpid. Use the inline version if you want to operate on the 00504 Process object's process ID. 00505 */ 00506 /* static */ pid_t Process::waitpid(pid_t pid, ExitStatus *statusp, int options = 0) 00507 { 00508 pid_t rtn_pid; 00509 int status; 00510 00511 if ((rtn_pid = ::waitpid(pid, &status, options)) == -1) 00512 throw Error(errno); 00513 if (statusp != NULL) 00514 statusp->set(status); 00515 return rtn_pid; 00516 } 00517