1 /*
2  *  R : A Computer Language for Statistical Data Analysis
3  *  Copyright (C) 2011--2018   The R Core Team.
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, a copy is available at
17  *  https://www.R-project.org/Licenses/
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 
24 #include "tools.h"
25 #include <signal.h> // C99
26 
27 #ifdef _WIN32
28 #define WIN32_LEAN_AND_MEAN
29 #include <windows.h>
30 #endif
31 
ps_kill(SEXP spid,SEXP ssignal)32 SEXP ps_kill(SEXP spid, SEXP ssignal)
33 {
34     SEXP sspid, sres;
35     int *pid, *res, signal = asInteger(ssignal);
36     PROTECT(sspid = coerceVector(spid, INTSXP));
37     unsigned int ns = LENGTH(sspid);
38     PROTECT(sres = allocVector(LGLSXP, ns));
39     pid = INTEGER(sspid);
40     res = INTEGER(sres);
41 #if !defined(_WIN32) && !defined(HAVE_KILL)
42     warning(_("pskill() is not supported on this platform"));
43 #endif
44     for (int i = 0; i < ns; i++) {
45 	res[i] = FALSE;
46 	if(signal != NA_INTEGER) {
47 #ifdef _WIN32
48 	    HANDLE hProc = OpenProcess(PROCESS_TERMINATE, FALSE, pid[i]);
49 	    if (hProc) {
50                 if (TerminateProcess(hProc, 1) != 0) res[i] = TRUE;
51                 CloseHandle(hProc);
52 	    }
53 #elif defined(HAVE_KILL)
54 	    if (pid[i] > 0 && pid[i] != NA_INTEGER &&
55 	        kill(pid[i], signal) == 0) res[i] = TRUE;
56 #endif
57 	}
58     }
59     UNPROTECT(2);
60     return sres;
61 }
62 
63 #if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETPRIORITY)
64 /* on macOS it seems sys/resource.h needed sys/time.h first at one time */
65 #include <sys/time.h>
66 #include <sys/resource.h>
67 #include <errno.h>
ps_priority(SEXP spid,SEXP svalue)68 SEXP ps_priority(SEXP spid, SEXP svalue)
69 {
70     SEXP sspid, sres;
71     int *pid, *res, val;
72     val = asInteger(svalue);
73     PROTECT(sspid = coerceVector(spid, INTSXP));
74     unsigned int ns = LENGTH(sspid);
75     PROTECT(sres = allocVector(INTSXP, ns));
76     pid = INTEGER(sspid);
77     res = INTEGER(sres);
78     for (int i = 0; i < ns; i++) {
79 	if (pid[i] <= 0) {
80 	    res[i] = NA_INTEGER;
81 	    continue;
82 	}
83 	if (pid[i] != NA_INTEGER) {
84 	    /* return value -1 is both an error value
85 	       and a legitimate niceness */
86 	    errno = 0;
87 	    res[i] = getpriority(PRIO_PROCESS, pid[i]);
88 	    if(errno) res[i] = NA_INTEGER;
89 	    if(val != NA_INTEGER) setpriority(PRIO_PROCESS, pid[i], val);
90 	} else res[i] = NA_INTEGER;
91     }
92     UNPROTECT(2);
93     return sres;
94 }
95 #elif defined(_WIN32)
ps_priority(SEXP spid,SEXP svalue)96 SEXP ps_priority(SEXP spid, SEXP svalue)
97 {
98     SEXP sspid, sres;
99     int *pid, *res, val;
100     val = asInteger(svalue);
101     PROTECT(sspid = coerceVector(spid, INTSXP));
102     unsigned int ns = LENGTH(sspid);
103     PROTECT(sres = allocVector(INTSXP, ns));
104     pid = INTEGER(sspid);
105     res = INTEGER(sres);
106     for (int i = 0; i < ns; i++) {
107 	HANDLE hProc = OpenProcess(val != NA_INTEGER ?
108 				   PROCESS_SET_INFORMATION
109 				   : PROCESS_QUERY_INFORMATION,
110 				   FALSE, pid[i]);
111 	if (hProc && pid[i] != NA_INTEGER) {
112 	    DWORD tmp = GetPriorityClass(hProc);
113 	    switch(tmp) {
114 	    case ABOVE_NORMAL_PRIORITY_CLASS: res[i] = -5; break;
115 	    case BELOW_NORMAL_PRIORITY_CLASS: res[i] = 15; break;
116 	    case HIGH_PRIORITY_CLASS: res[i] = -10; break;
117 	    case IDLE_PRIORITY_CLASS: res[i] = 19; break;
118 	    case NORMAL_PRIORITY_CLASS: res[i] = 0; break;
119 	    case REALTIME_PRIORITY_CLASS: res[i] = -20; break;
120 	    }
121 	    if(val != NA_INTEGER) {
122 		switch(val) {
123 		case 19: tmp = IDLE_PRIORITY_CLASS; break;
124 		case 15: tmp = BELOW_NORMAL_PRIORITY_CLASS; break;
125 		case 0: tmp = NORMAL_PRIORITY_CLASS; break;
126 		case -5: tmp = ABOVE_NORMAL_PRIORITY_CLASS; break;
127 		case -10: tmp = HIGH_PRIORITY_CLASS; break;
128 		}
129 		SetPriorityClass(hProc, tmp);
130 	    }
131 	    CloseHandle(hProc);
132 	} else res[i] = NA_INTEGER;
133     }
134     UNPROTECT(2);
135     return sres;
136 }
137 #else
ps_priority(SEXP spid,SEXP svalue)138 SEXP ps_priority(SEXP spid, SEXP svalue)
139 {
140     error(_("psnice() is not supported on this platform"));
141     return R_NilValue; /* -Wall */
142 }
143 #endif
144 
ps_sigs(SEXP signo)145 SEXP ps_sigs(SEXP signo)
146 {
147     int res = NA_INTEGER;
148     switch(asInteger(signo)) {
149 	/* only SIGINT and SIGTERM are in C99 */
150 #ifdef SIGHUP
151     case 1: res = SIGHUP; break;
152 #endif
153 #ifdef SIGINT
154     case 2: res = SIGINT; break;
155 #endif
156 #ifdef SIGQUIT
157     case 3: res = SIGQUIT; break;
158 #endif
159 #ifdef SIGKILL
160     case 9: res = SIGKILL; break;
161 #endif
162 #ifdef SIGTERM
163     case 15: res = SIGTERM; break;
164 #endif
165 #ifdef SIGSTOP
166     case 17: res = SIGSTOP; break;
167 #endif
168 #ifdef SIGTSTP
169     case 18: res = SIGTSTP; break;
170 #endif
171 #ifdef SIGCONT
172     case 19: res = SIGCONT; break;
173 #endif
174 #ifdef SIGCHLD
175     case 20: res = SIGCHLD; break;
176 #endif
177 #ifdef SIGUSR1
178     case 30: res = SIGUSR1; break;
179 #endif
180 #ifdef SIGUSR2
181     case 31: res = SIGUSR2; break;
182 #endif
183     default: break;
184     }
185     return ScalarInteger(res);
186 }
187