The R Project SVN R

Rev

Rev 73675 | Rev 78045 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4394 ripley 1
/*
2
 *  R : A Computer Language for Statistical Data Analysis
3
 *  file run.c: a simple 'reading' pipe (and a command executor)
64657 ripley 4
 *  Copyright  (C) 1999-2001  Guido Masarotto and Brian Ripley
75992 kalibera 5
 *             (C) 2007-2019  The R Core Team
4394 ripley 6
 *
7
 *  This program is free software; you can redistribute it and/or modify
8
 *  it under the terms of the GNU General Public License as published by
9
 *  the Free Software Foundation; either version 2 of the License, or
10
 *  (at your option) any later version.
11
 *
12
 *  This program is distributed in the hope that it will be useful,
13
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 *  GNU General Public License for more details.
16
 *
17
 *  You should have received a copy of the GNU General Public License
42300 ripley 18
 *  along with this program; if not, a copy is available at
68956 ripley 19
 *  https://www.R-project.org/Licenses/
5458 ripley 20
 */
4394 ripley 21
 
8872 pd 22
#ifdef HAVE_CONFIG_H
23
#include <config.h>
24
#endif
57538 ripley 25
 
26
#define R_USE_SIGNALS 1
40513 ripley 27
#include <Defn.h>
60667 ripley 28
#include <Internal.h>
32888 ripley 29
#include "win-nls.h"
4394 ripley 30
 
36901 ripley 31
#define WIN32_LEAN_AND_MEAN 1
4394 ripley 32
#include <windows.h>
72855 kalibera 33
#include <mmsystem.h> /* for timeGetTime */
4394 ripley 34
#include <string.h>
35
#include <stdlib.h>
36
#include <ctype.h>
37
#include "run.h"
38
 
53870 murdoch 39
#include <Startup.h> /* for CharacterMode and RGui */
40
 
67837 murdoch 41
#include <trioremap.h>
42
 
42639 ripley 43
static char RunError[501] = "";
4394 ripley 44
 
59546 ripley 45
/* This might be given a command line (whole = 0) or just the
65574 ripley 46
   executable (whole = 1).  In the later case the path may or may not
59546 ripley 47
   be quoted */
48
static char *expandcmd(const char *cmd, int whole)
4394 ripley 49
{
59546 ripley 50
    char c = '\0';
51
    char *s, *p, *q = NULL, *f, *dest, *src;
43800 ripley 52
    int   d, ext, len = strlen(cmd)+1;
65569 ripley 53
    char buf[len], fl[len], fn[MAX_PATH];
52814 ripley 54
 
41793 ripley 55
    /* make a copy as we manipulate in place */
56
    strcpy(buf, cmd);
57
 
58
    /* skip leading spaces */
59
    for (p = buf; *p && isspace(*p); p++);
60
    /* find the command itself, possibly double-quoted */
59546 ripley 61
    if (whole) {
62
	d = 0;
65574 ripley 63
    } else { // command line
59546 ripley 64
	for (q = p, d = 0; *q && ( d || !isspace(*q) ); q++)
65
	    if (*q == '\"') d = d ? 0 : 1;
66
	if (d) {
67
	    strcpy(RunError, "A \" is missing (expandcmd)");
68
	    return NULL;
69
	}
70
	c = *q; /* character after the command, normally a space */
71
	*q = '\0';
6153 guido 72
    }
12256 pd 73
 
73273 kalibera 74
    // This is the return value.
75
    if (!(s = (char *) malloc(MAX_PATH + strlen(cmd)))) {
76
	strcpy(RunError, "Insufficient memory (expandcmd)");
77
	return NULL;
78
    }
79
 
52804 ripley 80
    /*
81
     * Guido resorted to this since SearchPath returned FOUND also
82
     * for file name without extension -> explicitly set
83
     *  extension
84
     */
85
    for (f = p, ext = 0 ; *f ; f++) {
41793 ripley 86
	if ((*f == '\\') || (*f == '/')) ext = 0;
87
	else if (*f == '.') ext = 1;
88
    }
89
    /* SearchPath doesn't like ", so strip out quotes */
52804 ripley 90
    for (dest = fl , src = p; *src ; src++)
91
	if (*src != '"') *dest++ = *src;
41793 ripley 92
    *dest = '\0';
93
    if (ext) {
94
	/*
95
	 * user set extension; we don't check that it is executable;
96
	 * it might get an error after; but maybe sometimes
97
	 * in the future every extension will be executable
98
	 */
99
	d = SearchPath(NULL, fl, NULL, MAX_PATH, fn, &f);
100
    } else {
101
	int iexts = 0;
43800 ripley 102
	const char *exts[] = { ".exe" , ".com" , ".cmd" , ".bat" , NULL };
41793 ripley 103
	while (exts[iexts]) {
104
	    strcpy(dest, exts[iexts]);
105
	    if ((d = SearchPath(NULL, fl, NULL, MAX_PATH, fn, &f))) break;
106
	    iexts++ ;
107
	}
108
    }
109
    if (!d) {
110
	free(s);
52804 ripley 111
	snprintf(RunError, 500, "'%s' not found", p);
59546 ripley 112
	if(!whole) *q = c;
41793 ripley 113
	return NULL;
114
    }
115
    /*
65574 ripley 116
      NB: as of Windows 7 SearchPath does not return short names any more.
117
 
6153 guido 118
      Paranoia : on my system switching to short names is not needed
119
      since SearchPath already returns 'short names'. However,
120
      this is not documented so I prefer to be explicit.
41793 ripley 121
    */
73564 kalibera 122
    /* NOTE: short names are not always enabled */
41793 ripley 123
    GetShortPathName(fn, s, MAX_PATH);
59546 ripley 124
    if (!whole) {
125
	*q = c;
126
	strcat(s, q);
127
    }
41793 ripley 128
    return s;
4394 ripley 129
}
130
 
27774 murdoch 131
/*
12256 pd 132
   finput is either NULL or the name of a file from which to
133
     redirect stdin for the child.
134
   newconsole != 0 to use a new console (if not waiting)
135
   visible = -1, 0, 1 for hide, minimized, default
53870 murdoch 136
   inpipe != 0 to duplicate I/O handles
52813 ripley 137
   pi is set based on the newly created process,
138
   with the hThread handle closed.
12256 pd 139
*/
140
 
44013 ripley 141
extern size_t Rf_utf8towcs(wchar_t *wc, const char *s, size_t n);
142
 
52814 ripley 143
static void pcreate(const char* cmd, cetype_t enc,
144
		      int newconsole, int visible,
51030 murdoch 145
		      HANDLE hIN, HANDLE hOUT, HANDLE hERR,
75992 kalibera 146
		      pinfo *pi)
4394 ripley 147
{
148
    DWORD ret;
149
    STARTUPINFO si;
44013 ripley 150
    STARTUPINFOW wsi;
75992 kalibera 151
    HANDLE dupIN, dupOUT, dupERR, job, port;
51015 murdoch 152
    WORD showWindow = SW_SHOWDEFAULT;
75992 kalibera 153
    DWORD flags;
154
    BOOL inJob;
155
    Rboolean breakaway;
156
    JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli;
157
    JOBOBJECT_ASSOCIATE_COMPLETION_PORT cport;
53870 murdoch 158
    int inpipe;
4394 ripley 159
    char *ecmd;
51015 murdoch 160
    SECURITY_ATTRIBUTES sa;
4394 ripley 161
    sa.nLength = sizeof(sa);
162
    sa.lpSecurityDescriptor = NULL;
163
    sa.bInheritHandle = TRUE;
164
 
52813 ripley 165
    /* FIXME: this might need to be done in wchar_t */
59546 ripley 166
    if (!(ecmd = expandcmd(cmd, 0))) return; /* error message already set */
51015 murdoch 167
 
53870 murdoch 168
    inpipe = (hIN != INVALID_HANDLE_VALUE)
169
	|| (hOUT != INVALID_HANDLE_VALUE)
170
	|| (hERR != INVALID_HANDLE_VALUE);
52814 ripley 171
 
53870 murdoch 172
    if (inpipe) {
173
	HANDLE hNULL = CreateFile("NUL:", GENERIC_READ | GENERIC_WRITE, 0,
174
			   &sa, OPEN_EXISTING, 0, NULL);
175
	HANDLE hTHIS = GetCurrentProcess();
51015 murdoch 176
 
53870 murdoch 177
	if (hIN == INVALID_HANDLE_VALUE) hIN = hNULL;
178
	if (hOUT == INVALID_HANDLE_VALUE) hOUT = hNULL;
179
	if (hERR == INVALID_HANDLE_VALUE) hERR = hNULL;
180
 
181
	DuplicateHandle(hTHIS, hIN,
182
			hTHIS, &dupIN, 0, TRUE, DUPLICATE_SAME_ACCESS);
183
	DuplicateHandle(hTHIS, hOUT,
184
			hTHIS, &dupOUT, 0, TRUE, DUPLICATE_SAME_ACCESS);
185
	DuplicateHandle(hTHIS, hERR,
186
			hTHIS, &dupERR, 0, TRUE, DUPLICATE_SAME_ACCESS);
187
	CloseHandle(hTHIS);
188
	CloseHandle(hNULL);
189
    }
190
 
51015 murdoch 191
    switch (visible) {
192
    case -1:
193
	showWindow = SW_HIDE;
194
	break;
195
    case 0:
196
	showWindow = SW_SHOWMINIMIZED;
197
	break;
4394 ripley 198
    }
52814 ripley 199
 
44013 ripley 200
    if(enc == CE_UTF8) {
201
	wsi.cb = sizeof(wsi);
202
	wsi.lpReserved = NULL;
203
	wsi.lpReserved2 = NULL;
204
	wsi.cbReserved2 = 0;
205
	wsi.lpDesktop = NULL;
206
	wsi.lpTitle = NULL;
51015 murdoch 207
	wsi.dwFlags = STARTF_USESHOWWINDOW;
52814 ripley 208
	wsi.wShowWindow = showWindow;
53870 murdoch 209
	if (inpipe) {
210
	    wsi.dwFlags |= STARTF_USESTDHANDLES;
211
	    wsi.hStdInput  = dupIN;
212
	    wsi.hStdOutput = dupOUT;
213
	    wsi.hStdError  = dupERR;
214
	}
44013 ripley 215
    } else {
216
	si.cb = sizeof(si);
217
	si.lpReserved = NULL;
218
	si.lpReserved2 = NULL;
219
	si.cbReserved2 = 0;
220
	si.lpDesktop = NULL;
221
	si.lpTitle = NULL;
51015 murdoch 222
	si.dwFlags = STARTF_USESHOWWINDOW;
52814 ripley 223
	si.wShowWindow = showWindow;
53870 murdoch 224
	if (inpipe) {
225
	    si.dwFlags |= STARTF_USESTDHANDLES;
226
	    si.hStdInput  = dupIN;
227
	    si.hStdOutput = dupOUT;
228
	    si.hStdError  = dupERR;
229
	}
4394 ripley 230
    }
44013 ripley 231
 
75992 kalibera 232
    /* Originally, the external process has been waited for only using
233
       waitForSingleObject, but that has been proven unreliable: sometimes
234
       the output file would still be opened (and hence locked) by some
235
       child process after waitForSingleObject would finish. This has been
236
       observed also while running tests and particularly when building
237
       vignettes, resulting in spurious "Permission denied" errors.
238
 
239
       This has been happening almost surely due to a child process not
240
       waiting for its own children to finish, which has been reported
241
       to happen with Linux utilities ported to Windows as used for tests
242
       in Haskell/GHC. Inspired by Haskell process and a blog post about
243
       waiting for a process tree to finish, we now use job objects to
244
       wait also for process trees with this issue:
245
 
246
	https://github.com/haskell/process
247
	https://blogs.msdn.microsoft.com/oldnewthing/20130405-00/?p=4743
248
 
249
       In addition, we try to be easy on applications coded to rely on that
250
       they do not run in a job, when running in old Windows that do not
251
       support nested jobs. With nested jobs support, it might make sense
252
       to not breakaway to better support nested R processes.
253
    */
254
 
255
    /* Creating the process with CREATE_BREAKAWAY_FROM_JOB is safe when
256
       the process is not in any job or when it is in a job that allows it.
257
       The documentation does not say what would happen if we set the flag,
258
       but run in a job that does not allow it, so better don't. */
259
    breakaway = FALSE;
260
    if (IsProcessInJob(GetCurrentProcess(), NULL, &inJob) && inJob) {
261
	/* The documentation does not say that it would be ok to use
262
	   QueryInformationJobObject when the process is not in the job,
263
	   so we have better tested that upfront. */
264
	ZeroMemory(&jeli, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
265
	ret = QueryInformationJobObject(
266
		NULL,
267
	        JobObjectExtendedLimitInformation,
268
	        &jeli,
269
	        sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION),
270
		NULL);
271
	breakaway = ret &&
272
		(jeli.BasicLimitInformation.LimitFlags &
273
	         JOB_OBJECT_LIMIT_BREAKAWAY_OK);
274
    }
275
 
276
    /* create a job that allows breakaway */
277
    job = CreateJobObject(NULL, NULL);
278
    if (job) {
279
	ZeroMemory(&jeli, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
280
	jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_BREAKAWAY_OK;
281
	ret = SetInformationJobObject(
282
		job,
283
		JobObjectExtendedLimitInformation,
284
		&jeli,
285
                sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
286
	if (!ret) {
287
	    CloseHandle(job);
288
	    job = NULL;
289
	}
290
    }
291
 
292
    /* create a completion port to learn when processes exit */
293
    if (job) {
294
	port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
295
	if (!port) {
296
	    CloseHandle(job);
297
	    job = NULL;
298
	}
299
    }
300
    if (job) {
301
	ZeroMemory(&cport, sizeof(JOBOBJECT_ASSOCIATE_COMPLETION_PORT));
302
	cport.CompletionKey = job; /* use job handle as key */
303
	cport.CompletionPort = port;
304
	ret = SetInformationJobObject(
305
	    job,
306
	    JobObjectAssociateCompletionPortInformation,
307
	    &cport,
308
	    sizeof(JOBOBJECT_ASSOCIATE_COMPLETION_PORT));
309
	if (!ret) {
310
	    CloseHandle(job);
311
	    CloseHandle(port);
312
	    job = NULL;
313
	}
314
    }
315
 
316
    flags = 0;
317
    if (job)
318
	flags |= CREATE_SUSPENDED; /* assign to job before it runs */
319
    if (newconsole && (visible == 1))
320
	flags |= CREATE_NEW_CONSOLE;
321
    if (job && breakaway)
322
	flags |= CREATE_BREAKAWAY_FROM_JOB;
323
 
44013 ripley 324
    if(enc == CE_UTF8) {
325
	int n = strlen(ecmd); /* max no of chars */
52804 ripley 326
	wchar_t wcmd[n+1];
44013 ripley 327
	Rf_utf8towcs(wcmd, ecmd, n+1);
75992 kalibera 328
	ret = CreateProcessW(NULL, wcmd, &sa, &sa, TRUE, flags,
329
			     NULL, NULL, &wsi, &(pi->pi));
45070 ripley 330
    } else
75992 kalibera 331
	ret = CreateProcess(NULL, ecmd, &sa, &sa, TRUE, flags,
332
			    NULL, NULL, &si, &(pi->pi));
44013 ripley 333
 
75992 kalibera 334
    if (ret && job) {
335
	/* process was created as suspended */
336
	if (!AssignProcessToJobObject(job, pi->pi.hProcess)) {
337
	    /* will fail running on Windows without support for nested jobs,
338
	       when running in a job that does not allow breakaway */
339
	    CloseHandle(job);
340
	    CloseHandle(port);
341
	    job = NULL;
342
	}
343
	ResumeThread(pi->pi.hThread);
344
    }
345
 
346
    if (ret && job) {
347
	/* process is running in new job */
348
	pi->job = job;
349
	pi->port = port;
350
    } else {
351
	if (job) {
352
	    CloseHandle(job);
353
	    CloseHandle(port);
354
	    job = NULL;
355
	}
356
	pi->job = NULL;
357
	pi->port = NULL;
358
    }
359
 
53870 murdoch 360
    if (inpipe) {
361
	CloseHandle(dupIN);
362
	CloseHandle(dupOUT);
363
	CloseHandle(dupERR);
364
    }
52804 ripley 365
    if (!ret)
60844 ripley 366
	snprintf(RunError, 500, _("'CreateProcess' failed to run '%s'"), ecmd);
75992 kalibera 367
    else CloseHandle(pi->pi.hThread);
11169 ripley 368
    free(ecmd);
51030 murdoch 369
    return;
4394 ripley 370
}
371
 
12256 pd 372
/* used in rpipeOpen */
373
static DWORD CALLBACK
4394 ripley 374
threadedwait(LPVOID param)
375
{
376
    rpipe *p = (rpipe *) param;
377
 
72855 kalibera 378
    if (p->timeoutMillis) {
75992 kalibera 379
	DWORD wres = WaitForSingleObject(p->pi.pi.hProcess, p->timeoutMillis);
72855 kalibera 380
	if (wres == WAIT_TIMEOUT) {
75992 kalibera 381
	    TerminateProcess(p->pi.pi.hProcess, 124);
72855 kalibera 382
	    p->timedout = 1;
383
	    /* wait up to 10s for the  process to actually terminate */
75992 kalibera 384
	    WaitForSingleObject(p->pi.pi.hProcess, 10000);
72855 kalibera 385
	}
386
    } else 
75992 kalibera 387
	WaitForSingleObject(p->pi.pi.hProcess, INFINITE);
72855 kalibera 388
 
389
    DWORD ret;
75992 kalibera 390
    GetExitCodeProcess(p->pi.pi.hProcess, &ret);
72855 kalibera 391
    p->exitcode = ret;
392
 
4394 ripley 393
    FlushFileBuffers(p->write);
394
    FlushFileBuffers(p->read);
395
    p->active = 0;
51030 murdoch 396
    CloseHandle(p->thread);
397
    p->thread = NULL;
4394 ripley 398
    return 0;
399
}
400
 
44201 ripley 401
char *runerror(void)
4394 ripley 402
{
403
    return RunError;
404
}
405
 
52814 ripley 406
static HANDLE getInputHandle(const char *fin)
51015 murdoch 407
{
52814 ripley 408
    if (fin && fin[0]) {
51015 murdoch 409
	SECURITY_ATTRIBUTES sa;
410
	sa.nLength = sizeof(sa);
411
	sa.lpSecurityDescriptor = NULL;
52814 ripley 412
	sa.bInheritHandle = TRUE;
413
	HANDLE hIN = CreateFile(fin, GENERIC_READ, 0,
414
				&sa, OPEN_EXISTING, 0, NULL);
51015 murdoch 415
	if (hIN == INVALID_HANDLE_VALUE) {
52814 ripley 416
	    snprintf(RunError, 500, 
417
		     "unable to redirect input from '%s'", fin);
51015 murdoch 418
	    return NULL;
419
	}
420
	return hIN;
55955 murdoch 421
    } else if (fin) {
422
        /* GetStdHandle returns NULL for processes like RGui with no standard handles defined */
423
    	HANDLE result = GetStdHandle(STD_INPUT_HANDLE);
424
    	if (result) return result;
425
    }
51015 murdoch 426
    return INVALID_HANDLE_VALUE;
427
}
4394 ripley 428
 
53348 ripley 429
static HANDLE getOutputHandle(const char *fout, int type)
52814 ripley 430
{
431
    if (fout && fout[0]) {
432
	SECURITY_ATTRIBUTES sa;
433
	sa.nLength = sizeof(sa);
434
	sa.lpSecurityDescriptor = NULL;
435
	sa.bInheritHandle = TRUE;
436
	HANDLE hOUT = CreateFile(fout, GENERIC_WRITE, 0,
437
				 &sa, CREATE_ALWAYS, 0, NULL);
438
	if (hOUT == INVALID_HANDLE_VALUE) {
439
	    snprintf(RunError, 500, 
440
		     "unable to redirect output to '%s'", fout);
441
	    return NULL;
52836 ripley 442
	} else return hOUT;
55955 murdoch 443
    } else if (fout) {
444
        /* GetStdHandle returns NULL for processes like RGui */
445
        HANDLE result = GetStdHandle(type ? STD_ERROR_HANDLE : STD_OUTPUT_HANDLE);
446
        if (result) return result;
447
    }
52814 ripley 448
    return INVALID_HANDLE_VALUE;
449
}
450
 
51030 murdoch 451
BOOL CALLBACK TerminateWindow(HWND hwnd, LPARAM lParam)
452
{
453
    DWORD ID ;
454
 
455
    GetWindowThreadProcessId(hwnd, &ID);
456
 
457
    if (ID == (DWORD)lParam)
52814 ripley 458
	PostMessage(hwnd, WM_CLOSE, 0, 0);
51030 murdoch 459
    return TRUE;
460
}
461
 
462
/* Terminate the process pwait2 is waiting for. */
463
 
464
extern void GA_askok(const char *info);
465
 
75992 kalibera 466
static void waitForJob(pinfo *pi, DWORD timeoutMillis, int* timedout)
467
{
468
    DWORD code, ret;
469
    ULONG_PTR key;
470
    DWORD beforeMillis;
471
    JOBOBJECT_BASIC_ACCOUNTING_INFORMATION jbai;
472
    LPOVERLAPPED overlapped; /* not used */
473
    DWORD queryMillis;
474
 
475
    if (timeoutMillis)
476
	beforeMillis = timeGetTime();
477
 
478
    queryMillis = 0;
479
    for(;;) {
480
	ret = GetQueuedCompletionStatus(pi->port, &code, &key,
481
					&overlapped, queryMillis);
482
	if (ret && code == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO &&
483
	    (HANDLE)key == pi->job)
484
	    break;
485
 
486
	/* start with short query timeouts because notifications often get lost,
487
	   this is essentially polling */
488
 
489
	if (queryMillis == 0)
490
	    queryMillis = 1;
491
	else if (queryMillis < 100)
492
	    queryMillis *= 2;
493
 
494
	if (timeoutMillis && (timeGetTime() - beforeMillis >= timeoutMillis)) {
495
	    if (timedout)
496
		*timedout = 1;
497
	    break;
498
	}
499
 
500
	/* Check also explicitly because notifications are documented to get
501
	   lost and they often do. */
502
	ZeroMemory(&jbai, sizeof(JOBOBJECT_BASIC_ACCOUNTING_INFORMATION));
503
	ret = QueryInformationJobObject(
504
		pi->job,
505
		JobObjectBasicAccountingInformation,
506
		&jbai,
507
		sizeof(JOBOBJECT_BASIC_ACCOUNTING_INFORMATION),
508
		NULL);
509
	if (ret && jbai.ActiveProcesses == 0)
510
	    break;
511
    }
512
    CloseHandle(pi->port);
513
    CloseHandle(pi->job);
514
}
515
 
51030 murdoch 516
static void terminate_process(void *p)
517
{
75992 kalibera 518
    pinfo *pi = (pinfo*) p;
519
    EnumWindows((WNDENUMPROC)TerminateWindow, (LPARAM)pi->pi.dwProcessId);
52814 ripley 520
 
75992 kalibera 521
    if (WaitForSingleObject(pi->pi.hProcess, 5000) == WAIT_TIMEOUT) {
52814 ripley 522
	if (R_Interactive)
523
	    GA_askok(_("Child process not responding.  R will terminate it."));
75992 kalibera 524
	TerminateProcess(pi->pi.hProcess, 99);
51030 murdoch 525
    }
75992 kalibera 526
 
527
    if (pi->job)
528
	waitForJob(pi, 2000, NULL);
51030 murdoch 529
}
530
 
75992 kalibera 531
static int pwait2(pinfo *pi, DWORD timeoutMillis, int* timedout)
51030 murdoch 532
{
533
    DWORD ret;
534
 
72855 kalibera 535
    if (!timeoutMillis) {
75992 kalibera 536
	while( WaitForSingleObject(pi->pi.hProcess, 100) == WAIT_TIMEOUT )
72855 kalibera 537
	    R_CheckUserInterrupt();
538
    } else {
539
	DWORD beforeMillis = timeGetTime();
75992 kalibera 540
	while( WaitForSingleObject(pi->pi.hProcess, 100) == WAIT_TIMEOUT ) {
72855 kalibera 541
	    R_CheckUserInterrupt();
542
	    DWORD afterMillis = timeGetTime();
543
	    if (afterMillis - beforeMillis >= timeoutMillis) {
75992 kalibera 544
		TerminateProcess(pi->pi.hProcess, 124);
72855 kalibera 545
		if (timedout)
546
		    *timedout = 1;
547
		/* wait up to 10s for the process to actually terminate */
75992 kalibera 548
		WaitForSingleObject(pi->pi.hProcess, 10000);
72855 kalibera 549
		break;
550
	    }
551
	}
552
    }
52814 ripley 553
 
75992 kalibera 554
    GetExitCodeProcess(pi->pi.hProcess, &ret);
555
 
556
    if (pi->job)
557
	waitForJob(pi, timeoutMillis, timedout);
558
 
51030 murdoch 559
    return ret;
560
}
561
 
12256 pd 562
/*
52813 ripley 563
  Used for external commands in file.show() and edit(), and for
52814 ripley 564
  system(intern=FALSE).  Also called from postscript().
52813 ripley 565
 
566
  wait != 0 says wait for child to terminate before returning.
567
  visible = -1, 0, 1 for hide, minimized, default
52814 ripley 568
  fin is either NULL or the name of a file from which to
52813 ripley 569
  redirect stdin for the child.
53348 ripley 570
  fout/ferr are NULL (use NUL:), "" (use standard streams) or filenames.
52813 ripley 571
*/
52814 ripley 572
int runcmd(const char *cmd, cetype_t enc, int wait, int visible,
573
	   const char *fin, const char *fout, const char *ferr)
4394 ripley 574
{
72855 kalibera 575
    return runcmd_timeout(cmd, enc, wait, visible, fin, fout, ferr, 0, NULL);
576
}
577
 
578
int runcmd_timeout(const char *cmd, cetype_t enc, int wait, int visible,
579
                   const char *fin, const char *fout, const char *ferr,
580
                   int timeout, int *timedout)
581
{
582
    if (!wait && timeout)
583
	error("Timeout with background running processes is not supported.");
584
 
52837 ripley 585
    HANDLE hIN = getInputHandle(fin), hOUT, hERR;
51030 murdoch 586
    int ret = 0;
75992 kalibera 587
    pinfo pi;
53870 murdoch 588
    int close1 = 0, close2 = 0, close3 = 0;
589
 
590
    if (hIN && fin && fin[0]) close1 = 1;
12256 pd 591
 
53348 ripley 592
    hOUT = getOutputHandle(fout, 0);
593
    if (!hOUT) return 1;
53572 ripley 594
    if (fout && fout[0]) close2 = 1;
53348 ripley 595
    if (fout && fout[0] && ferr && streql(fout, ferr)) hERR = hOUT;
596
    else { 
597
	hERR = getOutputHandle(ferr, 1);
598
	if (!hERR) return 1;
599
	if (ferr && ferr[0]) close3 = 1;
600
    }
52836 ripley 601
 
53348 ripley 602
 
75992 kalibera 603
    memset(&(pi.pi), 0, sizeof(PROCESS_INFORMATION));
52814 ripley 604
    pcreate(cmd, enc, !wait, visible, hIN, hOUT, hERR, &pi);
75992 kalibera 605
    if (pi.pi.hProcess) {
64237 murdoch 606
	if (wait) {
607
	    RCNTXT cntxt;
608
	    begincontext(&cntxt, CTXT_CCODE, R_NilValue, R_BaseEnv, R_BaseEnv,
609
		     R_NilValue, R_NilValue);
610
	    cntxt.cend = &terminate_process;
611
	    cntxt.cenddata = &pi;
72855 kalibera 612
	    DWORD timeoutMillis = (DWORD) (1000*timeout);
75992 kalibera 613
	    ret = pwait2(&pi, timeoutMillis, timedout);
64237 murdoch 614
	    endcontext(&cntxt);
615
	    snprintf(RunError, 501, _("Exit code was %d"), ret);
616
	    ret &= 0xffff;
617
	} else ret = 0;
75992 kalibera 618
	CloseHandle(pi.pi.hProcess);
64237 murdoch 619
    } else {
620
    	ret = NOLAUNCH;
621
    }
53870 murdoch 622
    if (close1) CloseHandle(hIN);
53348 ripley 623
    if (close2) CloseHandle(hOUT);
624
    if (close3) CloseHandle(hERR);
4394 ripley 625
    return ret;
626
}
627
 
12256 pd 628
/*
629
   finput is either NULL or the name of a file from which to
630
     redirect stdin for the child.
631
   visible = -1, 0, 1 for hide, minimized, default
40468 ripley 632
   io = 0 to read stdout from pipe, 1 to write to pipe,
52814 ripley 633
   2 to read stderr from pipe, 
634
   3 to read both stdout and stderr from pipe.
12256 pd 635
 */
45070 ripley 636
rpipe * rpipeOpen(const char *cmd, cetype_t enc, int visible,
53572 ripley 637
		  const char *finput, int io,
72855 kalibera 638
		  const char *fout, const char *ferr,
639
		  int timeout)
4394 ripley 640
{
641
    rpipe *r;
53572 ripley 642
    HANDLE hTHIS, hIN, hOUT, hERR, hReadPipe, hWritePipe;
4394 ripley 643
    DWORD id;
12256 pd 644
    BOOL res;
53870 murdoch 645
    int close1 = 0, close2 = 0, close3 = 0;
4394 ripley 646
 
11169 ripley 647
    if (!(r = (rpipe *) malloc(sizeof(struct structRPIPE)))) {
32888 ripley 648
	strcpy(RunError, _("Insufficient memory (rpipeOpen)"));
4394 ripley 649
	return NULL;
650
    }
51030 murdoch 651
    r->active = 0;
75992 kalibera 652
    r->pi.pi.hProcess = NULL;
653
    r->pi.job = NULL;
51030 murdoch 654
    r->thread = NULL;
72855 kalibera 655
    r->timedout = 0;
656
    r->timeoutMillis = (DWORD) (1000*timeout);
51015 murdoch 657
    res = CreatePipe(&hReadPipe, &hWritePipe, NULL, 0);
658
    if (res == FALSE) {
72855 kalibera 659
	rpipeClose(r, NULL);
52804 ripley 660
	strcpy(RunError, "CreatePipe failed");
51015 murdoch 661
	return NULL;
662
    }
663
    if(io == 1) { /* pipe for R to write to */
27774 murdoch 664
	hTHIS = GetCurrentProcess();
51015 murdoch 665
	r->read = hReadPipe;
666
	DuplicateHandle(hTHIS, hWritePipe, hTHIS, &r->write,
12256 pd 667
			0, FALSE, DUPLICATE_SAME_ACCESS);
51015 murdoch 668
	CloseHandle(hWritePipe);
12256 pd 669
	CloseHandle(hTHIS);
53348 ripley 670
	/* This sends stdout and stderr to NUL: */
52814 ripley 671
	pcreate(cmd, enc, 1, visible,
672
		r->read, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE,
673
		&(r->pi));
12256 pd 674
	r->active = 1;
75992 kalibera 675
	if (!r->pi.pi.hProcess) return NULL; else return r;
12256 pd 676
    }
52837 ripley 677
 
51015 murdoch 678
    /* pipe for R to read from */
4394 ripley 679
    hTHIS = GetCurrentProcess();
51015 murdoch 680
    r->write = hWritePipe;
681
    DuplicateHandle(hTHIS, hReadPipe, hTHIS, &r->read,
4394 ripley 682
		    0, FALSE, DUPLICATE_SAME_ACCESS);
51015 murdoch 683
    CloseHandle(hReadPipe);
4394 ripley 684
    CloseHandle(hTHIS);
52814 ripley 685
 
53348 ripley 686
    hIN = getInputHandle(finput); /* a file or (usually NUL:) */
53870 murdoch 687
 
688
    if (hIN && finput && finput[0]) close1 = 1;
689
 
53572 ripley 690
    if ((io == 0 || io == 3)) 
691
	hOUT = r->write;
692
    else {
693
	if (fout && fout[0]) close2 = 1;
694
 	hOUT = getOutputHandle(fout, 0);
695
    }
696
    if (io >= 2) 
697
	hERR = r->write;
698
    else {
699
	if (ferr && ferr[0]) close3 = 1;
700
	hERR = getOutputHandle(ferr, 1);
701
    }
702
    pcreate(cmd, enc, 0, visible, hIN, hOUT, hERR, &(r->pi));
53870 murdoch 703
    if (close1) CloseHandle(hIN);
53572 ripley 704
    if (close2) CloseHandle(hOUT);
705
    if (close3) CloseHandle(hERR);
52814 ripley 706
 
4394 ripley 707
    r->active = 1;
75992 kalibera 708
    if (!r->pi.pi.hProcess)
4394 ripley 709
	return NULL;
51030 murdoch 710
    if (!(r->thread = CreateThread(NULL, 0, threadedwait, r, 0, &id))) {
72855 kalibera 711
	rpipeClose(r, NULL);
52804 ripley 712
	strcpy(RunError, "CreateThread failed");
4394 ripley 713
	return NULL;
714
    }
715
    return r;
716
}
717
 
52814 ripley 718
static void
51030 murdoch 719
rpipeTerminate(rpipe * r)
720
{
721
    if (r->thread) {
52814 ripley 722
	TerminateThread(r->thread, 0);
723
	CloseHandle(r->thread);
724
	r->thread = NULL;
51030 murdoch 725
    }
726
    if (r->active) {
52814 ripley 727
	terminate_process(&(r->pi));
728
	r->active = 0;
51030 murdoch 729
    }
730
}
731
 
40513 ripley 732
#include "graphapp/ga.h"
733
extern Rboolean UserBreak;
4394 ripley 734
 
12256 pd 735
int
4394 ripley 736
rpipeGetc(rpipe * r)
737
{
738
    DWORD a, b;
739
    char  c;
740
 
741
    if (!r)
742
	return NOLAUNCH;
743
    while (PeekNamedPipe(r->read, NULL, 0, NULL, &a, NULL)) {
744
	if (!a && !r->active) {
745
	    /* I got a case in which process terminated after Peek.. */
746
	    PeekNamedPipe(r->read, NULL, 0, NULL, &a, NULL);
12256 pd 747
	    if (!a) return NOLAUNCH;/* end of pipe */
4394 ripley 748
	}
749
	if (a) {
750
	    if (ReadFile(r->read, &c, 1, &b, NULL) == TRUE)
751
		return c;
752
	    else
753
		return NOLAUNCH;/* error but...treated as eof */
754
	}
40513 ripley 755
	/* we want to look for user break here */
756
	while (peekevent()) doevent();
757
	if (UserBreak) {
51030 murdoch 758
	    rpipeTerminate(r);
40513 ripley 759
	    break;
760
	}
761
	R_ProcessEvents();
762
	Sleep(100);
4394 ripley 763
    }
764
    return NOLAUNCH;		/* again.. */
765
}
766
 
767
 
12256 pd 768
char * rpipeGets(rpipe * r, char *buf, int len)
4394 ripley 769
{
770
    int   i, c;
771
 
12256 pd 772
    if ((len < 2) || !r) return NULL;
4394 ripley 773
    for (i = 0; i < (len - 1); i++) {
774
	if ((c = rpipeGetc(r)) == NOLAUNCH) {
12256 pd 775
	    if (i == 0) return NULL;
4394 ripley 776
	    else {
777
		buf[i] = '\0';
778
		return buf;
779
	    }
780
	}
781
	buf[i] = c;
782
	if (c == '\n') {
783
	    if ((i > 0) && (buf[i - 1] == '\r')) {
784
		buf[i - 1] = '\n';
785
		buf[i] = '\0';
786
	    } else
787
		buf[i + 1] = '\0';
788
	    return buf;
789
	}
790
    }
791
    buf[len - 1] = '\0';
792
    return buf;
793
}
794
 
72855 kalibera 795
int rpipeClose(rpipe *r, int *timedout)
4394 ripley 796
{
797
    int   i;
798
 
12256 pd 799
    if (!r) return NOLAUNCH;
51030 murdoch 800
    rpipeTerminate(r);
73675 kalibera 801
    /* threadedwait may have obtained the exit code of the pipe process,
802
       but also may have been terminated too early; retrieve the exit
803
       code again to avoid race condition */
804
    DWORD ret;
75992 kalibera 805
    GetExitCodeProcess(r->pi.pi.hProcess, &ret);
73675 kalibera 806
    r->exitcode = ret;
4394 ripley 807
    CloseHandle(r->read);
808
    CloseHandle(r->write);
75992 kalibera 809
    CloseHandle(r->pi.pi.hProcess);
4394 ripley 810
    i = r->exitcode;
72855 kalibera 811
    if (timedout)
812
	*timedout = r->timedout;
11169 ripley 813
    free(r);
42618 ripley 814
    return i &= 0xffff;
4394 ripley 815
}
6153 guido 816
 
12256 pd 817
/* ------------------- Windows pipe connections --------------------- */
6153 guido 818
 
12256 pd 819
#include <Fileio.h>
820
#include <Rconnections.h>
6153 guido 821
 
12256 pd 822
typedef struct Wpipeconn {
823
    rpipe *rp;
824
} *RWpipeconn;
6153 guido 825
 
826
 
18611 ripley 827
static Rboolean Wpipe_open(Rconnection con)
12256 pd 828
{
829
    rpipe *rp;
830
    int visible = -1, io;
6153 guido 831
 
12256 pd 832
    io = con->mode[0] == 'w';
833
    if(io) visible = 1; /* Somewhere to put the output */
72855 kalibera 834
    rp = rpipeOpen(con->description, con->enc, visible, NULL, io, NULL, NULL, 0);
18611 ripley 835
    if(!rp) {
836
	warning("cannot open cmd `%s'", con->description);
837
	return FALSE;
838
    }
12256 pd 839
    ((RWpipeconn)(con->private))->rp = rp;
840
    con->isopen = TRUE;
841
    con->canwrite = io;
842
    con->canread = !con->canwrite;
843
    if(strlen(con->mode) >= 2 && con->mode[1] == 'b') con->text = FALSE;
844
    else con->text = TRUE;
845
    con->save = -1000;
18611 ripley 846
    return TRUE;
12256 pd 847
}
6153 guido 848
 
12256 pd 849
static void Wpipe_close(Rconnection con)
850
{
72855 kalibera 851
    con->status = rpipeClose( ((RWpipeconn)con->private) ->rp, NULL);
12256 pd 852
    con->isopen = FALSE;
853
}
854
 
855
static void Wpipe_destroy(Rconnection con)
856
{
857
    free(con->private);
858
}
859
 
860
 
861
static int Wpipe_fgetc(Rconnection con)
862
{
863
    rpipe *rp = ((RWpipeconn)con->private) ->rp;
864
    int c;
27774 murdoch 865
 
13371 ripley 866
    c = rpipeGetc(rp);
12256 pd 867
    return c == NOLAUNCH ? R_EOF : c;
868
}
869
 
870
 
31166 ripley 871
static double null_seek(Rconnection con, double where, int origin, int rw)
12256 pd 872
{
32888 ripley 873
    error(_("seek not enabled for this connection"));
12256 pd 874
    return 0; /* -Wall */
875
}
876
 
13315 ripley 877
static void null_truncate(Rconnection con)
878
{
32888 ripley 879
    error(_("truncate not enabled for this connection"));
13315 ripley 880
}
881
 
12256 pd 882
static int Wpipe_fflush(Rconnection con)
883
{
884
    BOOL res;
885
 
886
    rpipe *rp = ((RWpipeconn)con->private) ->rp;
887
    res = FlushFileBuffers(rp->write);
888
    return res ? 0 : EOF;
889
}
890
 
891
static size_t Wpipe_read(void *ptr, size_t size, size_t nitems,
892
			Rconnection con)
893
{
894
    rpipe *rp = ((RWpipeconn)con->private) ->rp;
895
    DWORD ntoread, read;
896
 
897
    while (PeekNamedPipe(rp->read, NULL, 0, NULL, &ntoread, NULL)) {
898
	if (!ntoread && !rp->active) {
899
	    /* I got a case in which process terminated after Peek.. */
900
	    PeekNamedPipe(rp->read, NULL, 0, NULL, &ntoread, NULL);
901
	    if (!ntoread) return 0; /* end of pipe */
902
	}
903
	if (ntoread) {
904
	    if (ReadFile(rp->read, ptr, nitems * size, &read, NULL) == TRUE)
905
		return read/size;
906
	    else return 0; /* error */
907
	}
908
    }
909
    return 0;
910
}
911
 
912
static size_t Wpipe_write(const void *ptr, size_t size, size_t nitems,
913
			 Rconnection con)
914
{
915
    rpipe *rp = ((RWpipeconn)con->private) ->rp;
916
    DWORD towrite = nitems * size, write, ret;
917
 
918
    if(!rp->active) return 0;
75992 kalibera 919
    GetExitCodeProcess(rp->pi.pi.hProcess, &ret);
12256 pd 920
    if(ret != STILL_ACTIVE) {
921
	rp->active = 0;
922
	warning("broken Windows pipe");
923
	return 0;
924
    }
925
    if (WriteFile(rp->write, ptr, towrite, &write, NULL) != 0)
926
	return write/size;
927
    else return 0;
928
}
929
 
63220 ripley 930
#define BUFSIZE 10000
12256 pd 931
static int Wpipe_vfprintf(Rconnection con, const char *format, va_list ap)
932
{
63221 ripley 933
    R_CheckStack2(BUFSIZE);
63181 ripley 934
    char buf[BUFSIZE], *b = buf;
63220 ripley 935
    int res = 0;
12256 pd 936
 
937
    res = vsnprintf(b, BUFSIZE, format, ap);
938
    if(res < 0) { /* a failure indication, so try again */
63220 ripley 939
	b[BUFSIZE -1] = '\0';
940
	warning("printing of extremely long output is truncated");
941
	res = BUFSIZE;
12256 pd 942
    }
63220 ripley 943
    return Wpipe_write(buf, res, 1, con);
12256 pd 944
}
945
 
63219 ripley 946
 
44013 ripley 947
Rconnection newWpipe(const char *description, int ienc, const char *mode)
12256 pd 948
{
949
    Rconnection new;
42638 murdoch 950
    char *command;
951
    int len;
45070 ripley 952
 
12256 pd 953
    new = (Rconnection) malloc(sizeof(struct Rconn));
32888 ripley 954
    if(!new) error(_("allocation of pipe connection failed"));
12256 pd 955
    new->class = (char *) malloc(strlen("pipe") + 1);
956
    if(!new->class) {
957
	free(new);
32888 ripley 958
	error(_("allocation of pipe connection failed"));
12256 pd 959
    }
960
    strcpy(new->class, "pipe");
45070 ripley 961
 
42638 murdoch 962
    len = strlen(getenv("COMSPEC")) + strlen(description) + 5;
963
    command = (char *) malloc(len);
45070 ripley 964
    if (command)
965
	new->description = (char *) malloc(len);
42638 murdoch 966
    else
45070 ripley 967
	new->description = NULL;
968
 
12256 pd 969
    if(!new->description) {
45070 ripley 970
	free(command); free(new->class); free(new);
32888 ripley 971
	error(_("allocation of pipe connection failed"));
12256 pd 972
    }
45070 ripley 973
 
974
    /* We always use COMSPEC here, not R_SHELL or SHELL,
975
       for compatibility with Rterm.
976
       We also use /c for the same reason.
977
    */
978
 
42638 murdoch 979
    strcpy(command, getenv("COMSPEC"));
980
    strcat(command, " /c ");
981
    strcat(command, description);
45070 ripley 982
 
44013 ripley 983
    init_con(new, command, ienc, mode);
42638 murdoch 984
    free(command);
45070 ripley 985
 
12256 pd 986
    new->open = &Wpipe_open;
987
    new->close = &Wpipe_close;
988
    new->destroy = &Wpipe_destroy;
989
    new->vfprintf = &Wpipe_vfprintf;
990
    new->fgetc = &Wpipe_fgetc;
991
    new->seek = &null_seek;
13315 ripley 992
    new->truncate = &null_truncate;
12256 pd 993
    new->fflush = &Wpipe_fflush;
994
    new->read = &Wpipe_read;
995
    new->write = &Wpipe_write;
996
    new->private = (void *) malloc(sizeof(struct Wpipeconn));
997
    if(!new->private) {
998
	free(new->description); free(new->class); free(new);
32888 ripley 999
	error(_("allocation of pipe connection failed"));
12256 pd 1000
    }
1001
    return new;
1002
}
42480 ripley 1003
 
1004
 
1005
SEXP do_syswhich(SEXP call, SEXP op, SEXP args, SEXP env)
1006
{
1007
    SEXP nm, ans;
1008
    int i, n;
1009
 
1010
    checkArity(op, args);
1011
    nm = CAR(args);
1012
    if(!isString(nm))
61427 ripley 1013
	error(_("'names' is not a character vector"));
42480 ripley 1014
    n = LENGTH(nm);
1015
    PROTECT(ans = allocVector(STRSXP, n));
1016
    for(i = 0; i < n; i++) {
61427 ripley 1017
	if (STRING_ELT(nm, i) == NA_STRING) {
1018
	    SET_STRING_ELT(ans, i, NA_STRING);
1019
	} else {
1020
	    const char *this = CHAR(STRING_ELT(nm, i));
1021
	    char *that = expandcmd(this, 1);
1022
	    SET_STRING_ELT(ans, i, mkChar(that ? that : ""));
1023
	    free(that);
1024
	}
42480 ripley 1025
    }
1026
    setAttrib(ans, R_NamesSymbol, nm);
1027
    UNPROTECT(1);
1028
    return ans;
1029
}