NetWare update from C Aditya.
[perl.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_ "The telldir() function is not implemented on NetWare\n");
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 not implemented on NetWare\n");
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         dTHX;
398         Perl_croak(aTHX_ "The flock() function is not implemented on NetWare\n");
399         return 0;
400 }
401
402
403 FILE *
404 nw_fopen(const char *filename, const char *mode)
405 {
406         return (fopen(filename, mode));
407 }
408
409 int
410 nw_fputc(int c, FILE *pf)
411 {
412         if(pf)
413             return fputc(c,pf);
414         else
415             return -1;
416 }
417
418 int
419 nw_fputs(const char *s, FILE *pf)
420 {
421         if(pf)
422             return fputs(s, pf);
423         else
424             return -1;
425 }
426
427 size_t
428 nw_fread(void *buf, size_t size, size_t count, FILE *fp)
429 {
430         if(fp)
431             return fread(buf, size, count, fp);
432         else
433             return -1;
434 }
435
436 FILE *
437 nw_freopen(const char *path, const char *mode, FILE *stream)
438 {
439         if(stream)
440             return freopen(path, mode, stream);
441         else
442             return NULL;
443 }
444
445 int
446 nw_fseek(FILE *pf, long offset, int origin)
447 {
448         if(pf)
449             return (fseek(pf, offset, origin));
450         else
451             return -1;
452 }
453
454 int
455 nw_fsetpos(FILE *pf, const fpos_t *p)
456 {
457         if(pf)
458             return fsetpos(pf, p);
459         else
460             return -1;
461 }
462
463 long
464 nw_ftell(FILE *pf)
465 {
466         if(pf)
467             return ftell(pf);
468         else
469             return -1;
470 }
471
472 size_t
473 nw_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
474 {
475         if(fp)
476             return fwrite(buf, size, count, fp);
477         else
478             return -1;
479 }
480
481 long
482 nw_get_osfhandle(int fd)
483 {
484         return 0l;
485 }
486
487 int
488 nw_getc(FILE *pf)
489 {
490         if(pf)
491             return getc(pf);
492         else
493             return -1;
494 }
495
496 int
497 nw_putc(int c, FILE *pf)
498 {
499         if(pf)
500             return putc(c,pf);
501         else
502             return -1;
503 }
504
505 int
506 nw_fgetc(FILE *pf)
507 {
508         if(pf)
509             return fgetc(pf);
510         else
511             return -1;
512 }
513
514 int
515 nw_getpid(void)
516 {
517         return GetThreadGroupID();
518 }
519
520 int
521 nw_kill(int pid, int sig)
522 {
523         return 0;
524 }
525
526 int
527 nw_link(const char *oldname, const char *newname)
528 {
529         return 0;
530 }
531
532 long
533 nw_lseek(int fd, long offset, int origin)
534 {
535     return lseek(fd, offset, origin);
536 }
537
538 int
539 nw_chdir(const char *dir)
540 {
541     return chdir(dir);
542 }
543
544 int
545 nw_rmdir(const char *dir)
546 {
547     return rmdir(dir);
548 }
549
550 DIR *
551 nw_opendir(char *filename)
552 {
553         char    *buff = NULL;
554         int             len = 0;
555         DIR             *ret = NULL;
556         
557         len = strlen(filename);
558         buff = malloc(len + 5);
559         if (buff) {
560                 strcpy(buff, filename);
561                 if (buff[len-1]=='/' || buff[len-1]=='\\') {
562                         buff[--len] = 0;
563                 }
564                 strcpy(buff+len, "/*.*");
565                 ret = opendir(buff);
566                 free (buff);
567                 buff = NULL;
568                 return ret;
569         } else {
570                 return NULL;
571         }
572 }
573
574 int
575 nw_open(const char *path, int flag, ...)
576 {
577         va_list ap;
578         int pmode = -1;
579
580         va_start(ap, flag);
581     pmode = va_arg(ap, int);
582     va_end(ap);
583
584         if (stricmp(path, "/dev/nul")==0)
585         path = "NWNUL";
586
587         return open(path, flag, pmode);
588 }
589
590 int
591 nw_open_osfhandle(long handle, int flags)
592 {
593         return 0;
594 }
595
596 unsigned long
597 nw_os_id(void)
598 {
599         return 0l;
600 }
601
602 int nw_Pipe(int* a, int* e)
603 {
604         int ret = 0;
605
606         errno = 0;
607         ret = pipe(a);
608         if(errno)
609                 e = &errno;
610
611         return ret;
612 }
613
614 FILE* nw_Popen(char* command, char* mode, int* e)
615 {
616         int i = -1;
617
618         FILE* ret = NULL;
619         PTEMPPIPEFILE ptpf = NULL;
620
621         // this callback is supposed to call _popen, which spawns an
622         // asynchronous command and opens a pipe to it. The returned
623         // file handle can be read or written to; if read, it represents
624         // stdout of the called process and will return EOF when the
625         // called process finishes. If written to, it represents stdin
626         // of the called process. Naturally _popen is not available on
627         // NetWare so we must do some fancy stuff to simulate it. We will
628         // redirect to and from temp files; this has the side effect
629         // of having to run the process synchronously rather than
630         // asynchronously. This means that you will only be able to do
631         // this with CLIB NLMs built to run on the calling thread.
632
633         errno = 0;
634
635         ptpf1[iPopenCount] = (PTEMPPIPEFILE) malloc(sizeof(TEMPPIPEFILE));
636         if (!ptpf1[iPopenCount])
637                 return NULL;
638
639         ptpf = ptpf1[iPopenCount];
640         iPopenCount ++;
641         if(iPopenCount > MAX_PIPE_RECURSION)
642                 iPopenCount = MAX_PIPE_RECURSION;       // Limit to the max no of pipes to be open recursively.
643
644         fnTempPipeFile(ptpf);
645         ret = fnPipeFileOpen((PTEMPPIPEFILE) ptpf, (char *) command, (char *) mode);
646         if (ret)
647                 File1[iPopenCount-1] = ret;     // Store the obtained Pipe file handle.
648         else
649         {       // Pipe file not obtained. So free the allocated memory.
650                 if(ptpf1[iPopenCount-1])
651                 {
652                         free(ptpf1[iPopenCount-1]);
653                         ptpf1[iPopenCount-1] = NULL;
654                         ptpf = NULL;
655                         iPopenCount --;
656                 }
657         }
658
659         if (errno)
660                 e = &errno;
661
662         return ret;
663 }
664
665 int nw_Pclose(FILE* file, int* e)
666 {
667         int i=0, j=0;
668
669         errno = 0;
670
671         if(file)
672         {
673                 if(iPopenCount > 0)
674                 {
675                         for (i=0; i<iPopenCount; i++)
676                         {
677                                 if(File1[i] == file)
678                                 {
679                                         // Delete the memory allocated corresponding to the file handle passed-in and
680                                         // also close the file corresponding to the file handle passed-in!
681                                         if(ptpf1[i])
682                                         {
683                                                 fnPipeFileClose(ptpf1[i]);
684
685                                                 free(ptpf1[i]);
686                                                 ptpf1[i] = NULL;
687                                         }
688
689                                         fclose(File1[i]);
690                                         File1[i] = NULL;
691
692                                         break;
693                                 }
694                         }
695
696                         // Rearrange the file pointer array
697                         for(j=i; j<(iPopenCount-1); j++)
698                         {
699                                 File1[j] = File1[j+1];
700                                 ptpf1[j] = ptpf1[j+1];
701                         }
702                         iPopenCount--;
703                 }
704         }
705         else
706             return -1;
707
708         if (errno)
709                 e = &errno;
710
711         return 0;
712 }
713
714
715 int
716 nw_vprintf(const char *format, va_list args)
717 {
718     return (vprintf(format, args));
719 }
720
721 int
722 nw_printf(const char *format, ...)
723 {
724         
725         va_list marker;
726     va_start(marker, format);     /* Initialize variable arguments. */
727
728     return (vprintf(format, marker));
729 }
730
731 int
732 nw_read(int fd, void *buf, unsigned int cnt)
733 {
734         return read(fd, buf, cnt);
735 }
736
737 struct direct *
738 nw_readdir(DIR *dirp)
739 {
740         DIR* ret=NULL;
741
742         ret = readdir(dirp);
743         if(ret)
744                 return((struct direct *)ret);
745         return NULL;
746 }
747
748 int
749 nw_rename(const char *oname, const char *newname)
750 {
751         return(rename(oname,newname));
752 }
753
754 void
755 nw_rewinddir(DIR *dirp)
756 {
757         dTHX;
758         Perl_croak(aTHX_ "The rewinddir() function is not implemented on NetWare\n");
759 }
760
761 void
762 nw_rewind(FILE *pf)
763 {
764         if(pf)
765             rewind(pf);
766 }
767
768 void
769 nw_seekdir(DIR *dirp, long loc)
770 {
771         dTHX;
772         Perl_croak(aTHX_ "The seekdir() function is not implemented on NetWare\n");
773 }
774
775 int *
776 nw_errno(void)
777 {
778     return (&errno);
779 }
780
781 char ***
782 nw_environ(void)
783 {
784         return ((char ***)nw_getenviron());
785 }
786
787 char *
788 nw_strerror(int e)
789 {
790         return (strerror(e));
791 }
792
793 int
794 nw_isatty(int fd)
795 {
796         return(isatty(fd));
797 }
798
799 char *
800 nw_mktemp(char *Template)
801 {
802         return (fnMy_MkTemp(Template));
803 }
804
805 int
806 nw_chsize(int handle, long size)
807 {
808         return(chsize(handle,size));
809 }
810
811 #ifdef HAVE_INTERP_INTERN
812 void
813 sys_intern_init(pTHX)
814 {
815
816 }
817
818 void
819 sys_intern_clear(pTHX)
820 {
821
822 }
823
824 void
825 sys_intern_dup(pTHX_ struct interp_intern *src, struct interp_intern *dst)
826 {
827
828 }
829 #endif  /* HAVE_INTERP_INTERN */
830
831 void
832 Perl_init_os_extras(void)
833 {
834     
835 }
836
837 void
838 Perl_nw5_init(int *argcp, char ***argvp)
839 {
840     MALLOC_INIT;
841 }
842
843 #ifdef USE_ITHREADS
844 PerlInterpreter *
845 perl_clone_host(PerlInterpreter* proto_perl, UV flags)
846 {
847         // Perl Clone is not implemented on NetWare.
848     return NULL;
849 }
850 #endif
851
852 // Some more functions:
853
854 char *
855 nw_get_sitelib(const char *pl)
856 {
857     return (NULL);
858 }
859
860 int
861 execv(char *cmdname, char **argv)
862 {
863         // This feature needs to be implemented.
864         // _asm is commented out since it goes into the internal debugger.
865 //      _asm {int 3};
866         return(0);
867 }
868
869 int
870 execvp(char *cmdname, char **argv)
871 {
872         // This feature needs to be implemented.
873         // _asm is commented out since it goes into the internal debugger.
874 //      _asm {int 3};
875         return(0);
876 }
877
878 int
879 do_aspawn(void *vreally, void **vmark, void **vsp)
880 {
881         // This feature needs to be implemented.
882         // _asm is commented out since it goes into the internal debugger.
883 //      _asm {int 3};
884 ////    return(0);
885
886
887         // This below code is required for system() call.
888         // Otherwise system() does not work on NetWare.
889         // Ananth, 3 Sept 2001
890
891     dTHX;
892     SV *really = (SV*)vreally;
893     SV **mark = (SV**)vmark;
894     SV **sp = (SV**)vsp;
895     char **argv;
896     char *str;
897     int status;
898     int flag = P_WAIT;
899     int index = 0;
900
901
902     if (sp <= mark)
903         return -1;
904
905         nw_perlshell_items = 0; // No Shell
906     New(1306, argv, (sp - mark) + nw_perlshell_items + 3, char*);
907
908     if (SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
909         ++mark;
910         flag = SvIVx(*mark);
911     }
912
913     while (++mark <= sp) {
914         if (*mark && (str = (char *)SvPV_nolen(*mark)))
915         {
916             argv[index] = str;
917                 index++;
918         }
919         else
920         {
921                 argv[index] = "";
922 //              argv[index] = '\0';
923                 index++;
924     }
925         }
926     argv[index] = '\0';
927         index++;
928
929     status = nw_spawnvp(flag,
930                            (char*)(really ? SvPV_nolen(really) : argv[0]),
931                            (char**)argv);
932
933
934     if (flag != P_NOWAIT) {
935         if (status < 0) {
936             dTHR;
937             if (ckWARN(WARN_EXEC))
938                 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't spawn \"%s\": %s", argv[0], strerror(errno));
939             status = 255 * 256;
940         }
941         else
942             status *= 256;
943         PL_statusvalue = status;
944     }
945
946     Safefree(argv);
947     return (status);
948 }
949
950 int
951 do_spawn2(char *cmd, int exectype)
952 {
953         // This feature needs to be implemented.
954         // _asm is commented out since it goes into the internal debugger.
955 //      _asm {int 3};
956         return(0);
957 }
958
959 int
960 do_spawn(char *cmd)
961 {
962     return do_spawn2(cmd, 2);
963 }
964
965 int
966 fork(void)
967 {
968         return 0;
969 }
970