1 
2 /*
3  * Copyright © 2001 Novell, Inc. All Rights Reserved.
4  *
5  * You may distribute under the terms of either the GNU General Public
6  * License or the Artistic License, as specified in the README file.
7  *
8  */
9 
10 /*
11  * FILENAME		:	NWPipe.c
12  * DESCRIPTION	:	Functions to implement pipes on NetWare.
13  * Author		:	HYAK
14  * Date			:	January 2001.
15  *
16  */
17 
18 
19 
20 #include <nwadv.h>
21 #include <nwdsdefs.h>
22 
23 #include "win32ish.h"
24 #include "nwpipe.h"
25 #include "nwplglob.h"
26 
27 
28 // This was added since the compile failed saying "undefined P_WAIT"
29 // when USE_ITHREADS was commented in the makefile
30 #ifndef P_WAIT
31 #define	P_WAIT		0
32 #endif
33 
34 #ifndef P_NOWAIT
35 #define	P_NOWAIT	1
36 #endif
37 
38 
39 
40 
41 /*============================================================================================
42 
43  Function		:	fnPipeFileMakeArgv
44 
45  Description	:	This function makes the argument array.
46 
47  Parameters 	:	ptpf	(IN)	-	Input structure.
48 
49  Returns		:	Boolean.
50 
51 ==============================================================================================*/
52 
fnPipeFileMakeArgv(PTEMPPIPEFILE ptpf)53 BOOL fnPipeFileMakeArgv(PTEMPPIPEFILE ptpf)
54 {
55 	int i=0, j=0;
56 	int dindex = 0;
57 	int sindex = 0;
58 
59 	ptpf->m_argv_len = 0;
60 
61 
62 	// Below 2 is added for the following reason:
63 	//   - The first one is for an additional value that will be added through ptpf->m_redirect.
64 	//   - The second one is for a NULL termination of the array.
65 	//     This is required for spawnvp API that takes a NULL-terminated array as its 3rd parameter.
66 	//     If the array is NOT NULL-terminated, then the server abends at the spawnvp call !!
67 	ptpf->m_argv = (char **) malloc((ptpf->m_pipeCommand->m_argc + 2) * sizeof(char*));
68 	if (ptpf->m_argv == NULL)
69 		return FALSE;
70 
71 	// For memory allocation it is just +1 since the last one is only for NULL-termination
72 	// and no memory is required to be allocated.
73 	for(i=0; i<(ptpf->m_pipeCommand->m_argc + 1); i++)
74 	{
75 		ptpf->m_argv[i] = (char *) malloc(MAX_DN_BYTES * sizeof(char));
76 		if (ptpf->m_argv[i] == NULL)
77 		{
78 			for(j=0; j<i; j++)
79 			{
80 				if(ptpf->m_argv[j])
81 				{
82 					free(ptpf->m_argv[j]);
83 					ptpf->m_argv[j] = NULL;
84 				}
85 			}
86 			free(ptpf->m_argv);
87 			ptpf->m_argv = NULL;
88 
89 			return FALSE;
90 		}
91 	}
92 
93 	// Copy over parsed items, removing "load" keyword if necessary.
94 	sindex = ((stricmp(ptpf->m_pipeCommand->m_argv[0], LOAD_COMMAND) == 0) ? 1 : 0);
95 	while (sindex < ptpf->m_pipeCommand->m_argc)
96 	{
97 		strcpy(ptpf->m_argv[dindex], ptpf->m_pipeCommand->m_argv[sindex]);
98 		dindex++;
99 		sindex++;
100 	}
101 
102 	if (stricmp(ptpf->m_argv[0], PERL_COMMAND_NAME) == 0)	// If Perl is the first command.
103 	{
104 		ptpf->m_launchPerl = TRUE;
105 
106 		#ifdef MPK_ON
107 			ptpf->m_perlSynchSemaphore = kSemaphoreAlloc((BYTE *)"pipeSemaphore", 0);
108 		#else
109 			ptpf->m_perlSynchSemaphore = OpenLocalSemaphore(0);
110 		#endif	//MPK_ON
111 	}
112 	else if (stricmp(ptpf->m_argv[0], (char *)"perlglob") == 0)
113 		ptpf->m_doPerlGlob = TRUE;
114 
115 
116 	// Create last argument, which will redirect to or from the temp file
117 	if (!ptpf->m_doPerlGlob || ptpf->m_mode)
118 	{
119 		if (!ptpf->m_mode)	// If read mode?
120 		{
121 			if (ptpf->m_launchPerl)
122 				strcpy(ptpf->m_redirect, (char *)">");
123 			else
124 				strcpy(ptpf->m_redirect, (char *)"(CLIB_OPT)/>");
125 		}
126 		else
127 		{
128 			if (ptpf->m_launchPerl)
129 				strcpy(ptpf->m_redirect, (char *)"<");
130 			else
131 				strcpy(ptpf->m_redirect, (char *)"(CLIB_OPT)/<");
132 		}
133 		strcat(ptpf->m_redirect, ptpf->m_fileName);
134 
135 		if (ptpf->m_launchPerl)
136 		{
137 			char tbuf[15] = {'\0'};
138 			sprintf(tbuf, (char *)" -{%x", ptpf->m_perlSynchSemaphore);
139 			strcat(ptpf->m_redirect, tbuf);
140 		}
141 
142 		strcpy(ptpf->m_argv[dindex], (char*) ptpf->m_redirect);
143 		dindex++;
144 	}
145 
146 	if (dindex < (ptpf->m_pipeCommand->m_argc + 1))
147 	{
148 		if(ptpf->m_argv[dindex])
149 		{
150 			free(ptpf->m_argv[dindex]);
151 			ptpf->m_argv[dindex] = NULL;	// NULL termination - required for  spawnvp  call.
152 		}
153 	}
154 
155 	ptpf->m_argv_len = dindex;		// Length of the argv array  OR  number of argv string values.
156 	ptpf->m_argv[ptpf->m_argv_len] = NULL;	// NULL termination - required for  spawnvp  call.
157 
158 
159 	return TRUE;
160 }
161 
162 
163 /*============================================================================================
164 
165  Function		:	fnPipeFileOpen
166 
167  Description	:	This function opens the pipe file.
168 
169  Parameters 	:	ptpf	(IN)	-	Input structure.
170 					command	(IN)	-	Input command string.
171 					mode	(IN)	-	Mode of opening.
172 
173  Returns		:	File pointer.
174 
175 ==============================================================================================*/
176 
fnPipeFileOpen(PTEMPPIPEFILE ptpf,char * command,char * mode)177 FILE* fnPipeFileOpen(PTEMPPIPEFILE ptpf, char* command, char* mode)
178 {
179 	int i=0, j=0;
180 
181 	char tempName[_MAX_PATH] = {'\0'};
182 
183 
184 	ptpf->m_fileName = (char *) malloc(_MAX_PATH * sizeof(char));
185 	if(ptpf->m_fileName == NULL)
186 		return NULL;
187 
188 	// The char array is emptied so that there is no junk characters.
189 	strncpy(ptpf->m_fileName, "", (_MAX_PATH * sizeof(char)));
190 
191 
192 	// Save off stuff
193 	//
194 	if(strchr(mode,'r') != 0)
195 		ptpf->m_mode = FALSE;	// Read mode
196 	else if(strchr(mode,'w') != 0)
197 		ptpf->m_mode = TRUE;	// Write mode
198 	else
199 	{
200 		if(ptpf->m_fileName != NULL)
201 		{
202 //			if (strlen(ptpf->m_fileName))
203 			if (ptpf->m_fileName)
204 				unlink(ptpf->m_fileName);
205 
206 			free(ptpf->m_fileName);
207 			ptpf->m_fileName = NULL;
208 		}
209 
210 		return NULL;
211 	}
212 
213 
214 	ptpf->m_pipeCommand = (PCOMMANDLINEPARSER) malloc(sizeof(COMMANDLINEPARSER));
215 	if (!ptpf->m_pipeCommand)
216 	{
217 //		if (strlen(ptpf->m_fileName))
218 		if (ptpf->m_fileName)
219 			unlink(ptpf->m_fileName);
220 
221 		free(ptpf->m_fileName);
222 		ptpf->m_fileName = NULL;
223 
224 		return NULL;
225 	}
226 
227 	// Initialise the variables
228 	ptpf->m_pipeCommand->m_isValid = TRUE;
229 
230 /****
231 // Commented since these are not being used.  Still retained here.
232 // To be removed once things are proved to be working fine to a good confident level,
233 
234 	ptpf->m_pipeCommand->m_redirInName = NULL;
235 	ptpf->m_pipeCommand->m_redirOutName = NULL;
236 	ptpf->m_pipeCommand->m_redirErrName = NULL;
237 	ptpf->m_pipeCommand->m_redirBothName = NULL;
238 	ptpf->m_pipeCommand->nextarg = NULL;
239 ****/
240 
241 	ptpf->m_pipeCommand->sSkippedToken = NULL;
242 	ptpf->m_pipeCommand->m_argv = NULL;
243 	ptpf->m_pipeCommand->new_argv = NULL;
244 
245 	#ifdef MPK_ON
246 		ptpf->m_pipeCommand->m_qSemaphore = NULL;
247 	#else
248 		ptpf->m_pipeCommand->m_qSemaphore = 0L;
249 	#endif	//MPK_ON
250 
251 	ptpf->m_pipeCommand->m_noScreen = 0;
252 	ptpf->m_pipeCommand->m_AutoDestroy = 0;
253 	ptpf->m_pipeCommand->m_argc = 0;
254 	ptpf->m_pipeCommand->m_argv_len = 1;
255 
256 
257 	ptpf->m_pipeCommand->m_argv = (char **) malloc(ptpf->m_pipeCommand->m_argv_len * sizeof(char *));
258 	if (ptpf->m_pipeCommand->m_argv == NULL)
259 	{
260 		free(ptpf->m_pipeCommand);
261 		ptpf->m_pipeCommand = NULL;
262 
263 //		if (strlen(ptpf->m_fileName))
264 		if (ptpf->m_fileName)
265 			unlink(ptpf->m_fileName);
266 
267 		free(ptpf->m_fileName);
268 		ptpf->m_fileName = NULL;
269 
270 		return NULL;
271 	}
272 	ptpf->m_pipeCommand->m_argv[0] = (char *) malloc(MAX_DN_BYTES * sizeof(char));
273 	if (ptpf->m_pipeCommand->m_argv[0] == NULL)
274 	{
275 		for(j=0; j<i; j++)
276 		{
277 			if(ptpf->m_pipeCommand->m_argv[j])
278 			{
279 				free(ptpf->m_pipeCommand->m_argv[j]);
280 				ptpf->m_pipeCommand->m_argv[j]=NULL;
281 			}
282 		}
283 		free(ptpf->m_pipeCommand->m_argv);
284 		ptpf->m_pipeCommand->m_argv=NULL;
285 
286 		free(ptpf->m_pipeCommand);
287 		ptpf->m_pipeCommand = NULL;
288 
289 //		if (strlen(ptpf->m_fileName))
290 		if (ptpf->m_fileName)
291 			unlink(ptpf->m_fileName);
292 
293 		free(ptpf->m_fileName);
294 		ptpf->m_fileName = NULL;
295 
296 		return NULL;
297 	}
298 
299 
300 	ptpf->m_redirect = (char *) malloc(MAX_DN_BYTES * sizeof(char));
301 	if (ptpf->m_redirect == NULL)
302 	{
303 		for(i=0; i<ptpf->m_pipeCommand->m_argv_len; i++)
304 		{
305 			if(ptpf->m_pipeCommand->m_argv[i] != NULL)
306 			{
307 				free(ptpf->m_pipeCommand->m_argv[i]);
308 				ptpf->m_pipeCommand->m_argv[i] = NULL;
309 			}
310 		}
311 
312 		free(ptpf->m_pipeCommand->m_argv);
313 		ptpf->m_pipeCommand->m_argv = NULL;
314 
315 		free(ptpf->m_pipeCommand);
316 		ptpf->m_pipeCommand = NULL;
317 
318 
319 //		if (strlen(ptpf->m_fileName))
320 		if (ptpf->m_fileName)
321 			unlink(ptpf->m_fileName);
322 
323 		free(ptpf->m_fileName);
324 		ptpf->m_fileName = NULL;
325 
326 		return NULL;
327 	}
328 
329 	// The char array is emptied.
330 	// If it is not done so, then it could contain some junk values and the string length in that case
331 	// will not be zero.  This causes erroneous results in  fnPipeFileMakeArgv()  function
332 	// where  strlen(ptpf->m_redirect)  is used as a check for incrementing the parameter count and
333 	// it will wrongly get incremented in such cases.
334 	strncpy(ptpf->m_redirect, "", (MAX_DN_BYTES * sizeof(char)));
335 
336 	// Parse the parameters.
337 	fnCommandLineParser(ptpf->m_pipeCommand, (char *)command, TRUE);
338 	if (!ptpf->m_pipeCommand->m_isValid)
339 	{
340 		fnTempPipeFileReleaseMemory(ptpf);
341 		return NULL;
342 	}
343 
344 
345 	// Create a temporary file name
346 	//
347 	strncpy ( tempName, fnNwGetEnvironmentStr((char *)"TEMP", NWDEFPERLTEMP), (_MAX_PATH - 20) );
348 	tempName[_MAX_PATH-20] = '\0';
349 	strcat(tempName, (char *)"\\plXXXXXX.tmp");
350 	if (!fnMy_MkTemp(tempName))
351 	{
352 		fnTempPipeFileReleaseMemory(ptpf);
353 		return NULL;
354 	}
355 
356 	// create a temporary place-holder file
357 	fclose(fopen(tempName, (char *)"w"));
358 	strcpy(ptpf->m_fileName, tempName);
359 
360 
361 	// Make the argument array
362 	if(!fnPipeFileMakeArgv(ptpf))
363 	{
364 		fnTempPipeFileReleaseMemory(ptpf);
365 
366 		// Release additional memory
367 		if(ptpf->m_argv != NULL)
368 		{
369 			for(i=0; i<ptpf->m_argv_len; i++)
370 			{
371 				if(ptpf->m_argv[i] != NULL)
372 				{
373 					free(ptpf->m_argv[i]);
374 					ptpf->m_argv[i] = NULL;
375 				}
376 			}
377 
378 			free(ptpf->m_argv);
379 			ptpf->m_argv = NULL;
380 		}
381 
382 		return NULL;
383 	}
384 
385 
386 	// Open the temp file in the appropriate way...
387 	//
388 	if (!ptpf->m_mode)	// If Read mode?
389 	{
390 		// we wish to spawn a command, intercept its output,
391 		// and then get that output
392 		//
393 		if (!ptpf->m_argv[0])
394 		{
395 			fnTempPipeFileReleaseMemory(ptpf);
396 
397 			// Release additional memory
398 			if(ptpf->m_argv != NULL)
399 			{
400 				for(i=0; i<ptpf->m_argv_len; i++)
401 				{
402 					if(ptpf->m_argv[i] != NULL)
403 					{
404 						free(ptpf->m_argv[i]);
405 						ptpf->m_argv[i] = NULL;
406 					}
407 				}
408 
409 				free(ptpf->m_argv);
410 				ptpf->m_argv = NULL;
411 			}
412 
413 			return NULL;
414 		}
415 
416 		if (ptpf->m_launchPerl)
417 			fnPipeFileDoPerlLaunch(ptpf);
418 		else
419 			if (ptpf->m_doPerlGlob)
420 				fnDoPerlGlob(ptpf->m_argv, ptpf->m_fileName);	// hack to do perl globbing
421 		else
422 			spawnvp(P_WAIT, ptpf->m_argv[0], ptpf->m_argv);
423 
424 		ptpf->m_file = fopen (ptpf->m_fileName, (char *)"r");	// Get the Pipe file handle
425 	}
426 	else if (ptpf->m_mode)	// If Write mode?
427 	{
428 		// we wish to open the file for writing now and
429 		// do the command later
430 		//
431 		ptpf->m_file = fopen(ptpf->m_fileName, (char *)"w");
432 	}
433 
434 	fnTempPipeFileReleaseMemory(ptpf);
435 
436 	// Release additional memory
437 	if(ptpf->m_argv != NULL)
438 	{
439 		for(i=0; i<(ptpf->m_argv_len); i++)
440 		{
441 			if(ptpf->m_argv[i] != NULL)
442 			{
443 				free(ptpf->m_argv[i]);
444 				ptpf->m_argv[i] = NULL;
445 			}
446 		}
447 
448 		free(ptpf->m_argv);
449 		ptpf->m_argv = NULL;
450 	}
451 
452 
453 	return ptpf->m_file;	// Return the Pipe file handle.
454 }
455 
456 
457 /*============================================================================================
458 
459  Function		:	fnPipeFileClose
460 
461  Description	:	This function closes the pipe file.
462 
463  Parameters 	:	ptpf	(IN)	-	Input structure.
464 
465  Returns		:	Nothing.
466 
467 ==============================================================================================*/
468 
fnPipeFileClose(PTEMPPIPEFILE ptpf)469 void fnPipeFileClose(PTEMPPIPEFILE ptpf)
470 {
471 	int i = 0;
472 
473 	if (ptpf->m_mode)	// If Write mode?
474 	{
475 		// we wish to spawn a command using our temp file for
476 		// its input
477 		//
478 		if(ptpf->m_file != NULL)
479 		{
480 			fclose (ptpf->m_file);
481 			ptpf->m_file = NULL;
482 		}
483 
484 		if (ptpf->m_launchPerl)
485 			fnPipeFileDoPerlLaunch(ptpf);
486 		else if (ptpf->m_argv)
487 			spawnvp(P_WAIT, ptpf->m_argv[0], ptpf->m_argv);
488 	}
489 
490 
491 	// Close the temporary Pipe File, if opened
492 	if (ptpf->m_file)
493 	{
494 		fclose(ptpf->m_file);
495 		ptpf->m_file = NULL;
496 	}
497 	// Delete the temporary Pipe Filename if still valid and free the memory associated with the file name.
498 	if(ptpf->m_fileName != NULL)
499 	{
500 //		if (strlen(ptpf->m_fileName))
501 		if (ptpf->m_fileName)
502 			unlink(ptpf->m_fileName);
503 
504 		free(ptpf->m_fileName);
505 		ptpf->m_fileName = NULL;
506 	}
507 
508 /**
509 	if(ptpf->m_argv != NULL)
510 	{
511 		for(i=0; i<(ptpf->m_argv_len); i++)
512 		{
513 			if(ptpf->m_argv[i] != NULL)
514 			{
515 				free(ptpf->m_argv[i]);
516 				ptpf->m_argv[i] = NULL;
517 			}
518 		}
519 
520 		free(ptpf->m_argv);
521 		ptpf->m_argv = NULL;
522 	}
523 **/
524 
525 	if (ptpf->m_perlSynchSemaphore)
526 	{
527 		#ifdef MPK_ON
528 			kSemaphoreFree(ptpf->m_perlSynchSemaphore);
529 		#else
530 			CloseLocalSemaphore(ptpf->m_perlSynchSemaphore);
531 		#endif	//MPK_ON
532 	}
533 
534 
535 	return;
536 }
537 
538 
539 /*============================================================================================
540 
541  Function		:	fnPipeFileDoPerlLaunch
542 
543  Description	:	This function launches Perl.
544 
545  Parameters 	:	ptpf	(IN)	-	Input structure.
546 
547  Returns		:	Nothing.
548 
549 ==============================================================================================*/
550 
fnPipeFileDoPerlLaunch(PTEMPPIPEFILE ptpf)551 void fnPipeFileDoPerlLaunch(PTEMPPIPEFILE ptpf)
552 {
553 	char curdir[_MAX_PATH] = {'\0'};
554 	char* pcwd = NULL;
555 
556 	int i=0;
557 
558 
559 	// save off the current working directory to restore later
560 	// this is just a hack! these problems of synchronization and
561 	// restoring calling context need a much better solution!
562 	pcwd = (char *)getcwd(curdir, sizeof(curdir)-1);
563 	fnSystemCommand(ptpf->m_argv, ptpf->m_argv_len);
564 	if (ptpf->m_perlSynchSemaphore)
565 	{
566 		#ifdef MPK_ON
567 			kSemaphoreWait(ptpf->m_perlSynchSemaphore);
568 		#else
569 			WaitOnLocalSemaphore(ptpf->m_perlSynchSemaphore);
570 		#endif	//MPK_ON
571 	}
572 
573 	if (pcwd)
574 		chdir(pcwd);
575 
576 	return;
577 }
578 
579 
580 /*============================================================================================
581 
582  Function		:	fnTempPipeFile
583 
584  Description	:	This function initialises the variables of the structure passed in.
585 
586  Parameters 	:	ptpf	(IN)	-	Input structure.
587 
588  Returns		:	Nothing.
589 
590 ==============================================================================================*/
591 
fnTempPipeFile(PTEMPPIPEFILE ptpf)592 void fnTempPipeFile(PTEMPPIPEFILE ptpf)
593 {
594 	ptpf->m_fileName = NULL;
595 
596 	ptpf->m_mode = FALSE;	// Default mode = Read mode.
597 	ptpf->m_file = NULL;
598 	ptpf->m_pipeCommand = NULL;
599 	ptpf->m_argv = NULL;
600 
601 	ptpf->m_redirect = NULL;
602 
603 	ptpf->m_launchPerl = FALSE;
604 	ptpf->m_doPerlGlob = FALSE;
605 
606 	#ifdef MPK_ON
607 		ptpf->m_perlSynchSemaphore = NULL;
608 	#else
609 		ptpf->m_perlSynchSemaphore = 0L;
610 	#endif
611 
612 	ptpf->m_argv_len = 0;
613 
614 	return;
615 }
616 
617 
618 /*============================================================================================
619 
620  Function		:	fnTempPipeFileReleaseMemory
621 
622  Description	:	This function frees the memory allocated to various buffers.
623 
624  Parameters 	:	ptpf	(IN)	-	Input structure.
625 
626  Returns		:	Nothing.
627 
628 ==============================================================================================*/
629 
fnTempPipeFileReleaseMemory(PTEMPPIPEFILE ptpf)630 void fnTempPipeFileReleaseMemory(PTEMPPIPEFILE ptpf)
631 {
632 	int i=0;
633 
634 
635 	if (ptpf->m_pipeCommand)
636 	{
637 		if(ptpf->m_pipeCommand->m_argv != NULL)
638 		{
639 			for(i=0; i<ptpf->m_pipeCommand->m_argv_len; i++)
640 			{
641 				if(ptpf->m_pipeCommand->m_argv[i] != NULL)
642 				{
643 					free(ptpf->m_pipeCommand->m_argv[i]);
644 					ptpf->m_pipeCommand->m_argv[i] = NULL;
645 				}
646 			}
647 
648 			free(ptpf->m_pipeCommand->m_argv);
649 			ptpf->m_pipeCommand->m_argv = NULL;
650 		}
651 
652 		if(ptpf->m_pipeCommand->sSkippedToken != NULL)
653 		{
654 			free(ptpf->m_pipeCommand->sSkippedToken);
655 			ptpf->m_pipeCommand->sSkippedToken = NULL;
656 		}
657 /****
658 // Commented since these are not being used.  Still retained here.
659 // To be removed once things are proved to be working fine to a good confident level,
660 
661 		if(ptpf->m_pipeCommand->nextarg)
662 		{
663 			free(ptpf->m_pipeCommand->nextarg);
664 			ptpf->m_pipeCommand->nextarg = NULL;
665 		}
666 
667 		if(ptpf->m_pipeCommand->m_redirInName)
668 		{
669 			free(ptpf->m_pipeCommand->m_redirInName);
670 			ptpf->m_pipeCommand->m_redirInName = NULL;
671 		}
672 		if(ptpf->m_pipeCommand->m_redirOutName)
673 		{
674 			free(ptpf->m_pipeCommand->m_redirOutName);
675 			ptpf->m_pipeCommand->m_redirOutName = NULL;
676 		}
677 		if(ptpf->m_pipeCommand->m_redirErrName)
678 		{
679 			free(ptpf->m_pipeCommand->m_redirErrName);
680 			ptpf->m_pipeCommand->m_redirErrName = NULL;
681 		}
682 		if(ptpf->m_pipeCommand->m_redirBothName)
683 		{
684 			free(ptpf->m_pipeCommand->m_redirBothName);
685 			ptpf->m_pipeCommand->m_redirBothName = NULL;
686 		}
687 ****/
688 
689 		if(ptpf->m_pipeCommand != NULL)
690 		{
691 			free(ptpf->m_pipeCommand);
692 			ptpf->m_pipeCommand = NULL;
693 		}
694 	}
695 
696 	if(ptpf->m_redirect != NULL)
697 	{
698 		free(ptpf->m_redirect);
699 		ptpf->m_redirect = NULL;
700 	}
701 
702 	return;
703 }
704 
705