This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
$$ readonly, take two
[perl5.git] / NetWare / nw5.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             :       nw5.c
12  * DESCRIPTION  :       Definitions for the redefined functions for NetWare.
13  * Author               :       SGP, HYAK
14  * Date                 :       January 2001.
15  *
16  */
17
18
19
20 #include <perl.h>       // For dTHX, etc.
21 #include "nwpipe.h"
22
23
24 // This was added since the compile failed saying "undefined P_WAIT"
25 // when USE_ITHREADS was commented in the makefile
26 #ifndef P_WAIT
27 #define P_WAIT          0
28 #endif
29
30 #ifndef P_NOWAIT
31 #define P_NOWAIT        1
32 #endif
33
34 // The array is used to store pointer to the memory allocated to the TempPipeFile structure everytime
35 // a call to the function, nw_Popen. If a simple variable is used, everytime the memory is allocated before
36 // the previously allocated memory is freed, the pointer will get overwritten and the previous memory allocations
37 // are lost! Only the most recent one will get freed when calls are made to nw_Pclose.
38 // By using the array and the iPopenCount to index the array, all memory are freed!
39
40 // The size of the array indicates the limit on the no of times the nw_Popen function can be called (and
41 // memory allocted) from within a script through backtick operators!
42 // This is arbitrarily set to MAX_PIPE_RECURSION=256 which indicates there can be 256 nested backtick operators possible!
43 PTEMPPIPEFILE ptpf1[MAX_PIPE_RECURSION] = {'\0'};
44 int iPopenCount = 0;
45 FILE* File1[MAX_PIPE_RECURSION] = {'\0'};
46
47
48 /**
49 General:
50
51 In this code, wherever there is a  FILE *, the error condition is checked; and only if the FILE * is TRUE,
52 then the corresponding operation is done. Otherwise the error value is returned.
53 This is done because the file operations like "open" in the Perl code returns the FILE *,
54 returning a valid value if the file is found or NULL when the particular file is not found.
55 Now, if the return value is NULL, then an operation say "fgets", "fopen" etc. using this this NULL value
56 for FILE * will abend the server. If the check is made then an operation on a non existing file
57 does not abend the server.
58 **/
59
60 void
61 nw_abort(void)
62 {
63         abort();        // Terminate the NLM application abnormally.
64         return;
65 }
66
67 int
68 nw_access(const char *path, int mode) 
69 {
70     return access(path, mode);
71 }
72
73 int
74 nw_chmod(const char *path, int mode)
75 {
76     return chmod(path, mode);
77 }
78
79 void
80 nw_clearerr(FILE *pf)
81 {
82         if(pf)
83             clearerr(pf);
84 }
85
86 int
87 nw_close(int fd)
88 {
89     return close(fd);
90 }
91
92 nw_closedir(DIR *dirp)
93 {
94         return (closedir(dirp));
95 }
96
97 void
98 nw_setbuf(FILE *pf, char *buf)
99 {
100         if(pf)
101             setbuf(pf, buf);
102 }
103
104 int
105 nw_setmode(FILE *fp, int mode)
106 {
107         int *dummy = 0;
108         return(fnFpSetMode(fp, mode, dummy));
109 }
110
111 int
112 nw_setvbuf(FILE *pf, char *buf, int type, size_t size)
113 {
114         if(pf)
115             return setvbuf(pf, buf, type, size);
116         else
117             return -1;
118 }
119
120
121 unsigned int
122 nw_sleep(unsigned int t)
123 {
124         delay(t*1000);  // Put the thread to sleep for 't' seconds.  Initially 't' is passed in milliseconds.
125     return 0;
126 }
127
128 int
129 nw_spawnvp(int mode, char *cmdname, char **argv)
130 {
131         // There is no pass-around environment on NetWare so we throw that
132         // argument away for now.
133
134         //  The function "spawnvp" does not work in all situations. Loading
135         // edit.nlm seems to work, for example, but the name of the file
136         // to edit does not appear to get passed correctly. Another problem
137         // is that on Netware, P_WAIT does not really work reliably. It only
138         // works with NLMs built to use CLIB (according to Nile Thayne).
139         // NLMs such as EDIT that are written directly to the system have no
140         // way of running synchronously from another process. The whole
141         // architecture on NetWare seems pretty busted, so we just support it
142         // as best we can.
143         //
144         // The spawnvp function only launches NLMs, it will not execute a command;
145         // the NetWare "system" function is used for that purpose. Unfortunately, "system"
146         // always returns success whether the command is successful or not or even
147         // if the command was not found! To avoid ambiguity--you can have both an
148         // NLM named "perl" and a system command named "perl"--we need to
149         // force perl scripts to carry the word "load" when loading an NLM. This
150         // might be clearer anyway.
151
152         int ret = 0;
153         int argc = 0;
154
155
156         if (stricmp(cmdname, LOAD_COMMAND) == 0)
157         {
158                 if (argv[1] != NULL)
159                         ret = spawnvp(mode, argv[1], &argv[1]);
160         }
161         else
162         {
163                 int i=0;
164                 while (argv[i] != '\0')
165                         i++;
166                 argc = i;
167
168                 fnSystemCommand(argv, argc);
169         }
170
171         return ret;
172 }
173
174 int
175 nw_execv(char *cmdname, char **argv)
176 {
177         return spawnvp(P_WAIT, cmdname, (char **)argv);
178 }
179
180
181 int
182 nw_execvp(char *cmdname, char **argv)
183 {
184         return nw_spawnvp(P_WAIT, cmdname, (char **)argv);
185 }
186
187 int
188 nw_stat(const char *path, struct stat *sbuf)
189 {
190         return (stat(path, sbuf));
191 }
192
193 FILE *
194 nw_stderr(void)
195 {
196         return (stderr);
197 }
198
199 FILE *
200 nw_stdin(void)
201 {
202         return (stdin);
203 }
204
205 FILE *
206 nw_stdout()
207 {
208         return (stdout);
209 }
210
211 long
212 nw_telldir(DIR *dirp)
213 {
214         dTHX;
215         Perl_croak(aTHX_ "telldir function is not implemented");
216         return 0l;
217 }
218
219 int
220 nw_times(struct tms *timebuf)
221 {
222         clock_t now = clock();
223
224         timebuf->tms_utime = now;
225         timebuf->tms_stime = 0;
226         timebuf->tms_cutime = 0;
227         timebuf->tms_cstime = 0;
228
229         return 0;
230 }
231
232 FILE*
233 nw_tmpfile(void)
234 {
235     return tmpfile();
236 }
237
238 int
239 nw_uname(struct utsname *name)
240 {
241         return(uname(name));
242 }
243
244 int
245 nw_ungetc(int c, FILE *pf)
246 {
247         if(pf)
248             return ungetc(c, pf);
249         else
250             return -1;
251 }
252
253 int
254 nw_unlink(const char *filename)
255 {
256         return(unlink(filename));
257 }
258
259 int
260 nw_utime(const char *filename, struct utimbuf *times)
261 {
262          return(utime(filename, times));
263 }
264
265 int
266 nw_vfprintf(FILE *fp, const char *format, va_list args)
267 {
268         if(fp)
269             return (vfprintf(fp, format, args));
270         else
271             return -1;
272 }
273
274 int
275 nw_wait(int *status)
276 {
277     return 0;   
278 }
279
280 int
281 nw_waitpid(int pid, int *status, int flags)
282 {
283     return 0;   
284 }
285
286 int
287 nw_write(int fd, const void *buf, unsigned int cnt)
288 {
289     return write(fd, buf, cnt);
290 }
291
292 char *
293 nw_crypt(const char *txt, const char *salt)
294 {
295          dTHX;
296
297 #ifdef HAVE_DES_FCRYPT
298     dTHR;
299     return des_fcrypt(txt, salt, w32_crypt_buffer);
300 #else
301     Perl_croak(aTHX_ "The crypt() function is unimplemented due to excessive paranoia.");
302     return Nullch;
303 #endif
304 }
305
306 int
307 nw_dup(int fd)
308 {
309     return dup(fd);
310 }
311
312 int
313 nw_dup2(int fd1,int fd2)
314 {
315         return dup2(fd1,fd2);
316 }
317
318 void*
319 nw_dynaload(const char* filename)
320 {
321         return NULL;
322 }
323
324 int
325 nw_fclose(FILE *pf)
326 {
327         if(pf)
328             return (fclose(pf));
329         else
330             return -1;
331 }
332
333 FILE *
334 nw_fdopen(int handle, const char *mode)
335 {
336         return(fdopen(handle, mode));
337 }
338
339 int
340 nw_feof(FILE *fp)
341 {
342         if(fp)
343             return (feof(fp));
344         else
345             return -1;
346 }
347
348 int
349 nw_ferror(FILE *fp)
350 {
351         if(fp)
352             return (ferror(fp));
353         else
354             return -1;
355 }
356
357
358 int
359 nw_fflush(FILE *pf)
360 {
361         if(pf)
362             return fflush(pf);
363         else
364             return -1;
365 }
366
367 int
368 nw_fgetpos(FILE *pf, fpos_t *p)
369 {
370         if(pf)
371             return fgetpos(pf, p);
372         else
373             return -1;
374 }
375
376 char*
377 nw_fgets(char *s, int n, FILE *pf)
378 {
379         if(pf)
380             return(fgets(s, n, pf));
381         else
382             return NULL;
383 }
384
385 int
386 nw_fileno(FILE *pf)
387 {
388         if(pf)
389             return fileno(pf);
390         else
391             return -1;
392 }
393
394 int
395 nw_flock(int fd, int oper)
396 {
397         return 0;
398 }
399
400
401 FILE *
402 nw_fopen(const char *filename, const char *mode)
403 {
404         return (fopen(filename, mode));
405 }
406
407 int
408 nw_fputc(int c, FILE *pf)
409 {
410         if(pf)
411             return fputc(c,pf);
412         else
413             return -1;
414 }
415
416 int
417 nw_fputs(const char *s, FILE *pf)
418 {
419         if(pf)
420             return fputs(s, pf);
421         else
422             return -1;
423 }
424
425 size_t
426 nw_fread(void *buf, size_t size, size_t count, FILE *fp)
427 {
428         if(fp)
429             return fread(buf, size, count, fp);
430         else
431             return -1;
432 }
433
434 FILE *
435 nw_freopen(const char *path, const char *mode, FILE *stream)
436 {
437         if(stream)
438             return freopen(path, mode, stream);
439         else
440             return NULL;
441 }
442
443 int
444 nw_fseek(FILE *pf, long offset, int origin)
445 {
446         if(pf)
447             return (fseek(pf, offset, origin));
448         else
449             return -1;
450 }
451
452 int
453 nw_fsetpos(FILE *pf, const fpos_t *p)
454 {
455         if(pf)
456             return fsetpos(pf, p);
457         else
458             return -1;
459 }
460
461 long
462 nw_ftell(FILE *pf)
463 {
464         if(pf)
465             return ftell(pf);
466         else
467             return -1;
468 }
469
470 size_t
471 nw_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
472 {
473         if(fp)
474             return fwrite(buf, size, count, fp);
475         else
476             return -1;
477 }
478
479 long
480 nw_get_osfhandle(int fd)
481 {
482         return 0l;
483 }
484
485 int
486 nw_getc(FILE *pf)
487 {
488         if(pf)
489             return getc(pf);
490         else
491             return -1;
492 }
493
494 int
495 nw_putc(int c, FILE *pf)
496 {
497         if(pf)
498             return putc(c,pf);
499         else
500             return -1;
501 }
502
503 int
504 nw_fgetc(FILE *pf)
505 {
506         if(pf)
507             return fgetc(pf);
508         else
509             return -1;
510 }
511
512 int
513 nw_getpid(void)
514 {
515         return GetThreadGroupID();
516 }
517
518 int
519 nw_kill(int pid, int sig)
520 {
521         return 0;
522 }
523
524 int
525 nw_link(const char *oldname, const char *newname)
526 {
527         return 0;
528 }
529
530 long
531 nw_lseek(int fd, long offset, int origin)
532 {
533     return lseek(fd, offset, origin);
534 }
535
536 int
537 nw_chdir(const char *dir)
538 {
539     return chdir(dir);
540 }
541
542 int
543 nw_rmdir(const char *dir)
544 {
545     return rmdir(dir);
546 }
547
548 DIR *
549 nw_opendir(char *filename)
550 {
551         char    *buff = NULL;
552         int             len = 0;
553         DIR             *ret = NULL;
554         
555         len = strlen(filename);
556         buff = malloc(len + 5);
557         if (buff) {
558                 strcpy(buff, filename);
559                 if (buff[len-1]=='/' || buff[len-1]=='\\') {
560                         buff[--len] = 0;
561                 }
562                 strcpy(buff+len, "/*.*");
563                 ret = opendir(buff);
564                 free (buff);
565                 buff = NULL;
566                 return ret;
567         } else {
568                 return NULL;
569         }
570 }
571
572 int
573 nw_open(const char *path, int flag, ...)
574 {
575         va_list ap;
576         int pmode = -1;
577
578         va_start(ap, flag);
579     pmode = va_arg(ap, int);
580     va_end(ap);
581
582         if (stricmp(path, "/dev/null")==0)
583         path = "NUL";
584
585         return open(path, flag, pmode);
586 }
587
588 int
589 nw_open_osfhandle(long handle, int flags)
590 {
591         return 0;
592 }
593
594 unsigned long
595 nw_os_id(void)
596 {
597         return 0l;
598 }
599
600 int nw_Pipe(int* a, int* e)
601 {
602         int ret = 0;
603
604         errno = 0;
605         ret = pipe(a);
606         if(errno)
607                 e = &errno;
608
609         return ret;
610 }
611
612 FILE* nw_Popen(char* command, char* mode, int* e)
613 {
614         int i = -1;
615
616         FILE* ret = NULL;
617         PTEMPPIPEFILE ptpf = NULL;
618
619         // this callback is supposed to call _popen, which spawns an
620         // asynchronous command and opens a pipe to it. The returned
621         // file handle can be read or written to; if read, it represents
622         // stdout of the called process and will return EOF when the
623         // called process finishes. If written to, it represents stdin
624         // of the called process. Naturally _popen is not available on
625         // NetWare so we must do some fancy stuff to simulate it. We will
626         // redirect to and from temp files; this has the side effect
627         // of having to run the process synchronously rather than
628         // asynchronously. This means that you will only be able to do
629         // this with CLIB NLMs built to run on the calling thread.
630
631         errno = 0;
632
633         ptpf1[iPopenCount] = (PTEMPPIPEFILE) malloc(sizeof(TEMPPIPEFILE));
634         if (!ptpf1[iPopenCount])
635                 return NULL;
636
637         ptpf = ptpf1[iPopenCount];
638         iPopenCount ++;
639         if(iPopenCount > MAX_PIPE_RECURSION)
640                 iPopenCount = MAX_PIPE_RECURSION;       // Limit to the max no of pipes to be open recursively.
641
642         fnTempPipeFile(ptpf);
643         ret = fnPipeFileOpen((PTEMPPIPEFILE) ptpf, (char *) command, (char *) mode);
644         if (ret)
645                 File1[iPopenCount-1] = ret;     // Store the obtained Pipe file handle.
646         else
647         {       // Pipe file not obtained. So free the allocated memory.
648                 if(ptpf1[iPopenCount-1])
649                 {
650                         free(ptpf1[iPopenCount-1]);
651                         ptpf1[iPopenCount-1] = NULL;
652                         ptpf = NULL;
653                         iPopenCount --;
654                 }
655         }
656
657         if (errno)
658                 e = &errno;
659
660         return ret;
661 }
662
663 int nw_Pclose(FILE* file, int* e)
664 {
665         int i=0, j=0;
666
667         errno = 0;
668
669         if(file)
670         {
671                 if(iPopenCount > 0)
672                 {
673                         for (i=0; i<iPopenCount; i++)
674                         {
675                                 if(File1[i] == file)
676                                 {
677                                         // Delete the memory allocated corresponding to the file handle passed-in and
678                                         // also close the file corresponding to the file handle passed-in!
679                                         if(ptpf1[i])
680                                         {
681                                                 fnPipeFileClose(ptpf1[i]);
682
683                                                 free(ptpf1[i]);
684                                                 ptpf1[i] = NULL;
685                                         }
686
687                                         fclose(File1[i]);
688                                         File1[i] = NULL;
689
690                                         break;
691                                 }
692                         }
693
694                         // Rearrange the file pointer array
695                         for(j=i; j<(iPopenCount-1); j++)
696                         {
697                                 File1[j] = File1[j+1];
698                                 ptpf1[j] = ptpf1[j+1];
699                         }
700                         iPopenCount--;
701                 }
702         }
703         else
704             return -1;
705
706         if (errno)
707                 e = &errno;
708
709         return 0;
710 }
711
712
713 int
714 nw_vprintf(const char *format, va_list args)
715 {
716     return (vprintf(format, args));
717 }
718
719 int
720 nw_printf(const char *format, ...)
721 {
722         
723         va_list marker;
724     va_start(marker, format);     /* Initialize variable arguments. */
725
726     return (vprintf(format, marker));
727 }
728
729 int
730 nw_read(int fd, void *buf, unsigned int cnt)
731 {
732         return read(fd, buf, cnt);
733 }
734
735 struct direct *
736 nw_readdir(DIR *dirp)
737 {
738         DIR* ret=NULL;
739
740         ret = readdir(dirp);
741         if(ret)
742                 return((struct direct *)ret);
743         return NULL;
744 }
745
746 int
747 nw_rename(const char *oname, const char *newname)
748 {
749         return(rename(oname,newname));
750 }
751
752 void
753 nw_rewinddir(DIR *dirp)
754 {
755         dTHX;
756         Perl_croak(aTHX_ "rewinddir function is not implemented");
757 }
758
759 void
760 nw_rewind(FILE *pf)
761 {
762         if(pf)
763             rewind(pf);
764 }
765
766 void
767 nw_seekdir(DIR *dirp, long loc)
768 {
769         dTHX;
770         Perl_croak(aTHX_ "seekdir function is not implemented");
771 }
772
773 int *
774 nw_errno(void)
775 {
776     return (&errno);
777 }
778
779 char ***
780 nw_environ(void)
781 {
782         return ((char ***)nw_getenviron());
783 }
784
785 char *
786 nw_strerror(int e)
787 {
788         return (strerror(e));
789 }
790
791 int
792 nw_isatty(int fd)
793 {
794         return(isatty(fd));
795 }
796
797 char *
798 nw_mktemp(char *Template)
799 {
800         return (fnMy_MkTemp(Template));
801 }
802
803 int
804 nw_chsize(int handle, long size)
805 {
806         return(chsize(handle,size));
807 }
808
809 #ifdef HAVE_INTERP_INTERN
810 void
811 sys_intern_init(pTHX)
812 {
813
814 }
815
816 void
817 sys_intern_clear(pTHX)
818 {
819
820 }
821
822 void
823 sys_intern_dup(pTHX_ struct interp_intern *src, struct interp_intern *dst)
824 {
825
826 }
827 #endif  /* HAVE_INTERP_INTERN */
828
829 void
830 Perl_init_os_extras(void)
831 {
832     
833 }
834
835 void
836 Perl_nw5_init(int *argcp, char ***argvp)
837 {
838     MALLOC_INIT;
839 }
840
841 #ifdef USE_ITHREADS
842 PerlInterpreter *
843 perl_clone_host(PerlInterpreter* proto_perl, UV flags)
844 {
845         // Perl Clone is not implemented on NetWare.
846     return NULL;
847 }
848 #endif
849
850 // Some more functions:
851
852 char *
853 nw_get_sitelib(const char *pl)
854 {
855     return (NULL);
856 }
857
858 int
859 execv(char *cmdname, char **argv)
860 {
861         // This feature needs to be implemented.
862         // _asm is commented out since it goes into the internal debugger.
863 //      _asm {int 3};
864         return(0);
865 }
866
867 int
868 execvp(char *cmdname, char **argv)
869 {
870         // This feature needs to be implemented.
871         // _asm is commented out since it goes into the internal debugger.
872 //      _asm {int 3};
873         return(0);
874 }
875
876 int
877 do_aspawn(void *vreally, void **vmark, void **vsp)
878 {
879         // This feature needs to be implemented.
880         // _asm is commented out since it goes into the internal debugger.
881 //      _asm {int 3};
882 ////    return(0);
883
884
885         // This below code is required for system() call.
886         // Otherwise system() does not work on NetWare.
887         // Ananth, 3 Sept 2001
888
889     dTHX;
890     SV *really = (SV*)vreally;
891     SV **mark = (SV**)vmark;
892     SV **sp = (SV**)vsp;
893     char **argv;
894     char *str;
895     int status;
896     int flag = P_WAIT;
897     int index = 0;
898
899
900     if (sp <= mark)
901         return -1;
902
903         nw_perlshell_items = 0; // No Shell
904     New(1306, argv, (sp - mark) + nw_perlshell_items + 3, char*);
905
906     if (SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
907         ++mark;
908         flag = SvIVx(*mark);
909     }
910
911     while (++mark <= sp) {
912         if (*mark && (str = (char *)SvPV_nolen(*mark)))
913         {
914             argv[index] = str;
915                 index++;
916         }
917         else
918         {
919                 argv[index] = "";
920 //              argv[index] = '\0';
921                 index++;
922     }
923         }
924     argv[index] = '\0';
925         index++;
926
927     status = nw_spawnvp(flag,
928                            (char*)(really ? SvPV_nolen(really) : argv[0]),
929                            (char**)argv);
930
931
932     if (flag != P_NOWAIT) {
933         if (status < 0) {
934             dTHR;
935             if (ckWARN(WARN_EXEC))
936                 Perl_warner(aTHX_ WARN_EXEC, "Can't spawn \"%s\": %s", argv[0], strerror(errno));
937             status = 255 * 256;
938         }
939         else
940             status *= 256;
941         PL_statusvalue = status;
942     }
943
944     Safefree(argv);
945     return (status);
946 }
947
948 int
949 do_spawn2(char *cmd, int exectype)
950 {
951         // This feature needs to be implemented.
952         // _asm is commented out since it goes into the internal debugger.
953 //      _asm {int 3};
954         return(0);
955 }
956
957 int
958 do_spawn(char *cmd)
959 {
960     return do_spawn2(cmd, 2);
961 }
962
963 int
964 fork(void)
965 {
966         return 0;
967 }
968