This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
perlfaq is not the only exception; just say "few"
[perl5.git] / NetWare / Nwpipe.c
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
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
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
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
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
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
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