3 * VMS-specific routines for perl5
5 * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
6 * 2002, 2003, 2004, 2005, 2006, 2007 by Charles Bailey and others.
8 * You may distribute under the terms of either the GNU General Public
9 * License or the Artistic License, as specified in the README file.
11 * Please see Changes*.* or the Perl Repository Browser for revision history.
15 * Yet small as was their hunted band
16 * still fell and fearless was each hand,
17 * and strong deeds they wrought yet oft,
18 * and loved the woods, whose ways more soft
19 * them seemed than thralls of that black throne
20 * to live and languish in halls of stone.
21 * "The Lay of Leithian", Canto II, lines 135-40
23 * [p.162 of _The Lays of Beleriand_]
29 #if __CRTL_VER < 70300000
30 /* needed for home-rolled utime() */
36 #include <climsgdef.h>
46 #include <libclidef.h>
48 #include <lib$routines.h>
51 #if __CRTL_VER >= 70301000 && !defined(__VAX)
61 #include <str$routines.h>
66 #if __CRTL_VER >= 70000000 /* FIXME to earliest version */
68 #define NO_EFN EFN$C_ENF
73 #if __CRTL_VER < 70301000 && __CRTL_VER >= 70300000
74 int decc$feature_get_index(const char *name);
75 char* decc$feature_get_name(int index);
76 int decc$feature_get_value(int index, int mode);
77 int decc$feature_set_value(int index, int mode, int value);
82 #pragma member_alignment save
83 #pragma nomember_alignment longword
88 unsigned short * retadr;
90 #pragma member_alignment restore
92 #if __CRTL_VER >= 70300000 && !defined(__VAX)
94 static int set_feature_default(const char *name, int value)
99 index = decc$feature_get_index(name);
101 status = decc$feature_set_value(index, 1, value);
102 if (index == -1 || (status == -1)) {
106 status = decc$feature_get_value(index, 1);
107 if (status != value) {
115 /* Older versions of ssdef.h don't have these */
116 #ifndef SS$_INVFILFOROP
117 # define SS$_INVFILFOROP 3930
119 #ifndef SS$_NOSUCHOBJECT
120 # define SS$_NOSUCHOBJECT 2696
123 /* We implement I/O here, so we will be mixing PerlIO and stdio calls. */
124 #define PERLIO_NOT_STDIO 0
126 /* Don't replace system definitions of vfork, getenv, lstat, and stat,
127 * code below needs to get to the underlying CRTL routines. */
128 #define DONT_MASK_RTL_CALLS
132 /* Anticipating future expansion in lexical warnings . . . */
133 #ifndef WARN_INTERNAL
134 # define WARN_INTERNAL WARN_MISC
137 #ifdef VMS_LONGNAME_SUPPORT
138 #include <libfildef.h>
141 #if defined(__VMS_VER) && __VMS_VER >= 70000000 && __DECC_VER >= 50200000
142 # define RTL_USES_UTC 1
145 #if !defined(__VAX) && __CRTL_VER >= 80200000
153 #define lstat(_x, _y) stat(_x, _y)
156 /* Routine to create a decterm for use with the Perl debugger */
157 /* No headers, this information was found in the Programming Concepts Manual */
159 static int (*decw_term_port)
160 (const struct dsc$descriptor_s * display,
161 const struct dsc$descriptor_s * setup_file,
162 const struct dsc$descriptor_s * customization,
163 struct dsc$descriptor_s * result_device_name,
164 unsigned short * result_device_name_length,
167 void * char_change_buffer) = 0;
169 /* gcc's header files don't #define direct access macros
170 * corresponding to VAXC's variant structs */
172 # define uic$v_format uic$r_uic_form.uic$v_format
173 # define uic$v_group uic$r_uic_form.uic$v_group
174 # define uic$v_member uic$r_uic_form.uic$v_member
175 # define prv$v_bypass prv$r_prvdef_bits0.prv$v_bypass
176 # define prv$v_grpprv prv$r_prvdef_bits0.prv$v_grpprv
177 # define prv$v_readall prv$r_prvdef_bits0.prv$v_readall
178 # define prv$v_sysprv prv$r_prvdef_bits0.prv$v_sysprv
181 #if defined(NEED_AN_H_ERRNO)
186 #pragma message disable pragma
187 #pragma member_alignment save
188 #pragma nomember_alignment longword
190 #pragma message disable misalgndmem
193 unsigned short int buflen;
194 unsigned short int itmcode;
196 unsigned short int *retlen;
199 struct filescan_itmlst_2 {
200 unsigned short length;
201 unsigned short itmcode;
206 unsigned short length;
211 #pragma message restore
212 #pragma member_alignment restore
215 #define do_fileify_dirspec(a,b,c,d) mp_do_fileify_dirspec(aTHX_ a,b,c,d)
216 #define do_pathify_dirspec(a,b,c,d) mp_do_pathify_dirspec(aTHX_ a,b,c,d)
217 #define do_tovmsspec(a,b,c,d) mp_do_tovmsspec(aTHX_ a,b,c,0,d)
218 #define do_tovmspath(a,b,c,d) mp_do_tovmspath(aTHX_ a,b,c,d)
219 #define do_rmsexpand(a,b,c,d,e,f,g) mp_do_rmsexpand(aTHX_ a,b,c,d,e,f,g)
220 #define do_vms_realpath(a,b,c) mp_do_vms_realpath(aTHX_ a,b,c)
221 #define do_vms_realname(a,b,c) mp_do_vms_realname(aTHX_ a,b,c)
222 #define do_tounixspec(a,b,c,d) mp_do_tounixspec(aTHX_ a,b,c,d)
223 #define do_tounixpath(a,b,c,d) mp_do_tounixpath(aTHX_ a,b,c,d)
224 #define do_vms_case_tolerant(a) mp_do_vms_case_tolerant(a)
225 #define expand_wild_cards(a,b,c,d) mp_expand_wild_cards(aTHX_ a,b,c,d)
226 #define getredirection(a,b) mp_getredirection(aTHX_ a,b)
228 static char *mp_do_tovmspath(pTHX_ const char *path, char *buf, int ts, int *);
229 static char *mp_do_tounixpath(pTHX_ const char *path, char *buf, int ts, int *);
230 static char *mp_do_tounixspec(pTHX_ const char *, char *, int, int *);
231 static char *mp_do_pathify_dirspec(pTHX_ const char *dir,char *buf, int ts, int *);
233 static char * int_rmsexpand_vms(
234 const char * filespec, char * outbuf, unsigned opts);
235 static char * int_rmsexpand_tovms(
236 const char * filespec, char * outbuf, unsigned opts);
237 static char *int_tovmsspec
238 (const char *path, char *buf, int dir_flag, int * utf8_flag);
239 static char * int_fileify_dirspec(const char *dir, char *buf, int *utf8_fl);
240 static char * int_tounixspec(const char *spec, char *buf, int * utf8_fl);
241 static char * int_tovmspath(const char *path, char *buf, int * utf8_fl);
243 /* see system service docs for $TRNLNM -- NOT the same as LNM$_MAX_INDEX */
244 #define PERL_LNM_MAX_ALLOWED_INDEX 127
246 /* OpenVMS User's Guide says at least 9 iterative translations will be performed,
247 * depending on the facility. SHOW LOGICAL does 10, so we'll imitate that for
250 #define PERL_LNM_MAX_ITER 10
252 /* New values with 7.3-2*/ /* why does max DCL have 4 byte subtracted from it? */
253 #if __CRTL_VER >= 70302000 && !defined(__VAX)
254 #define MAX_DCL_SYMBOL (8192)
255 #define MAX_DCL_LINE_LENGTH (4096 - 4)
257 #define MAX_DCL_SYMBOL (1024)
258 #define MAX_DCL_LINE_LENGTH (1024 - 4)
261 static char *__mystrtolower(char *str)
263 if (str) for (; *str; ++str) *str= tolower(*str);
267 static struct dsc$descriptor_s fildevdsc =
268 { 12, DSC$K_DTYPE_T, DSC$K_CLASS_S, "LNM$FILE_DEV" };
269 static struct dsc$descriptor_s crtlenvdsc =
270 { 8, DSC$K_DTYPE_T, DSC$K_CLASS_S, "CRTL_ENV" };
271 static struct dsc$descriptor_s *fildev[] = { &fildevdsc, NULL };
272 static struct dsc$descriptor_s *defenv[] = { &fildevdsc, &crtlenvdsc, NULL };
273 static struct dsc$descriptor_s **env_tables = defenv;
274 static bool will_taint = FALSE; /* tainting active, but no PL_curinterp yet */
276 /* True if we shouldn't treat barewords as logicals during directory */
278 static int no_translate_barewords;
281 static int tz_updated = 1;
284 /* DECC Features that may need to affect how Perl interprets
285 * displays filename information
287 static int decc_disable_to_vms_logname_translation = 1;
288 static int decc_disable_posix_root = 1;
289 int decc_efs_case_preserve = 0;
290 static int decc_efs_charset = 0;
291 static int decc_efs_charset_index = -1;
292 static int decc_filename_unix_no_version = 0;
293 static int decc_filename_unix_only = 0;
294 int decc_filename_unix_report = 0;
295 int decc_posix_compliant_pathnames = 0;
296 int decc_readdir_dropdotnotype = 0;
297 static int vms_process_case_tolerant = 1;
298 int vms_vtf7_filenames = 0;
299 int gnv_unix_shell = 0;
300 static int vms_unlink_all_versions = 0;
301 static int vms_posix_exit = 0;
303 /* bug workarounds if needed */
304 int decc_bug_devnull = 1;
305 int decc_dir_barename = 0;
306 int vms_bug_stat_filename = 0;
308 static int vms_debug_on_exception = 0;
309 static int vms_debug_fileify = 0;
311 /* Simple logical name translation */
312 static int simple_trnlnm
313 (const char * logname,
317 const $DESCRIPTOR(table_dsc, "LNM$FILE_DEV");
318 const unsigned long attr = LNM$M_CASE_BLIND;
319 struct dsc$descriptor_s name_dsc;
321 unsigned short result;
322 struct itmlst_3 itlst[2] = {{value_len, LNM$_STRING, value, &result},
325 name_dsc.dsc$w_length = strlen(logname);
326 name_dsc.dsc$a_pointer = (char *)logname;
327 name_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
328 name_dsc.dsc$b_class = DSC$K_CLASS_S;
330 status = sys$trnlnm(&attr, &table_dsc, &name_dsc, 0, itlst);
332 if ($VMS_STATUS_SUCCESS(status)) {
334 /* Null terminate and return the string */
335 /*--------------------------------------*/
344 /* Is this a UNIX file specification?
345 * No longer a simple check with EFS file specs
346 * For now, not a full check, but need to
347 * handle POSIX ^UP^ specifications
348 * Fixing to handle ^/ cases would require
349 * changes to many other conversion routines.
352 static int is_unix_filespec(const char *path)
358 if (strncmp(path,"\"^UP^",5) != 0) {
359 pch1 = strchr(path, '/');
364 /* If the user wants UNIX files, "." needs to be treated as in UNIX */
365 if (decc_filename_unix_report || decc_filename_unix_only) {
366 if (strcmp(path,".") == 0)
374 /* This routine converts a UCS-2 character to be VTF-7 encoded.
377 static void ucs2_to_vtf7
379 unsigned long ucs2_char,
382 unsigned char * ucs_ptr;
385 ucs_ptr = (unsigned char *)&ucs2_char;
389 hex = (ucs_ptr[1] >> 4) & 0xf;
391 outspec[2] = hex + '0';
393 outspec[2] = (hex - 9) + 'A';
394 hex = ucs_ptr[1] & 0xF;
396 outspec[3] = hex + '0';
398 outspec[3] = (hex - 9) + 'A';
400 hex = (ucs_ptr[0] >> 4) & 0xf;
402 outspec[4] = hex + '0';
404 outspec[4] = (hex - 9) + 'A';
405 hex = ucs_ptr[1] & 0xF;
407 outspec[5] = hex + '0';
409 outspec[5] = (hex - 9) + 'A';
415 /* This handles the conversion of a UNIX extended character set to a ^
416 * escaped VMS character.
417 * in a UNIX file specification.
419 * The output count variable contains the number of characters added
420 * to the output string.
422 * The return value is the number of characters read from the input string
424 static int copy_expand_unix_filename_escape
425 (char *outspec, const char *inspec, int *output_cnt, const int * utf8_fl)
432 utf8_flag = *utf8_fl;
436 if (*inspec >= 0x80) {
437 if (utf8_fl && vms_vtf7_filenames) {
438 unsigned long ucs_char;
442 if ((*inspec & 0xE0) == 0xC0) {
444 ucs_char = ((inspec[0] & 0x1F) << 6) + (inspec[1] & 0x3f);
445 if (ucs_char >= 0x80) {
446 ucs2_to_vtf7(outspec, ucs_char, output_cnt);
449 } else if ((*inspec & 0xF0) == 0xE0) {
451 ucs_char = ((inspec[0] & 0xF) << 12) +
452 ((inspec[1] & 0x3f) << 6) +
454 if (ucs_char >= 0x800) {
455 ucs2_to_vtf7(outspec, ucs_char, output_cnt);
459 #if 0 /* I do not see longer sequences supported by OpenVMS */
460 /* Maybe some one can fix this later */
461 } else if ((*inspec & 0xF8) == 0xF0) {
464 } else if ((*inspec & 0xFC) == 0xF8) {
467 } else if ((*inspec & 0xFE) == 0xFC) {
474 /* High bit set, but not a Unicode character! */
476 /* Non printing DECMCS or ISO Latin-1 character? */
477 if ((unsigned char)*inspec <= 0x9F) {
481 hex = (*inspec >> 4) & 0xF;
483 outspec[1] = hex + '0';
485 outspec[1] = (hex - 9) + 'A';
489 outspec[2] = hex + '0';
491 outspec[2] = (hex - 9) + 'A';
495 } else if ((unsigned char)*inspec == 0xA0) {
501 } else if ((unsigned char)*inspec == 0xFF) {
513 /* Is this a macro that needs to be passed through?
514 * Macros start with $( and an alpha character, followed
515 * by a string of alpha numeric characters ending with a )
516 * If this does not match, then encode it as ODS-5.
518 if ((inspec[0] == '$') && (inspec[1] == '(')) {
521 if (isalnum(inspec[2]) || (inspec[2] == '.') || (inspec[2] == '_')) {
523 outspec[0] = inspec[0];
524 outspec[1] = inspec[1];
525 outspec[2] = inspec[2];
527 while(isalnum(inspec[tcnt]) ||
528 (inspec[2] == '.') || (inspec[2] == '_')) {
529 outspec[tcnt] = inspec[tcnt];
532 if (inspec[tcnt] == ')') {
533 outspec[tcnt] = inspec[tcnt];
550 if (decc_efs_charset == 0)
577 /* Don't escape again if following character is
578 * already something we escape.
580 if (strchr(".~!#&\'`()+@{},;[]%^=_\\", *(inspec+1))) {
586 /* But otherwise fall through and escape it. */
588 /* Assume that this is to be escaped */
590 outspec[1] = *inspec;
594 case ' ': /* space */
595 /* Assume that this is to be escaped */
610 /* This handles the expansion of a '^' prefix to the proper character
611 * in a UNIX file specification.
613 * The output count variable contains the number of characters added
614 * to the output string.
616 * The return value is the number of characters read from the input
619 static int copy_expand_vms_filename_escape
620 (char *outspec, const char *inspec, int *output_cnt)
627 if (*inspec == '^') {
630 /* Spaces and non-trailing dots should just be passed through,
631 * but eat the escape character.
638 case '_': /* space */
644 /* Hmm. Better leave the escape escaped. */
650 case 'U': /* Unicode - FIX-ME this is wrong. */
653 scnt = strspn(inspec, "0123456789ABCDEFabcdef");
656 scnt = sscanf(inspec, "%2x%2x", &c1, &c2);
657 outspec[0] = c1 & 0xff;
658 outspec[1] = c2 & 0xff;
665 /* Error - do best we can to continue */
675 scnt = strspn(inspec, "0123456789ABCDEFabcdef");
679 scnt = sscanf(inspec, "%2x", &c1);
680 outspec[0] = c1 & 0xff;
701 /* vms_split_path - Verify that the input file specification is a
702 * VMS format file specification, and provide pointers to the components of
703 * it. With EFS format filenames, this is virtually the only way to
704 * parse a VMS path specification into components.
706 * If the sum of the components do not add up to the length of the
707 * string, then the passed file specification is probably a UNIX style
710 static int vms_split_path
725 struct dsc$descriptor path_desc;
729 struct filescan_itmlst_2 item_list[9];
730 const int filespec = 0;
731 const int nodespec = 1;
732 const int devspec = 2;
733 const int rootspec = 3;
734 const int dirspec = 4;
735 const int namespec = 5;
736 const int typespec = 6;
737 const int verspec = 7;
739 /* Assume the worst for an easy exit */
753 path_desc.dsc$a_pointer = (char *)path; /* cast ok */
754 path_desc.dsc$w_length = strlen(path);
755 path_desc.dsc$b_dtype = DSC$K_DTYPE_T;
756 path_desc.dsc$b_class = DSC$K_CLASS_S;
758 /* Get the total length, if it is shorter than the string passed
759 * then this was probably not a VMS formatted file specification
761 item_list[filespec].itmcode = FSCN$_FILESPEC;
762 item_list[filespec].length = 0;
763 item_list[filespec].component = NULL;
765 /* If the node is present, then it gets considered as part of the
766 * volume name to hopefully make things simple.
768 item_list[nodespec].itmcode = FSCN$_NODE;
769 item_list[nodespec].length = 0;
770 item_list[nodespec].component = NULL;
772 item_list[devspec].itmcode = FSCN$_DEVICE;
773 item_list[devspec].length = 0;
774 item_list[devspec].component = NULL;
776 /* root is a special case, adding it to either the directory or
777 * the device components will probably complicate things for the
778 * callers of this routine, so leave it separate.
780 item_list[rootspec].itmcode = FSCN$_ROOT;
781 item_list[rootspec].length = 0;
782 item_list[rootspec].component = NULL;
784 item_list[dirspec].itmcode = FSCN$_DIRECTORY;
785 item_list[dirspec].length = 0;
786 item_list[dirspec].component = NULL;
788 item_list[namespec].itmcode = FSCN$_NAME;
789 item_list[namespec].length = 0;
790 item_list[namespec].component = NULL;
792 item_list[typespec].itmcode = FSCN$_TYPE;
793 item_list[typespec].length = 0;
794 item_list[typespec].component = NULL;
796 item_list[verspec].itmcode = FSCN$_VERSION;
797 item_list[verspec].length = 0;
798 item_list[verspec].component = NULL;
800 item_list[8].itmcode = 0;
801 item_list[8].length = 0;
802 item_list[8].component = NULL;
804 status = sys$filescan
805 ((const struct dsc$descriptor_s *)&path_desc, item_list,
807 _ckvmssts_noperl(status); /* All failure status values indicate a coding error */
809 /* If we parsed it successfully these two lengths should be the same */
810 if (path_desc.dsc$w_length != item_list[filespec].length)
813 /* If we got here, then it is a VMS file specification */
816 /* set the volume name */
817 if (item_list[nodespec].length > 0) {
818 *volume = item_list[nodespec].component;
819 *vol_len = item_list[nodespec].length + item_list[devspec].length;
822 *volume = item_list[devspec].component;
823 *vol_len = item_list[devspec].length;
826 *root = item_list[rootspec].component;
827 *root_len = item_list[rootspec].length;
829 *dir = item_list[dirspec].component;
830 *dir_len = item_list[dirspec].length;
832 /* Now fun with versions and EFS file specifications
833 * The parser can not tell the difference when a "." is a version
834 * delimiter or a part of the file specification.
836 if ((decc_efs_charset) &&
837 (item_list[verspec].length > 0) &&
838 (item_list[verspec].component[0] == '.')) {
839 *name = item_list[namespec].component;
840 *name_len = item_list[namespec].length + item_list[typespec].length;
841 *ext = item_list[verspec].component;
842 *ext_len = item_list[verspec].length;
847 *name = item_list[namespec].component;
848 *name_len = item_list[namespec].length;
849 *ext = item_list[typespec].component;
850 *ext_len = item_list[typespec].length;
851 *version = item_list[verspec].component;
852 *ver_len = item_list[verspec].length;
857 /* Routine to determine if the file specification ends with .dir */
858 static int is_dir_ext(char * e_spec, int e_len, char * vs_spec, int vs_len) {
860 /* e_len must be 4, and version must be <= 2 characters */
861 if (e_len != 4 || vs_len > 2)
864 /* If a version number is present, it needs to be one */
865 if ((vs_len == 2) && (vs_spec[1] != '1'))
868 /* Look for the DIR on the extension */
869 if (vms_process_case_tolerant) {
870 if ((toupper(e_spec[1]) == 'D') &&
871 (toupper(e_spec[2]) == 'I') &&
872 (toupper(e_spec[3]) == 'R')) {
876 /* Directory extensions are supposed to be in upper case only */
877 /* I would not be surprised if this rule can not be enforced */
878 /* if and when someone fully debugs the case sensitive mode */
879 if ((e_spec[1] == 'D') &&
880 (e_spec[2] == 'I') &&
881 (e_spec[3] == 'R')) {
890 * Routine to retrieve the maximum equivalence index for an input
891 * logical name. Some calls to this routine have no knowledge if
892 * the variable is a logical or not. So on error we return a max
895 /*{{{int my_maxidx(const char *lnm) */
897 my_maxidx(const char *lnm)
901 int attr = LNM$M_CASE_BLIND;
902 struct dsc$descriptor lnmdsc;
903 struct itmlst_3 itlst[2] = {{sizeof(midx), LNM$_MAX_INDEX, &midx, 0},
906 lnmdsc.dsc$w_length = strlen(lnm);
907 lnmdsc.dsc$b_dtype = DSC$K_DTYPE_T;
908 lnmdsc.dsc$b_class = DSC$K_CLASS_S;
909 lnmdsc.dsc$a_pointer = (char *) lnm; /* Cast ok for read only parameter */
911 status = sys$trnlnm(&attr, &fildevdsc, &lnmdsc, 0, itlst);
912 if ((status & 1) == 0)
919 /*{{{int vmstrnenv(const char *lnm, char *eqv, unsigned long int idx, struct dsc$descriptor_s **tabvec, unsigned long int flags) */
921 Perl_vmstrnenv(const char *lnm, char *eqv, unsigned long int idx,
922 struct dsc$descriptor_s **tabvec, unsigned long int flags)
925 char uplnm[LNM$C_NAMLENGTH+1], *cp2;
926 unsigned short int eqvlen, curtab, ivlnm = 0, ivsym = 0, ivenv = 0, secure;
927 unsigned long int retsts, attr = LNM$M_CASE_BLIND;
929 unsigned char acmode;
930 struct dsc$descriptor_s lnmdsc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0},
931 tmpdsc = {6,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
932 struct itmlst_3 lnmlst[3] = {{sizeof idx, LNM$_INDEX, &idx, 0},
933 {LNM$C_NAMLENGTH, LNM$_STRING, eqv, &eqvlen},
935 $DESCRIPTOR(crtlenv,"CRTL_ENV"); $DESCRIPTOR(clisym,"CLISYM");
936 #if defined(PERL_IMPLICIT_CONTEXT)
939 aTHX = PERL_GET_INTERP;
945 if (!lnm || !eqv || ((idx != 0) && ((idx-1) > PERL_LNM_MAX_ALLOWED_INDEX))) {
946 set_errno(EINVAL); set_vaxc_errno(SS$_BADPARAM); return 0;
948 for (cp1 = lnm, cp2 = uplnm; *cp1; cp1++, cp2++) {
949 *cp2 = _toupper(*cp1);
950 if (cp1 - lnm > LNM$C_NAMLENGTH) {
951 set_errno(EINVAL); set_vaxc_errno(SS$_IVLOGNAM);
955 lnmdsc.dsc$w_length = cp1 - lnm;
956 lnmdsc.dsc$a_pointer = uplnm;
957 uplnm[lnmdsc.dsc$w_length] = '\0';
958 secure = flags & PERL__TRNENV_SECURE;
959 acmode = secure ? PSL$C_EXEC : PSL$C_USER;
960 if (!tabvec || !*tabvec) tabvec = env_tables;
962 for (curtab = 0; tabvec[curtab]; curtab++) {
963 if (!str$case_blind_compare(tabvec[curtab],&crtlenv)) {
964 if (!ivenv && !secure) {
969 #if defined(PERL_IMPLICIT_CONTEXT)
972 "Can't read CRTL environ\n");
975 Perl_warn(aTHX_ "Can't read CRTL environ\n");
978 retsts = SS$_NOLOGNAM;
979 for (i = 0; environ[i]; i++) {
980 if ((eq = strchr(environ[i],'=')) &&
981 lnmdsc.dsc$w_length == (eq - environ[i]) &&
982 !strncmp(environ[i],uplnm,eq - environ[i])) {
984 for (eqvlen = 0; eq[eqvlen]; eqvlen++) eqv[eqvlen] = eq[eqvlen];
985 if (!eqvlen) continue;
990 if (retsts != SS$_NOLOGNAM) break;
993 else if ((tmpdsc.dsc$a_pointer = tabvec[curtab]->dsc$a_pointer) &&
994 !str$case_blind_compare(&tmpdsc,&clisym)) {
995 if (!ivsym && !secure) {
996 unsigned short int deflen = LNM$C_NAMLENGTH;
997 struct dsc$descriptor_d eqvdsc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_D,0};
998 /* dynamic dsc to accommodate possible long value */
999 _ckvmssts_noperl(lib$sget1_dd(&deflen,&eqvdsc));
1000 retsts = lib$get_symbol(&lnmdsc,&eqvdsc,&eqvlen,0);
1002 if (eqvlen > MAX_DCL_SYMBOL) {
1003 set_errno(EVMSERR); set_vaxc_errno(LIB$_STRTRU);
1004 eqvlen = MAX_DCL_SYMBOL;
1005 /* Special hack--we might be called before the interpreter's */
1006 /* fully initialized, in which case either thr or PL_curcop */
1007 /* might be bogus. We have to check, since ckWARN needs them */
1008 /* both to be valid if running threaded */
1009 #if defined(PERL_IMPLICIT_CONTEXT)
1012 "Value of CLI symbol \"%s\" too long",lnm);
1015 if (ckWARN(WARN_MISC)) {
1016 Perl_warner(aTHX_ packWARN(WARN_MISC),"Value of CLI symbol \"%s\" too long",lnm);
1019 strncpy(eqv,eqvdsc.dsc$a_pointer,eqvlen);
1021 _ckvmssts_noperl(lib$sfree1_dd(&eqvdsc));
1022 if (retsts == LIB$_INVSYMNAM) { ivsym = 1; continue; }
1023 if (retsts == LIB$_NOSUCHSYM) continue;
1028 if ( (idx == 0) && (flags & PERL__TRNENV_JOIN_SEARCHLIST) ) {
1029 midx = my_maxidx(lnm);
1030 for (idx = 0, cp2 = eqv; idx <= midx; idx++) {
1031 lnmlst[1].bufadr = cp2;
1033 retsts = sys$trnlnm(&attr,tabvec[curtab],&lnmdsc,&acmode,lnmlst);
1034 if (retsts == SS$_IVLOGNAM) { ivlnm = 1; break; }
1035 if (retsts == SS$_NOLOGNAM) break;
1036 /* PPFs have a prefix */
1039 *((int *)uplnm) == *((int *)"SYS$") &&
1041 eqvlen >= 4 && eqv[0] == 0x1b && eqv[1] == 0x00 &&
1042 ( (uplnm[4] == 'O' && !strcmp(uplnm,"SYS$OUTPUT")) ||
1043 (uplnm[4] == 'I' && !strcmp(uplnm,"SYS$INPUT")) ||
1044 (uplnm[4] == 'E' && !strcmp(uplnm,"SYS$ERROR")) ||
1045 (uplnm[4] == 'C' && !strcmp(uplnm,"SYS$COMMAND")) ) ) {
1046 memmove(eqv,eqv+4,eqvlen-4);
1052 if ((retsts == SS$_IVLOGNAM) ||
1053 (retsts == SS$_NOLOGNAM)) { continue; }
1056 retsts = sys$trnlnm(&attr,tabvec[curtab],&lnmdsc,&acmode,lnmlst);
1057 if (retsts == SS$_IVLOGNAM) { ivlnm = 1; continue; }
1058 if (retsts == SS$_NOLOGNAM) continue;
1061 eqvlen = strlen(eqv);
1065 if (retsts & 1) { eqv[eqvlen] = '\0'; return eqvlen; }
1066 else if (retsts == LIB$_NOSUCHSYM || retsts == LIB$_INVSYMNAM ||
1067 retsts == SS$_IVLOGNAM || retsts == SS$_IVLOGTAB ||
1068 retsts == SS$_NOLOGNAM) {
1069 set_errno(EINVAL); set_vaxc_errno(retsts);
1071 else _ckvmssts_noperl(retsts);
1073 } /* end of vmstrnenv */
1076 /*{{{ int my_trnlnm(const char *lnm, char *eqv, unsigned long int idx)*/
1077 /* Define as a function so we can access statics. */
1078 int Perl_my_trnlnm(pTHX_ const char *lnm, char *eqv, unsigned long int idx)
1082 #if defined(PERL_IMPLICIT_CONTEXT)
1085 #ifdef SECURE_INTERNAL_GETENV
1086 flags = (PL_curinterp ? PL_tainting : will_taint) ?
1087 PERL__TRNENV_SECURE : 0;
1090 return vmstrnenv(lnm, eqv, idx, fildev, flags);
1095 * Note: Uses Perl temp to store result so char * can be returned to
1096 * caller; this pointer will be invalidated at next Perl statement
1098 * We define this as a function rather than a macro in terms of my_getenv_len()
1099 * so that it'll work when PL_curinterp is undefined (and we therefore can't
1102 /*{{{ char *my_getenv(const char *lnm, bool sys)*/
1104 Perl_my_getenv(pTHX_ const char *lnm, bool sys)
1107 static char *__my_getenv_eqv = NULL;
1108 char uplnm[LNM$C_NAMLENGTH+1], *cp2, *eqv;
1109 unsigned long int idx = 0;
1110 int success, secure, saverr, savvmserr;
1114 midx = my_maxidx(lnm) + 1;
1116 if (PL_curinterp) { /* Perl interpreter running -- may be threaded */
1117 /* Set up a temporary buffer for the return value; Perl will
1118 * clean it up at the next statement transition */
1119 tmpsv = sv_2mortal(newSVpv("",(LNM$C_NAMLENGTH*midx)+1));
1120 if (!tmpsv) return NULL;
1124 /* Assume no interpreter ==> single thread */
1125 if (__my_getenv_eqv != NULL) {
1126 Renew(__my_getenv_eqv,LNM$C_NAMLENGTH*midx+1,char);
1129 Newx(__my_getenv_eqv,LNM$C_NAMLENGTH*midx+1,char);
1131 eqv = __my_getenv_eqv;
1134 for (cp1 = lnm, cp2 = eqv; *cp1; cp1++,cp2++) *cp2 = _toupper(*cp1);
1135 if (cp1 - lnm == 7 && !strncmp(eqv,"DEFAULT",7)) {
1137 getcwd(eqv,LNM$C_NAMLENGTH);
1141 /* Get rid of "000000/ in rooted filespecs */
1144 zeros = strstr(eqv, "/000000/");
1145 if (zeros != NULL) {
1147 mlen = len - (zeros - eqv) - 7;
1148 memmove(zeros, &zeros[7], mlen);
1156 /* Impose security constraints only if tainting */
1158 /* Impose security constraints only if tainting */
1159 secure = PL_curinterp ? PL_tainting : will_taint;
1160 saverr = errno; savvmserr = vaxc$errno;
1167 #ifdef SECURE_INTERNAL_GETENV
1168 secure ? PERL__TRNENV_SECURE : 0
1174 /* For the getenv interface we combine all the equivalence names
1175 * of a search list logical into one value to acquire a maximum
1176 * value length of 255*128 (assuming %ENV is using logicals).
1178 flags |= PERL__TRNENV_JOIN_SEARCHLIST;
1180 /* If the name contains a semicolon-delimited index, parse it
1181 * off and make sure we only retrieve the equivalence name for
1183 if ((cp2 = strchr(lnm,';')) != NULL) {
1185 uplnm[cp2-lnm] = '\0';
1186 idx = strtoul(cp2+1,NULL,0);
1188 flags &= ~PERL__TRNENV_JOIN_SEARCHLIST;
1191 success = vmstrnenv(lnm,eqv,idx,secure ? fildev : NULL,flags);
1193 /* Discard NOLOGNAM on internal calls since we're often looking
1194 * for an optional name, and this "error" often shows up as the
1195 * (bogus) exit status for a die() call later on. */
1196 if (sys && vaxc$errno == SS$_NOLOGNAM) SETERRNO(saverr,savvmserr);
1197 return success ? eqv : NULL;
1200 } /* end of my_getenv() */
1204 /*{{{ SV *my_getenv_len(const char *lnm, bool sys)*/
1206 Perl_my_getenv_len(pTHX_ const char *lnm, unsigned long *len, bool sys)
1210 unsigned long idx = 0;
1212 static char *__my_getenv_len_eqv = NULL;
1213 int secure, saverr, savvmserr;
1216 midx = my_maxidx(lnm) + 1;
1218 if (PL_curinterp) { /* Perl interpreter running -- may be threaded */
1219 /* Set up a temporary buffer for the return value; Perl will
1220 * clean it up at the next statement transition */
1221 tmpsv = sv_2mortal(newSVpv("",(LNM$C_NAMLENGTH*midx)+1));
1222 if (!tmpsv) return NULL;
1226 /* Assume no interpreter ==> single thread */
1227 if (__my_getenv_len_eqv != NULL) {
1228 Renew(__my_getenv_len_eqv,LNM$C_NAMLENGTH*midx+1,char);
1231 Newx(__my_getenv_len_eqv,LNM$C_NAMLENGTH*midx+1,char);
1233 buf = __my_getenv_len_eqv;
1236 for (cp1 = lnm, cp2 = buf; *cp1; cp1++,cp2++) *cp2 = _toupper(*cp1);
1237 if (cp1 - lnm == 7 && !strncmp(buf,"DEFAULT",7)) {
1240 getcwd(buf,LNM$C_NAMLENGTH);
1243 /* Get rid of "000000/ in rooted filespecs */
1245 zeros = strstr(buf, "/000000/");
1246 if (zeros != NULL) {
1248 mlen = *len - (zeros - buf) - 7;
1249 memmove(zeros, &zeros[7], mlen);
1258 /* Impose security constraints only if tainting */
1259 secure = PL_curinterp ? PL_tainting : will_taint;
1260 saverr = errno; savvmserr = vaxc$errno;
1267 #ifdef SECURE_INTERNAL_GETENV
1268 secure ? PERL__TRNENV_SECURE : 0
1274 flags |= PERL__TRNENV_JOIN_SEARCHLIST;
1276 if ((cp2 = strchr(lnm,';')) != NULL) {
1278 buf[cp2-lnm] = '\0';
1279 idx = strtoul(cp2+1,NULL,0);
1281 flags &= ~PERL__TRNENV_JOIN_SEARCHLIST;
1284 *len = vmstrnenv(lnm,buf,idx,secure ? fildev : NULL,flags);
1286 /* Get rid of "000000/ in rooted filespecs */
1289 zeros = strstr(buf, "/000000/");
1290 if (zeros != NULL) {
1292 mlen = *len - (zeros - buf) - 7;
1293 memmove(zeros, &zeros[7], mlen);
1299 /* Discard NOLOGNAM on internal calls since we're often looking
1300 * for an optional name, and this "error" often shows up as the
1301 * (bogus) exit status for a die() call later on. */
1302 if (sys && vaxc$errno == SS$_NOLOGNAM) SETERRNO(saverr,savvmserr);
1303 return *len ? buf : NULL;
1306 } /* end of my_getenv_len() */
1309 static void create_mbx(unsigned short int *, struct dsc$descriptor_s *);
1311 static void riseandshine(unsigned long int dummy) { sys$wake(0,0); }
1313 /*{{{ void prime_env_iter() */
1315 prime_env_iter(void)
1316 /* Fill the %ENV associative array with all logical names we can
1317 * find, in preparation for iterating over it.
1320 static int primed = 0;
1321 HV *seenhv = NULL, *envhv;
1323 char cmd[LNM$C_NAMLENGTH+24], mbxnam[LNM$C_NAMLENGTH], *buf = NULL;
1324 unsigned short int chan;
1325 #ifndef CLI$M_TRUSTED
1326 # define CLI$M_TRUSTED 0x40 /* Missing from VAXC headers */
1328 unsigned long int defflags = CLI$M_NOWAIT | CLI$M_NOKEYPAD | CLI$M_TRUSTED;
1329 unsigned long int mbxbufsiz, flags, retsts, subpid = 0, substs = 0;
1331 bool have_sym = FALSE, have_lnm = FALSE;
1332 struct dsc$descriptor_s tmpdsc = {6,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
1333 $DESCRIPTOR(cmddsc,cmd); $DESCRIPTOR(nldsc,"_NLA0:");
1334 $DESCRIPTOR(clidsc,"DCL"); $DESCRIPTOR(clitabdsc,"DCLTABLES");
1335 $DESCRIPTOR(crtlenv,"CRTL_ENV"); $DESCRIPTOR(clisym,"CLISYM");
1336 $DESCRIPTOR(local,"_LOCAL"); $DESCRIPTOR(mbxdsc,mbxnam);
1337 #if defined(PERL_IMPLICIT_CONTEXT)
1340 #if defined(USE_ITHREADS)
1341 static perl_mutex primenv_mutex;
1342 MUTEX_INIT(&primenv_mutex);
1345 #if defined(PERL_IMPLICIT_CONTEXT)
1346 /* We jump through these hoops because we can be called at */
1347 /* platform-specific initialization time, which is before anything is */
1348 /* set up--we can't even do a plain dTHX since that relies on the */
1349 /* interpreter structure to be initialized */
1351 aTHX = PERL_GET_INTERP;
1353 /* we never get here because the NULL pointer will cause the */
1354 /* several of the routines called by this routine to access violate */
1356 /* This routine is only called by hv.c/hv_iterinit which has a */
1357 /* context, so the real fix may be to pass it through instead of */
1358 /* the hoops above */
1363 if (primed || !PL_envgv) return;
1364 MUTEX_LOCK(&primenv_mutex);
1365 if (primed) { MUTEX_UNLOCK(&primenv_mutex); return; }
1366 envhv = GvHVn(PL_envgv);
1367 /* Perform a dummy fetch as an lval to insure that the hash table is
1368 * set up. Otherwise, the hv_store() will turn into a nullop. */
1369 (void) hv_fetch(envhv,"DEFAULT",7,TRUE);
1371 for (i = 0; env_tables[i]; i++) {
1372 if (!have_sym && (tmpdsc.dsc$a_pointer = env_tables[i]->dsc$a_pointer) &&
1373 !str$case_blind_compare(&tmpdsc,&clisym)) have_sym = 1;
1374 if (!have_lnm && str$case_blind_compare(env_tables[i],&crtlenv)) have_lnm = 1;
1376 if (have_sym || have_lnm) {
1377 long int syiitm = SYI$_MAXBUF, dviitm = DVI$_DEVNAM;
1378 _ckvmssts(lib$getsyi(&syiitm, &mbxbufsiz, 0, 0, 0, 0));
1379 _ckvmssts(sys$crembx(0,&chan,mbxbufsiz,mbxbufsiz,0xff0f,0,0));
1380 _ckvmssts(lib$getdvi(&dviitm, &chan, NULL, NULL, &mbxdsc, &mbxdsc.dsc$w_length));
1383 for (i--; i >= 0; i--) {
1384 if (!str$case_blind_compare(env_tables[i],&crtlenv)) {
1387 for (j = 0; environ[j]; j++) {
1388 if (!(start = strchr(environ[j],'='))) {
1389 if (ckWARN(WARN_INTERNAL))
1390 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"Ill-formed CRTL environ value \"%s\"\n",environ[j]);
1394 sv = newSVpv(start,0);
1396 (void) hv_store(envhv,environ[j],start - environ[j] - 1,sv,0);
1401 else if ((tmpdsc.dsc$a_pointer = env_tables[i]->dsc$a_pointer) &&
1402 !str$case_blind_compare(&tmpdsc,&clisym)) {
1403 strcpy(cmd,"Show Symbol/Global *");
1404 cmddsc.dsc$w_length = 20;
1405 if (env_tables[i]->dsc$w_length == 12 &&
1406 (tmpdsc.dsc$a_pointer = env_tables[i]->dsc$a_pointer + 6) &&
1407 !str$case_blind_compare(&tmpdsc,&local)) strcpy(cmd+12,"Local *");
1408 flags = defflags | CLI$M_NOLOGNAM;
1411 strcpy(cmd,"Show Logical *");
1412 if (str$case_blind_compare(env_tables[i],&fildevdsc)) {
1413 strcat(cmd," /Table=");
1414 strncat(cmd,env_tables[i]->dsc$a_pointer,env_tables[i]->dsc$w_length);
1415 cmddsc.dsc$w_length = strlen(cmd);
1417 else cmddsc.dsc$w_length = 14; /* N.B. We test this below */
1418 flags = defflags | CLI$M_NOCLISYM;
1421 /* Create a new subprocess to execute each command, to exclude the
1422 * remote possibility that someone could subvert a mbx or file used
1423 * to write multiple commands to a single subprocess.
1426 retsts = lib$spawn(&cmddsc,&nldsc,&mbxdsc,&flags,0,&subpid,&substs,
1427 0,&riseandshine,0,0,&clidsc,&clitabdsc);
1428 flags &= ~CLI$M_TRUSTED; /* Just in case we hit a really old version */
1429 defflags &= ~CLI$M_TRUSTED;
1430 } while (retsts == LIB$_INVARG && (flags | CLI$M_TRUSTED));
1432 if (!buf) Newx(buf,mbxbufsiz + 1,char);
1433 if (seenhv) SvREFCNT_dec(seenhv);
1436 char *cp1, *cp2, *key;
1437 unsigned long int sts, iosb[2], retlen, keylen;
1440 sts = sys$qiow(0,chan,IO$_READVBLK,iosb,0,0,buf,mbxbufsiz,0,0,0,0);
1441 if (sts & 1) sts = iosb[0] & 0xffff;
1442 if (sts == SS$_ENDOFFILE) {
1444 while (substs == 0) { sys$hiber(); wakect++;}
1445 if (wakect > 1) sys$wake(0,0); /* Stole someone else's wake */
1450 retlen = iosb[0] >> 16;
1451 if (!retlen) continue; /* blank line */
1453 if (iosb[1] != subpid) {
1455 Perl_croak(aTHX_ "Unknown process %x sent message to prime_env_iter: %s",buf);
1459 if (sts == SS$_BUFFEROVF && ckWARN(WARN_INTERNAL))
1460 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"Buffer overflow in prime_env_iter: %s",buf);
1462 for (cp1 = buf; *cp1 && isspace(*cp1); cp1++) ;
1463 if (*cp1 == '(' || /* Logical name table name */
1464 *cp1 == '=' /* Next eqv of searchlist */) continue;
1465 if (*cp1 == '"') cp1++;
1466 for (cp2 = cp1; *cp2 && *cp2 != '"' && *cp2 != ' '; cp2++) ;
1467 key = cp1; keylen = cp2 - cp1;
1468 if (keylen && hv_exists(seenhv,key,keylen)) continue;
1469 while (*cp2 && *cp2 != '=') cp2++;
1470 while (*cp2 && *cp2 == '=') cp2++;
1471 while (*cp2 && *cp2 == ' ') cp2++;
1472 if (*cp2 == '"') { /* String translation; may embed "" */
1473 for (cp1 = buf + retlen; *cp1 != '"'; cp1--) ;
1474 cp2++; cp1--; /* Skip "" surrounding translation */
1476 else { /* Numeric translation */
1477 for (cp1 = cp2; *cp1 && *cp1 != ' '; cp1++) ;
1478 cp1--; /* stop on last non-space char */
1480 if ((!keylen || (cp1 - cp2 < -1)) && ckWARN(WARN_INTERNAL)) {
1481 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"Ill-formed message in prime_env_iter: |%s|",buf);
1484 PERL_HASH(hash,key,keylen);
1486 if (cp1 == cp2 && *cp2 == '.') {
1487 /* A single dot usually means an unprintable character, such as a null
1488 * to indicate a zero-length value. Get the actual value to make sure.
1490 char lnm[LNM$C_NAMLENGTH+1];
1491 char eqv[MAX_DCL_SYMBOL+1];
1493 strncpy(lnm, key, keylen);
1494 trnlen = vmstrnenv(lnm, eqv, 0, fildev, 0);
1495 sv = newSVpvn(eqv, strlen(eqv));
1498 sv = newSVpvn(cp2,cp1 - cp2 + 1);
1502 hv_store(envhv,key,keylen,sv,hash);
1503 hv_store(seenhv,key,keylen,&PL_sv_yes,hash);
1505 if (cmddsc.dsc$w_length == 14) { /* We just read LNM$FILE_DEV */
1506 /* get the PPFs for this process, not the subprocess */
1507 const char *ppfs[] = {"SYS$COMMAND", "SYS$INPUT", "SYS$OUTPUT", "SYS$ERROR", NULL};
1508 char eqv[LNM$C_NAMLENGTH+1];
1510 for (i = 0; ppfs[i]; i++) {
1511 trnlen = vmstrnenv(ppfs[i],eqv,0,fildev,0);
1512 sv = newSVpv(eqv,trnlen);
1514 hv_store(envhv,ppfs[i],strlen(ppfs[i]),sv,0);
1519 if (have_sym || have_lnm) _ckvmssts(sys$dassgn(chan));
1520 if (buf) Safefree(buf);
1521 if (seenhv) SvREFCNT_dec(seenhv);
1522 MUTEX_UNLOCK(&primenv_mutex);
1525 } /* end of prime_env_iter */
1529 /*{{{ int vmssetenv(const char *lnm, const char *eqv)*/
1530 /* Define or delete an element in the same "environment" as
1531 * vmstrnenv(). If an element is to be deleted, it's removed from
1532 * the first place it's found. If it's to be set, it's set in the
1533 * place designated by the first element of the table vector.
1534 * Like setenv() returns 0 for success, non-zero on error.
1537 Perl_vmssetenv(pTHX_ const char *lnm, const char *eqv, struct dsc$descriptor_s **tabvec)
1540 char uplnm[LNM$C_NAMLENGTH], *cp2, *c;
1541 unsigned short int curtab, ivlnm = 0, ivsym = 0, ivenv = 0;
1543 unsigned long int retsts, usermode = PSL$C_USER;
1544 struct itmlst_3 *ile, *ilist;
1545 struct dsc$descriptor_s lnmdsc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,uplnm},
1546 eqvdsc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0},
1547 tmpdsc = {6,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
1548 $DESCRIPTOR(crtlenv,"CRTL_ENV"); $DESCRIPTOR(clisym,"CLISYM");
1549 $DESCRIPTOR(local,"_LOCAL");
1552 set_errno(EINVAL); set_vaxc_errno(SS$_IVLOGNAM);
1553 return SS$_IVLOGNAM;
1556 for (cp1 = lnm, cp2 = uplnm; *cp1; cp1++, cp2++) {
1557 *cp2 = _toupper(*cp1);
1558 if (cp1 - lnm > LNM$C_NAMLENGTH) {
1559 set_errno(EINVAL); set_vaxc_errno(SS$_IVLOGNAM);
1560 return SS$_IVLOGNAM;
1563 lnmdsc.dsc$w_length = cp1 - lnm;
1564 if (!tabvec || !*tabvec) tabvec = env_tables;
1566 if (!eqv) { /* we're deleting n element */
1567 for (curtab = 0; tabvec[curtab]; curtab++) {
1568 if (!ivenv && !str$case_blind_compare(tabvec[curtab],&crtlenv)) {
1570 for (i = 0; environ[i]; i++) { /* If it's an environ elt, reset */
1571 if ((cp1 = strchr(environ[i],'=')) &&
1572 lnmdsc.dsc$w_length == (cp1 - environ[i]) &&
1573 !strncmp(environ[i],lnm,cp1 - environ[i])) {
1575 return setenv(lnm,"",1) ? vaxc$errno : 0;
1578 ivenv = 1; retsts = SS$_NOLOGNAM;
1580 if (ckWARN(WARN_INTERNAL))
1581 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"This Perl can't reset CRTL environ elements (%s)",lnm);
1582 ivenv = 1; retsts = SS$_NOSUCHPGM;
1588 else if ((tmpdsc.dsc$a_pointer = tabvec[curtab]->dsc$a_pointer) &&
1589 !str$case_blind_compare(&tmpdsc,&clisym)) {
1590 unsigned int symtype;
1591 if (tabvec[curtab]->dsc$w_length == 12 &&
1592 (tmpdsc.dsc$a_pointer = tabvec[curtab]->dsc$a_pointer + 6) &&
1593 !str$case_blind_compare(&tmpdsc,&local))
1594 symtype = LIB$K_CLI_LOCAL_SYM;
1595 else symtype = LIB$K_CLI_GLOBAL_SYM;
1596 retsts = lib$delete_symbol(&lnmdsc,&symtype);
1597 if (retsts == LIB$_INVSYMNAM) { ivsym = 1; continue; }
1598 if (retsts == LIB$_NOSUCHSYM) continue;
1602 retsts = sys$dellnm(tabvec[curtab],&lnmdsc,&usermode); /* try user mode first */
1603 if (retsts == SS$_IVLOGNAM) { ivlnm = 1; continue; }
1604 if (retsts != SS$_NOLOGNAM && retsts != SS$_NOLOGTAB) break;
1605 retsts = lib$delete_logical(&lnmdsc,tabvec[curtab]); /* then supervisor mode */
1606 if (retsts != SS$_NOLOGNAM && retsts != SS$_NOLOGTAB) break;
1610 else { /* we're defining a value */
1611 if (!ivenv && !str$case_blind_compare(tabvec[0],&crtlenv)) {
1613 return setenv(lnm,eqv,1) ? vaxc$errno : 0;
1615 if (ckWARN(WARN_INTERNAL))
1616 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"This Perl can't set CRTL environ elements (%s=%s)",lnm,eqv);
1617 retsts = SS$_NOSUCHPGM;
1621 eqvdsc.dsc$a_pointer = (char *) eqv; /* cast ok to readonly parameter */
1622 eqvdsc.dsc$w_length = strlen(eqv);
1623 if ((tmpdsc.dsc$a_pointer = tabvec[0]->dsc$a_pointer) &&
1624 !str$case_blind_compare(&tmpdsc,&clisym)) {
1625 unsigned int symtype;
1626 if (tabvec[0]->dsc$w_length == 12 &&
1627 (tmpdsc.dsc$a_pointer = tabvec[0]->dsc$a_pointer + 6) &&
1628 !str$case_blind_compare(&tmpdsc,&local))
1629 symtype = LIB$K_CLI_LOCAL_SYM;
1630 else symtype = LIB$K_CLI_GLOBAL_SYM;
1631 retsts = lib$set_symbol(&lnmdsc,&eqvdsc,&symtype);
1634 if (!*eqv) eqvdsc.dsc$w_length = 1;
1635 if (eqvdsc.dsc$w_length > LNM$C_NAMLENGTH) {
1637 nseg = (eqvdsc.dsc$w_length + LNM$C_NAMLENGTH - 1) / LNM$C_NAMLENGTH;
1638 if (nseg > PERL_LNM_MAX_ALLOWED_INDEX + 1) {
1639 Perl_warner(aTHX_ packWARN(WARN_MISC),"Value of logical \"%s\" too long. Truncating to %i bytes",
1640 lnm, LNM$C_NAMLENGTH * (PERL_LNM_MAX_ALLOWED_INDEX+1));
1641 eqvdsc.dsc$w_length = LNM$C_NAMLENGTH * (PERL_LNM_MAX_ALLOWED_INDEX+1);
1642 nseg = PERL_LNM_MAX_ALLOWED_INDEX + 1;
1645 Newx(ilist,nseg+1,struct itmlst_3);
1648 set_errno(ENOMEM); set_vaxc_errno(SS$_INSFMEM);
1651 memset(ilist, 0, (sizeof(struct itmlst_3) * (nseg+1)));
1653 for (j = 0, c = eqvdsc.dsc$a_pointer; j < nseg; j++, ile++, c += LNM$C_NAMLENGTH) {
1654 ile->itmcode = LNM$_STRING;
1656 if ((j+1) == nseg) {
1657 ile->buflen = strlen(c);
1658 /* in case we are truncating one that's too long */
1659 if (ile->buflen > LNM$C_NAMLENGTH) ile->buflen = LNM$C_NAMLENGTH;
1662 ile->buflen = LNM$C_NAMLENGTH;
1666 retsts = lib$set_logical(&lnmdsc,0,tabvec[0],0,ilist);
1670 retsts = lib$set_logical(&lnmdsc,&eqvdsc,tabvec[0],0,0);
1675 if (!(retsts & 1)) {
1677 case LIB$_AMBSYMDEF: case LIB$_INSCLIMEM:
1678 case SS$_NOLOGTAB: case SS$_TOOMANYLNAM: case SS$_IVLOGTAB:
1679 set_errno(EVMSERR); break;
1680 case LIB$_INVARG: case LIB$_INVSYMNAM: case SS$_IVLOGNAM:
1681 case LIB$_NOSUCHSYM: case SS$_NOLOGNAM:
1682 set_errno(EINVAL); break;
1684 set_errno(EACCES); break;
1689 set_vaxc_errno(retsts);
1690 return (int) retsts || 44; /* retsts should never be 0, but just in case */
1693 /* We reset error values on success because Perl does an hv_fetch()
1694 * before each hv_store(), and if the thing we're setting didn't
1695 * previously exist, we've got a leftover error message. (Of course,
1696 * this fails in the face of
1697 * $foo = $ENV{nonexistent}; $ENV{existent} = 'foo';
1698 * in that the error reported in $! isn't spurious,
1699 * but it's right more often than not.)
1701 set_errno(0); set_vaxc_errno(retsts);
1705 } /* end of vmssetenv() */
1708 /*{{{ void my_setenv(const char *lnm, const char *eqv)*/
1709 /* This has to be a function since there's a prototype for it in proto.h */
1711 Perl_my_setenv(pTHX_ const char *lnm, const char *eqv)
1714 int len = strlen(lnm);
1718 for (i = 0; lnm[i]; i++) uplnm[i] = _toupper(lnm[i]);
1719 if (!strcmp(uplnm,"DEFAULT")) {
1720 if (eqv && *eqv) my_chdir(eqv);
1724 #ifndef RTL_USES_UTC
1725 if (len == 6 || len == 2) {
1728 for (i = 0; lnm[i]; i++) uplnm[i] = _toupper(lnm[i]);
1730 if (!strcmp(uplnm,"UCX$TZ")) tz_updated = 1;
1731 if (!strcmp(uplnm,"TZ")) tz_updated = 1;
1735 (void) vmssetenv(lnm,eqv,NULL);
1739 /*{{{static void vmssetuserlnm(char *name, char *eqv); */
1741 * sets a user-mode logical in the process logical name table
1742 * used for redirection of sys$error
1744 * Fix-me: The pTHX is not needed for this routine, however doio.c
1745 * is calling it with one instead of using a macro.
1746 * A macro needs to be added to vmsish.h and doio.c updated to use it.
1750 Perl_vmssetuserlnm(pTHX_ const char *name, const char *eqv)
1752 $DESCRIPTOR(d_tab, "LNM$PROCESS");
1753 struct dsc$descriptor_d d_name = {0,DSC$K_DTYPE_T,DSC$K_CLASS_D,0};
1754 unsigned long int iss, attr = LNM$M_CONFINE;
1755 unsigned char acmode = PSL$C_USER;
1756 struct itmlst_3 lnmlst[2] = {{0, LNM$_STRING, 0, 0},
1758 d_name.dsc$a_pointer = (char *)name; /* Cast OK for read only parameter */
1759 d_name.dsc$w_length = strlen(name);
1761 lnmlst[0].buflen = strlen(eqv);
1762 lnmlst[0].bufadr = (char *)eqv; /* Cast OK for read only parameter */
1764 iss = sys$crelnm(&attr,&d_tab,&d_name,&acmode,lnmlst);
1765 if (!(iss&1)) lib$signal(iss);
1770 /*{{{ char *my_crypt(const char *textpasswd, const char *usrname)*/
1771 /* my_crypt - VMS password hashing
1772 * my_crypt() provides an interface compatible with the Unix crypt()
1773 * C library function, and uses sys$hash_password() to perform VMS
1774 * password hashing. The quadword hashed password value is returned
1775 * as a NUL-terminated 8 character string. my_crypt() does not change
1776 * the case of its string arguments; in order to match the behavior
1777 * of LOGINOUT et al., alphabetic characters in both arguments must
1778 * be upcased by the caller.
1780 * - fix me to call ACM services when available
1783 Perl_my_crypt(pTHX_ const char *textpasswd, const char *usrname)
1785 # ifndef UAI$C_PREFERRED_ALGORITHM
1786 # define UAI$C_PREFERRED_ALGORITHM 127
1788 unsigned char alg = UAI$C_PREFERRED_ALGORITHM;
1789 unsigned short int salt = 0;
1790 unsigned long int sts;
1792 unsigned short int dsc$w_length;
1793 unsigned char dsc$b_type;
1794 unsigned char dsc$b_class;
1795 const char * dsc$a_pointer;
1796 } usrdsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0},
1797 txtdsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
1798 struct itmlst_3 uailst[3] = {
1799 { sizeof alg, UAI$_ENCRYPT, &alg, 0},
1800 { sizeof salt, UAI$_SALT, &salt, 0},
1801 { 0, 0, NULL, NULL}};
1802 static char hash[9];
1804 usrdsc.dsc$w_length = strlen(usrname);
1805 usrdsc.dsc$a_pointer = usrname;
1806 if (!((sts = sys$getuai(0, 0, &usrdsc, uailst, 0, 0, 0)) & 1)) {
1808 case SS$_NOGRPPRV: case SS$_NOSYSPRV:
1812 set_errno(ESRCH); /* There isn't a Unix no-such-user error */
1817 set_vaxc_errno(sts);
1818 if (sts != RMS$_RNF) return NULL;
1821 txtdsc.dsc$w_length = strlen(textpasswd);
1822 txtdsc.dsc$a_pointer = textpasswd;
1823 if (!((sts = sys$hash_password(&txtdsc, alg, salt, &usrdsc, &hash)) & 1)) {
1824 set_errno(EVMSERR); set_vaxc_errno(sts); return NULL;
1827 return (char *) hash;
1829 } /* end of my_crypt() */
1833 static char *mp_do_rmsexpand(pTHX_ const char *, char *, int, const char *, unsigned, int *, int *);
1834 static char *mp_do_fileify_dirspec(pTHX_ const char *, char *, int, int *);
1835 static char *mp_do_tovmsspec(pTHX_ const char *, char *, int, int, int *);
1837 /* fixup barenames that are directories for internal use.
1838 * There have been problems with the consistent handling of UNIX
1839 * style directory names when routines are presented with a name that
1840 * has no directory delimiters at all. So this routine will eventually
1843 static char * fixup_bare_dirnames(const char * name)
1845 if (decc_disable_to_vms_logname_translation) {
1851 /* 8.3, remove() is now broken on symbolic links */
1852 static int rms_erase(const char * vmsname);
1856 * A little hack to get around a bug in some implementation of remove()
1857 * that do not know how to delete a directory
1859 * Delete any file to which user has control access, regardless of whether
1860 * delete access is explicitly allowed.
1861 * Limitations: User must have write access to parent directory.
1862 * Does not block signals or ASTs; if interrupted in midstream
1863 * may leave file with an altered ACL.
1866 /*{{{int mp_do_kill_file(const char *name, int dirflag)*/
1868 mp_do_kill_file(pTHX_ const char *name, int dirflag)
1872 unsigned long int jpicode = JPI$_UIC, type = ACL$C_FILE;
1873 unsigned long int cxt = 0, aclsts, fndsts, rmsts = -1;
1874 struct dsc$descriptor_s fildsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
1876 unsigned char myace$b_length;
1877 unsigned char myace$b_type;
1878 unsigned short int myace$w_flags;
1879 unsigned long int myace$l_access;
1880 unsigned long int myace$l_ident;
1881 } newace = { sizeof(struct myacedef), ACE$C_KEYID, 0,
1882 ACE$M_READ | ACE$M_WRITE | ACE$M_DELETE | ACE$M_CONTROL, 0},
1883 oldace = { sizeof(struct myacedef), ACE$C_KEYID, 0, 0, 0};
1885 findlst[3] = {{sizeof oldace, ACL$C_FNDACLENT, &oldace, 0},
1886 {sizeof oldace, ACL$C_READACE, &oldace, 0},{0,0,0,0}},
1887 addlst[2] = {{sizeof newace, ACL$C_ADDACLENT, &newace, 0},{0,0,0,0}},
1888 dellst[2] = {{sizeof newace, ACL$C_DELACLENT, &newace, 0},{0,0,0,0}},
1889 lcklst[2] = {{sizeof newace, ACL$C_WLOCK_ACL, &newace, 0},{0,0,0,0}},
1890 ulklst[2] = {{sizeof newace, ACL$C_UNLOCK_ACL, &newace, 0},{0,0,0,0}};
1892 /* Expand the input spec using RMS, since the CRTL remove() and
1893 * system services won't do this by themselves, so we may miss
1894 * a file "hiding" behind a logical name or search list. */
1895 vmsname = PerlMem_malloc(NAM$C_MAXRSS+1);
1896 if (vmsname == NULL) _ckvmssts_noperl(SS$_INSFMEM);
1898 rslt = int_rmsexpand_tovms(name, vmsname, PERL_RMSEXPAND_M_SYMLINK);
1900 PerlMem_free(vmsname);
1904 /* Erase the file */
1905 rmsts = rms_erase(vmsname);
1907 /* Did it succeed */
1908 if ($VMS_STATUS_SUCCESS(rmsts)) {
1909 PerlMem_free(vmsname);
1913 /* If not, can changing protections help? */
1914 if (rmsts != RMS$_PRV) {
1915 set_vaxc_errno(rmsts);
1916 PerlMem_free(vmsname);
1920 /* No, so we get our own UIC to use as a rights identifier,
1921 * and the insert an ACE at the head of the ACL which allows us
1922 * to delete the file.
1924 _ckvmssts_noperl(lib$getjpi(&jpicode,0,0,&(oldace.myace$l_ident),0,0));
1925 fildsc.dsc$w_length = strlen(vmsname);
1926 fildsc.dsc$a_pointer = vmsname;
1928 newace.myace$l_ident = oldace.myace$l_ident;
1930 if (!((aclsts = sys$change_acl(0,&type,&fildsc,lcklst,0,0,0)) & 1)) {
1932 case RMS$_FNF: case RMS$_DNF: case SS$_NOSUCHOBJECT:
1933 set_errno(ENOENT); break;
1935 set_errno(ENOTDIR); break;
1937 set_errno(ENODEV); break;
1938 case RMS$_SYN: case SS$_INVFILFOROP:
1939 set_errno(EINVAL); break;
1941 set_errno(EACCES); break;
1943 _ckvmssts_noperl(aclsts);
1945 set_vaxc_errno(aclsts);
1946 PerlMem_free(vmsname);
1949 /* Grab any existing ACEs with this identifier in case we fail */
1950 aclsts = fndsts = sys$change_acl(0,&type,&fildsc,findlst,0,0,&cxt);
1951 if ( fndsts & 1 || fndsts == SS$_ACLEMPTY || fndsts == SS$_NOENTRY
1952 || fndsts == SS$_NOMOREACE ) {
1953 /* Add the new ACE . . . */
1954 if (!((aclsts = sys$change_acl(0,&type,&fildsc,addlst,0,0,0)) & 1))
1957 rmsts = rms_erase(vmsname);
1958 if ($VMS_STATUS_SUCCESS(rmsts)) {
1963 /* We blew it - dir with files in it, no write priv for
1964 * parent directory, etc. Put things back the way they were. */
1965 if (!((aclsts = sys$change_acl(0,&type,&fildsc,dellst,0,0,0)) & 1))
1968 addlst[0].bufadr = &oldace;
1969 if (!((aclsts = sys$change_acl(0,&type,&fildsc,addlst,0,0,&cxt)) & 1))
1976 fndsts = sys$change_acl(0,&type,&fildsc,ulklst,0,0,0);
1977 /* We just deleted it, so of course it's not there. Some versions of
1978 * VMS seem to return success on the unlock operation anyhow (after all
1979 * the unlock is successful), but others don't.
1981 if (fndsts == RMS$_FNF || fndsts == SS$_NOSUCHOBJECT) fndsts = SS$_NORMAL;
1982 if (aclsts & 1) aclsts = fndsts;
1983 if (!(aclsts & 1)) {
1985 set_vaxc_errno(aclsts);
1988 PerlMem_free(vmsname);
1991 } /* end of kill_file() */
1995 /*{{{int do_rmdir(char *name)*/
1997 Perl_do_rmdir(pTHX_ const char *name)
2003 /* lstat returns a VMS fileified specification of the name */
2004 /* that is looked up, and also lets verifies that this is a directory */
2006 retval = flex_lstat(name, &st);
2010 /* Due to a historical feature, flex_stat/lstat can not see some */
2011 /* Unix format file names that the rest of the CRTL can see */
2012 /* Fixing that feature will cause some perl tests to fail */
2013 /* So try this one more time. */
2015 retval = lstat(name, &st.crtl_stat);
2019 /* force it to a file spec for the kill file to work. */
2020 ret_spec = do_fileify_dirspec(name, st.st_devnam, 0, NULL);
2021 if (ret_spec == NULL) {
2027 if (!S_ISDIR(st.st_mode)) {
2032 dirfile = st.st_devnam;
2034 /* It may be possible for flex_stat to find a file and vmsify() to */
2035 /* fail with ODS-2 specifications. mp_do_kill_file can not deal */
2036 /* with that case, so fail it */
2037 if (dirfile[0] == 0) {
2042 retval = mp_do_kill_file(aTHX_ dirfile, 1);
2047 } /* end of do_rmdir */
2051 * Delete any file to which user has control access, regardless of whether
2052 * delete access is explicitly allowed.
2053 * Limitations: User must have write access to parent directory.
2054 * Does not block signals or ASTs; if interrupted in midstream
2055 * may leave file with an altered ACL.
2058 /*{{{int kill_file(char *name)*/
2060 Perl_kill_file(pTHX_ const char *name)
2066 /* Convert the filename to VMS format and see if it is a directory */
2067 /* flex_lstat returns a vmsified file specification */
2068 rmsts = flex_lstat(name, &st);
2071 /* Due to a historical feature, flex_stat/lstat can not see some */
2072 /* Unix format file names that the rest of the CRTL can see when */
2073 /* ODS-2 file specifications are in use. */
2074 /* Fixing that feature will cause some perl tests to fail */
2075 /* [.lib.ExtUtils.t]Manifest.t is one of them */
2077 vmsfile = (char *) name; /* cast ok */
2080 vmsfile = st.st_devnam;
2081 if (vmsfile[0] == 0) {
2082 /* It may be possible for flex_stat to find a file and vmsify() */
2083 /* to fail with ODS-2 specifications. mp_do_kill_file can not */
2084 /* deal with that case, so fail it */
2090 /* Remove() is allowed to delete directories, according to the X/Open
2092 * This may need special handling to work with the ACL hacks.
2094 if (S_ISDIR(st.st_mode)) {
2095 rmsts = mp_do_kill_file(aTHX_ vmsfile, 1);
2099 rmsts = mp_do_kill_file(aTHX_ vmsfile, 0);
2101 /* Need to delete all versions ? */
2102 if ((rmsts == 0) && (vms_unlink_all_versions == 1)) {
2105 /* Just use lstat() here as do not need st_dev */
2106 /* and we know that the file is in VMS format or that */
2107 /* because of a historical bug, flex_stat can not see the file */
2108 while (lstat(vmsfile, (stat_t *)&st) == 0) {
2109 rmsts = mp_do_kill_file(aTHX_ vmsfile, 0);
2114 /* Make sure that we do not loop forever */
2125 } /* end of kill_file() */
2129 /*{{{int my_mkdir(char *,Mode_t)*/
2131 Perl_my_mkdir(pTHX_ const char *dir, Mode_t mode)
2133 STRLEN dirlen = strlen(dir);
2135 /* zero length string sometimes gives ACCVIO */
2136 if (dirlen == 0) return -1;
2138 /* CRTL mkdir() doesn't tolerate trailing /, since that implies
2139 * null file name/type. However, it's commonplace under Unix,
2140 * so we'll allow it for a gain in portability.
2142 if (dir[dirlen-1] == '/') {
2143 char *newdir = savepvn(dir,dirlen-1);
2144 int ret = mkdir(newdir,mode);
2148 else return mkdir(dir,mode);
2149 } /* end of my_mkdir */
2152 /*{{{int my_chdir(char *)*/
2154 Perl_my_chdir(pTHX_ const char *dir)
2156 STRLEN dirlen = strlen(dir);
2158 /* zero length string sometimes gives ACCVIO */
2159 if (dirlen == 0) return -1;
2162 /* Perl is passing the output of the DCL SHOW DEFAULT with leading spaces.
2163 * This does not work if DECC$EFS_CHARSET is active. Hack it here
2164 * so that existing scripts do not need to be changed.
2167 while ((dirlen > 0) && (*dir1 == ' ')) {
2172 /* some versions of CRTL chdir() doesn't tolerate trailing /, since
2174 * null file name/type. However, it's commonplace under Unix,
2175 * so we'll allow it for a gain in portability.
2177 * '/' is valid when SYS$POSIX_ROOT or POSIX compliant pathnames are active.
2179 if ((dirlen > 1) && (dir1[dirlen-1] == '/')) {
2182 newdir = PerlMem_malloc(dirlen);
2184 _ckvmssts_noperl(SS$_INSFMEM);
2185 strncpy(newdir, dir1, dirlen-1);
2186 newdir[dirlen-1] = '\0';
2187 ret = chdir(newdir);
2188 PerlMem_free(newdir);
2191 else return chdir(dir1);
2192 } /* end of my_chdir */
2196 /*{{{int my_chmod(char *, mode_t)*/
2198 Perl_my_chmod(pTHX_ const char *file_spec, mode_t mode)
2203 STRLEN speclen = strlen(file_spec);
2205 /* zero length string sometimes gives ACCVIO */
2206 if (speclen == 0) return -1;
2208 /* some versions of CRTL chmod() doesn't tolerate trailing /, since
2209 * that implies null file name/type. However, it's commonplace under Unix,
2210 * so we'll allow it for a gain in portability.
2212 * Tests are showing that chmod() on VMS 8.3 is only accepting directories
2213 * in VMS file.dir notation.
2215 changefile = (char *) file_spec; /* cast ok */
2216 ret = flex_lstat(file_spec, &st);
2219 /* Due to a historical feature, flex_stat/lstat can not see some */
2220 /* Unix format file names that the rest of the CRTL can see when */
2221 /* ODS-2 file specifications are in use. */
2222 /* Fixing that feature will cause some perl tests to fail */
2223 /* [.lib.ExtUtils.t]Manifest.t is one of them */
2227 /* It may be possible to get here with nothing in st_devname */
2228 /* chmod still may work though */
2229 if (st.st_devnam[0] != 0) {
2230 changefile = st.st_devnam;
2233 ret = chmod(changefile, mode);
2235 } /* end of my_chmod */
2239 /*{{{FILE *my_tmpfile()*/
2246 if ((fp = tmpfile())) return fp;
2248 cp = PerlMem_malloc(L_tmpnam+24);
2249 if (cp == NULL) _ckvmssts_noperl(SS$_INSFMEM);
2251 if (decc_filename_unix_only == 0)
2252 strcpy(cp,"Sys$Scratch:");
2255 tmpnam(cp+strlen(cp));
2256 strcat(cp,".Perltmp");
2257 fp = fopen(cp,"w+","fop=dlt");
2264 #ifndef HOMEGROWN_POSIX_SIGNALS
2266 * The C RTL's sigaction fails to check for invalid signal numbers so we
2267 * help it out a bit. The docs are correct, but the actual routine doesn't
2268 * do what the docs say it will.
2270 /*{{{int Perl_my_sigaction (pTHX_ int, const struct sigaction*, struct sigaction*);*/
2272 Perl_my_sigaction (pTHX_ int sig, const struct sigaction* act,
2273 struct sigaction* oact)
2275 if (sig == SIGKILL || sig == SIGSTOP || sig == SIGCONT) {
2276 SETERRNO(EINVAL, SS$_INVARG);
2279 return sigaction(sig, act, oact);
2284 #ifdef KILL_BY_SIGPRC
2285 #include <errnodef.h>
2287 /* We implement our own kill() using the undocumented system service
2288 sys$sigprc for one of two reasons:
2290 1.) If the kill() in an older CRTL uses sys$forcex, causing the
2291 target process to do a sys$exit, which usually can't be handled
2292 gracefully...certainly not by Perl and the %SIG{} mechanism.
2294 2.) If the kill() in the CRTL can't be called from a signal
2295 handler without disappearing into the ether, i.e., the signal
2296 it purportedly sends is never trapped. Still true as of VMS 7.3.
2298 sys$sigprc has the same parameters as sys$forcex, but throws an exception
2299 in the target process rather than calling sys$exit.
2301 Note that distinguishing SIGSEGV from SIGBUS requires an extra arg
2302 on the ACCVIO condition, which sys$sigprc (and sys$forcex) don't
2303 provide. On VMS 7.0+ this is taken care of by doing sys$sigprc
2304 with condition codes C$_SIG0+nsig*8, catching the exception on the
2305 target process and resignaling with appropriate arguments.
2307 But we don't have that VMS 7.0+ exception handler, so if you
2308 Perl_my_kill(.., SIGSEGV) it will show up as a SIGBUS. Oh well.
2310 Also note that SIGTERM is listed in the docs as being "unimplemented",
2311 yet always seems to be signaled with a VMS condition code of 4 (and
2312 correctly handled for that code). So we hardwire it in.
2314 Unlike the VMS 7.0+ CRTL kill() function, we actually check the signal
2315 number to see if it's valid. So Perl_my_kill(pid,0) returns -1 rather
2316 than signalling with an unrecognized (and unhandled by CRTL) code.
2319 #define _MY_SIG_MAX 28
2322 Perl_sig_to_vmscondition_int(int sig)
2324 static unsigned int sig_code[_MY_SIG_MAX+1] =
2327 SS$_HANGUP, /* 1 SIGHUP */
2328 SS$_CONTROLC, /* 2 SIGINT */
2329 SS$_CONTROLY, /* 3 SIGQUIT */
2330 SS$_RADRMOD, /* 4 SIGILL */
2331 SS$_BREAK, /* 5 SIGTRAP */
2332 SS$_OPCCUS, /* 6 SIGABRT */
2333 SS$_COMPAT, /* 7 SIGEMT */
2335 SS$_FLTOVF, /* 8 SIGFPE VAX */
2337 SS$_HPARITH, /* 8 SIGFPE AXP */
2339 SS$_ABORT, /* 9 SIGKILL */
2340 SS$_ACCVIO, /* 10 SIGBUS */
2341 SS$_ACCVIO, /* 11 SIGSEGV */
2342 SS$_BADPARAM, /* 12 SIGSYS */
2343 SS$_NOMBX, /* 13 SIGPIPE */
2344 SS$_ASTFLT, /* 14 SIGALRM */
2361 #if __VMS_VER >= 60200000
2362 static int initted = 0;
2365 sig_code[16] = C$_SIGUSR1;
2366 sig_code[17] = C$_SIGUSR2;
2367 #if __CRTL_VER >= 70000000
2368 sig_code[20] = C$_SIGCHLD;
2370 #if __CRTL_VER >= 70300000
2371 sig_code[28] = C$_SIGWINCH;
2376 if (sig < _SIG_MIN) return 0;
2377 if (sig > _MY_SIG_MAX) return 0;
2378 return sig_code[sig];
2382 Perl_sig_to_vmscondition(int sig)
2385 if (vms_debug_on_exception != 0)
2386 lib$signal(SS$_DEBUG);
2388 return Perl_sig_to_vmscondition_int(sig);
2393 Perl_my_kill(int pid, int sig)
2397 #define sys$sigprc SYS$SIGPRC
2398 int sys$sigprc(unsigned int *pidadr,
2399 struct dsc$descriptor_s *prcname,
2402 /* sig 0 means validate the PID */
2403 /*------------------------------*/
2405 const unsigned long int jpicode = JPI$_PID;
2408 status = lib$getjpi(&jpicode, &pid, NULL, &ret_pid, NULL, NULL);
2409 if ($VMS_STATUS_SUCCESS(status))
2412 case SS$_NOSUCHNODE:
2413 case SS$_UNREACHABLE:
2427 code = Perl_sig_to_vmscondition_int(sig);
2430 SETERRNO(EINVAL, SS$_BADPARAM);
2434 /* Fixme: Per official UNIX specification: If pid = 0, or negative then
2435 * signals are to be sent to multiple processes.
2436 * pid = 0 - all processes in group except ones that the system exempts
2437 * pid = -1 - all processes except ones that the system exempts
2438 * pid = -n - all processes in group (abs(n)) except ...
2439 * For now, just report as not supported.
2443 SETERRNO(ENOTSUP, SS$_UNSUPPORTED);
2447 iss = sys$sigprc((unsigned int *)&pid,0,code);
2448 if (iss&1) return 0;
2452 set_errno(EPERM); break;
2454 case SS$_NOSUCHNODE:
2455 case SS$_UNREACHABLE:
2456 set_errno(ESRCH); break;
2458 set_errno(ENOMEM); break;
2460 _ckvmssts_noperl(iss);
2463 set_vaxc_errno(iss);
2469 /* Routine to convert a VMS status code to a UNIX status code.
2470 ** More tricky than it appears because of conflicting conventions with
2473 ** VMS status codes are a bit mask, with the least significant bit set for
2476 ** Special UNIX status of EVMSERR indicates that no translation is currently
2477 ** available, and programs should check the VMS status code.
2479 ** Programs compiled with _POSIX_EXIT have a special encoding that requires
2483 #ifndef C_FACILITY_NO
2484 #define C_FACILITY_NO 0x350000
2487 #define DCL_IVVERB 0x38090
2490 int Perl_vms_status_to_unix(int vms_status, int child_flag)
2498 /* Assume the best or the worst */
2499 if (vms_status & STS$M_SUCCESS)
2502 unix_status = EVMSERR;
2504 msg_status = vms_status & ~STS$M_CONTROL;
2506 facility = vms_status & STS$M_FAC_NO;
2507 fac_sp = vms_status & STS$M_FAC_SP;
2508 msg_no = vms_status & (STS$M_MSG_NO | STS$M_SEVERITY);
2510 if (((facility == 0) || (fac_sp == 0)) && (child_flag == 0)) {
2516 unix_status = EFAULT;
2518 case SS$_DEVOFFLINE:
2519 unix_status = EBUSY;
2522 unix_status = ENOTCONN;
2530 case SS$_INVFILFOROP:
2534 unix_status = EINVAL;
2536 case SS$_UNSUPPORTED:
2537 unix_status = ENOTSUP;
2542 unix_status = EACCES;
2544 case SS$_DEVICEFULL:
2545 unix_status = ENOSPC;
2548 unix_status = ENODEV;
2550 case SS$_NOSUCHFILE:
2551 case SS$_NOSUCHOBJECT:
2552 unix_status = ENOENT;
2554 case SS$_ABORT: /* Fatal case */
2555 case ((SS$_ABORT & STS$M_COND_ID) | STS$K_ERROR): /* Error case */
2556 case ((SS$_ABORT & STS$M_COND_ID) | STS$K_WARNING): /* Warning case */
2557 unix_status = EINTR;
2560 unix_status = E2BIG;
2563 unix_status = ENOMEM;
2566 unix_status = EPERM;
2568 case SS$_NOSUCHNODE:
2569 case SS$_UNREACHABLE:
2570 unix_status = ESRCH;
2573 unix_status = ECHILD;
2576 if ((facility == 0) && (msg_no < 8)) {
2577 /* These are not real VMS status codes so assume that they are
2578 ** already UNIX status codes
2580 unix_status = msg_no;
2586 /* Translate a POSIX exit code to a UNIX exit code */
2587 if ((facility == C_FACILITY_NO) && ((msg_no & 0xA000) == 0xA000)) {
2588 unix_status = (msg_no & 0x07F8) >> 3;
2592 /* Documented traditional behavior for handling VMS child exits */
2593 /*--------------------------------------------------------------*/
2594 if (child_flag != 0) {
2596 /* Success / Informational return 0 */
2597 /*----------------------------------*/
2598 if (msg_no & STS$K_SUCCESS)
2601 /* Warning returns 1 */
2602 /*-------------------*/
2603 if ((msg_no & (STS$K_ERROR | STS$K_SEVERE)) == 0)
2606 /* Everything else pass through the severity bits */
2607 /*------------------------------------------------*/
2608 return (msg_no & STS$M_SEVERITY);
2611 /* Normal VMS status to ERRNO mapping attempt */
2612 /*--------------------------------------------*/
2613 switch(msg_status) {
2614 /* case RMS$_EOF: */ /* End of File */
2615 case RMS$_FNF: /* File Not Found */
2616 case RMS$_DNF: /* Dir Not Found */
2617 unix_status = ENOENT;
2619 case RMS$_RNF: /* Record Not Found */
2620 unix_status = ESRCH;
2623 unix_status = ENOTDIR;
2626 unix_status = ENODEV;
2631 unix_status = EBADF;
2634 unix_status = EEXIST;
2638 case LIB$_INVSTRDES:
2640 case LIB$_NOSUCHSYM:
2641 case LIB$_INVSYMNAM:
2643 unix_status = EINVAL;
2649 unix_status = E2BIG;
2651 case RMS$_PRV: /* No privilege */
2652 case RMS$_ACC: /* ACP file access failed */
2653 case RMS$_WLK: /* Device write locked */
2654 unix_status = EACCES;
2656 case RMS$_MKD: /* Failed to mark for delete */
2657 unix_status = EPERM;
2659 /* case RMS$_NMF: */ /* No more files */
2667 /* Try to guess at what VMS error status should go with a UNIX errno
2668 * value. This is hard to do as there could be many possible VMS
2669 * error statuses that caused the errno value to be set.
2672 int Perl_unix_status_to_vms(int unix_status)
2674 int test_unix_status;
2676 /* Trivial cases first */
2677 /*---------------------*/
2678 if (unix_status == EVMSERR)
2681 /* Is vaxc$errno sane? */
2682 /*---------------------*/
2683 test_unix_status = Perl_vms_status_to_unix(vaxc$errno, 0);
2684 if (test_unix_status == unix_status)
2687 /* If way out of range, must be VMS code already */
2688 /*-----------------------------------------------*/
2689 if (unix_status > EVMSERR)
2692 /* If out of range, punt */
2693 /*-----------------------*/
2694 if (unix_status > __ERRNO_MAX)
2698 /* Ok, now we have to do it the hard way. */
2699 /*----------------------------------------*/
2700 switch(unix_status) {
2701 case 0: return SS$_NORMAL;
2702 case EPERM: return SS$_NOPRIV;
2703 case ENOENT: return SS$_NOSUCHOBJECT;
2704 case ESRCH: return SS$_UNREACHABLE;
2705 case EINTR: return SS$_ABORT;
2708 case E2BIG: return SS$_BUFFEROVF;
2710 case EBADF: return RMS$_IFI;
2711 case ECHILD: return SS$_NONEXPR;
2713 case ENOMEM: return SS$_INSFMEM;
2714 case EACCES: return SS$_FILACCERR;
2715 case EFAULT: return SS$_ACCVIO;
2717 case EBUSY: return SS$_DEVOFFLINE;
2718 case EEXIST: return RMS$_FEX;
2720 case ENODEV: return SS$_NOSUCHDEV;
2721 case ENOTDIR: return RMS$_DIR;
2723 case EINVAL: return SS$_INVARG;
2729 case ENOSPC: return SS$_DEVICEFULL;
2730 case ESPIPE: return LIB$_INVARG;
2735 case ERANGE: return LIB$_INVARG;
2736 /* case EWOULDBLOCK */
2737 /* case EINPROGRESS */
2740 /* case EDESTADDRREQ */
2742 /* case EPROTOTYPE */
2743 /* case ENOPROTOOPT */
2744 /* case EPROTONOSUPPORT */
2745 /* case ESOCKTNOSUPPORT */
2746 /* case EOPNOTSUPP */
2747 /* case EPFNOSUPPORT */
2748 /* case EAFNOSUPPORT */
2749 /* case EADDRINUSE */
2750 /* case EADDRNOTAVAIL */
2752 /* case ENETUNREACH */
2753 /* case ENETRESET */
2754 /* case ECONNABORTED */
2755 /* case ECONNRESET */
2758 case ENOTCONN: return SS$_CLEARED;
2759 /* case ESHUTDOWN */
2760 /* case ETOOMANYREFS */
2761 /* case ETIMEDOUT */
2762 /* case ECONNREFUSED */
2764 /* case ENAMETOOLONG */
2765 /* case EHOSTDOWN */
2766 /* case EHOSTUNREACH */
2767 /* case ENOTEMPTY */
2779 /* case ECANCELED */
2783 return SS$_UNSUPPORTED;
2789 /* case EABANDONED */
2791 return SS$_ABORT; /* punt */
2796 /* default piping mailbox size */
2798 # define PERL_BUFSIZ 512
2800 # define PERL_BUFSIZ 8192
2805 create_mbx(unsigned short int *chan, struct dsc$descriptor_s *namdsc)
2807 unsigned long int mbxbufsiz;
2808 static unsigned long int syssize = 0;
2809 unsigned long int dviitm = DVI$_DEVNAM;
2810 char csize[LNM$C_NAMLENGTH+1];
2814 unsigned long syiitm = SYI$_MAXBUF;
2816 * Get the SYSGEN parameter MAXBUF
2818 * If the logical 'PERL_MBX_SIZE' is defined
2819 * use the value of the logical instead of PERL_BUFSIZ, but
2820 * keep the size between 128 and MAXBUF.
2823 _ckvmssts_noperl(lib$getsyi(&syiitm, &syssize, 0, 0, 0, 0));
2826 if (vmstrnenv("PERL_MBX_SIZE", csize, 0, fildev, 0)) {
2827 mbxbufsiz = atoi(csize);
2829 mbxbufsiz = PERL_BUFSIZ;
2831 if (mbxbufsiz < 128) mbxbufsiz = 128;
2832 if (mbxbufsiz > syssize) mbxbufsiz = syssize;
2834 _ckvmssts_noperl(sts = sys$crembx(0,chan,mbxbufsiz,mbxbufsiz,0,0,0));
2836 sts = lib$getdvi(&dviitm, chan, NULL, NULL, namdsc, &namdsc->dsc$w_length);
2837 _ckvmssts_noperl(sts);
2838 namdsc->dsc$a_pointer[namdsc->dsc$w_length] = '\0';
2840 } /* end of create_mbx() */
2843 /*{{{ my_popen and my_pclose*/
2845 typedef struct _iosb IOSB;
2846 typedef struct _iosb* pIOSB;
2847 typedef struct _pipe Pipe;
2848 typedef struct _pipe* pPipe;
2849 typedef struct pipe_details Info;
2850 typedef struct pipe_details* pInfo;
2851 typedef struct _srqp RQE;
2852 typedef struct _srqp* pRQE;
2853 typedef struct _tochildbuf CBuf;
2854 typedef struct _tochildbuf* pCBuf;
2857 unsigned short status;
2858 unsigned short count;
2859 unsigned long dvispec;
2862 #pragma member_alignment save
2863 #pragma nomember_alignment quadword
2864 struct _srqp { /* VMS self-relative queue entry */
2865 unsigned long qptr[2];
2867 #pragma member_alignment restore
2868 static RQE RQE_ZERO = {0,0};
2870 struct _tochildbuf {
2873 unsigned short size;
2881 unsigned short chan_in;
2882 unsigned short chan_out;
2884 unsigned int bufsize;
2896 #if defined(PERL_IMPLICIT_CONTEXT)
2897 void *thx; /* Either a thread or an interpreter */
2898 /* pointer, depending on how we're built */
2906 PerlIO *fp; /* file pointer to pipe mailbox */
2907 int useFILE; /* using stdio, not perlio */
2908 int pid; /* PID of subprocess */
2909 int mode; /* == 'r' if pipe open for reading */
2910 int done; /* subprocess has completed */
2911 int waiting; /* waiting for completion/closure */
2912 int closing; /* my_pclose is closing this pipe */
2913 unsigned long completion; /* termination status of subprocess */
2914 pPipe in; /* pipe in to sub */
2915 pPipe out; /* pipe out of sub */
2916 pPipe err; /* pipe of sub's sys$error */
2917 int in_done; /* true when in pipe finished */
2920 unsigned short xchan; /* channel to debug xterm */
2921 unsigned short xchan_valid; /* channel is assigned */
2924 struct exit_control_block
2926 struct exit_control_block *flink;
2927 unsigned long int (*exit_routine)(void);
2928 unsigned long int arg_count;
2929 unsigned long int *status_address;
2930 unsigned long int exit_status;
2933 typedef struct _closed_pipes Xpipe;
2934 typedef struct _closed_pipes* pXpipe;
2936 struct _closed_pipes {
2937 int pid; /* PID of subprocess */
2938 unsigned long completion; /* termination status of subprocess */
2940 #define NKEEPCLOSED 50
2941 static Xpipe closed_list[NKEEPCLOSED];
2942 static int closed_index = 0;
2943 static int closed_num = 0;
2945 #define RETRY_DELAY "0 ::0.20"
2946 #define MAX_RETRY 50
2948 static int pipe_ef = 0; /* first call to safe_popen inits these*/
2949 static unsigned long mypid;
2950 static unsigned long delaytime[2];
2952 static pInfo open_pipes = NULL;
2953 static $DESCRIPTOR(nl_desc, "NL:");
2955 #define PIPE_COMPLETION_WAIT 30 /* seconds, for EOF/FORCEX wait */
2959 static unsigned long int
2960 pipe_exit_routine(void)
2963 unsigned long int retsts = SS$_NORMAL, abort = SS$_TIMEOUT;
2964 int sts, did_stuff, j;
2967 * Flush any pending i/o, but since we are in process run-down, be
2968 * careful about referencing PerlIO structures that may already have
2969 * been deallocated. We may not even have an interpreter anymore.
2974 #if defined(PERL_IMPLICIT_CONTEXT)
2975 /* We need to use the Perl context of the thread that created */
2979 aTHX = info->err->thx;
2981 aTHX = info->out->thx;
2983 aTHX = info->in->thx;
2986 #if defined(USE_ITHREADS)
2990 && PL_perlio_fd_refcnt
2993 PerlIO_flush(info->fp);
2995 fflush((FILE *)info->fp);
3001 next we try sending an EOF...ignore if doesn't work, make sure we
3008 _ckvmssts_noperl(sys$setast(0));
3009 if (info->in && !info->in->shut_on_empty) {
3010 _ckvmssts_noperl(sys$qio(0,info->in->chan_in,IO$_WRITEOF,0,0,0,
3015 _ckvmssts_noperl(sys$setast(1));
3019 /* wait for EOF to have effect, up to ~ 30 sec [default] */
3021 for (j = 0; did_stuff && j < PIPE_COMPLETION_WAIT; j++) {
3026 _ckvmssts_noperl(sys$setast(0));
3027 if (info->waiting && info->done)
3029 nwait += info->waiting;
3030 _ckvmssts_noperl(sys$setast(1));
3040 _ckvmssts_noperl(sys$setast(0));
3041 if (!info->done) { /* Tap them gently on the shoulder . . .*/
3042 sts = sys$forcex(&info->pid,0,&abort);
3043 if (!(sts&1) && sts != SS$_NONEXPR) _ckvmssts_noperl(sts);
3046 _ckvmssts_noperl(sys$setast(1));
3050 /* again, wait for effect */
3052 for (j = 0; did_stuff && j < PIPE_COMPLETION_WAIT; j++) {
3057 _ckvmssts_noperl(sys$setast(0));
3058 if (info->waiting && info->done)
3060 nwait += info->waiting;
3061 _ckvmssts_noperl(sys$setast(1));
3070 _ckvmssts_noperl(sys$setast(0));
3071 if (!info->done) { /* We tried to be nice . . . */
3072 sts = sys$delprc(&info->pid,0);
3073 if (!(sts&1) && sts != SS$_NONEXPR) _ckvmssts_noperl(sts);
3074 info->done = 1; /* sys$delprc is as done as we're going to get. */
3076 _ckvmssts_noperl(sys$setast(1));
3082 #if defined(PERL_IMPLICIT_CONTEXT)
3083 /* We need to use the Perl context of the thread that created */
3086 if (open_pipes->err)
3087 aTHX = open_pipes->err->thx;
3088 else if (open_pipes->out)
3089 aTHX = open_pipes->out->thx;
3090 else if (open_pipes->in)
3091 aTHX = open_pipes->in->thx;
3093 if ((sts = my_pclose(open_pipes->fp)) == -1) retsts = vaxc$errno;
3094 else if (!(sts & 1)) retsts = sts;
3099 static struct exit_control_block pipe_exitblock =
3100 {(struct exit_control_block *) 0,
3101 pipe_exit_routine, 0, &pipe_exitblock.exit_status, 0};
3103 static void pipe_mbxtofd_ast(pPipe p);
3104 static void pipe_tochild1_ast(pPipe p);
3105 static void pipe_tochild2_ast(pPipe p);
3108 popen_completion_ast(pInfo info)
3110 pInfo i = open_pipes;
3113 info->completion &= 0x0FFFFFFF; /* strip off "control" field */
3114 closed_list[closed_index].pid = info->pid;
3115 closed_list[closed_index].completion = info->completion;
3117 if (closed_index == NKEEPCLOSED)
3122 if (i == info) break;
3125 if (!i) return; /* unlinked, probably freed too */
3130 Writing to subprocess ...
3131 if my_pclose'd: EOF already sent, should shutdown chan_in part of pipe
3133 chan_out may be waiting for "done" flag, or hung waiting
3134 for i/o completion to child...cancel the i/o. This will
3135 put it into "snarf mode" (done but no EOF yet) that discards
3138 Output from subprocess (stdout, stderr) needs to be flushed and
3139 shut down. We try sending an EOF, but if the mbx is full the pipe
3140 routine should still catch the "shut_on_empty" flag, telling it to
3141 use immediate-style reads so that "mbx empty" -> EOF.
3145 if (info->in && !info->in_done) { /* only for mode=w */
3146 if (info->in->shut_on_empty && info->in->need_wake) {
3147 info->in->need_wake = FALSE;
3148 _ckvmssts_noperl(sys$dclast(pipe_tochild2_ast,info->in,0));
3150 _ckvmssts_noperl(sys$cancel(info->in->chan_out));
3154 if (info->out && !info->out_done) { /* were we also piping output? */
3155 info->out->shut_on_empty = TRUE;
3156 iss = sys$qio(0,info->out->chan_in,IO$_WRITEOF|IO$M_NORSWAIT, 0, 0, 0, 0, 0, 0, 0, 0, 0);
3157 if (iss == SS$_MBFULL) iss = SS$_NORMAL;
3158 _ckvmssts_noperl(iss);
3161 if (info->err && !info->err_done) { /* we were piping stderr */
3162 info->err->shut_on_empty = TRUE;
3163 iss = sys$qio(0,info->err->chan_in,IO$_WRITEOF|IO$M_NORSWAIT, 0, 0, 0, 0, 0, 0, 0, 0, 0);
3164 if (iss == SS$_MBFULL) iss = SS$_NORMAL;
3165 _ckvmssts_noperl(iss);
3167 _ckvmssts_noperl(sys$setef(pipe_ef));
3171 static unsigned long int setup_cmddsc(pTHX_ const char *cmd, int check_img, int *suggest_quote, struct dsc$descriptor_s **pvmscmd);
3172 static void vms_execfree(struct dsc$descriptor_s *vmscmd);
3173 static void pipe_infromchild_ast(pPipe p);
3176 I'm using LIB$(GET|FREE)_VM here so that we can allocate and deallocate
3177 inside an AST routine without worrying about reentrancy and which Perl
3178 memory allocator is being used.
3180 We read data and queue up the buffers, then spit them out one at a
3181 time to the output mailbox when the output mailbox is ready for one.
3184 #define INITIAL_TOCHILDQUEUE 2
3187 pipe_tochild_setup(pTHX_ char *rmbx, char *wmbx)
3191 char mbx1[64], mbx2[64];
3192 struct dsc$descriptor_s d_mbx1 = {sizeof mbx1, DSC$K_DTYPE_T,
3193 DSC$K_CLASS_S, mbx1},
3194 d_mbx2 = {sizeof mbx2, DSC$K_DTYPE_T,
3195 DSC$K_CLASS_S, mbx2};
3196 unsigned int dviitm = DVI$_DEVBUFSIZ;
3200 _ckvmssts_noperl(lib$get_vm(&n, &p));
3202 create_mbx(&p->chan_in , &d_mbx1);
3203 create_mbx(&p->chan_out, &d_mbx2);
3204 _ckvmssts_noperl(lib$getdvi(&dviitm, &p->chan_in, 0, &p->bufsize));
3207 p->shut_on_empty = FALSE;
3208 p->need_wake = FALSE;
3211 p->iosb.status = SS$_NORMAL;
3212 p->iosb2.status = SS$_NORMAL;
3218 #ifdef PERL_IMPLICIT_CONTEXT
3222 n = sizeof(CBuf) + p->bufsize;
3224 for (j = 0; j < INITIAL_TOCHILDQUEUE; j++) {
3225 _ckvmssts_noperl(lib$get_vm(&n, &b));
3226 b->buf = (char *) b + sizeof(CBuf);
3227 _ckvmssts_noperl(lib$insqhi(b, &p->free));
3230 pipe_tochild2_ast(p);
3231 pipe_tochild1_ast(p);
3237 /* reads the MBX Perl is writing, and queues */
3240 pipe_tochild1_ast(pPipe p)
3243 int iss = p->iosb.status;
3244 int eof = (iss == SS$_ENDOFFILE);
3246 #ifdef PERL_IMPLICIT_CONTEXT
3252 p->shut_on_empty = TRUE;
3254 _ckvmssts_noperl(sys$dassgn(p->chan_in));
3256 _ckvmssts_noperl(iss);
3260 b->size = p->iosb.count;
3261 _ckvmssts_noperl(sts = lib$insqhi(b, &p->wait));
3263 p->need_wake = FALSE;
3264 _ckvmssts_noperl(sys$dclast(pipe_tochild2_ast,p,0));
3267 p->retry = 1; /* initial call */
3270 if (eof) { /* flush the free queue, return when done */
3271 int n = sizeof(CBuf) + p->bufsize;
3273 iss = lib$remqti(&p->free, &b);
3274 if (iss == LIB$_QUEWASEMP) return;
3275 _ckvmssts_noperl(iss);
3276 _ckvmssts_noperl(lib$free_vm(&n, &b));
3280 iss = lib$remqti(&p->free, &b);
3281 if (iss == LIB$_QUEWASEMP) {
3282 int n = sizeof(CBuf) + p->bufsize;
3283 _ckvmssts_noperl(lib$get_vm(&n, &b));
3284 b->buf = (char *) b + sizeof(CBuf);
3286 _ckvmssts_noperl(iss);
3290 iss = sys$qio(0,p->chan_in,
3291 IO$_READVBLK|(p->shut_on_empty ? IO$M_NOWAIT : 0),
3293 pipe_tochild1_ast, p, b->buf, p->bufsize, 0, 0, 0, 0);
3294 if (iss == SS$_ENDOFFILE && p->shut_on_empty) iss = SS$_NORMAL;
3295 _ckvmssts_noperl(iss);
3299 /* writes queued buffers to output, waits for each to complete before
3303 pipe_tochild2_ast(pPipe p)
3306 int iss = p->iosb2.status;
3307 int n = sizeof(CBuf) + p->bufsize;
3308 int done = (p->info && p->info->done) ||
3309 iss == SS$_CANCEL || iss == SS$_ABORT;
3310 #if defined(PERL_IMPLICIT_CONTEXT)
3315 if (p->type) { /* type=1 has old buffer, dispose */
3316 if (p->shut_on_empty) {
3317 _ckvmssts_noperl(lib$free_vm(&n, &b));
3319 _ckvmssts_noperl(lib$insqhi(b, &p->free));
3324 iss = lib$remqti(&p->wait, &b);
3325 if (iss == LIB$_QUEWASEMP) {
3326 if (p->shut_on_empty) {
3328 _ckvmssts_noperl(sys$dassgn(p->chan_out));
3329 *p->pipe_done = TRUE;
3330 _ckvmssts_noperl(sys$setef(pipe_ef));
3332 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEOF,
3333 &p->iosb2, pipe_tochild2_ast, p, 0, 0, 0, 0, 0, 0));
3337 p->need_wake = TRUE;
3340 _ckvmssts_noperl(iss);
3347 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEOF,
3348 &p->iosb2, pipe_tochild2_ast, p, 0, 0, 0, 0, 0, 0));
3350 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEVBLK,
3351 &p->iosb2, pipe_tochild2_ast, p, b->buf, b->size, 0, 0, 0, 0));
3360 pipe_infromchild_setup(pTHX_ char *rmbx, char *wmbx)
3363 char mbx1[64], mbx2[64];
3364 struct dsc$descriptor_s d_mbx1 = {sizeof mbx1, DSC$K_DTYPE_T,
3365 DSC$K_CLASS_S, mbx1},
3366 d_mbx2 = {sizeof mbx2, DSC$K_DTYPE_T,
3367 DSC$K_CLASS_S, mbx2};
3368 unsigned int dviitm = DVI$_DEVBUFSIZ;
3370 int n = sizeof(Pipe);
3371 _ckvmssts_noperl(lib$get_vm(&n, &p));
3372 create_mbx(&p->chan_in , &d_mbx1);
3373 create_mbx(&p->chan_out, &d_mbx2);
3375 _ckvmssts_noperl(lib$getdvi(&dviitm, &p->chan_in, 0, &p->bufsize));
3376 n = p->bufsize * sizeof(char);
3377 _ckvmssts_noperl(lib$get_vm(&n, &p->buf));
3378 p->shut_on_empty = FALSE;
3381 p->iosb.status = SS$_NORMAL;
3382 #if defined(PERL_IMPLICIT_CONTEXT)
3385 pipe_infromchild_ast(p);
3393 pipe_infromchild_ast(pPipe p)
3395 int iss = p->iosb.status;
3396 int eof = (iss == SS$_ENDOFFILE);
3397 int myeof = (eof && (p->iosb.dvispec == mypid || p->iosb.dvispec == 0));
3398 int kideof = (eof && (p->iosb.dvispec == p->info->pid));
3399 #if defined(PERL_IMPLICIT_CONTEXT)
3403 if (p->info && p->info->closing && p->chan_out) { /* output shutdown */
3404 _ckvmssts_noperl(sys$dassgn(p->chan_out));
3409 input shutdown if EOF from self (done or shut_on_empty)
3410 output shutdown if closing flag set (my_pclose)
3411 send data/eof from child or eof from self
3412 otherwise, re-read (snarf of data from child)
3417 if (myeof && p->chan_in) { /* input shutdown */
3418 _ckvmssts_noperl(sys$dassgn(p->chan_in));
3423 if (myeof || kideof) { /* pass EOF to parent */
3424 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEOF, &p->iosb,
3425 pipe_infromchild_ast, p,
3428 } else if (eof) { /* eat EOF --- fall through to read*/
3430 } else { /* transmit data */
3431 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEVBLK,&p->iosb,
3432 pipe_infromchild_ast,p,
3433 p->buf, p->iosb.count, 0, 0, 0, 0));
3439 /* everything shut? flag as done */
3441 if (!p->chan_in && !p->chan_out) {
3442 *p->pipe_done = TRUE;
3443 _ckvmssts_noperl(sys$setef(pipe_ef));
3447 /* write completed (or read, if snarfing from child)
3448 if still have input active,
3449 queue read...immediate mode if shut_on_empty so we get EOF if empty
3451 check if Perl reading, generate EOFs as needed
3457 iss = sys$qio(0,p->chan_in,IO$_READVBLK|(p->shut_on_empty ? IO$M_NOW : 0),&p->iosb,
3458 pipe_infromchild_ast,p,
3459 p->buf, p->bufsize, 0, 0, 0, 0);
3460 if (p->shut_on_empty && iss == SS$_ENDOFFILE) iss = SS$_NORMAL;
3461 _ckvmssts_noperl(iss);
3462 } else { /* send EOFs for extra reads */
3463 p->iosb.status = SS$_ENDOFFILE;
3464 p->iosb.dvispec = 0;
3465 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_SETMODE|IO$M_READATTN,
3467 pipe_infromchild_ast, p, 0, 0, 0, 0));
3473 pipe_mbxtofd_setup(pTHX_ int fd, char *out)
3477 unsigned long dviitm = DVI$_DEVBUFSIZ;
3479 struct dsc$descriptor_s d_mbx = {sizeof mbx, DSC$K_DTYPE_T,
3480 DSC$K_CLASS_S, mbx};
3481 int n = sizeof(Pipe);
3483 /* things like terminals and mbx's don't need this filter */
3484 if (fd && fstat(fd,&s) == 0) {
3485 unsigned long devchar;
3487 unsigned short dev_len;
3488 struct dsc$descriptor_s d_dev;
3490 struct item_list_3 items[3];
3492 unsigned short dvi_iosb[4];
3494 cptr = getname(fd, out, 1);
3495 if (cptr == NULL) _ckvmssts_noperl(SS$_NOSUCHDEV);
3496 d_dev.dsc$a_pointer = out;
3497 d_dev.dsc$w_length = strlen(out);
3498 d_dev.dsc$b_dtype = DSC$K_DTYPE_T;
3499 d_dev.dsc$b_class = DSC$K_CLASS_S;
3502 items[0].code = DVI$_DEVCHAR;
3503 items[0].bufadr = &devchar;
3504 items[0].retadr = NULL;
3506 items[1].code = DVI$_FULLDEVNAM;
3507 items[1].bufadr = device;
3508 items[1].retadr = &dev_len;
3512 status = sys$getdviw
3513 (NO_EFN, 0, &d_dev, items, dvi_iosb, NULL, NULL, NULL);
3514 _ckvmssts_noperl(status);
3515 if ($VMS_STATUS_SUCCESS(dvi_iosb[0])) {
3516 device[dev_len] = 0;
3518 if (!(devchar & DEV$M_DIR)) {
3519 strcpy(out, device);
3525 _ckvmssts_noperl(lib$get_vm(&n, &p));
3526 p->fd_out = dup(fd);
3527 create_mbx(&p->chan_in, &d_mbx);
3528 _ckvmssts_noperl(lib$getdvi(&dviitm, &p->chan_in, 0, &p->bufsize));
3529 n = (p->bufsize+1) * sizeof(char);
3530 _ckvmssts_noperl(lib$get_vm(&n, &p->buf));
3531 p->shut_on_empty = FALSE;
3536 _ckvmssts_noperl(sys$qio(0, p->chan_in, IO$_READVBLK, &p->iosb,
3537 pipe_mbxtofd_ast, p,
3538 p->buf, p->bufsize, 0, 0, 0, 0));
3544 pipe_mbxtofd_ast(pPipe p)
3546 int iss = p->iosb.status;
3547 int done = p->info->done;
3549 int eof = (iss == SS$_ENDOFFILE);
3550 int myeof = eof && ((p->iosb.dvispec == mypid)||(p->iosb.dvispec == 0));
3551 int err = !(iss&1) && !eof;
3552 #if defined(PERL_IMPLICIT_CONTEXT)
3556 if (done && myeof) { /* end piping */
3558 sys$dassgn(p->chan_in);
3559 *p->pipe_done = TRUE;
3560 _ckvmssts_noperl(sys$setef(pipe_ef));
3564 if (!err && !eof) { /* good data to send to file */
3565 p->buf[p->iosb.count] = '\n';
3566 iss2 = write(p->fd_out, p->buf, p->iosb.count+1);
3569 if (p->retry < MAX_RETRY) {
3570 _ckvmssts_noperl(sys$setimr(0,delaytime,pipe_mbxtofd_ast,p));
3576 _ckvmssts_noperl(iss);
3580 iss = sys$qio(0, p->chan_in, IO$_READVBLK|(p->shut_on_empty ? IO$M_NOW : 0), &p->iosb,
3581 pipe_mbxtofd_ast, p,
3582 p->buf, p->bufsize, 0, 0, 0, 0);
3583 if (p->shut_on_empty && (iss == SS$_ENDOFFILE)) iss = SS$_NORMAL;
3584 _ckvmssts_noperl(iss);
3588 typedef struct _pipeloc PLOC;
3589 typedef struct _pipeloc* pPLOC;
3593 char dir[NAM$C_MAXRSS+1];
3595 static pPLOC head_PLOC = 0;
3598 free_pipelocs(pTHX_ void *head)
3601 pPLOC *pHead = (pPLOC *)head;
3613 store_pipelocs(pTHX)
3621 char temp[NAM$C_MAXRSS+1];
3625 free_pipelocs(aTHX_ &head_PLOC);
3627 /* the . directory from @INC comes last */
3629 p = (pPLOC) PerlMem_malloc(sizeof(PLOC));
3630 if (p == NULL) _ckvmssts_noperl(SS$_INSFMEM);
3631 p->next = head_PLOC;
3633 strcpy(p->dir,"./");
3635 /* get the directory from $^X */
3637 unixdir = PerlMem_malloc(VMS_MAXRSS);
3638 if (unixdir == NULL) _ckvmssts_noperl(SS$_INSFMEM);
3640 #ifdef PERL_IMPLICIT_CONTEXT
3641 if (aTHX && PL_origargv && PL_origargv[0]) { /* maybe nul if embedded Perl */
3643 if (PL_origargv && PL_origargv[0]) { /* maybe nul if embedded Perl */
3645 strcpy(temp, PL_origargv[0]);
3646 x = strrchr(temp,']');
3648 x = strrchr(temp,'>');
3650 /* It could be a UNIX path */
3651 x = strrchr(temp,'/');
3657 /* Got a bare name, so use default directory */
3662 if ((tounixpath_utf8(temp, unixdir, NULL)) != NULL) {
3663 p = (pPLOC) PerlMem_malloc(sizeof(PLOC));
3664 if (p == NULL) _ckvmssts_noperl(SS$_INSFMEM);
3665 p->next = head_PLOC;
3667 strncpy(p->dir,unixdir,sizeof(p->dir)-1);
3668 p->dir[NAM$C_MAXRSS] = '\0';
3672 /* reverse order of @INC entries, skip "." since entered above */
3674 #ifdef PERL_IMPLICIT_CONTEXT
3677 if (PL_incgv) av = GvAVn(PL_incgv);
3679 for (i = 0; av && i <= AvFILL(av); i++) {
3680 dirsv = *av_fetch(av,i,TRUE);
3682 if (SvROK(dirsv)) continue;
3683 dir = SvPVx(dirsv,n_a);
3684 if (strcmp(dir,".") == 0) continue;
3685 if ((tounixpath_utf8(dir, unixdir, NULL)) == NULL)
3688 p = (pPLOC) PerlMem_malloc(sizeof(PLOC));
3689 p->next = head_PLOC;
3691 strncpy(p->dir,unixdir,sizeof(p->dir)-1);
3692 p->dir[NAM$C_MAXRSS] = '\0';
3695 /* most likely spot (ARCHLIB) put first in the list */
3698 if ((tounixpath_utf8(ARCHLIB_EXP, unixdir, NULL)) != NULL) {
3699 p = (pPLOC) PerlMem_malloc(sizeof(PLOC));
3700 if (p == NULL) _ckvmssts_noperl(SS$_INSFMEM);
3701 p->next = head_PLOC;
3703 strncpy(p->dir,unixdir,sizeof(p->dir)-1);
3704 p->dir[NAM$C_MAXRSS] = '\0';
3707 PerlMem_free(unixdir);
3711 Perl_cando_by_name_int
3712 (pTHX_ I32 bit, bool effective, const char *fname, int opts);
3713 #if !defined(PERL_IMPLICIT_CONTEXT)
3714 #define cando_by_name_int Perl_cando_by_name_int
3716 #define cando_by_name_int(a,b,c,d) Perl_cando_by_name_int(aTHX_ a,b,c,d)
3722 static int vmspipe_file_status = 0;
3723 static char vmspipe_file[NAM$C_MAXRSS+1];
3725 /* already found? Check and use ... need read+execute permission */
3727 if (vmspipe_file_status == 1) {
3728 if (cando_by_name_int(S_IRUSR, 0, vmspipe_file, PERL_RMSEXPAND_M_VMS_IN)
3729 && cando_by_name_int
3730 (S_IXUSR, 0, vmspipe_file, PERL_RMSEXPAND_M_VMS_IN)) {
3731 return vmspipe_file;
3733 vmspipe_file_status = 0;
3736 /* scan through stored @INC, $^X */
3738 if (vmspipe_file_status == 0) {
3739 char file[NAM$C_MAXRSS+1];
3740 pPLOC p = head_PLOC;
3745 strcpy(file, p->dir);
3746 dirlen = strlen(file);
3747 strncat(file, "vmspipe.com",NAM$C_MAXRSS - dirlen);
3748 file[NAM$C_MAXRSS] = '\0';
3751 exp_res = int_rmsexpand_tovms(file, vmspipe_file, 0);
3752 if (!exp_res) continue;
3754 if (cando_by_name_int
3755 (S_IRUSR, 0, vmspipe_file, PERL_RMSEXPAND_M_VMS_IN)
3756 && cando_by_name_int
3757 (S_IXUSR, 0, vmspipe_file, PERL_RMSEXPAND_M_VMS_IN)) {
3758 vmspipe_file_status = 1;
3759 return vmspipe_file;
3762 vmspipe_file_status = -1; /* failed, use tempfiles */
3769 vmspipe_tempfile(pTHX)
3771 char file[NAM$C_MAXRSS+1];
3773 static int index = 0;
3777 /* create a tempfile */
3779 /* we can't go from W, shr=get to R, shr=get without
3780 an intermediate vulnerable state, so don't bother trying...
3782 and lib$spawn doesn't shr=put, so have to close the write
3784 So... match up the creation date/time and the FID to
3785 make sure we're dealing with the same file
3790 if (!decc_filename_unix_only) {
3791 sprintf(file,"sys$scratch:perlpipe_%08.8x_%d.com",mypid,index);
3792 fp = fopen(file,"w");
3794 sprintf(file,"sys$login:perlpipe_%08.8x_%d.com",mypid,index);
3795 fp = fopen(file,"w");
3797 sprintf(file,"sys$disk:[]perlpipe_%08.8x_%d.com",mypid,index);
3798 fp = fopen(file,"w");
3803 sprintf(file,"/tmp/perlpipe_%08.8x_%d.com",mypid,index);
3804 fp = fopen(file,"w");
3806 sprintf(file,"/sys$login/perlpipe_%08.8x_%d.com",mypid,index);
3807 fp = fopen(file,"w");
3809 sprintf(file,"./perlpipe_%08.8x_%d.com",mypid,index);
3810 fp = fopen(file,"w");
3814 if (!fp) return 0; /* we're hosed */
3816 fprintf(fp,"$! 'f$verify(0)'\n");
3817 fprintf(fp,"$! --- protect against nonstandard definitions ---\n");
3818 fprintf(fp,"$ perl_cfile = f$environment(\"procedure\")\n");
3819 fprintf(fp,"$ perl_define = \"define/nolog\"\n");
3820 fprintf(fp,"$ perl_on = \"set noon\"\n");
3821 fprintf(fp,"$ perl_exit = \"exit\"\n");
3822 fprintf(fp,"$ perl_del = \"delete\"\n");
3823 fprintf(fp,"$ pif = \"if\"\n");
3824 fprintf(fp,"$! --- define i/o redirection (sys$output set by lib$spawn)\n");
3825 fprintf(fp,"$ pif perl_popen_in .nes. \"\" then perl_define/user/name_attributes=confine sys$input 'perl_popen_in'\n");
3826 fprintf(fp,"$ pif perl_popen_err .nes. \"\" then perl_define/user/name_attributes=confine sys$error 'perl_popen_err'\n");
3827 fprintf(fp,"$ pif perl_popen_out .nes. \"\" then perl_define sys$output 'perl_popen_out'\n");
3828 fprintf(fp,"$! --- build command line to get max possible length\n");
3829 fprintf(fp,"$c=perl_popen_cmd0\n");
3830 fprintf(fp,"$c=c+perl_popen_cmd1\n");
3831 fprintf(fp,"$c=c+perl_popen_cmd2\n");
3832 fprintf(fp,"$x=perl_popen_cmd3\n");
3833 fprintf(fp,"$c=c+x\n");
3834 fprintf(fp,"$ perl_on\n");
3835 fprintf(fp,"$ 'c'\n");
3836 fprintf(fp,"$ perl_status = $STATUS\n");
3837 fprintf(fp,"$ perl_del 'perl_cfile'\n");
3838 fprintf(fp,"$ perl_exit 'perl_status'\n");
3841 fgetname(fp, file, 1);
3842 fstat(fileno(fp), &s0.crtl_stat);
3845 if (decc_filename_unix_only)
3846 int_tounixspec(file, file, NULL);
3847 fp = fopen(file,"r","shr=get");
3849 fstat(fileno(fp), &s1.crtl_stat);
3851 cmp_result = VMS_INO_T_COMPARE(s0.crtl_stat.st_ino, s1.crtl_stat.st_ino);
3852 if ((cmp_result != 0) && (s0.st_ctime != s1.st_ctime)) {
3861 static int vms_is_syscommand_xterm(void)
3863 const static struct dsc$descriptor_s syscommand_dsc =
3864 { 11, DSC$K_DTYPE_T, DSC$K_CLASS_S, "SYS$COMMAND" };
3866 const static struct dsc$descriptor_s decwdisplay_dsc =
3867 { 12, DSC$K_DTYPE_T, DSC$K_CLASS_S, "DECW$DISPLAY" };
3869 struct item_list_3 items[2];
3870 unsigned short dvi_iosb[4];
3871 unsigned long devchar;
3872 unsigned long devclass;
3875 /* Very simple check to guess if sys$command is a decterm? */
3876 /* First see if the DECW$DISPLAY: device exists */
3878 items[0].code = DVI$_DEVCHAR;
3879 items[0].bufadr = &devchar;
3880 items[0].retadr = NULL;
3884 status = sys$getdviw
3885 (NO_EFN, 0, &decwdisplay_dsc, items, dvi_iosb, NULL, NULL, NULL);
3887 if ($VMS_STATUS_SUCCESS(status)) {
3888 status = dvi_iosb[0];
3891 if (!$VMS_STATUS_SUCCESS(status)) {
3892 SETERRNO(EVMSERR, status);
3896 /* If it does, then for now assume that we are on a workstation */
3897 /* Now verify that SYS$COMMAND is a terminal */
3898 /* for creating the debugger DECTerm */
3901 items[0].code = DVI$_DEVCLASS;
3902 items[0].bufadr = &devclass;
3903 items[0].retadr = NULL;
3907 status = sys$getdviw
3908 (NO_EFN, 0, &syscommand_dsc, items, dvi_iosb, NULL, NULL, NULL);
3910 if ($VMS_STATUS_SUCCESS(status)) {
3911 status = dvi_iosb[0];
3914 if (!$VMS_STATUS_SUCCESS(status)) {
3915 SETERRNO(EVMSERR, status);
3919 if (devclass == DC$_TERM) {
3926 /* If we are on a DECTerm, we can pretend to fork xterms when requested */
3927 static PerlIO * create_forked_xterm(pTHX_ const char *cmd, const char *mode)
3932 char device_name[65];
3933 unsigned short device_name_len;
3934 struct dsc$descriptor_s customization_dsc;
3935 struct dsc$descriptor_s device_name_dsc;
3937 char customization[200];
3941 unsigned short p_chan;
3943 unsigned short iosb[4];
3944 const char * cust_str =
3945 "DECW$TERMINAL.iconName:\tPerl Dbg\nDECW$TERMINAL.title:\t%40s\n";
3946 struct dsc$descriptor_s d_mbx1 = {sizeof mbx1, DSC$K_DTYPE_T,
3947 DSC$K_CLASS_S, mbx1};
3949 /* LIB$FIND_IMAGE_SIGNAL needs a handler */
3950 /*---------------------------------------*/
3951 VAXC$ESTABLISH((__vms_handler)lib$sig_to_ret);
3954 /* Make sure that this is from the Perl debugger */
3955 ret_char = strstr(cmd," xterm ");
3956 if (ret_char == NULL)
3958 cptr = ret_char + 7;
3959 ret_char = strstr(cmd,"tty");
3960 if (ret_char == NULL)
3962 ret_char = strstr(cmd,"sleep");
3963 if (ret_char == NULL)
3966 if (decw_term_port == 0) {
3967 $DESCRIPTOR(filename1_dsc, "DECW$TERMINALSHR12");
3968 $DESCRIPTOR(filename2_dsc, "DECW$TERMINALSHR");
3969 $DESCRIPTOR(decw_term_port_dsc, "DECW$TERM_PORT");
3971 status = lib$find_image_symbol
3973 &decw_term_port_dsc,
3974 (void *)&decw_term_port,
3978 /* Try again with the other image name */
3979 if (!$VMS_STATUS_SUCCESS(status)) {
3981 status = lib$find_image_symbol
3983 &decw_term_port_dsc,
3984 (void *)&decw_term_port,
3993 /* No decw$term_port, give it up */
3994 if (!$VMS_STATUS_SUCCESS(status))
3997 /* Are we on a workstation? */
3998 /* to do: capture the rows / columns and pass their properties */
3999 ret_stat = vms_is_syscommand_xterm();
4003 /* Make the title: */
4004 ret_char = strstr(cptr,"-title");
4005 if (ret_char != NULL) {
4006 while ((*cptr != 0) && (*cptr != '\"')) {
4012 while ((*cptr != 0) && (*cptr != '\"')) {
4025 strcpy(title,"Perl Debug DECTerm");
4027 sprintf(customization, cust_str, title);
4029 customization_dsc.dsc$a_pointer = customization;
4030 customization_dsc.dsc$w_length = strlen(customization);
4031 customization_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
4032 customization_dsc.dsc$b_class = DSC$K_CLASS_S;
4034 device_name_dsc.dsc$a_pointer = device_name;
4035 device_name_dsc.dsc$w_length = sizeof device_name -1;
4036 device_name_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
4037 device_name_dsc.dsc$b_class = DSC$K_CLASS_S;
4039 device_name_len = 0;
4041 /* Try to create the window */
4042 status = (*decw_term_port)
4051 if (!$VMS_STATUS_SUCCESS(status)) {
4052 SETERRNO(EVMSERR, status);
4056 device_name[device_name_len] = '\0';
4058 /* Need to set this up to look like a pipe for cleanup */
4060 status = lib$get_vm(&n, &info);
4061 if (!$VMS_STATUS_SUCCESS(status)) {
4062 SETERRNO(ENOMEM, status);
4068 info->completion = 0;
4069 info->closing = FALSE;
4076 info->in_done = TRUE;
4077 info->out_done = TRUE;
4078 info->err_done = TRUE;
4080 /* Assign a channel on this so that it will persist, and not login */
4081 /* We stash this channel in the info structure for reference. */
4082 /* The created xterm self destructs when the last channel is removed */
4083 /* and it appears that perl5db.pl (perl debugger) does this routinely */
4084 /* So leave this assigned. */
4085 device_name_dsc.dsc$w_length = device_name_len;
4086 status = sys$assign(&device_name_dsc,&info->xchan,0,0);
4087 if (!$VMS_STATUS_SUCCESS(status)) {
4088 SETERRNO(EVMSERR, status);
4091 info->xchan_valid = 1;
4093 /* Now create a mailbox to be read by the application */
4095 create_mbx(&p_chan, &d_mbx1);
4097 /* write the name of the created terminal to the mailbox */
4098 status = sys$qiow(NO_EFN, p_chan, IO$_WRITEVBLK|IO$M_NOW,
4099 iosb, NULL, NULL, device_name, device_name_len, 0, 0, 0, 0);
4101 if (!$VMS_STATUS_SUCCESS(status)) {
4102 SETERRNO(EVMSERR, status);
4106 info->fp = PerlIO_open(mbx1, mode);
4108 /* Done with this channel */
4111 /* If any errors, then clean up */
4114 _ckvmssts_noperl(lib$free_vm(&n, &info));
4122 static I32 my_pclose_pinfo(pTHX_ pInfo info);
4125 safe_popen(pTHX_ const char *cmd, const char *in_mode, int *psts)
4127 static int handler_set_up = FALSE;
4129 unsigned long int sts, flags = CLI$M_NOWAIT;
4130 /* The use of a GLOBAL table (as was done previously) rendered
4131 * Perl's qx() or `` unusable from a C<$ SET SYMBOL/SCOPE=NOGLOBAL> DCL
4132 * environment. Hence we've switched to LOCAL symbol table.
4134 unsigned int table = LIB$K_CLI_LOCAL_SYM;
4136 char *p, mode[10], symbol[MAX_DCL_SYMBOL+1], *vmspipe;
4137 char *in, *out, *err, mbx[512];
4139 char tfilebuf[NAM$C_MAXRSS+1];
4141 char cmd_sym_name[20];
4142 struct dsc$descriptor_s d_symbol= {0, DSC$K_DTYPE_T,
4143 DSC$K_CLASS_S, symbol};
4144 struct dsc$descriptor_s vmspipedsc = {0, DSC$K_DTYPE_T,
4146 struct dsc$descriptor_s d_sym_cmd = {0, DSC$K_DTYPE_T,
4147 DSC$K_CLASS_S, cmd_sym_name};
4148 struct dsc$descriptor_s *vmscmd;
4149 $DESCRIPTOR(d_sym_in ,"PERL_POPEN_IN");
4150 $DESCRIPTOR(d_sym_out,"PERL_POPEN_OUT");
4151 $DESCRIPTOR(d_sym_err,"PERL_POPEN_ERR");
4153 /* Check here for Xterm create request. This means looking for
4154 * "3>&1 xterm\b" and "\btty 1>&3\b$" in the command, and that it
4155 * is possible to create an xterm.
4157 if (*in_mode == 'r') {
4160 #if defined(PERL_IMPLICIT_CONTEXT)
4161 /* Can not fork an xterm with a NULL context */
4162 /* This probably could never happen */
4166 xterm_fd = create_forked_xterm(aTHX_ cmd, in_mode);
4167 if (xterm_fd != NULL)
4171 if (!head_PLOC) store_pipelocs(aTHX); /* at least TRY to use a static vmspipe file */
4173 /* once-per-program initialization...
4174 note that the SETAST calls and the dual test of pipe_ef
4175 makes sure that only the FIRST thread through here does
4176 the initialization...all other threads wait until it's
4179 Yeah, uglier than a pthread call, it's got all the stuff inline
4180 rather than in a separate routine.
4184 _ckvmssts_noperl(sys$setast(0));
4186 unsigned long int pidcode = JPI$_PID;
4187 $DESCRIPTOR(d_delay, RETRY_DELAY);
4188 _ckvmssts_noperl(lib$get_ef(&pipe_ef));
4189 _ckvmssts_noperl(lib$getjpi(&pidcode,0,0,&mypid,0,0));
4190 _ckvmssts_noperl(sys$bintim(&d_delay, delaytime));
4192 if (!handler_set_up) {
4193 _ckvmssts_noperl(sys$dclexh(&pipe_exitblock));
4194 handler_set_up = TRUE;
4196 _ckvmssts_noperl(sys$setast(1));
4199 /* see if we can find a VMSPIPE.COM */
4202 vmspipe = find_vmspipe(aTHX);
4204 strcpy(tfilebuf+1,vmspipe);
4205 } else { /* uh, oh...we're in tempfile hell */
4206 tpipe = vmspipe_tempfile(aTHX);
4207 if (!tpipe) { /* a fish popular in Boston */
4208 if (ckWARN(WARN_PIPE)) {
4209 Perl_warner(aTHX_ packWARN(WARN_PIPE),"unable to find VMSPIPE.COM for i/o piping");
4213 fgetname(tpipe,tfilebuf+1,1);
4215 vmspipedsc.dsc$a_pointer = tfilebuf;
4216 vmspipedsc.dsc$w_length = strlen(tfilebuf);
4218 sts = setup_cmddsc(aTHX_ cmd,0,0,&vmscmd);
4221 case RMS$_FNF: case RMS$_DNF:
4222 set_errno(ENOENT); break;
4224 set_errno(ENOTDIR); break;
4226 set_errno(ENODEV); break;
4228 set_errno(EACCES); break;
4230 set_errno(EINVAL); break;
4231 case CLI$_BUFOVF: case RMS$_RTB: case CLI$_TKNOVF: case CLI$_RSLOVF:
4232 set_errno(E2BIG); break;
4233 case LIB$_INVARG: case LIB$_INVSTRDES: case SS$_ACCVIO: /* shouldn't happen */
4234 _ckvmssts_noperl(sts); /* fall through */
4235 default: /* SS$_DUPLNAM, SS$_CLI, resource exhaustion, etc. */
4238 set_vaxc_errno(sts);
4239 if (*in_mode != 'n' && ckWARN(WARN_PIPE)) {
4240 Perl_warner(aTHX_ packWARN(WARN_PIPE),"Can't pipe \"%*s\": %s", strlen(cmd), cmd, Strerror(errno));
4246 _ckvmssts_noperl(lib$get_vm(&n, &info));
4248 strcpy(mode,in_mode);
4251 info->completion = 0;
4252 info->closing = FALSE;
4259 info->in_done = TRUE;
4260 info->out_done = TRUE;
4261 info->err_done = TRUE;
4263 info->xchan_valid = 0;
4265 in = PerlMem_malloc(VMS_MAXRSS);
4266 if (in == NULL) _ckvmssts_noperl(SS$_INSFMEM);
4267 out = PerlMem_malloc(VMS_MAXRSS);
4268 if (out == NULL) _ckvmssts_noperl(SS$_INSFMEM);
4269 err = PerlMem_malloc(VMS_MAXRSS);
4270 if (err == NULL) _ckvmssts_noperl(SS$_INSFMEM);
4272 in[0] = out[0] = err[0] = '\0';
4274 if ((p = strchr(mode,'F')) != NULL) { /* F -> use FILE* */
4278 if ((p = strchr(mode,'W')) != NULL) { /* W -> wait for completion */
4283 if (*mode == 'r') { /* piping from subroutine */
4285 info->out = pipe_infromchild_setup(aTHX_ mbx,out);
4287 info->out->pipe_done = &info->out_done;
4288 info->out_done = FALSE;
4289 info->out->info = info;
4291 if (!info->useFILE) {
4292 info->fp = PerlIO_open(mbx, mode);
4294 info->fp = (PerlIO *) freopen(mbx, mode, stdin);
4295 Perl_vmssetuserlnm(aTHX_ "SYS$INPUT",mbx);
4298 if (!info->fp && info->out) {
4299 sys$cancel(info->out->chan_out);
4301 while (!info->out_done) {
4303 _ckvmssts_noperl(sys$setast(0));
4304 done = info->out_done;
4305 if (!done) _ckvmssts_noperl(sys$clref(pipe_ef));
4306 _ckvmssts_noperl(sys$setast(1));
4307 if (!done) _ckvmssts_noperl(sys$waitfr(pipe_ef));
4310 if (info->out->buf) {
4311 n = info->out->bufsize * sizeof(char);
4312 _ckvmssts_noperl(lib$free_vm(&n, &info->out->buf));
4315 _ckvmssts_noperl(lib$free_vm(&n, &info->out));
4317 _ckvmssts_noperl(lib$free_vm(&n, &info));
4322 info->err = pipe_mbxtofd_setup(aTHX_ fileno(stderr), err);
4324 info->err->pipe_done = &info->err_done;
4325 info->err_done = FALSE;
4326 info->err->info = info;
4329 } else if (*mode == 'w') { /* piping to subroutine */
4331 info->out = pipe_mbxtofd_setup(aTHX_ fileno(stdout), out);
4333 info->out->pipe_done = &info->out_done;
4334 info->out_done = FALSE;
4335 info->out->info = info;
4338 info->err = pipe_mbxtofd_setup(aTHX_ fileno(stderr), err);
4340 info->err->pipe_done = &info->err_done;
4341 info->err_done = FALSE;
4342 info->err->info = info;
4345 info->in = pipe_tochild_setup(aTHX_ in,mbx);
4346 if (!info->useFILE) {
4347 info->fp = PerlIO_open(mbx, mode);
4349 info->fp = (PerlIO *) freopen(mbx, mode, stdout);
4350 Perl_vmssetuserlnm(aTHX_ "SYS$OUTPUT",mbx);
4354 info->in->pipe_done = &info->in_done;
4355 info->in_done = FALSE;
4356 info->in->info = info;
4360 if (!info->fp && info->in) {
4362 _ckvmssts_noperl(sys$qiow(0,info->in->chan_in, IO$_WRITEOF, 0,
4363 0, 0, 0, 0, 0, 0, 0, 0));
4365 while (!info->in_done) {
4367 _ckvmssts_noperl(sys$setast(0));
4368 done = info->in_done;
4369 if (!done) _ckvmssts_noperl(sys$clref(pipe_ef));
4370 _ckvmssts_noperl(sys$setast(1));
4371 if (!done) _ckvmssts_noperl(sys$waitfr(pipe_ef));
4374 if (info->in->buf) {
4375 n = info->in->bufsize * sizeof(char);
4376 _ckvmssts_noperl(lib$free_vm(&n, &info->in->buf));
4379 _ckvmssts_noperl(lib$free_vm(&n, &info->in));
4381 _ckvmssts_noperl(lib$free_vm(&n, &info));
4387 } else if (*mode == 'n') { /* separate subprocess, no Perl i/o */
4388 info->out = pipe_mbxtofd_setup(aTHX_ fileno(stdout), out);
4390 info->out->pipe_done = &info->out_done;
4391 info->out_done = FALSE;
4392 info->out->info = info;
4395 info->err = pipe_mbxtofd_setup(aTHX_ fileno(stderr), err);
4397 info->err->pipe_done = &info->err_done;
4398 info->err_done = FALSE;
4399 info->err->info = info;
4403 symbol[MAX_DCL_SYMBOL] = '\0';
4405 strncpy(symbol, in, MAX_DCL_SYMBOL);
4406 d_symbol.dsc$w_length = strlen(symbol);
4407 _ckvmssts_noperl(lib$set_symbol(&d_sym_in, &d_symbol, &table));
4409 strncpy(symbol, err, MAX_DCL_SYMBOL);
4410 d_symbol.dsc$w_length = strlen(symbol);
4411 _ckvmssts_noperl(lib$set_symbol(&d_sym_err, &d_symbol, &table));
4413 strncpy(symbol, out, MAX_DCL_SYMBOL);
4414 d_symbol.dsc$w_length = strlen(symbol);
4415 _ckvmssts_noperl(lib$set_symbol(&d_sym_out, &d_symbol, &table));
4417 /* Done with the names for the pipes */
4422 p = vmscmd->dsc$a_pointer;
4423 while (*p == ' ' || *p == '\t') p++; /* remove leading whitespace */
4424 if (*p == '$') p++; /* remove leading $ */
4425 while (*p == ' ' || *p == '\t') p++;
4427 for (j = 0; j < 4; j++) {
4428 sprintf(cmd_sym_name,"PERL_POPEN_CMD%d",j);
4429 d_sym_cmd.dsc$w_length = strlen(cmd_sym_name);
4431 strncpy(symbol, p, MAX_DCL_SYMBOL);
4432 d_symbol.dsc$w_length = strlen(symbol);
4433 _ckvmssts_noperl(lib$set_symbol(&d_sym_cmd, &d_symbol, &table));
4435 if (strlen(p) > MAX_DCL_SYMBOL) {
4436 p += MAX_DCL_SYMBOL;
4441 _ckvmssts_noperl(sys$setast(0));
4442 info->next=open_pipes; /* prepend to list */
4444 _ckvmssts_noperl(sys$setast(1));
4445 /* Omit arg 2 (input file) so the child will get the parent's SYS$INPUT
4446 * and SYS$COMMAND. vmspipe.com will redefine SYS$INPUT, but we'll still
4447 * have SYS$COMMAND if we need it.
4449 _ckvmssts_noperl(lib$spawn(&vmspipedsc, 0, &nl_desc, &flags,
4450 0, &info->pid, &info->completion,
4451 0, popen_completion_ast,info,0,0,0));
4453 /* if we were using a tempfile, close it now */
4455 if (tpipe) fclose(tpipe);
4457 /* once the subprocess is spawned, it has copied the symbols and
4458 we can get rid of ours */
4460 for (j = 0; j < 4; j++) {
4461 sprintf(cmd_sym_name,"PERL_POPEN_CMD%d",j);
4462 d_sym_cmd.dsc$w_length = strlen(cmd_sym_name);
4463 _ckvmssts_noperl(lib$delete_symbol(&d_sym_cmd, &table));
4465 _ckvmssts_noperl(lib$delete_symbol(&d_sym_in, &table));
4466 _ckvmssts_noperl(lib$delete_symbol(&d_sym_err, &table));
4467 _ckvmssts_noperl(lib$delete_symbol(&d_sym_out, &table));
4468 vms_execfree(vmscmd);
4470 #ifdef PERL_IMPLICIT_CONTEXT
4473 PL_forkprocess = info->pid;
4480 _ckvmssts_noperl(sys$setast(0));
4482 if (!done) _ckvmssts_noperl(sys$clref(pipe_ef));
4483 _ckvmssts_noperl(sys$setast(1));
4484 if (!done) _ckvmssts_noperl(sys$waitfr(pipe_ef));
4486 *psts = info->completion;
4487 /* Caller thinks it is open and tries to close it. */
4488 /* This causes some problems, as it changes the error status */
4489 /* my_pclose(info->fp); */
4491 /* If we did not have a file pointer open, then we have to */
4492 /* clean up here or eventually we will run out of something */
4494 if (info->fp == NULL) {
4495 my_pclose_pinfo(aTHX_ info);
4503 } /* end of safe_popen */
4506 /*{{{ PerlIO *my_popen(char *cmd, char *mode)*/
4508 Perl_my_popen(pTHX_ const char *cmd, const char *mode)
4512 TAINT_PROPER("popen");
4513 PERL_FLUSHALL_FOR_CHILD;
4514 return safe_popen(aTHX_ cmd,mode,&sts);
4520 /* Routine to close and cleanup a pipe info structure */
4522 static I32 my_pclose_pinfo(pTHX_ pInfo info) {
4524 unsigned long int retsts;
4528 /* If we were writing to a subprocess, insure that someone reading from
4529 * the mailbox gets an EOF. It looks like a simple fclose() doesn't
4530 * produce an EOF record in the mailbox.
4532 * well, at least sometimes it *does*, so we have to watch out for
4533 * the first EOF closing the pipe (and DASSGN'ing the channel)...
4537 #if defined(USE_ITHREADS)
4541 && PL_perlio_fd_refcnt
4544 PerlIO_flush(info->fp);
4546 fflush((FILE *)info->fp);
4549 _ckvmssts(sys$setast(0));
4550 info->closing = TRUE;
4551 done = info->done && info->in_done && info->out_done && info->err_done;
4552 /* hanging on write to Perl's input? cancel it */
4553 if (info->mode == 'r' && info->out && !info->out_done) {
4554 if (info->out->chan_out) {
4555 _ckvmssts(sys$cancel(info->out->chan_out));
4556 if (!info->out->chan_in) { /* EOF generation, need AST */
4557 _ckvmssts(sys$dclast(pipe_infromchild_ast,info->out,0));
4561 if (info->in && !info->in_done && !info->in->shut_on_empty) /* EOF if hasn't had one yet */
4562 _ckvmssts(sys$qio(0,info->in->chan_in,IO$_WRITEOF,0,0,0,
4564 _ckvmssts(sys$setast(1));
4567 #if defined(USE_ITHREADS)
4571 && PL_perlio_fd_refcnt
4574 PerlIO_close(info->fp);
4576 fclose((FILE *)info->fp);
4579 we have to wait until subprocess completes, but ALSO wait until all
4580 the i/o completes...otherwise we'll be freeing the "info" structure
4581 that the i/o ASTs could still be using...
4585 _ckvmssts(sys$setast(0));
4586 done = info->done && info->in_done && info->out_done && info->err_done;
4587 if (!done) _ckvmssts(sys$clref(pipe_ef));
4588 _ckvmssts(sys$setast(1));
4589 if (!done) _ckvmssts(sys$waitfr(pipe_ef));
4591 retsts = info->completion;
4593 /* remove from list of open pipes */
4594 _ckvmssts(sys$setast(0));
4596 for (next = open_pipes; next != NULL; last = next, next = next->next) {
4602 last->next = info->next;
4604 open_pipes = info->next;
4605 _ckvmssts(sys$setast(1));
4607 /* free buffers and structures */
4610 if (info->in->buf) {
4611 n = info->in->bufsize * sizeof(char);
4612 _ckvmssts(lib$free_vm(&n, &info->in->buf));
4615 _ckvmssts(lib$free_vm(&n, &info->in));
4618 if (info->out->buf) {
4619 n = info->out->bufsize * sizeof(char);
4620 _ckvmssts(lib$free_vm(&n, &info->out->buf));
4623 _ckvmssts(lib$free_vm(&n, &info->out));
4626 if (info->err->buf) {
4627 n = info->err->bufsize * sizeof(char);
4628 _ckvmssts(lib$free_vm(&n, &info->err->buf));
4631 _ckvmssts(lib$free_vm(&n, &info->err));
4634 _ckvmssts(lib$free_vm(&n, &info));
4640 /*{{{ I32 my_pclose(PerlIO *fp)*/
4641 I32 Perl_my_pclose(pTHX_ PerlIO *fp)
4643 pInfo info, last = NULL;
4646 /* Fixme - need ast and mutex protection here */
4647 for (info = open_pipes; info != NULL; last = info, info = info->next)
4648 if (info->fp == fp) break;
4650 if (info == NULL) { /* no such pipe open */
4651 set_errno(ECHILD); /* quoth POSIX */
4652 set_vaxc_errno(SS$_NONEXPR);
4656 ret_status = my_pclose_pinfo(aTHX_ info);
4660 } /* end of my_pclose() */
4662 #if defined(__CRTL_VER) && __CRTL_VER >= 70200000
4663 /* Roll our own prototype because we want this regardless of whether
4664 * _VMS_WAIT is defined.
4666 __pid_t __vms_waitpid( __pid_t __pid, int *__stat_loc, int __options );
4668 /* sort-of waitpid; special handling of pipe clean-up for subprocesses
4669 created with popen(); otherwise partially emulate waitpid() unless
4670 we have a suitable one from the CRTL that came with VMS 7.2 and later.
4671 Also check processes not considered by the CRTL waitpid().
4673 /*{{{Pid_t my_waitpid(Pid_t pid, int *statusp, int flags)*/
4675 Perl_my_waitpid(pTHX_ Pid_t pid, int *statusp, int flags)
4682 if (statusp) *statusp = 0;
4684 for (info = open_pipes; info != NULL; info = info->next)
4685 if (info->pid == pid) break;
4687 if (info != NULL) { /* we know about this child */
4688 while (!info->done) {
4689 _ckvmssts(sys$setast(0));
4691 if (!done) _ckvmssts(sys$clref(pipe_ef));
4692 _ckvmssts(sys$setast(1));
4693 if (!done) _ckvmssts(sys$waitfr(pipe_ef));
4696 if (statusp) *statusp = info->completion;
4700 /* child that already terminated? */
4702 for (j = 0; j < NKEEPCLOSED && j < closed_num; j++) {
4703 if (closed_list[j].pid == pid) {
4704 if (statusp) *statusp = closed_list[j].completion;
4709 /* fall through if this child is not one of our own pipe children */
4711 #if defined(__CRTL_VER) && __CRTL_VER >= 70200000
4713 /* waitpid() became available in the CRTL as of VMS 7.0, but only
4714 * in 7.2 did we get a version that fills in the VMS completion
4715 * status as Perl has always tried to do.
4718 sts = __vms_waitpid( pid, statusp, flags );
4720 if ( sts == 0 || !(sts == -1 && errno == ECHILD) )
4723 /* If the real waitpid tells us the child does not exist, we
4724 * fall through here to implement waiting for a child that
4725 * was created by some means other than exec() (say, spawned
4726 * from DCL) or to wait for a process that is not a subprocess
4727 * of the current process.
4730 #endif /* defined(__CRTL_VER) && __CRTL_VER >= 70200000 */
4733 $DESCRIPTOR(intdsc,"0 00:00:01");
4734 unsigned long int ownercode = JPI$_OWNER, ownerpid;
4735 unsigned long int pidcode = JPI$_PID, mypid;
4736 unsigned long int interval[2];
4737 unsigned int jpi_iosb[2];
4738 struct itmlst_3 jpilist[2] = {
4739 {sizeof(ownerpid), JPI$_OWNER, &ownerpid, 0},
4744 /* Sorry folks, we don't presently implement rooting around for
4745 the first child we can find, and we definitely don't want to
4746 pass a pid of -1 to $getjpi, where it is a wildcard operation.
4752 /* Get the owner of the child so I can warn if it's not mine. If the
4753 * process doesn't exist or I don't have the privs to look at it,
4754 * I can go home early.
4756 sts = sys$getjpiw(0,&pid,NULL,&jpilist,&jpi_iosb,NULL,NULL);
4757 if (sts & 1) sts = jpi_iosb[0];
4769 set_vaxc_errno(sts);
4773 if (ckWARN(WARN_EXEC)) {
4774 /* remind folks they are asking for non-standard waitpid behavior */
4775 _ckvmssts(lib$getjpi(&pidcode,0,0,&mypid,0,0));
4776 if (ownerpid != mypid)
4777 Perl_warner(aTHX_ packWARN(WARN_EXEC),
4778 "waitpid: process %x is not a child of process %x",
4782 /* simply check on it once a second until it's not there anymore. */
4784 _ckvmssts(sys$bintim(&intdsc,interval));
4785 while ((sts=lib$getjpi(&ownercode,&pid,0,&ownerpid,0,0)) & 1) {
4786 _ckvmssts(sys$schdwk(0,0,interval,0));
4787 _ckvmssts(sys$hiber());
4789 if (sts == SS$_NONEXPR) sts = SS$_NORMAL;
4794 } /* end of waitpid() */
4799 /*{{{ char *my_gconvert(double val, int ndig, int trail, char *buf) */
4801 my_gconvert(double val, int ndig, int trail, char *buf)
4803 static char __gcvtbuf[DBL_DIG+1];
4806 loc = buf ? buf : __gcvtbuf;
4808 #ifndef __DECC /* VAXCRTL gcvt uses E format for numbers < 1 */
4810 sprintf(loc,"%.*g",ndig,val);
4816 if (!buf && ndig > DBL_DIG) ndig = DBL_DIG;
4817 return gcvt(val,ndig,loc);
4820 loc[0] = '0'; loc[1] = '\0';
4827 #if defined(__VAX) || !defined(NAML$C_MAXRSS)
4828 static int rms_free_search_context(struct FAB * fab)
4832 nam = fab->fab$l_nam;
4833 nam->nam$b_nop |= NAM$M_SYNCHK;
4834 nam->nam$l_rlf = NULL;
4836 return sys$parse(fab, NULL, NULL);
4839 #define rms_setup_nam(nam) struct NAM nam = cc$rms_nam
4840 #define rms_clear_nam_nop(nam) nam.nam$b_nop = 0;
4841 #define rms_set_nam_nop(nam, opt) nam.nam$b_nop |= (opt)
4842 #define rms_set_nam_fnb(nam, opt) nam.nam$l_fnb |= (opt)
4843 #define rms_is_nam_fnb(nam, opt) (nam.nam$l_fnb & (opt))
4844 #define rms_nam_esll(nam) nam.nam$b_esl
4845 #define rms_nam_esl(nam) nam.nam$b_esl
4846 #define rms_nam_name(nam) nam.nam$l_name
4847 #define rms_nam_namel(nam) nam.nam$l_name
4848 #define rms_nam_type(nam) nam.nam$l_type
4849 #define rms_nam_typel(nam) nam.nam$l_type
4850 #define rms_nam_ver(nam) nam.nam$l_ver