// Copyright (C) 1999-2005 Open Source Telecom Corporation. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. This exception does not however // invalidate any other reasons why the executable file might be covered by // the GNU General Public License. // // This exception applies only to the code released under the name GNU // Common C++. If you copy code from other releases into a copy of GNU // Common C++, as the General Public License permits, the exception does // not apply to the code that you add in this way. To avoid misleading // anyone as to the status of such modified files, you must delete // this exception notice from them. // // If you write modifications of your own for GNU Common C++, it is your choice // whether to permit this exception to apply to your modifications. // If you do not wish that, delete this exception notice. // #include #include #include #include #include #include #include #include #include #ifdef MACOSX #undef _POSIX_PRIORITY_SCHEDULING #endif #ifndef WIN32 #ifdef HAVE_SYS_TIME_H #include #endif #ifdef HAVE_SYS_WAIT_H #include #endif #include #include #ifdef SIGTSTP #include #include #endif #ifndef _PATH_TTY #define _PATH_TTY "/dev/tty" #endif #endif #ifdef WIN32 #include #include #endif #ifdef CCXX_NAMESPACES namespace ost { #endif static char *_pUser = NULL; static char *_pHome = NULL; bool Process::rtflag = false; #ifdef WIN32 static SYSTEM_INFO sysinfo; static LPSYSTEM_INFO lpSysInfo = NULL; static void init_sysinfo(void) { if(!lpSysInfo) { lpSysInfo = &sysinfo; memset(&sysinfo, 0, sizeof(sysinfo)); GetSystemInfo(lpSysInfo); } } const char *Process::getUser(void) { static char userid[65]; DWORD length = sizeof(userid); if(GetUserName(userid, &length)) return userid; return NULL; } size_t Process::getPageSize(void) { init_sysinfo(); return (size_t) lpSysInfo->dwPageSize; } int Process::spawn(const char *exename, const char **args, bool wait) { int mode = P_NOWAIT; if(wait) mode = P_WAIT; return (int)::spawnvp(mode, (char *)exename, (char **)args); } int Process::join(int pid) { int status, result; if(pid == -1) return pid; result = (int)cwait(&status, pid, WAIT_CHILD); if(status & 0x0) return -1; return result; } bool Process::cancel(int pid, int sig) { HANDLE hPid = OpenProcess(PROCESS_TERMINATE, FALSE, pid); bool rtn = true; if(!hPid) return false; switch(sig) { case SIGABRT: case SIGTERM: if(!TerminateProcess(hPid, -1)) rtn = false; case 0: break; default: rtn = false; } CloseHandle(hPid); return rtn; } void Process::setPriority(int pri) { DWORD pc = NORMAL_PRIORITY_CLASS; DWORD pid = GetCurrentProcessId(); HANDLE hProcess = OpenProcess(PROCESS_DUP_HANDLE, TRUE, pid); #ifdef BELOW_NORMAL_PRIORITY_CLASS if(pri == -1) pc = BELOW_NORMAL_PRIORITY_CLASS; else if(pri == 1) pc = ABOVE_NORMAL_PRIORITY_CLASS; else #endif if(pri == 2) pc = HIGH_PRIORITY_CLASS; else if(pri > 2) pc = REALTIME_PRIORITY_CLASS; else if(pri < -1) pc = IDLE_PRIORITY_CLASS; SetPriorityClass(hProcess, pc); CloseHandle(hProcess); } void Process::setScheduler(const char *cp) { if(!stricmp(cp, "fifo")) setPriority(3); else if(!stricmp(cp, "rr")) setPriority(2); else if(!stricmp(cp, "idle")) setPriority(-2); else setPriority(0); } void Process::setRealtime(int pri) { setPriority(3); } bool Process::isScheduler(void) { return false; } #else #ifndef WEXITSTATUS #define WEXITSTATUS(status) ((unsigned)(status) >> 8) #endif #ifndef WIFEXITED #define WIFEXITED(status) (((status) & 255) == 0) #endif #ifndef WTERMSIG #define WTERMSIG(status) (((unsigned)(status)) & 0x7F) #endif #ifndef WIFSIGNALLED #define WIFSIGNALLED(status) (((status) & 255) != 0) #endif #ifndef WCOREDUMP #define WCOREDUMP(status) (((status) & 0x80) != 0) #endif static void lookup(void) { struct passwd *pw = NULL; #ifdef HAVE_GETPWUID_R struct passwd pwd; char buffer[1024]; ::getpwuid_r(geteuid(), &pwd, buffer, 1024, &pw); #else pw = ::getpwuid(geteuid()); #endif if(_pHome) delString(_pHome); if(_pUser) delString(_pUser); _pUser = _pHome = NULL; if(pw != NULL && pw->pw_dir != NULL) _pHome = newString(pw->pw_dir); if(pw != NULL && pw->pw_name != NULL) _pUser = newString(pw->pw_name); endpwent(); } const char *Process::getUser(void) { if(!_pUser) lookup(); return (const char *)_pUser; } const char *Process::getConfigDir(void) { #ifdef ETC_CONFDIR return ETC_CONFDIR; #else return ETC_PREFIX; #endif } const char *Process::getHomeDir(void) { if(!_pHome) lookup(); return (const char *)_pHome; } #ifdef HAVE_GETPAGESIZE size_t Process::getPageSize(void) { return (size_t)getpagesize(); } #else size_t Process::getPageSize(void) { return 1024; } #endif bool Process::setUser(const char *id, bool grp) { struct passwd *pw = NULL; #ifdef HAVE_GETPWNAM_R struct passwd pwd; char buffer[1024]; ::getpwnam_r(id, &pwd, buffer, 1024, &pw); #else pw = ::getpwnam(id); #endif if(!pw) return false; if(grp) if(setgid(pw->pw_gid)) return false; if(setuid(pw->pw_uid)) return false; lookup(); return true; } bool Process::setGroup(const char *id) { struct group *group = NULL; #ifdef HAVE_GETGRNAM_R struct group grp; char buffer[2048]; ::getgrnam_r(id, &grp, buffer, 1024, &group); #else group = ::getgrnam(id); #endif if(!group) { endgrent(); return false; } #ifdef HAVE_SETEGID setegid(group->gr_gid); #endif if(setgid(group->gr_gid)) { endgrent(); return false; } endgrent(); return true; } bool Process::cancel(int pid, int sig) { if(!sig) sig = SIGTERM; if(pid < 1) return false; if(::kill(pid, sig)) return false; return true; } int Process::join(int pid) { int status; if(pid < 1) return -1; #ifdef HAVE_WAITPID waitpid(pid, &status, 0); #else #ifdef HAVE_WAIT4 wait4(pid, &status, 0, NULL); #else int result; while((result = wait(&status)) != pid && result != -1) ; #endif #endif if(WIFEXITED(status)) return WEXITSTATUS(status); else if(WIFSIGNALLED(status)) return -WTERMSIG(status); else return -1; } int Process::spawn(const char *exename, const char **args, bool wait) { int pid; pid = vfork(); if(pid == -1) return -1; if(!pid) { execvp((char *)exename, (char **)args); _exit(-1); } if(!wait) return pid; return join(pid); } Process::Trap Process::setInterruptSignal(int signo, Trap func) { struct sigaction sig_act, old_act; memset(&sig_act, 0, sizeof(sig_act)); sig_act.sa_handler = func; sigemptyset(&sig_act.sa_mask); if(signo != SIGALRM) sigaddset(&sig_act.sa_mask, SIGALRM); sig_act.sa_flags = 0; #ifdef SA_INTERRUPT sig_act.sa_flags |= SA_INTERRUPT; #endif if(sigaction(signo, &sig_act, &old_act) < 0) return SIG_ERR; return old_act.sa_handler; } Process::Trap Process::setPosixSignal(int signo, Trap func) { struct sigaction sig_act, old_act; memset(&sig_act, 0, sizeof(sig_act)); sig_act.sa_handler = func; sigemptyset(&sig_act.sa_mask); sig_act.sa_flags = 0; if(signo == SIGALRM) { #ifdef SA_INTERRUPT sig_act.sa_flags |= SA_INTERRUPT; #endif } else { sigaddset(&sig_act.sa_mask, SIGALRM); #ifdef SA_RESTART sig_act.sa_flags |= SA_RESTART; #endif } if(sigaction(signo, &sig_act, &old_act) < 0) return SIG_ERR; return old_act.sa_handler; } void Process::detach(void) { attach("/dev/null"); } void Process::attach(const char *dev) { int pid; int fd; if(getppid() == 1) return; ::close(0); ::close(1); ::close(2); #ifdef SIGTTOU setPosixSignal(SIGTTOU, SIG_IGN); #endif #ifdef SIGTTIN setPosixSignal(SIGTTIN, SIG_IGN); #endif #ifdef SIGTSTP setPosixSignal(SIGTSTP, SIG_IGN); #endif if((pid = fork()) < 0) THROW(pid); else if(pid > 0) exit(0); #if defined(SIGTSTP) && defined(TIOCNOTTY) if(setpgid(0, getpid()) == -1) THROW(-1); if((fd = open(_PATH_TTY, O_RDWR)) >= 0) { ioctl(fd, TIOCNOTTY, NULL); close(fd); } #else #ifdef HAVE_SETPGRP if(setpgrp() == -1) THROW(-1); #else if(setpgid(0, getpid()) == -1) THROW(-1); #endif setPosixSignal(SIGHUP, SIG_IGN); if((pid = fork()) < 0) THROW(-1); else if(pid > 0) exit(0); #endif if(dev && *dev) { ::open(dev, O_RDWR); ::open(dev, O_RDWR); ::open(dev, O_RDWR); } } void Process::setScheduler(const char *pol) { #ifdef _POSIX_PRIORITY_SCHEDULING struct sched_param p; int policy; sched_getparam(0, &p); if(pol) { #if defined(SCHED_TS) policy = SCHED_TS; #elif defined(SCHED_OTHER) policy = SCHED_OTHER; #else policy = 0; #endif #ifdef SCHED_RR if(!stricmp(pol, "rr")) policy = SCHED_RR; #endif #if !defined(SCHED_RR) && defined(SCHED_FIFO) if(!stricmp(pol, "rr")) policy = SCHED_FIFO; #endif #ifdef SCHED_FIFO if(!stricmp(pol, "fifo")) { rtflag = true; policy = SCHED_FIFO; } #endif #ifdef SCHED_TS if(!stricmp(pol, "ts")) policy = SCHED_TS; #endif #ifdef SCHED_OTHER if(!stricmp(pol, "other")) policy = SCHED_OTHER; #endif } else policy = sched_getscheduler(0); int min = sched_get_priority_min(policy); int max = sched_get_priority_max(policy); if(p.sched_priority < min) p.sched_priority = min; else if(p.sched_priority > max) p.sched_priority = max; sched_setscheduler(0, policy, &p); #endif } void Process::setPriority(int pri) { #ifdef _POSIX_PRIORITY_SCHEDULING struct sched_param p; int policy = sched_getscheduler(0); int min = sched_get_priority_min(policy); int max = sched_get_priority_max(policy); sched_getparam(0, &p); if(pri < min) pri = min; if(pri > max) pri = max; p.sched_priority = pri; sched_setparam(0, &p); #else if(pri < -20) pri = -20; if(pri > 20) pri = 20; nice(-pri); #endif } bool Process::isScheduler(void) { #ifdef _POSIX_PRIORITY_SCHEDULING return true; #else return false; #endif } void Process::setRealtime(int pri) { if(pri < 1) pri = 1; setScheduler("rr"); setPriority(pri); } #endif // not win32 #ifdef _OSF_SOURCE #undef HAVE_SETENV #endif void Process::setEnv(const char *name, const char *value, bool overwrite) { #ifdef HAVE_SETENV ::setenv(name, value, (int)overwrite); #else char strbuf[256]; snprintf(strbuf, sizeof(strbuf), "%s=%s", name, value); if(!overwrite) if(getenv(strbuf)) return; ::putenv(strdup(strbuf)); #endif } const char *Process::getEnv(const char *name) { return ::getenv(name); } #if defined(HAVE_MLOCKALL) && defined(MCL_FUTURE) #include bool Process::lock(bool future) { int rc; if(future) rc = mlockall(MCL_CURRENT | MCL_FUTURE); else rc = mlockall(MCL_CURRENT); if(rc) return false; return true; } void Process::unlock(void) { munlockall(); } #else bool Process::lock(bool future) { return false; } void Process::unlock(void) { } #endif #ifdef CCXX_NAMESPACES } #endif /** EMACS ** * Local variables: * mode: c++ * c-basic-offset: 8 * End: */