©2004 by Marc J. Rochkind. All rights reserved. Portions marked "Open Source" may be copied under license.

 

Main Page   Modules   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members  

ux/uxprocess.cpp

Go to the documentation of this file.
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 

Generated on Fri Apr 23 10:57:05 2004 for AUP2 Example Source by doxygen 1.3.1