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_]
32 #include <climsgdef.h>
43 #include <libclidef.h>
45 #include <lib$routines.h>
49 #if __CRTL_VER >= 70301000 && !defined(__VAX)
59 #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 /* More specific prototype than in starlet_c.h makes programming errors
100 const struct dsc$descriptor_s * devnam,
101 const struct item_list_3 * itmlst,
103 void * (astadr)(unsigned long),
108 #ifdef sys$get_security
109 #undef sys$get_security
111 (const struct dsc$descriptor_s * clsnam,
112 const struct dsc$descriptor_s * objnam,
113 const unsigned int *objhan,
115 const struct item_list_3 * itmlst,
116 unsigned int * contxt,
117 const unsigned int * acmode);
120 #ifdef sys$set_security
121 #undef sys$set_security
123 (const struct dsc$descriptor_s * clsnam,
124 const struct dsc$descriptor_s * objnam,
125 const unsigned int *objhan,
127 const struct item_list_3 * itmlst,
128 unsigned int * contxt,
129 const unsigned int * acmode);
132 #ifdef lib$find_image_symbol
133 #undef lib$find_image_symbol
134 int lib$find_image_symbol
135 (const struct dsc$descriptor_s * imgname,
136 const struct dsc$descriptor_s * symname,
138 const struct dsc$descriptor_s * defspec,
142 #ifdef lib$rename_file
143 #undef lib$rename_file
145 (const struct dsc$descriptor_s * old_file_dsc,
146 const struct dsc$descriptor_s * new_file_dsc,
147 const struct dsc$descriptor_s * default_file_dsc,
148 const struct dsc$descriptor_s * related_file_dsc,
149 const unsigned long * flags,
150 void * (success)(const struct dsc$descriptor_s * old_dsc,
151 const struct dsc$descriptor_s * new_dsc,
153 void * (error)(const struct dsc$descriptor_s * old_dsc,
154 const struct dsc$descriptor_s * new_dsc,
157 const int * error_src,
158 const void * usr_arg),
159 int (confirm)(const struct dsc$descriptor_s * old_dsc,
160 const struct dsc$descriptor_s * new_dsc,
161 const void * old_fab,
162 const void * usr_arg),
164 struct dsc$descriptor_s * old_result_name_dsc,
165 struct dsc$descriptor_s * new_result_name_dsc,
166 unsigned long * file_scan_context);
169 #if __CRTL_VER >= 70300000 && !defined(__VAX)
171 static int set_feature_default(const char *name, int value)
176 index = decc$feature_get_index(name);
178 status = decc$feature_set_value(index, 1, value);
179 if (index == -1 || (status == -1)) {
183 status = decc$feature_get_value(index, 1);
184 if (status != value) {
192 /* Older versions of ssdef.h don't have these */
193 #ifndef SS$_INVFILFOROP
194 # define SS$_INVFILFOROP 3930
196 #ifndef SS$_NOSUCHOBJECT
197 # define SS$_NOSUCHOBJECT 2696
200 /* We implement I/O here, so we will be mixing PerlIO and stdio calls. */
201 #define PERLIO_NOT_STDIO 0
203 /* Don't replace system definitions of vfork, getenv, lstat, and stat,
204 * code below needs to get to the underlying CRTL routines. */
205 #define DONT_MASK_RTL_CALLS
209 /* Anticipating future expansion in lexical warnings . . . */
210 #ifndef WARN_INTERNAL
211 # define WARN_INTERNAL WARN_MISC
214 #ifdef VMS_LONGNAME_SUPPORT
215 #include <libfildef.h>
218 #if defined(__VMS_VER) && __VMS_VER >= 70000000 && __DECC_VER >= 50200000
219 # define RTL_USES_UTC 1
222 #if !defined(__VAX) && __CRTL_VER >= 80200000
230 #define lstat(_x, _y) stat(_x, _y)
233 /* Routine to create a decterm for use with the Perl debugger */
234 /* No headers, this information was found in the Programming Concepts Manual */
236 static int (*decw_term_port)
237 (const struct dsc$descriptor_s * display,
238 const struct dsc$descriptor_s * setup_file,
239 const struct dsc$descriptor_s * customization,
240 struct dsc$descriptor_s * result_device_name,
241 unsigned short * result_device_name_length,
244 void * char_change_buffer) = 0;
246 /* gcc's header files don't #define direct access macros
247 * corresponding to VAXC's variant structs */
249 # define uic$v_format uic$r_uic_form.uic$v_format
250 # define uic$v_group uic$r_uic_form.uic$v_group
251 # define uic$v_member uic$r_uic_form.uic$v_member
252 # define prv$v_bypass prv$r_prvdef_bits0.prv$v_bypass
253 # define prv$v_grpprv prv$r_prvdef_bits0.prv$v_grpprv
254 # define prv$v_readall prv$r_prvdef_bits0.prv$v_readall
255 # define prv$v_sysprv prv$r_prvdef_bits0.prv$v_sysprv
258 #if defined(NEED_AN_H_ERRNO)
263 #pragma message disable pragma
264 #pragma member_alignment save
265 #pragma nomember_alignment longword
267 #pragma message disable misalgndmem
270 unsigned short int buflen;
271 unsigned short int itmcode;
273 unsigned short int *retlen;
276 struct filescan_itmlst_2 {
277 unsigned short length;
278 unsigned short itmcode;
283 unsigned short length;
288 #pragma message restore
289 #pragma member_alignment restore
292 #define do_fileify_dirspec(a,b,c,d) mp_do_fileify_dirspec(aTHX_ a,b,c,d)
293 #define do_pathify_dirspec(a,b,c,d) mp_do_pathify_dirspec(aTHX_ a,b,c,d)
294 #define do_tovmsspec(a,b,c,d) mp_do_tovmsspec(aTHX_ a,b,c,0,d)
295 #define do_tovmspath(a,b,c,d) mp_do_tovmspath(aTHX_ a,b,c,d)
296 #define do_rmsexpand(a,b,c,d,e,f,g) mp_do_rmsexpand(aTHX_ a,b,c,d,e,f,g)
297 #define do_vms_realpath(a,b,c) mp_do_vms_realpath(aTHX_ a,b,c)
298 #define do_vms_realname(a,b,c) mp_do_vms_realname(aTHX_ a,b,c)
299 #define do_tounixspec(a,b,c,d) mp_do_tounixspec(aTHX_ a,b,c,d)
300 #define do_tounixpath(a,b,c,d) mp_do_tounixpath(aTHX_ a,b,c,d)
301 #define do_vms_case_tolerant(a) mp_do_vms_case_tolerant(a)
302 #define expand_wild_cards(a,b,c,d) mp_expand_wild_cards(aTHX_ a,b,c,d)
303 #define getredirection(a,b) mp_getredirection(aTHX_ a,b)
305 static char *mp_do_tovmspath(pTHX_ const char *path, char *buf, int ts, int *);
306 static char *mp_do_tounixpath(pTHX_ const char *path, char *buf, int ts, int *);
307 static char *mp_do_tounixspec(pTHX_ const char *, char *, int, int *);
308 static char *mp_do_pathify_dirspec(pTHX_ const char *dir,char *buf, int ts, int *);
310 static char * int_rmsexpand_vms(
311 const char * filespec, char * outbuf, unsigned opts);
312 static char * int_rmsexpand_tovms(
313 const char * filespec, char * outbuf, unsigned opts);
314 static char *int_tovmsspec
315 (const char *path, char *buf, int dir_flag, int * utf8_flag);
316 static char * int_fileify_dirspec(const char *dir, char *buf, int *utf8_fl);
317 static char * int_tounixspec(const char *spec, char *buf, int * utf8_fl);
318 static char * int_tovmspath(const char *path, char *buf, int * utf8_fl);
320 /* see system service docs for $TRNLNM -- NOT the same as LNM$_MAX_INDEX */
321 #define PERL_LNM_MAX_ALLOWED_INDEX 127
323 /* OpenVMS User's Guide says at least 9 iterative translations will be performed,
324 * depending on the facility. SHOW LOGICAL does 10, so we'll imitate that for
327 #define PERL_LNM_MAX_ITER 10
329 /* New values with 7.3-2*/ /* why does max DCL have 4 byte subtracted from it? */
330 #if __CRTL_VER >= 70302000 && !defined(__VAX)
331 #define MAX_DCL_SYMBOL (8192)
332 #define MAX_DCL_LINE_LENGTH (4096 - 4)
334 #define MAX_DCL_SYMBOL (1024)
335 #define MAX_DCL_LINE_LENGTH (1024 - 4)
338 static char *__mystrtolower(char *str)
340 if (str) for (; *str; ++str) *str= tolower(*str);
344 static struct dsc$descriptor_s fildevdsc =
345 { 12, DSC$K_DTYPE_T, DSC$K_CLASS_S, "LNM$FILE_DEV" };
346 static struct dsc$descriptor_s crtlenvdsc =
347 { 8, DSC$K_DTYPE_T, DSC$K_CLASS_S, "CRTL_ENV" };
348 static struct dsc$descriptor_s *fildev[] = { &fildevdsc, NULL };
349 static struct dsc$descriptor_s *defenv[] = { &fildevdsc, &crtlenvdsc, NULL };
350 static struct dsc$descriptor_s **env_tables = defenv;
351 static bool will_taint = FALSE; /* tainting active, but no PL_curinterp yet */
353 /* True if we shouldn't treat barewords as logicals during directory */
355 static int no_translate_barewords;
358 static int tz_updated = 1;
361 /* DECC Features that may need to affect how Perl interprets
362 * displays filename information
364 static int decc_disable_to_vms_logname_translation = 1;
365 static int decc_disable_posix_root = 1;
366 int decc_efs_case_preserve = 0;
367 static int decc_efs_charset = 0;
368 static int decc_efs_charset_index = -1;
369 static int decc_filename_unix_no_version = 0;
370 static int decc_filename_unix_only = 0;
371 int decc_filename_unix_report = 0;
372 int decc_posix_compliant_pathnames = 0;
373 int decc_readdir_dropdotnotype = 0;
374 static int vms_process_case_tolerant = 1;
375 int vms_vtf7_filenames = 0;
376 int gnv_unix_shell = 0;
377 static int vms_unlink_all_versions = 0;
378 static int vms_posix_exit = 0;
380 /* bug workarounds if needed */
381 int decc_bug_devnull = 1;
382 int decc_dir_barename = 0;
383 int vms_bug_stat_filename = 0;
385 static int vms_debug_on_exception = 0;
386 static int vms_debug_fileify = 0;
388 /* Simple logical name translation */
389 static int simple_trnlnm
390 (const char * logname,
394 const $DESCRIPTOR(table_dsc, "LNM$FILE_DEV");
395 const unsigned long attr = LNM$M_CASE_BLIND;
396 struct dsc$descriptor_s name_dsc;
398 unsigned short result;
399 struct itmlst_3 itlst[2] = {{value_len, LNM$_STRING, value, &result},
402 name_dsc.dsc$w_length = strlen(logname);
403 name_dsc.dsc$a_pointer = (char *)logname;
404 name_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
405 name_dsc.dsc$b_class = DSC$K_CLASS_S;
407 status = sys$trnlnm(&attr, &table_dsc, &name_dsc, 0, itlst);
409 if ($VMS_STATUS_SUCCESS(status)) {
411 /* Null terminate and return the string */
412 /*--------------------------------------*/
421 /* Is this a UNIX file specification?
422 * No longer a simple check with EFS file specs
423 * For now, not a full check, but need to
424 * handle POSIX ^UP^ specifications
425 * Fixing to handle ^/ cases would require
426 * changes to many other conversion routines.
429 static int is_unix_filespec(const char *path)
435 if (strncmp(path,"\"^UP^",5) != 0) {
436 pch1 = strchr(path, '/');
441 /* If the user wants UNIX files, "." needs to be treated as in UNIX */
442 if (decc_filename_unix_report || decc_filename_unix_only) {
443 if (strcmp(path,".") == 0)
451 /* This routine converts a UCS-2 character to be VTF-7 encoded.
454 static void ucs2_to_vtf7
456 unsigned long ucs2_char,
459 unsigned char * ucs_ptr;
462 ucs_ptr = (unsigned char *)&ucs2_char;
466 hex = (ucs_ptr[1] >> 4) & 0xf;
468 outspec[2] = hex + '0';
470 outspec[2] = (hex - 9) + 'A';
471 hex = ucs_ptr[1] & 0xF;
473 outspec[3] = hex + '0';
475 outspec[3] = (hex - 9) + 'A';
477 hex = (ucs_ptr[0] >> 4) & 0xf;
479 outspec[4] = hex + '0';
481 outspec[4] = (hex - 9) + 'A';
482 hex = ucs_ptr[1] & 0xF;
484 outspec[5] = hex + '0';
486 outspec[5] = (hex - 9) + 'A';
492 /* This handles the conversion of a UNIX extended character set to a ^
493 * escaped VMS character.
494 * in a UNIX file specification.
496 * The output count variable contains the number of characters added
497 * to the output string.
499 * The return value is the number of characters read from the input string
501 static int copy_expand_unix_filename_escape
502 (char *outspec, const char *inspec, int *output_cnt, const int * utf8_fl)
510 utf8_flag = *utf8_fl;
514 if (*inspec >= 0x80) {
515 if (utf8_fl && vms_vtf7_filenames) {
516 unsigned long ucs_char;
520 if ((*inspec & 0xE0) == 0xC0) {
522 ucs_char = ((inspec[0] & 0x1F) << 6) + (inspec[1] & 0x3f);
523 if (ucs_char >= 0x80) {
524 ucs2_to_vtf7(outspec, ucs_char, output_cnt);
527 } else if ((*inspec & 0xF0) == 0xE0) {
529 ucs_char = ((inspec[0] & 0xF) << 12) +
530 ((inspec[1] & 0x3f) << 6) +
532 if (ucs_char >= 0x800) {
533 ucs2_to_vtf7(outspec, ucs_char, output_cnt);
537 #if 0 /* I do not see longer sequences supported by OpenVMS */
538 /* Maybe some one can fix this later */
539 } else if ((*inspec & 0xF8) == 0xF0) {
542 } else if ((*inspec & 0xFC) == 0xF8) {
545 } else if ((*inspec & 0xFE) == 0xFC) {
552 /* High bit set, but not a Unicode character! */
554 /* Non printing DECMCS or ISO Latin-1 character? */
555 if (*inspec <= 0x9F) {
559 hex = (*inspec >> 4) & 0xF;
561 outspec[1] = hex + '0';
563 outspec[1] = (hex - 9) + 'A';
567 outspec[2] = hex + '0';
569 outspec[2] = (hex - 9) + 'A';
573 } else if (*inspec == 0xA0) {
579 } else if (*inspec == 0xFF) {
591 /* Is this a macro that needs to be passed through?
592 * Macros start with $( and an alpha character, followed
593 * by a string of alpha numeric characters ending with a )
594 * If this does not match, then encode it as ODS-5.
596 if ((inspec[0] == '$') && (inspec[1] == '(')) {
599 if (isalnum(inspec[2]) || (inspec[2] == '.') || (inspec[2] == '_')) {
601 outspec[0] = inspec[0];
602 outspec[1] = inspec[1];
603 outspec[2] = inspec[2];
605 while(isalnum(inspec[tcnt]) ||
606 (inspec[2] == '.') || (inspec[2] == '_')) {
607 outspec[tcnt] = inspec[tcnt];
610 if (inspec[tcnt] == ')') {
611 outspec[tcnt] = inspec[tcnt];
628 if (decc_efs_charset == 0)
655 /* Don't escape again if following character is
656 * already something we escape.
658 if (strchr(".~!#&\'`()+@{},;[]%^=_\\", *(inspec+1))) {
664 /* But otherwise fall through and escape it. */
666 /* Assume that this is to be escaped */
668 outspec[1] = *inspec;
672 case ' ': /* space */
673 /* Assume that this is to be escaped */
688 /* This handles the expansion of a '^' prefix to the proper character
689 * in a UNIX file specification.
691 * The output count variable contains the number of characters added
692 * to the output string.
694 * The return value is the number of characters read from the input
697 static int copy_expand_vms_filename_escape
698 (char *outspec, const char *inspec, int *output_cnt)
705 if (*inspec == '^') {
708 /* Spaces and non-trailing dots should just be passed through,
709 * but eat the escape character.
716 case '_': /* space */
722 /* Hmm. Better leave the escape escaped. */
728 case 'U': /* Unicode - FIX-ME this is wrong. */
731 scnt = strspn(inspec, "0123456789ABCDEFabcdef");
734 scnt = sscanf(inspec, "%2x%2x", &c1, &c2);
735 outspec[0] == c1 & 0xff;
736 outspec[1] == c2 & 0xff;
743 /* Error - do best we can to continue */
753 scnt = strspn(inspec, "0123456789ABCDEFabcdef");
757 scnt = sscanf(inspec, "%2x", &c1);
758 outspec[0] = c1 & 0xff;
782 (const struct dsc$descriptor_s * srcstr,
783 struct filescan_itmlst_2 * valuelist,
784 unsigned long * fldflags,
785 struct dsc$descriptor_s *auxout,
786 unsigned short * retlen);
789 /* vms_split_path - Verify that the input file specification is a
790 * VMS format file specification, and provide pointers to the components of
791 * it. With EFS format filenames, this is virtually the only way to
792 * parse a VMS path specification into components.
794 * If the sum of the components do not add up to the length of the
795 * string, then the passed file specification is probably a UNIX style
798 static int vms_split_path
813 struct dsc$descriptor path_desc;
817 struct filescan_itmlst_2 item_list[9];
818 const int filespec = 0;
819 const int nodespec = 1;
820 const int devspec = 2;
821 const int rootspec = 3;
822 const int dirspec = 4;
823 const int namespec = 5;
824 const int typespec = 6;
825 const int verspec = 7;
827 /* Assume the worst for an easy exit */
842 path_desc.dsc$a_pointer = (char *)path; /* cast ok */
843 path_desc.dsc$w_length = strlen(path);
844 path_desc.dsc$b_dtype = DSC$K_DTYPE_T;
845 path_desc.dsc$b_class = DSC$K_CLASS_S;
847 /* Get the total length, if it is shorter than the string passed
848 * then this was probably not a VMS formatted file specification
850 item_list[filespec].itmcode = FSCN$_FILESPEC;
851 item_list[filespec].length = 0;
852 item_list[filespec].component = NULL;
854 /* If the node is present, then it gets considered as part of the
855 * volume name to hopefully make things simple.
857 item_list[nodespec].itmcode = FSCN$_NODE;
858 item_list[nodespec].length = 0;
859 item_list[nodespec].component = NULL;
861 item_list[devspec].itmcode = FSCN$_DEVICE;
862 item_list[devspec].length = 0;
863 item_list[devspec].component = NULL;
865 /* root is a special case, adding it to either the directory or
866 * the device components will probalby complicate things for the
867 * callers of this routine, so leave it separate.
869 item_list[rootspec].itmcode = FSCN$_ROOT;
870 item_list[rootspec].length = 0;
871 item_list[rootspec].component = NULL;
873 item_list[dirspec].itmcode = FSCN$_DIRECTORY;
874 item_list[dirspec].length = 0;
875 item_list[dirspec].component = NULL;
877 item_list[namespec].itmcode = FSCN$_NAME;
878 item_list[namespec].length = 0;
879 item_list[namespec].component = NULL;
881 item_list[typespec].itmcode = FSCN$_TYPE;
882 item_list[typespec].length = 0;
883 item_list[typespec].component = NULL;
885 item_list[verspec].itmcode = FSCN$_VERSION;
886 item_list[verspec].length = 0;
887 item_list[verspec].component = NULL;
889 item_list[8].itmcode = 0;
890 item_list[8].length = 0;
891 item_list[8].component = NULL;
893 status = sys$filescan
894 ((const struct dsc$descriptor_s *)&path_desc, item_list,
896 _ckvmssts_noperl(status); /* All failure status values indicate a coding error */
898 /* If we parsed it successfully these two lengths should be the same */
899 if (path_desc.dsc$w_length != item_list[filespec].length)
902 /* If we got here, then it is a VMS file specification */
905 /* set the volume name */
906 if (item_list[nodespec].length > 0) {
907 *volume = item_list[nodespec].component;
908 *vol_len = item_list[nodespec].length + item_list[devspec].length;
911 *volume = item_list[devspec].component;
912 *vol_len = item_list[devspec].length;
915 *root = item_list[rootspec].component;
916 *root_len = item_list[rootspec].length;
918 *dir = item_list[dirspec].component;
919 *dir_len = item_list[dirspec].length;
921 /* Now fun with versions and EFS file specifications
922 * The parser can not tell the difference when a "." is a version
923 * delimiter or a part of the file specification.
925 if ((decc_efs_charset) &&
926 (item_list[verspec].length > 0) &&
927 (item_list[verspec].component[0] == '.')) {
928 *name = item_list[namespec].component;
929 *name_len = item_list[namespec].length + item_list[typespec].length;
930 *ext = item_list[verspec].component;
931 *ext_len = item_list[verspec].length;
936 *name = item_list[namespec].component;
937 *name_len = item_list[namespec].length;
938 *ext = item_list[typespec].component;
939 *ext_len = item_list[typespec].length;
940 *version = item_list[verspec].component;
941 *ver_len = item_list[verspec].length;
946 /* Routine to determine if the file specification ends with .dir */
947 static int is_dir_ext(char * e_spec, int e_len, char * vs_spec, int vs_len) {
949 /* e_len must be 4, and version must be <= 2 characters */
950 if (e_len != 4 || vs_len > 2)
953 /* If a version number is present, it needs to be one */
954 if ((vs_len == 2) && (vs_spec[1] != '1'))
957 /* Look for the DIR on the extension */
958 if (vms_process_case_tolerant) {
959 if ((toupper(e_spec[1]) == 'D') &&
960 (toupper(e_spec[2]) == 'I') &&
961 (toupper(e_spec[3]) == 'R')) {
965 /* Directory extensions are supposed to be in upper case only */
966 /* I would not be surprised if this rule can not be enforced */
967 /* if and when someone fully debugs the case sensitive mode */
968 if ((e_spec[1] == 'D') &&
969 (e_spec[2] == 'I') &&
970 (e_spec[3] == 'R')) {
979 * Routine to retrieve the maximum equivalence index for an input
980 * logical name. Some calls to this routine have no knowledge if
981 * the variable is a logical or not. So on error we return a max
984 /*{{{int my_maxidx(const char *lnm) */
986 my_maxidx(const char *lnm)
990 int attr = LNM$M_CASE_BLIND;
991 struct dsc$descriptor lnmdsc;
992 struct itmlst_3 itlst[2] = {{sizeof(midx), LNM$_MAX_INDEX, &midx, 0},
995 lnmdsc.dsc$w_length = strlen(lnm);
996 lnmdsc.dsc$b_dtype = DSC$K_DTYPE_T;
997 lnmdsc.dsc$b_class = DSC$K_CLASS_S;
998 lnmdsc.dsc$a_pointer = (char *) lnm; /* Cast ok for read only parameter */
1000 status = sys$trnlnm(&attr, &fildevdsc, &lnmdsc, 0, itlst);
1001 if ((status & 1) == 0)
1008 /*{{{int vmstrnenv(const char *lnm, char *eqv, unsigned long int idx, struct dsc$descriptor_s **tabvec, unsigned long int flags) */
1010 Perl_vmstrnenv(const char *lnm, char *eqv, unsigned long int idx,
1011 struct dsc$descriptor_s **tabvec, unsigned long int flags)
1014 char uplnm[LNM$C_NAMLENGTH+1], *cp2;
1015 unsigned short int eqvlen, curtab, ivlnm = 0, ivsym = 0, ivenv = 0, secure;
1016 unsigned long int retsts, attr = LNM$M_CASE_BLIND;
1018 unsigned char acmode;
1019 struct dsc$descriptor_s lnmdsc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0},
1020 tmpdsc = {6,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
1021 struct itmlst_3 lnmlst[3] = {{sizeof idx, LNM$_INDEX, &idx, 0},
1022 {LNM$C_NAMLENGTH, LNM$_STRING, eqv, &eqvlen},
1024 $DESCRIPTOR(crtlenv,"CRTL_ENV"); $DESCRIPTOR(clisym,"CLISYM");
1025 #if defined(PERL_IMPLICIT_CONTEXT)
1028 aTHX = PERL_GET_INTERP;
1034 if (!lnm || !eqv || ((idx != 0) && ((idx-1) > PERL_LNM_MAX_ALLOWED_INDEX))) {
1035 set_errno(EINVAL); set_vaxc_errno(SS$_BADPARAM); return 0;
1037 for (cp1 = lnm, cp2 = uplnm; *cp1; cp1++, cp2++) {
1038 *cp2 = _toupper(*cp1);
1039 if (cp1 - lnm > LNM$C_NAMLENGTH) {
1040 set_errno(EINVAL); set_vaxc_errno(SS$_IVLOGNAM);
1044 lnmdsc.dsc$w_length = cp1 - lnm;
1045 lnmdsc.dsc$a_pointer = uplnm;
1046 uplnm[lnmdsc.dsc$w_length] = '\0';
1047 secure = flags & PERL__TRNENV_SECURE;
1048 acmode = secure ? PSL$C_EXEC : PSL$C_USER;
1049 if (!tabvec || !*tabvec) tabvec = env_tables;
1051 for (curtab = 0; tabvec[curtab]; curtab++) {
1052 if (!str$case_blind_compare(tabvec[curtab],&crtlenv)) {
1053 if (!ivenv && !secure) {
1058 #if defined(PERL_IMPLICIT_CONTEXT)
1061 "%%PERL-W-VMS_INIT Can't read CRTL environ\n");
1064 Perl_warn(aTHX_ "Can't read CRTL environ\n");
1067 retsts = SS$_NOLOGNAM;
1068 for (i = 0; environ[i]; i++) {
1069 if ((eq = strchr(environ[i],'=')) &&
1070 lnmdsc.dsc$w_length == (eq - environ[i]) &&
1071 !strncmp(environ[i],uplnm,eq - environ[i])) {
1073 for (eqvlen = 0; eq[eqvlen]; eqvlen++) eqv[eqvlen] = eq[eqvlen];
1074 if (!eqvlen) continue;
1075 retsts = SS$_NORMAL;
1079 if (retsts != SS$_NOLOGNAM) break;
1082 else if ((tmpdsc.dsc$a_pointer = tabvec[curtab]->dsc$a_pointer) &&
1083 !str$case_blind_compare(&tmpdsc,&clisym)) {
1084 if (!ivsym && !secure) {
1085 unsigned short int deflen = LNM$C_NAMLENGTH;
1086 struct dsc$descriptor_d eqvdsc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_D,0};
1087 /* dynamic dsc to accomodate possible long value */
1088 _ckvmssts_noperl(lib$sget1_dd(&deflen,&eqvdsc));
1089 retsts = lib$get_symbol(&lnmdsc,&eqvdsc,&eqvlen,0);
1091 if (eqvlen > MAX_DCL_SYMBOL) {
1092 set_errno(EVMSERR); set_vaxc_errno(LIB$_STRTRU);
1093 eqvlen = MAX_DCL_SYMBOL;
1094 /* Special hack--we might be called before the interpreter's */
1095 /* fully initialized, in which case either thr or PL_curcop */
1096 /* might be bogus. We have to check, since ckWARN needs them */
1097 /* both to be valid if running threaded */
1098 #if defined(PERL_IMPLICIT_CONTEXT)
1101 "%Perl-VMS-Init, Value of CLI symbol \"%s\" too long",lnm);
1104 if (ckWARN(WARN_MISC)) {
1105 Perl_warner(aTHX_ packWARN(WARN_MISC),"Value of CLI symbol \"%s\" too long",lnm);
1108 strncpy(eqv,eqvdsc.dsc$a_pointer,eqvlen);
1110 _ckvmssts_noperl(lib$sfree1_dd(&eqvdsc));
1111 if (retsts == LIB$_INVSYMNAM) { ivsym = 1; continue; }
1112 if (retsts == LIB$_NOSUCHSYM) continue;
1117 if ( (idx == 0) && (flags & PERL__TRNENV_JOIN_SEARCHLIST) ) {
1118 midx = my_maxidx(lnm);
1119 for (idx = 0, cp2 = eqv; idx <= midx; idx++) {
1120 lnmlst[1].bufadr = cp2;
1122 retsts = sys$trnlnm(&attr,tabvec[curtab],&lnmdsc,&acmode,lnmlst);
1123 if (retsts == SS$_IVLOGNAM) { ivlnm = 1; break; }
1124 if (retsts == SS$_NOLOGNAM) break;
1125 /* PPFs have a prefix */
1128 *((int *)uplnm) == *((int *)"SYS$") &&
1130 eqvlen >= 4 && eqv[0] == 0x1b && eqv[1] == 0x00 &&
1131 ( (uplnm[4] == 'O' && !strcmp(uplnm,"SYS$OUTPUT")) ||
1132 (uplnm[4] == 'I' && !strcmp(uplnm,"SYS$INPUT")) ||
1133 (uplnm[4] == 'E' && !strcmp(uplnm,"SYS$ERROR")) ||
1134 (uplnm[4] == 'C' && !strcmp(uplnm,"SYS$COMMAND")) ) ) {
1135 memmove(eqv,eqv+4,eqvlen-4);
1141 if ((retsts == SS$_IVLOGNAM) ||
1142 (retsts == SS$_NOLOGNAM)) { continue; }
1145 retsts = sys$trnlnm(&attr,tabvec[curtab],&lnmdsc,&acmode,lnmlst);
1146 if (retsts == SS$_IVLOGNAM) { ivlnm = 1; continue; }
1147 if (retsts == SS$_NOLOGNAM) continue;
1150 eqvlen = strlen(eqv);
1154 if (retsts & 1) { eqv[eqvlen] = '\0'; return eqvlen; }
1155 else if (retsts == LIB$_NOSUCHSYM || retsts == LIB$_INVSYMNAM ||
1156 retsts == SS$_IVLOGNAM || retsts == SS$_IVLOGTAB ||
1157 retsts == SS$_NOLOGNAM) {
1158 set_errno(EINVAL); set_vaxc_errno(retsts);
1160 else _ckvmssts_noperl(retsts);
1162 } /* end of vmstrnenv */
1165 /*{{{ int my_trnlnm(const char *lnm, char *eqv, unsigned long int idx)*/
1166 /* Define as a function so we can access statics. */
1167 int Perl_my_trnlnm(pTHX_ const char *lnm, char *eqv, unsigned long int idx)
1171 #if defined(PERL_IMPLICIT_CONTEXT)
1174 #ifdef SECURE_INTERNAL_GETENV
1175 flags = (PL_curinterp ? PL_tainting : will_taint) ?
1176 PERL__TRNENV_SECURE : 0;
1179 return vmstrnenv(lnm, eqv, idx, fildev, flags);
1184 * Note: Uses Perl temp to store result so char * can be returned to
1185 * caller; this pointer will be invalidated at next Perl statement
1187 * We define this as a function rather than a macro in terms of my_getenv_len()
1188 * so that it'll work when PL_curinterp is undefined (and we therefore can't
1191 /*{{{ char *my_getenv(const char *lnm, bool sys)*/
1193 Perl_my_getenv(pTHX_ const char *lnm, bool sys)
1196 static char *__my_getenv_eqv = NULL;
1197 char uplnm[LNM$C_NAMLENGTH+1], *cp2, *eqv;
1198 unsigned long int idx = 0;
1199 int trnsuccess, success, secure, saverr, savvmserr;
1203 midx = my_maxidx(lnm) + 1;
1205 if (PL_curinterp) { /* Perl interpreter running -- may be threaded */
1206 /* Set up a temporary buffer for the return value; Perl will
1207 * clean it up at the next statement transition */
1208 tmpsv = sv_2mortal(newSVpv("",(LNM$C_NAMLENGTH*midx)+1));
1209 if (!tmpsv) return NULL;
1213 /* Assume no interpreter ==> single thread */
1214 if (__my_getenv_eqv != NULL) {
1215 Renew(__my_getenv_eqv,LNM$C_NAMLENGTH*midx+1,char);
1218 Newx(__my_getenv_eqv,LNM$C_NAMLENGTH*midx+1,char);
1220 eqv = __my_getenv_eqv;
1223 for (cp1 = lnm, cp2 = eqv; *cp1; cp1++,cp2++) *cp2 = _toupper(*cp1);
1224 if (cp1 - lnm == 7 && !strncmp(eqv,"DEFAULT",7)) {
1226 getcwd(eqv,LNM$C_NAMLENGTH);
1230 /* Get rid of "000000/ in rooted filespecs */
1233 zeros = strstr(eqv, "/000000/");
1234 if (zeros != NULL) {
1236 mlen = len - (zeros - eqv) - 7;
1237 memmove(zeros, &zeros[7], mlen);
1245 /* Impose security constraints only if tainting */
1247 /* Impose security constraints only if tainting */
1248 secure = PL_curinterp ? PL_tainting : will_taint;
1249 saverr = errno; savvmserr = vaxc$errno;
1256 #ifdef SECURE_INTERNAL_GETENV
1257 secure ? PERL__TRNENV_SECURE : 0
1263 /* For the getenv interface we combine all the equivalence names
1264 * of a search list logical into one value to acquire a maximum
1265 * value length of 255*128 (assuming %ENV is using logicals).
1267 flags |= PERL__TRNENV_JOIN_SEARCHLIST;
1269 /* If the name contains a semicolon-delimited index, parse it
1270 * off and make sure we only retrieve the equivalence name for
1272 if ((cp2 = strchr(lnm,';')) != NULL) {
1274 uplnm[cp2-lnm] = '\0';
1275 idx = strtoul(cp2+1,NULL,0);
1277 flags &= ~PERL__TRNENV_JOIN_SEARCHLIST;
1280 success = vmstrnenv(lnm,eqv,idx,secure ? fildev : NULL,flags);
1282 /* Discard NOLOGNAM on internal calls since we're often looking
1283 * for an optional name, and this "error" often shows up as the
1284 * (bogus) exit status for a die() call later on. */
1285 if (sys && vaxc$errno == SS$_NOLOGNAM) SETERRNO(saverr,savvmserr);
1286 return success ? eqv : NULL;
1289 } /* end of my_getenv() */
1293 /*{{{ SV *my_getenv_len(const char *lnm, bool sys)*/
1295 Perl_my_getenv_len(pTHX_ const char *lnm, unsigned long *len, bool sys)
1299 unsigned long idx = 0;
1301 static char *__my_getenv_len_eqv = NULL;
1302 int secure, saverr, savvmserr;
1305 midx = my_maxidx(lnm) + 1;
1307 if (PL_curinterp) { /* Perl interpreter running -- may be threaded */
1308 /* Set up a temporary buffer for the return value; Perl will
1309 * clean it up at the next statement transition */
1310 tmpsv = sv_2mortal(newSVpv("",(LNM$C_NAMLENGTH*midx)+1));
1311 if (!tmpsv) return NULL;
1315 /* Assume no interpreter ==> single thread */
1316 if (__my_getenv_len_eqv != NULL) {
1317 Renew(__my_getenv_len_eqv,LNM$C_NAMLENGTH*midx+1,char);
1320 Newx(__my_getenv_len_eqv,LNM$C_NAMLENGTH*midx+1,char);
1322 buf = __my_getenv_len_eqv;
1325 for (cp1 = lnm, cp2 = buf; *cp1; cp1++,cp2++) *cp2 = _toupper(*cp1);
1326 if (cp1 - lnm == 7 && !strncmp(buf,"DEFAULT",7)) {
1329 getcwd(buf,LNM$C_NAMLENGTH);
1332 /* Get rid of "000000/ in rooted filespecs */
1334 zeros = strstr(buf, "/000000/");
1335 if (zeros != NULL) {
1337 mlen = *len - (zeros - buf) - 7;
1338 memmove(zeros, &zeros[7], mlen);
1347 /* Impose security constraints only if tainting */
1348 secure = PL_curinterp ? PL_tainting : will_taint;
1349 saverr = errno; savvmserr = vaxc$errno;
1356 #ifdef SECURE_INTERNAL_GETENV
1357 secure ? PERL__TRNENV_SECURE : 0
1363 flags |= PERL__TRNENV_JOIN_SEARCHLIST;
1365 if ((cp2 = strchr(lnm,';')) != NULL) {
1367 buf[cp2-lnm] = '\0';
1368 idx = strtoul(cp2+1,NULL,0);
1370 flags &= ~PERL__TRNENV_JOIN_SEARCHLIST;
1373 *len = vmstrnenv(lnm,buf,idx,secure ? fildev : NULL,flags);
1375 /* Get rid of "000000/ in rooted filespecs */
1378 zeros = strstr(buf, "/000000/");
1379 if (zeros != NULL) {
1381 mlen = *len - (zeros - buf) - 7;
1382 memmove(zeros, &zeros[7], mlen);
1388 /* Discard NOLOGNAM on internal calls since we're often looking
1389 * for an optional name, and this "error" often shows up as the
1390 * (bogus) exit status for a die() call later on. */
1391 if (sys && vaxc$errno == SS$_NOLOGNAM) SETERRNO(saverr,savvmserr);
1392 return *len ? buf : NULL;
1395 } /* end of my_getenv_len() */
1398 static void create_mbx(unsigned short int *, struct dsc$descriptor_s *);
1400 static void riseandshine(unsigned long int dummy) { sys$wake(0,0); }
1402 /*{{{ void prime_env_iter() */
1404 prime_env_iter(void)
1405 /* Fill the %ENV associative array with all logical names we can
1406 * find, in preparation for iterating over it.
1409 static int primed = 0;
1410 HV *seenhv = NULL, *envhv;
1412 char cmd[LNM$C_NAMLENGTH+24], mbxnam[LNM$C_NAMLENGTH], *buf = NULL;
1413 unsigned short int chan;
1414 #ifndef CLI$M_TRUSTED
1415 # define CLI$M_TRUSTED 0x40 /* Missing from VAXC headers */
1417 unsigned long int defflags = CLI$M_NOWAIT | CLI$M_NOKEYPAD | CLI$M_TRUSTED;
1418 unsigned long int mbxbufsiz, flags, retsts, subpid = 0, substs = 0, wakect = 0;
1420 bool have_sym = FALSE, have_lnm = FALSE;
1421 struct dsc$descriptor_s tmpdsc = {6,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
1422 $DESCRIPTOR(cmddsc,cmd); $DESCRIPTOR(nldsc,"_NLA0:");
1423 $DESCRIPTOR(clidsc,"DCL"); $DESCRIPTOR(clitabdsc,"DCLTABLES");
1424 $DESCRIPTOR(crtlenv,"CRTL_ENV"); $DESCRIPTOR(clisym,"CLISYM");
1425 $DESCRIPTOR(local,"_LOCAL"); $DESCRIPTOR(mbxdsc,mbxnam);
1426 #if defined(PERL_IMPLICIT_CONTEXT)
1429 #if defined(USE_ITHREADS)
1430 static perl_mutex primenv_mutex;
1431 MUTEX_INIT(&primenv_mutex);
1434 #if defined(PERL_IMPLICIT_CONTEXT)
1435 /* We jump through these hoops because we can be called at */
1436 /* platform-specific initialization time, which is before anything is */
1437 /* set up--we can't even do a plain dTHX since that relies on the */
1438 /* interpreter structure to be initialized */
1440 aTHX = PERL_GET_INTERP;
1442 /* we never get here because the NULL pointer will cause the */
1443 /* several of the routines called by this routine to access violate */
1445 /* This routine is only called by hv.c/hv_iterinit which has a */
1446 /* context, so the real fix may be to pass it through instead of */
1447 /* the hoops above */
1452 if (primed || !PL_envgv) return;
1453 MUTEX_LOCK(&primenv_mutex);
1454 if (primed) { MUTEX_UNLOCK(&primenv_mutex); return; }
1455 envhv = GvHVn(PL_envgv);
1456 /* Perform a dummy fetch as an lval to insure that the hash table is
1457 * set up. Otherwise, the hv_store() will turn into a nullop. */
1458 (void) hv_fetch(envhv,"DEFAULT",7,TRUE);
1460 for (i = 0; env_tables[i]; i++) {
1461 if (!have_sym && (tmpdsc.dsc$a_pointer = env_tables[i]->dsc$a_pointer) &&
1462 !str$case_blind_compare(&tmpdsc,&clisym)) have_sym = 1;
1463 if (!have_lnm && str$case_blind_compare(env_tables[i],&crtlenv)) have_lnm = 1;
1465 if (have_sym || have_lnm) {
1466 long int syiitm = SYI$_MAXBUF, dviitm = DVI$_DEVNAM;
1467 _ckvmssts(lib$getsyi(&syiitm, &mbxbufsiz, 0, 0, 0, 0));
1468 _ckvmssts(sys$crembx(0,&chan,mbxbufsiz,mbxbufsiz,0xff0f,0,0));
1469 _ckvmssts(lib$getdvi(&dviitm, &chan, NULL, NULL, &mbxdsc, &mbxdsc.dsc$w_length));
1472 for (i--; i >= 0; i--) {
1473 if (!str$case_blind_compare(env_tables[i],&crtlenv)) {
1476 for (j = 0; environ[j]; j++) {
1477 if (!(start = strchr(environ[j],'='))) {
1478 if (ckWARN(WARN_INTERNAL))
1479 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"Ill-formed CRTL environ value \"%s\"\n",environ[j]);
1483 sv = newSVpv(start,0);
1485 (void) hv_store(envhv,environ[j],start - environ[j] - 1,sv,0);
1490 else if ((tmpdsc.dsc$a_pointer = env_tables[i]->dsc$a_pointer) &&
1491 !str$case_blind_compare(&tmpdsc,&clisym)) {
1492 strcpy(cmd,"Show Symbol/Global *");
1493 cmddsc.dsc$w_length = 20;
1494 if (env_tables[i]->dsc$w_length == 12 &&
1495 (tmpdsc.dsc$a_pointer = env_tables[i]->dsc$a_pointer + 6) &&
1496 !str$case_blind_compare(&tmpdsc,&local)) strcpy(cmd+12,"Local *");
1497 flags = defflags | CLI$M_NOLOGNAM;
1500 strcpy(cmd,"Show Logical *");
1501 if (str$case_blind_compare(env_tables[i],&fildevdsc)) {
1502 strcat(cmd," /Table=");
1503 strncat(cmd,env_tables[i]->dsc$a_pointer,env_tables[i]->dsc$w_length);
1504 cmddsc.dsc$w_length = strlen(cmd);
1506 else cmddsc.dsc$w_length = 14; /* N.B. We test this below */
1507 flags = defflags | CLI$M_NOCLISYM;
1510 /* Create a new subprocess to execute each command, to exclude the
1511 * remote possibility that someone could subvert a mbx or file used
1512 * to write multiple commands to a single subprocess.
1515 retsts = lib$spawn(&cmddsc,&nldsc,&mbxdsc,&flags,0,&subpid,&substs,
1516 0,&riseandshine,0,0,&clidsc,&clitabdsc);
1517 flags &= ~CLI$M_TRUSTED; /* Just in case we hit a really old version */
1518 defflags &= ~CLI$M_TRUSTED;
1519 } while (retsts == LIB$_INVARG && (flags | CLI$M_TRUSTED));
1521 if (!buf) Newx(buf,mbxbufsiz + 1,char);
1522 if (seenhv) SvREFCNT_dec(seenhv);
1525 char *cp1, *cp2, *key;
1526 unsigned long int sts, iosb[2], retlen, keylen;
1529 sts = sys$qiow(0,chan,IO$_READVBLK,iosb,0,0,buf,mbxbufsiz,0,0,0,0);
1530 if (sts & 1) sts = iosb[0] & 0xffff;
1531 if (sts == SS$_ENDOFFILE) {
1533 while (substs == 0) { sys$hiber(); wakect++;}
1534 if (wakect > 1) sys$wake(0,0); /* Stole someone else's wake */
1539 retlen = iosb[0] >> 16;
1540 if (!retlen) continue; /* blank line */
1542 if (iosb[1] != subpid) {
1544 Perl_croak(aTHX_ "Unknown process %x sent message to prime_env_iter: %s",buf);
1548 if (sts == SS$_BUFFEROVF && ckWARN(WARN_INTERNAL))
1549 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"Buffer overflow in prime_env_iter: %s",buf);
1551 for (cp1 = buf; *cp1 && isspace(*cp1); cp1++) ;
1552 if (*cp1 == '(' || /* Logical name table name */
1553 *cp1 == '=' /* Next eqv of searchlist */) continue;
1554 if (*cp1 == '"') cp1++;
1555 for (cp2 = cp1; *cp2 && *cp2 != '"' && *cp2 != ' '; cp2++) ;
1556 key = cp1; keylen = cp2 - cp1;
1557 if (keylen && hv_exists(seenhv,key,keylen)) continue;
1558 while (*cp2 && *cp2 != '=') cp2++;
1559 while (*cp2 && *cp2 == '=') cp2++;
1560 while (*cp2 && *cp2 == ' ') cp2++;
1561 if (*cp2 == '"') { /* String translation; may embed "" */
1562 for (cp1 = buf + retlen; *cp1 != '"'; cp1--) ;
1563 cp2++; cp1--; /* Skip "" surrounding translation */
1565 else { /* Numeric translation */
1566 for (cp1 = cp2; *cp1 && *cp1 != ' '; cp1++) ;
1567 cp1--; /* stop on last non-space char */
1569 if ((!keylen || (cp1 - cp2 < -1)) && ckWARN(WARN_INTERNAL)) {
1570 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"Ill-formed message in prime_env_iter: |%s|",buf);
1573 PERL_HASH(hash,key,keylen);
1575 if (cp1 == cp2 && *cp2 == '.') {
1576 /* A single dot usually means an unprintable character, such as a null
1577 * to indicate a zero-length value. Get the actual value to make sure.
1579 char lnm[LNM$C_NAMLENGTH+1];
1580 char eqv[MAX_DCL_SYMBOL+1];
1582 strncpy(lnm, key, keylen);
1583 trnlen = vmstrnenv(lnm, eqv, 0, fildev, 0);
1584 sv = newSVpvn(eqv, strlen(eqv));
1587 sv = newSVpvn(cp2,cp1 - cp2 + 1);
1591 hv_store(envhv,key,keylen,sv,hash);
1592 hv_store(seenhv,key,keylen,&PL_sv_yes,hash);
1594 if (cmddsc.dsc$w_length == 14) { /* We just read LNM$FILE_DEV */
1595 /* get the PPFs for this process, not the subprocess */
1596 const char *ppfs[] = {"SYS$COMMAND", "SYS$INPUT", "SYS$OUTPUT", "SYS$ERROR", NULL};
1597 char eqv[LNM$C_NAMLENGTH+1];
1599 for (i = 0; ppfs[i]; i++) {
1600 trnlen = vmstrnenv(ppfs[i],eqv,0,fildev,0);
1601 sv = newSVpv(eqv,trnlen);
1603 hv_store(envhv,ppfs[i],strlen(ppfs[i]),sv,0);
1608 if (have_sym || have_lnm) _ckvmssts(sys$dassgn(chan));
1609 if (buf) Safefree(buf);
1610 if (seenhv) SvREFCNT_dec(seenhv);
1611 MUTEX_UNLOCK(&primenv_mutex);
1614 } /* end of prime_env_iter */
1618 /*{{{ int vmssetenv(const char *lnm, const char *eqv)*/
1619 /* Define or delete an element in the same "environment" as
1620 * vmstrnenv(). If an element is to be deleted, it's removed from
1621 * the first place it's found. If it's to be set, it's set in the
1622 * place designated by the first element of the table vector.
1623 * Like setenv() returns 0 for success, non-zero on error.
1626 Perl_vmssetenv(pTHX_ const char *lnm, const char *eqv, struct dsc$descriptor_s **tabvec)
1629 char uplnm[LNM$C_NAMLENGTH], *cp2, *c;
1630 unsigned short int curtab, ivlnm = 0, ivsym = 0, ivenv = 0;
1632 unsigned long int retsts, usermode = PSL$C_USER;
1633 struct itmlst_3 *ile, *ilist;
1634 struct dsc$descriptor_s lnmdsc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,uplnm},
1635 eqvdsc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0},
1636 tmpdsc = {6,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
1637 $DESCRIPTOR(crtlenv,"CRTL_ENV"); $DESCRIPTOR(clisym,"CLISYM");
1638 $DESCRIPTOR(local,"_LOCAL");
1641 set_errno(EINVAL); set_vaxc_errno(SS$_IVLOGNAM);
1642 return SS$_IVLOGNAM;
1645 for (cp1 = lnm, cp2 = uplnm; *cp1; cp1++, cp2++) {
1646 *cp2 = _toupper(*cp1);
1647 if (cp1 - lnm > LNM$C_NAMLENGTH) {
1648 set_errno(EINVAL); set_vaxc_errno(SS$_IVLOGNAM);
1649 return SS$_IVLOGNAM;
1652 lnmdsc.dsc$w_length = cp1 - lnm;
1653 if (!tabvec || !*tabvec) tabvec = env_tables;
1655 if (!eqv) { /* we're deleting n element */
1656 for (curtab = 0; tabvec[curtab]; curtab++) {
1657 if (!ivenv && !str$case_blind_compare(tabvec[curtab],&crtlenv)) {
1659 for (i = 0; environ[i]; i++) { /* If it's an environ elt, reset */
1660 if ((cp1 = strchr(environ[i],'=')) &&
1661 lnmdsc.dsc$w_length == (cp1 - environ[i]) &&
1662 !strncmp(environ[i],lnm,cp1 - environ[i])) {
1664 return setenv(lnm,"",1) ? vaxc$errno : 0;
1667 ivenv = 1; retsts = SS$_NOLOGNAM;
1669 if (ckWARN(WARN_INTERNAL))
1670 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"This Perl can't reset CRTL environ elements (%s)",lnm);
1671 ivenv = 1; retsts = SS$_NOSUCHPGM;
1677 else if ((tmpdsc.dsc$a_pointer = tabvec[curtab]->dsc$a_pointer) &&
1678 !str$case_blind_compare(&tmpdsc,&clisym)) {
1679 unsigned int symtype;
1680 if (tabvec[curtab]->dsc$w_length == 12 &&
1681 (tmpdsc.dsc$a_pointer = tabvec[curtab]->dsc$a_pointer + 6) &&
1682 !str$case_blind_compare(&tmpdsc,&local))
1683 symtype = LIB$K_CLI_LOCAL_SYM;
1684 else symtype = LIB$K_CLI_GLOBAL_SYM;
1685 retsts = lib$delete_symbol(&lnmdsc,&symtype);
1686 if (retsts == LIB$_INVSYMNAM) { ivsym = 1; continue; }
1687 if (retsts == LIB$_NOSUCHSYM) continue;
1691 retsts = sys$dellnm(tabvec[curtab],&lnmdsc,&usermode); /* try user mode first */
1692 if (retsts == SS$_IVLOGNAM) { ivlnm = 1; continue; }
1693 if (retsts != SS$_NOLOGNAM && retsts != SS$_NOLOGTAB) break;
1694 retsts = lib$delete_logical(&lnmdsc,tabvec[curtab]); /* then supervisor mode */
1695 if (retsts != SS$_NOLOGNAM && retsts != SS$_NOLOGTAB) break;
1699 else { /* we're defining a value */
1700 if (!ivenv && !str$case_blind_compare(tabvec[0],&crtlenv)) {
1702 return setenv(lnm,eqv,1) ? vaxc$errno : 0;
1704 if (ckWARN(WARN_INTERNAL))
1705 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"This Perl can't set CRTL environ elements (%s=%s)",lnm,eqv);
1706 retsts = SS$_NOSUCHPGM;
1710 eqvdsc.dsc$a_pointer = (char *) eqv; /* cast ok to readonly parameter */
1711 eqvdsc.dsc$w_length = strlen(eqv);
1712 if ((tmpdsc.dsc$a_pointer = tabvec[0]->dsc$a_pointer) &&
1713 !str$case_blind_compare(&tmpdsc,&clisym)) {
1714 unsigned int symtype;
1715 if (tabvec[0]->dsc$w_length == 12 &&
1716 (tmpdsc.dsc$a_pointer = tabvec[0]->dsc$a_pointer + 6) &&
1717 !str$case_blind_compare(&tmpdsc,&local))
1718 symtype = LIB$K_CLI_LOCAL_SYM;
1719 else symtype = LIB$K_CLI_GLOBAL_SYM;
1720 retsts = lib$set_symbol(&lnmdsc,&eqvdsc,&symtype);
1723 if (!*eqv) eqvdsc.dsc$w_length = 1;
1724 if (eqvdsc.dsc$w_length > LNM$C_NAMLENGTH) {
1726 nseg = (eqvdsc.dsc$w_length + LNM$C_NAMLENGTH - 1) / LNM$C_NAMLENGTH;
1727 if (nseg > PERL_LNM_MAX_ALLOWED_INDEX + 1) {
1728 Perl_warner(aTHX_ packWARN(WARN_MISC),"Value of logical \"%s\" too long. Truncating to %i bytes",
1729 lnm, LNM$C_NAMLENGTH * (PERL_LNM_MAX_ALLOWED_INDEX+1));
1730 eqvdsc.dsc$w_length = LNM$C_NAMLENGTH * (PERL_LNM_MAX_ALLOWED_INDEX+1);
1731 nseg = PERL_LNM_MAX_ALLOWED_INDEX + 1;
1734 Newx(ilist,nseg+1,struct itmlst_3);
1737 set_errno(ENOMEM); set_vaxc_errno(SS$_INSFMEM);
1740 memset(ilist, 0, (sizeof(struct itmlst_3) * (nseg+1)));
1742 for (j = 0, c = eqvdsc.dsc$a_pointer; j < nseg; j++, ile++, c += LNM$C_NAMLENGTH) {
1743 ile->itmcode = LNM$_STRING;
1745 if ((j+1) == nseg) {
1746 ile->buflen = strlen(c);
1747 /* in case we are truncating one that's too long */
1748 if (ile->buflen > LNM$C_NAMLENGTH) ile->buflen = LNM$C_NAMLENGTH;
1751 ile->buflen = LNM$C_NAMLENGTH;
1755 retsts = lib$set_logical(&lnmdsc,0,tabvec[0],0,ilist);
1759 retsts = lib$set_logical(&lnmdsc,&eqvdsc,tabvec[0],0,0);
1764 if (!(retsts & 1)) {
1766 case LIB$_AMBSYMDEF: case LIB$_INSCLIMEM:
1767 case SS$_NOLOGTAB: case SS$_TOOMANYLNAM: case SS$_IVLOGTAB:
1768 set_errno(EVMSERR); break;
1769 case LIB$_INVARG: case LIB$_INVSYMNAM: case SS$_IVLOGNAM:
1770 case LIB$_NOSUCHSYM: case SS$_NOLOGNAM:
1771 set_errno(EINVAL); break;
1773 set_errno(EACCES); break;
1778 set_vaxc_errno(retsts);
1779 return (int) retsts || 44; /* retsts should never be 0, but just in case */
1782 /* We reset error values on success because Perl does an hv_fetch()
1783 * before each hv_store(), and if the thing we're setting didn't
1784 * previously exist, we've got a leftover error message. (Of course,
1785 * this fails in the face of
1786 * $foo = $ENV{nonexistent}; $ENV{existent} = 'foo';
1787 * in that the error reported in $! isn't spurious,
1788 * but it's right more often than not.)
1790 set_errno(0); set_vaxc_errno(retsts);
1794 } /* end of vmssetenv() */
1797 /*{{{ void my_setenv(const char *lnm, const char *eqv)*/
1798 /* This has to be a function since there's a prototype for it in proto.h */
1800 Perl_my_setenv(pTHX_ const char *lnm, const char *eqv)
1803 int len = strlen(lnm);
1807 for (i = 0; lnm[i]; i++) uplnm[i] = _toupper(lnm[i]);
1808 if (!strcmp(uplnm,"DEFAULT")) {
1809 if (eqv && *eqv) my_chdir(eqv);
1813 #ifndef RTL_USES_UTC
1814 if (len == 6 || len == 2) {
1817 for (i = 0; lnm[i]; i++) uplnm[i] = _toupper(lnm[i]);
1819 if (!strcmp(uplnm,"UCX$TZ")) tz_updated = 1;
1820 if (!strcmp(uplnm,"TZ")) tz_updated = 1;
1824 (void) vmssetenv(lnm,eqv,NULL);
1828 /*{{{static void vmssetuserlnm(char *name, char *eqv); */
1830 * sets a user-mode logical in the process logical name table
1831 * used for redirection of sys$error
1833 * Fix-me: The pTHX is not needed for this routine, however doio.c
1834 * is calling it with one instead of using a macro.
1835 * A macro needs to be added to vmsish.h and doio.c updated to use it.
1839 Perl_vmssetuserlnm(pTHX_ const char *name, const char *eqv)
1841 $DESCRIPTOR(d_tab, "LNM$PROCESS");
1842 struct dsc$descriptor_d d_name = {0,DSC$K_DTYPE_T,DSC$K_CLASS_D,0};
1843 unsigned long int iss, attr = LNM$M_CONFINE;
1844 unsigned char acmode = PSL$C_USER;
1845 struct itmlst_3 lnmlst[2] = {{0, LNM$_STRING, 0, 0},
1847 d_name.dsc$a_pointer = (char *)name; /* Cast OK for read only parameter */
1848 d_name.dsc$w_length = strlen(name);
1850 lnmlst[0].buflen = strlen(eqv);
1851 lnmlst[0].bufadr = (char *)eqv; /* Cast OK for read only parameter */
1853 iss = sys$crelnm(&attr,&d_tab,&d_name,&acmode,lnmlst);
1854 if (!(iss&1)) lib$signal(iss);
1859 /*{{{ char *my_crypt(const char *textpasswd, const char *usrname)*/
1860 /* my_crypt - VMS password hashing
1861 * my_crypt() provides an interface compatible with the Unix crypt()
1862 * C library function, and uses sys$hash_password() to perform VMS
1863 * password hashing. The quadword hashed password value is returned
1864 * as a NUL-terminated 8 character string. my_crypt() does not change
1865 * the case of its string arguments; in order to match the behavior
1866 * of LOGINOUT et al., alphabetic characters in both arguments must
1867 * be upcased by the caller.
1869 * - fix me to call ACM services when available
1872 Perl_my_crypt(pTHX_ const char *textpasswd, const char *usrname)
1874 # ifndef UAI$C_PREFERRED_ALGORITHM
1875 # define UAI$C_PREFERRED_ALGORITHM 127
1877 unsigned char alg = UAI$C_PREFERRED_ALGORITHM;
1878 unsigned short int salt = 0;
1879 unsigned long int sts;
1881 unsigned short int dsc$w_length;
1882 unsigned char dsc$b_type;
1883 unsigned char dsc$b_class;
1884 const char * dsc$a_pointer;
1885 } usrdsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0},
1886 txtdsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
1887 struct itmlst_3 uailst[3] = {
1888 { sizeof alg, UAI$_ENCRYPT, &alg, 0},
1889 { sizeof salt, UAI$_SALT, &salt, 0},
1890 { 0, 0, NULL, NULL}};
1891 static char hash[9];
1893 usrdsc.dsc$w_length = strlen(usrname);
1894 usrdsc.dsc$a_pointer = usrname;
1895 if (!((sts = sys$getuai(0, 0, &usrdsc, uailst, 0, 0, 0)) & 1)) {
1897 case SS$_NOGRPPRV: case SS$_NOSYSPRV:
1901 set_errno(ESRCH); /* There isn't a Unix no-such-user error */
1906 set_vaxc_errno(sts);
1907 if (sts != RMS$_RNF) return NULL;
1910 txtdsc.dsc$w_length = strlen(textpasswd);
1911 txtdsc.dsc$a_pointer = textpasswd;
1912 if (!((sts = sys$hash_password(&txtdsc, alg, salt, &usrdsc, &hash)) & 1)) {
1913 set_errno(EVMSERR); set_vaxc_errno(sts); return NULL;
1916 return (char *) hash;
1918 } /* end of my_crypt() */
1922 static char *mp_do_rmsexpand(pTHX_ const char *, char *, int, const char *, unsigned, int *, int *);
1923 static char *mp_do_fileify_dirspec(pTHX_ const char *, char *, int, int *);
1924 static char *mp_do_tovmsspec(pTHX_ const char *, char *, int, int, int *);
1926 /* fixup barenames that are directories for internal use.
1927 * There have been problems with the consistent handling of UNIX
1928 * style directory names when routines are presented with a name that
1929 * has no directory delimitors at all. So this routine will eventually
1932 static char * fixup_bare_dirnames(const char * name)
1934 if (decc_disable_to_vms_logname_translation) {
1940 /* 8.3, remove() is now broken on symbolic links */
1941 static int rms_erase(const char * vmsname);
1945 * A little hack to get around a bug in some implemenation of remove()
1946 * that do not know how to delete a directory
1948 * Delete any file to which user has control access, regardless of whether
1949 * delete access is explicitly allowed.
1950 * Limitations: User must have write access to parent directory.
1951 * Does not block signals or ASTs; if interrupted in midstream
1952 * may leave file with an altered ACL.
1955 /*{{{int mp_do_kill_file(const char *name, int dirflag)*/
1957 mp_do_kill_file(pTHX_ const char *name, int dirflag)
1961 unsigned long int jpicode = JPI$_UIC, type = ACL$C_FILE;
1962 unsigned long int cxt = 0, aclsts, fndsts, rmsts = -1;
1963 struct dsc$descriptor_s fildsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
1965 unsigned char myace$b_length;
1966 unsigned char myace$b_type;
1967 unsigned short int myace$w_flags;
1968 unsigned long int myace$l_access;
1969 unsigned long int myace$l_ident;
1970 } newace = { sizeof(struct myacedef), ACE$C_KEYID, 0,
1971 ACE$M_READ | ACE$M_WRITE | ACE$M_DELETE | ACE$M_CONTROL, 0},
1972 oldace = { sizeof(struct myacedef), ACE$C_KEYID, 0, 0, 0};
1974 findlst[3] = {{sizeof oldace, ACL$C_FNDACLENT, &oldace, 0},
1975 {sizeof oldace, ACL$C_READACE, &oldace, 0},{0,0,0,0}},
1976 addlst[2] = {{sizeof newace, ACL$C_ADDACLENT, &newace, 0},{0,0,0,0}},
1977 dellst[2] = {{sizeof newace, ACL$C_DELACLENT, &newace, 0},{0,0,0,0}},
1978 lcklst[2] = {{sizeof newace, ACL$C_WLOCK_ACL, &newace, 0},{0,0,0,0}},
1979 ulklst[2] = {{sizeof newace, ACL$C_UNLOCK_ACL, &newace, 0},{0,0,0,0}};
1981 /* Expand the input spec using RMS, since the CRTL remove() and
1982 * system services won't do this by themselves, so we may miss
1983 * a file "hiding" behind a logical name or search list. */
1984 vmsname = PerlMem_malloc(NAM$C_MAXRSS+1);
1985 if (vmsname == NULL) _ckvmssts_noperl(SS$_INSFMEM);
1987 rslt = int_rmsexpand_tovms(name, vmsname, PERL_RMSEXPAND_M_SYMLINK);
1989 PerlMem_free(vmsname);
1993 /* Erase the file */
1994 rmsts = rms_erase(vmsname);
1996 /* Did it succeed */
1997 if ($VMS_STATUS_SUCCESS(rmsts)) {
1998 PerlMem_free(vmsname);
2002 /* If not, can changing protections help? */
2003 if (rmsts != RMS$_PRV) {
2004 set_vaxc_errno(rmsts);
2005 PerlMem_free(vmsname);
2009 /* No, so we get our own UIC to use as a rights identifier,
2010 * and the insert an ACE at the head of the ACL which allows us
2011 * to delete the file.
2013 _ckvmssts_noperl(lib$getjpi(&jpicode,0,0,&(oldace.myace$l_ident),0,0));
2014 fildsc.dsc$w_length = strlen(vmsname);
2015 fildsc.dsc$a_pointer = vmsname;
2017 newace.myace$l_ident = oldace.myace$l_ident;
2019 if (!((aclsts = sys$change_acl(0,&type,&fildsc,lcklst,0,0,0)) & 1)) {
2021 case RMS$_FNF: case RMS$_DNF: case SS$_NOSUCHOBJECT:
2022 set_errno(ENOENT); break;
2024 set_errno(ENOTDIR); break;
2026 set_errno(ENODEV); break;
2027 case RMS$_SYN: case SS$_INVFILFOROP:
2028 set_errno(EINVAL); break;
2030 set_errno(EACCES); break;
2032 _ckvmssts_noperl(aclsts);
2034 set_vaxc_errno(aclsts);
2035 PerlMem_free(vmsname);
2038 /* Grab any existing ACEs with this identifier in case we fail */
2039 aclsts = fndsts = sys$change_acl(0,&type,&fildsc,findlst,0,0,&cxt);
2040 if ( fndsts & 1 || fndsts == SS$_ACLEMPTY || fndsts == SS$_NOENTRY
2041 || fndsts == SS$_NOMOREACE ) {
2042 /* Add the new ACE . . . */
2043 if (!((aclsts = sys$change_acl(0,&type,&fildsc,addlst,0,0,0)) & 1))
2046 rmsts = rms_erase(vmsname);
2047 if ($VMS_STATUS_SUCCESS(rmsts)) {
2052 /* We blew it - dir with files in it, no write priv for
2053 * parent directory, etc. Put things back the way they were. */
2054 if (!((aclsts = sys$change_acl(0,&type,&fildsc,dellst,0,0,0)) & 1))
2057 addlst[0].bufadr = &oldace;
2058 if (!((aclsts = sys$change_acl(0,&type,&fildsc,addlst,0,0,&cxt)) & 1))
2065 fndsts = sys$change_acl(0,&type,&fildsc,ulklst,0,0,0);
2066 /* We just deleted it, so of course it's not there. Some versions of
2067 * VMS seem to return success on the unlock operation anyhow (after all
2068 * the unlock is successful), but others don't.
2070 if (fndsts == RMS$_FNF || fndsts == SS$_NOSUCHOBJECT) fndsts = SS$_NORMAL;
2071 if (aclsts & 1) aclsts = fndsts;
2072 if (!(aclsts & 1)) {
2074 set_vaxc_errno(aclsts);
2077 PerlMem_free(vmsname);
2080 } /* end of kill_file() */
2084 /*{{{int do_rmdir(char *name)*/
2086 Perl_do_rmdir(pTHX_ const char *name)
2092 /* lstat returns a VMS fileified specification of the name */
2093 /* that is looked up, and also lets verifies that this is a directory */
2095 retval = flex_lstat(name, &st);
2099 /* Due to a historical feature, flex_stat/lstat can not see some */
2100 /* Unix format file names that the rest of the CRTL can see */
2101 /* Fixing that feature will cause some perl tests to fail */
2102 /* So try this one more time. */
2104 retval = lstat(name, &st.crtl_stat);
2108 /* force it to a file spec for the kill file to work. */
2109 ret_spec = do_fileify_dirspec(name, st.st_devnam, 0, NULL);
2110 if (ret_spec == NULL) {
2116 if (!S_ISDIR(st.st_mode)) {
2121 dirfile = st.st_devnam;
2123 /* It may be possible for flex_stat to find a file and vmsify() to */
2124 /* fail with ODS-2 specifications. mp_do_kill_file can not deal */
2125 /* with that case, so fail it */
2126 if (dirfile[0] == 0) {
2131 retval = mp_do_kill_file(aTHX_ dirfile, 1);
2136 } /* end of do_rmdir */
2140 * Delete any file to which user has control access, regardless of whether
2141 * delete access is explicitly allowed.
2142 * Limitations: User must have write access to parent directory.
2143 * Does not block signals or ASTs; if interrupted in midstream
2144 * may leave file with an altered ACL.
2147 /*{{{int kill_file(char *name)*/
2149 Perl_kill_file(pTHX_ const char *name)
2155 /* Convert the filename to VMS format and see if it is a directory */
2156 /* flex_lstat returns a vmsified file specification */
2157 rmsts = flex_lstat(name, &st);
2160 /* Due to a historical feature, flex_stat/lstat can not see some */
2161 /* Unix format file names that the rest of the CRTL can see when */
2162 /* ODS-2 file specifications are in use. */
2163 /* Fixing that feature will cause some perl tests to fail */
2164 /* [.lib.ExtUtils.t]Manifest.t is one of them */
2166 vmsfile = (char *) name; /* cast ok */
2169 vmsfile = st.st_devnam;
2170 if (vmsfile[0] == 0) {
2171 /* It may be possible for flex_stat to find a file and vmsify() */
2172 /* to fail with ODS-2 specifications. mp_do_kill_file can not */
2173 /* deal with that case, so fail it */
2179 /* Remove() is allowed to delete directories, according to the X/Open
2181 * This may need special handling to work with the ACL hacks.
2183 if (S_ISDIR(st.st_mode)) {
2184 rmsts = mp_do_kill_file(aTHX_ vmsfile, 1);
2188 rmsts = mp_do_kill_file(aTHX_ vmsfile, 0);
2190 /* Need to delete all versions ? */
2191 if ((rmsts == 0) && (vms_unlink_all_versions == 1)) {
2194 /* Just use lstat() here as do not need st_dev */
2195 /* and we know that the file is in VMS format or that */
2196 /* because of a historical bug, flex_stat can not see the file */
2197 while (lstat(vmsfile, (stat_t *)&st) == 0) {
2198 rmsts = mp_do_kill_file(aTHX_ vmsfile, 0);
2203 /* Make sure that we do not loop forever */
2214 } /* end of kill_file() */
2218 /*{{{int my_mkdir(char *,Mode_t)*/
2220 Perl_my_mkdir(pTHX_ const char *dir, Mode_t mode)
2222 STRLEN dirlen = strlen(dir);
2224 /* zero length string sometimes gives ACCVIO */
2225 if (dirlen == 0) return -1;
2227 /* CRTL mkdir() doesn't tolerate trailing /, since that implies
2228 * null file name/type. However, it's commonplace under Unix,
2229 * so we'll allow it for a gain in portability.
2231 if (dir[dirlen-1] == '/') {
2232 char *newdir = savepvn(dir,dirlen-1);
2233 int ret = mkdir(newdir,mode);
2237 else return mkdir(dir,mode);
2238 } /* end of my_mkdir */
2241 /*{{{int my_chdir(char *)*/
2243 Perl_my_chdir(pTHX_ const char *dir)
2245 STRLEN dirlen = strlen(dir);
2247 /* zero length string sometimes gives ACCVIO */
2248 if (dirlen == 0) return -1;
2251 /* Perl is passing the output of the DCL SHOW DEFAULT with leading spaces.
2252 * This does not work if DECC$EFS_CHARSET is active. Hack it here
2253 * so that existing scripts do not need to be changed.
2256 while ((dirlen > 0) && (*dir1 == ' ')) {
2261 /* some versions of CRTL chdir() doesn't tolerate trailing /, since
2263 * null file name/type. However, it's commonplace under Unix,
2264 * so we'll allow it for a gain in portability.
2266 * '/' is valid when SYS$POSIX_ROOT or POSIX compliant pathnames are active.
2268 if ((dirlen > 1) && (dir1[dirlen-1] == '/')) {
2271 newdir = PerlMem_malloc(dirlen);
2273 _ckvmssts_noperl(SS$_INSFMEM);
2274 strncpy(newdir, dir1, dirlen-1);
2275 newdir[dirlen-1] = '\0';
2276 ret = chdir(newdir);
2277 PerlMem_free(newdir);
2280 else return chdir(dir1);
2281 } /* end of my_chdir */
2285 /*{{{int my_chmod(char *, mode_t)*/
2287 Perl_my_chmod(pTHX_ const char *file_spec, mode_t mode)
2292 STRLEN speclen = strlen(file_spec);
2294 /* zero length string sometimes gives ACCVIO */
2295 if (speclen == 0) return -1;
2297 /* some versions of CRTL chmod() doesn't tolerate trailing /, since
2298 * that implies null file name/type. However, it's commonplace under Unix,
2299 * so we'll allow it for a gain in portability.
2301 * Tests are showing that chmod() on VMS 8.3 is only accepting directories
2302 * in VMS file.dir notation.
2304 changefile = (char *) file_spec; /* cast ok */
2305 ret = flex_lstat(file_spec, &st);
2308 /* Due to a historical feature, flex_stat/lstat can not see some */
2309 /* Unix format file names that the rest of the CRTL can see when */
2310 /* ODS-2 file specifications are in use. */
2311 /* Fixing that feature will cause some perl tests to fail */
2312 /* [.lib.ExtUtils.t]Manifest.t is one of them */
2316 /* It may be possible to get here with nothing in st_devname */
2317 /* chmod still may work though */
2318 if (st.st_devnam[0] != 0) {
2319 changefile = st.st_devnam;
2322 ret = chmod(changefile, mode);
2324 } /* end of my_chmod */
2328 /*{{{FILE *my_tmpfile()*/
2335 if ((fp = tmpfile())) return fp;
2337 cp = PerlMem_malloc(L_tmpnam+24);
2338 if (cp == NULL) _ckvmssts_noperl(SS$_INSFMEM);
2340 if (decc_filename_unix_only == 0)
2341 strcpy(cp,"Sys$Scratch:");
2344 tmpnam(cp+strlen(cp));
2345 strcat(cp,".Perltmp");
2346 fp = fopen(cp,"w+","fop=dlt");
2353 #ifndef HOMEGROWN_POSIX_SIGNALS
2355 * The C RTL's sigaction fails to check for invalid signal numbers so we
2356 * help it out a bit. The docs are correct, but the actual routine doesn't
2357 * do what the docs say it will.
2359 /*{{{int Perl_my_sigaction (pTHX_ int, const struct sigaction*, struct sigaction*);*/
2361 Perl_my_sigaction (pTHX_ int sig, const struct sigaction* act,
2362 struct sigaction* oact)
2364 if (sig == SIGKILL || sig == SIGSTOP || sig == SIGCONT) {
2365 SETERRNO(EINVAL, SS$_INVARG);
2368 return sigaction(sig, act, oact);
2373 #ifdef KILL_BY_SIGPRC
2374 #include <errnodef.h>
2376 /* We implement our own kill() using the undocumented system service
2377 sys$sigprc for one of two reasons:
2379 1.) If the kill() in an older CRTL uses sys$forcex, causing the
2380 target process to do a sys$exit, which usually can't be handled
2381 gracefully...certainly not by Perl and the %SIG{} mechanism.
2383 2.) If the kill() in the CRTL can't be called from a signal
2384 handler without disappearing into the ether, i.e., the signal
2385 it purportedly sends is never trapped. Still true as of VMS 7.3.
2387 sys$sigprc has the same parameters as sys$forcex, but throws an exception
2388 in the target process rather than calling sys$exit.
2390 Note that distinguishing SIGSEGV from SIGBUS requires an extra arg
2391 on the ACCVIO condition, which sys$sigprc (and sys$forcex) don't
2392 provide. On VMS 7.0+ this is taken care of by doing sys$sigprc
2393 with condition codes C$_SIG0+nsig*8, catching the exception on the
2394 target process and resignaling with appropriate arguments.
2396 But we don't have that VMS 7.0+ exception handler, so if you
2397 Perl_my_kill(.., SIGSEGV) it will show up as a SIGBUS. Oh well.
2399 Also note that SIGTERM is listed in the docs as being "unimplemented",
2400 yet always seems to be signaled with a VMS condition code of 4 (and
2401 correctly handled for that code). So we hardwire it in.
2403 Unlike the VMS 7.0+ CRTL kill() function, we actually check the signal
2404 number to see if it's valid. So Perl_my_kill(pid,0) returns -1 rather
2405 than signalling with an unrecognized (and unhandled by CRTL) code.
2408 #define _MY_SIG_MAX 28
2411 Perl_sig_to_vmscondition_int(int sig)
2413 static unsigned int sig_code[_MY_SIG_MAX+1] =
2416 SS$_HANGUP, /* 1 SIGHUP */
2417 SS$_CONTROLC, /* 2 SIGINT */
2418 SS$_CONTROLY, /* 3 SIGQUIT */
2419 SS$_RADRMOD, /* 4 SIGILL */
2420 SS$_BREAK, /* 5 SIGTRAP */
2421 SS$_OPCCUS, /* 6 SIGABRT */
2422 SS$_COMPAT, /* 7 SIGEMT */
2424 SS$_FLTOVF, /* 8 SIGFPE VAX */
2426 SS$_HPARITH, /* 8 SIGFPE AXP */
2428 SS$_ABORT, /* 9 SIGKILL */
2429 SS$_ACCVIO, /* 10 SIGBUS */
2430 SS$_ACCVIO, /* 11 SIGSEGV */
2431 SS$_BADPARAM, /* 12 SIGSYS */
2432 SS$_NOMBX, /* 13 SIGPIPE */
2433 SS$_ASTFLT, /* 14 SIGALRM */
2450 #if __VMS_VER >= 60200000
2451 static int initted = 0;
2454 sig_code[16] = C$_SIGUSR1;
2455 sig_code[17] = C$_SIGUSR2;
2456 #if __CRTL_VER >= 70000000
2457 sig_code[20] = C$_SIGCHLD;
2459 #if __CRTL_VER >= 70300000
2460 sig_code[28] = C$_SIGWINCH;
2465 if (sig < _SIG_MIN) return 0;
2466 if (sig > _MY_SIG_MAX) return 0;
2467 return sig_code[sig];
2471 Perl_sig_to_vmscondition(int sig)
2474 if (vms_debug_on_exception != 0)
2475 lib$signal(SS$_DEBUG);
2477 return Perl_sig_to_vmscondition_int(sig);
2482 Perl_my_kill(int pid, int sig)
2487 int sys$sigprc(unsigned int *pidadr,
2488 struct dsc$descriptor_s *prcname,
2491 /* sig 0 means validate the PID */
2492 /*------------------------------*/
2494 const unsigned long int jpicode = JPI$_PID;
2497 status = lib$getjpi(&jpicode, &pid, NULL, &ret_pid, NULL, NULL);
2498 if ($VMS_STATUS_SUCCESS(status))
2501 case SS$_NOSUCHNODE:
2502 case SS$_UNREACHABLE:
2516 code = Perl_sig_to_vmscondition_int(sig);
2519 SETERRNO(EINVAL, SS$_BADPARAM);
2523 /* Fixme: Per official UNIX specification: If pid = 0, or negative then
2524 * signals are to be sent to multiple processes.
2525 * pid = 0 - all processes in group except ones that the system exempts
2526 * pid = -1 - all processes except ones that the system exempts
2527 * pid = -n - all processes in group (abs(n)) except ...
2528 * For now, just report as not supported.
2532 SETERRNO(ENOTSUP, SS$_UNSUPPORTED);
2536 iss = sys$sigprc((unsigned int *)&pid,0,code);
2537 if (iss&1) return 0;
2541 set_errno(EPERM); break;
2543 case SS$_NOSUCHNODE:
2544 case SS$_UNREACHABLE:
2545 set_errno(ESRCH); break;
2547 set_errno(ENOMEM); break;
2549 _ckvmssts_noperl(iss);
2552 set_vaxc_errno(iss);
2558 /* Routine to convert a VMS status code to a UNIX status code.
2559 ** More tricky than it appears because of conflicting conventions with
2562 ** VMS status codes are a bit mask, with the least significant bit set for
2565 ** Special UNIX status of EVMSERR indicates that no translation is currently
2566 ** available, and programs should check the VMS status code.
2568 ** Programs compiled with _POSIX_EXIT have a special encoding that requires
2572 #ifndef C_FACILITY_NO
2573 #define C_FACILITY_NO 0x350000
2576 #define DCL_IVVERB 0x38090
2579 int Perl_vms_status_to_unix(int vms_status, int child_flag)
2587 /* Assume the best or the worst */
2588 if (vms_status & STS$M_SUCCESS)
2591 unix_status = EVMSERR;
2593 msg_status = vms_status & ~STS$M_CONTROL;
2595 facility = vms_status & STS$M_FAC_NO;
2596 fac_sp = vms_status & STS$M_FAC_SP;
2597 msg_no = vms_status & (STS$M_MSG_NO | STS$M_SEVERITY);
2599 if (((facility == 0) || (fac_sp == 0)) && (child_flag == 0)) {
2605 unix_status = EFAULT;
2607 case SS$_DEVOFFLINE:
2608 unix_status = EBUSY;
2611 unix_status = ENOTCONN;
2619 case SS$_INVFILFOROP:
2623 unix_status = EINVAL;
2625 case SS$_UNSUPPORTED:
2626 unix_status = ENOTSUP;
2631 unix_status = EACCES;
2633 case SS$_DEVICEFULL:
2634 unix_status = ENOSPC;
2637 unix_status = ENODEV;
2639 case SS$_NOSUCHFILE:
2640 case SS$_NOSUCHOBJECT:
2641 unix_status = ENOENT;
2643 case SS$_ABORT: /* Fatal case */
2644 case ((SS$_ABORT & STS$M_COND_ID) | STS$K_ERROR): /* Error case */
2645 case ((SS$_ABORT & STS$M_COND_ID) | STS$K_WARNING): /* Warning case */
2646 unix_status = EINTR;
2649 unix_status = E2BIG;
2652 unix_status = ENOMEM;
2655 unix_status = EPERM;
2657 case SS$_NOSUCHNODE:
2658 case SS$_UNREACHABLE:
2659 unix_status = ESRCH;
2662 unix_status = ECHILD;
2665 if ((facility == 0) && (msg_no < 8)) {
2666 /* These are not real VMS status codes so assume that they are
2667 ** already UNIX status codes
2669 unix_status = msg_no;
2675 /* Translate a POSIX exit code to a UNIX exit code */
2676 if ((facility == C_FACILITY_NO) && ((msg_no & 0xA000) == 0xA000)) {
2677 unix_status = (msg_no & 0x07F8) >> 3;
2681 /* Documented traditional behavior for handling VMS child exits */
2682 /*--------------------------------------------------------------*/
2683 if (child_flag != 0) {
2685 /* Success / Informational return 0 */
2686 /*----------------------------------*/
2687 if (msg_no & STS$K_SUCCESS)
2690 /* Warning returns 1 */
2691 /*-------------------*/
2692 if ((msg_no & (STS$K_ERROR | STS$K_SEVERE)) == 0)
2695 /* Everything else pass through the severity bits */
2696 /*------------------------------------------------*/
2697 return (msg_no & STS$M_SEVERITY);
2700 /* Normal VMS status to ERRNO mapping attempt */
2701 /*--------------------------------------------*/
2702 switch(msg_status) {
2703 /* case RMS$_EOF: */ /* End of File */
2704 case RMS$_FNF: /* File Not Found */
2705 case RMS$_DNF: /* Dir Not Found */
2706 unix_status = ENOENT;
2708 case RMS$_RNF: /* Record Not Found */
2709 unix_status = ESRCH;
2712 unix_status = ENOTDIR;
2715 unix_status = ENODEV;
2720 unix_status = EBADF;
2723 unix_status = EEXIST;
2727 case LIB$_INVSTRDES:
2729 case LIB$_NOSUCHSYM:
2730 case LIB$_INVSYMNAM:
2732 unix_status = EINVAL;
2738 unix_status = E2BIG;
2740 case RMS$_PRV: /* No privilege */
2741 case RMS$_ACC: /* ACP file access failed */
2742 case RMS$_WLK: /* Device write locked */
2743 unix_status = EACCES;
2745 case RMS$_MKD: /* Failed to mark for delete */
2746 unix_status = EPERM;
2748 /* case RMS$_NMF: */ /* No more files */
2756 /* Try to guess at what VMS error status should go with a UNIX errno
2757 * value. This is hard to do as there could be many possible VMS
2758 * error statuses that caused the errno value to be set.
2761 int Perl_unix_status_to_vms(int unix_status)
2763 int test_unix_status;
2765 /* Trivial cases first */
2766 /*---------------------*/
2767 if (unix_status == EVMSERR)
2770 /* Is vaxc$errno sane? */
2771 /*---------------------*/
2772 test_unix_status = Perl_vms_status_to_unix(vaxc$errno, 0);
2773 if (test_unix_status == unix_status)
2776 /* If way out of range, must be VMS code already */
2777 /*-----------------------------------------------*/
2778 if (unix_status > EVMSERR)
2781 /* If out of range, punt */
2782 /*-----------------------*/
2783 if (unix_status > __ERRNO_MAX)
2787 /* Ok, now we have to do it the hard way. */
2788 /*----------------------------------------*/
2789 switch(unix_status) {
2790 case 0: return SS$_NORMAL;
2791 case EPERM: return SS$_NOPRIV;
2792 case ENOENT: return SS$_NOSUCHOBJECT;
2793 case ESRCH: return SS$_UNREACHABLE;
2794 case EINTR: return SS$_ABORT;
2797 case E2BIG: return SS$_BUFFEROVF;
2799 case EBADF: return RMS$_IFI;
2800 case ECHILD: return SS$_NONEXPR;
2802 case ENOMEM: return SS$_INSFMEM;
2803 case EACCES: return SS$_FILACCERR;
2804 case EFAULT: return SS$_ACCVIO;
2806 case EBUSY: return SS$_DEVOFFLINE;
2807 case EEXIST: return RMS$_FEX;
2809 case ENODEV: return SS$_NOSUCHDEV;
2810 case ENOTDIR: return RMS$_DIR;
2812 case EINVAL: return SS$_INVARG;
2818 case ENOSPC: return SS$_DEVICEFULL;
2819 case ESPIPE: return LIB$_INVARG;
2824 case ERANGE: return LIB$_INVARG;
2825 /* case EWOULDBLOCK */
2826 /* case EINPROGRESS */
2829 /* case EDESTADDRREQ */
2831 /* case EPROTOTYPE */
2832 /* case ENOPROTOOPT */
2833 /* case EPROTONOSUPPORT */
2834 /* case ESOCKTNOSUPPORT */
2835 /* case EOPNOTSUPP */
2836 /* case EPFNOSUPPORT */
2837 /* case EAFNOSUPPORT */
2838 /* case EADDRINUSE */
2839 /* case EADDRNOTAVAIL */
2841 /* case ENETUNREACH */
2842 /* case ENETRESET */
2843 /* case ECONNABORTED */
2844 /* case ECONNRESET */
2847 case ENOTCONN: return SS$_CLEARED;
2848 /* case ESHUTDOWN */
2849 /* case ETOOMANYREFS */
2850 /* case ETIMEDOUT */
2851 /* case ECONNREFUSED */
2853 /* case ENAMETOOLONG */
2854 /* case EHOSTDOWN */
2855 /* case EHOSTUNREACH */
2856 /* case ENOTEMPTY */
2868 /* case ECANCELED */
2872 return SS$_UNSUPPORTED;
2878 /* case EABANDONED */
2880 return SS$_ABORT; /* punt */
2883 return SS$_ABORT; /* Should not get here */
2887 /* default piping mailbox size */
2888 #define PERL_BUFSIZ 512
2892 create_mbx(unsigned short int *chan, struct dsc$descriptor_s *namdsc)
2894 unsigned long int mbxbufsiz;
2895 static unsigned long int syssize = 0;
2896 unsigned long int dviitm = DVI$_DEVNAM;
2897 char csize[LNM$C_NAMLENGTH+1];
2901 unsigned long syiitm = SYI$_MAXBUF;
2903 * Get the SYSGEN parameter MAXBUF
2905 * If the logical 'PERL_MBX_SIZE' is defined
2906 * use the value of the logical instead of PERL_BUFSIZ, but
2907 * keep the size between 128 and MAXBUF.
2910 _ckvmssts_noperl(lib$getsyi(&syiitm, &syssize, 0, 0, 0, 0));
2913 if (vmstrnenv("PERL_MBX_SIZE", csize, 0, fildev, 0)) {
2914 mbxbufsiz = atoi(csize);
2916 mbxbufsiz = PERL_BUFSIZ;
2918 if (mbxbufsiz < 128) mbxbufsiz = 128;
2919 if (mbxbufsiz > syssize) mbxbufsiz = syssize;
2921 _ckvmssts_noperl(sts = sys$crembx(0,chan,mbxbufsiz,mbxbufsiz,0,0,0));
2923 sts = lib$getdvi(&dviitm, chan, NULL, NULL, namdsc, &namdsc->dsc$w_length);
2924 _ckvmssts_noperl(sts);
2925 namdsc->dsc$a_pointer[namdsc->dsc$w_length] = '\0';
2927 } /* end of create_mbx() */
2930 /*{{{ my_popen and my_pclose*/
2932 typedef struct _iosb IOSB;
2933 typedef struct _iosb* pIOSB;
2934 typedef struct _pipe Pipe;
2935 typedef struct _pipe* pPipe;
2936 typedef struct pipe_details Info;
2937 typedef struct pipe_details* pInfo;
2938 typedef struct _srqp RQE;
2939 typedef struct _srqp* pRQE;
2940 typedef struct _tochildbuf CBuf;
2941 typedef struct _tochildbuf* pCBuf;
2944 unsigned short status;
2945 unsigned short count;
2946 unsigned long dvispec;
2949 #pragma member_alignment save
2950 #pragma nomember_alignment quadword
2951 struct _srqp { /* VMS self-relative queue entry */
2952 unsigned long qptr[2];
2954 #pragma member_alignment restore
2955 static RQE RQE_ZERO = {0,0};
2957 struct _tochildbuf {
2960 unsigned short size;
2968 unsigned short chan_in;
2969 unsigned short chan_out;
2971 unsigned int bufsize;
2983 #if defined(PERL_IMPLICIT_CONTEXT)
2984 void *thx; /* Either a thread or an interpreter */
2985 /* pointer, depending on how we're built */
2993 PerlIO *fp; /* file pointer to pipe mailbox */
2994 int useFILE; /* using stdio, not perlio */
2995 int pid; /* PID of subprocess */
2996 int mode; /* == 'r' if pipe open for reading */
2997 int done; /* subprocess has completed */
2998 int waiting; /* waiting for completion/closure */
2999 int closing; /* my_pclose is closing this pipe */
3000 unsigned long completion; /* termination status of subprocess */
3001 pPipe in; /* pipe in to sub */
3002 pPipe out; /* pipe out of sub */
3003 pPipe err; /* pipe of sub's sys$error */
3004 int in_done; /* true when in pipe finished */
3007 unsigned short xchan; /* channel to debug xterm */
3008 unsigned short xchan_valid; /* channel is assigned */
3011 struct exit_control_block
3013 struct exit_control_block *flink;
3014 unsigned long int (*exit_routine)();
3015 unsigned long int arg_count;
3016 unsigned long int *status_address;
3017 unsigned long int exit_status;
3020 typedef struct _closed_pipes Xpipe;
3021 typedef struct _closed_pipes* pXpipe;
3023 struct _closed_pipes {
3024 int pid; /* PID of subprocess */
3025 unsigned long completion; /* termination status of subprocess */
3027 #define NKEEPCLOSED 50
3028 static Xpipe closed_list[NKEEPCLOSED];
3029 static int closed_index = 0;
3030 static int closed_num = 0;
3032 #define RETRY_DELAY "0 ::0.20"
3033 #define MAX_RETRY 50
3035 static int pipe_ef = 0; /* first call to safe_popen inits these*/
3036 static unsigned long mypid;
3037 static unsigned long delaytime[2];
3039 static pInfo open_pipes = NULL;
3040 static $DESCRIPTOR(nl_desc, "NL:");
3042 #define PIPE_COMPLETION_WAIT 30 /* seconds, for EOF/FORCEX wait */
3046 static unsigned long int
3050 unsigned long int retsts = SS$_NORMAL, abort = SS$_TIMEOUT;
3051 int sts, did_stuff, need_eof, j;
3054 * Flush any pending i/o, but since we are in process run-down, be
3055 * careful about referencing PerlIO structures that may already have
3056 * been deallocated. We may not even have an interpreter anymore.
3061 #if defined(PERL_IMPLICIT_CONTEXT)
3062 /* We need to use the Perl context of the thread that created */
3066 aTHX = info->err->thx;
3068 aTHX = info->out->thx;
3070 aTHX = info->in->thx;
3073 #if defined(USE_ITHREADS)
3076 && PL_perlio_fd_refcnt)
3077 PerlIO_flush(info->fp);
3079 fflush((FILE *)info->fp);
3085 next we try sending an EOF...ignore if doesn't work, make sure we
3093 _ckvmssts_noperl(sys$setast(0));
3094 if (info->in && !info->in->shut_on_empty) {
3095 _ckvmssts_noperl(sys$qio(0,info->in->chan_in,IO$_WRITEOF,0,0,0,
3100 _ckvmssts_noperl(sys$setast(1));
3104 /* wait for EOF to have effect, up to ~ 30 sec [default] */
3106 for (j = 0; did_stuff && j < PIPE_COMPLETION_WAIT; j++) {
3111 _ckvmssts_noperl(sys$setast(0));
3112 if (info->waiting && info->done)
3114 nwait += info->waiting;
3115 _ckvmssts_noperl(sys$setast(1));
3125 _ckvmssts_noperl(sys$setast(0));
3126 if (!info->done) { /* Tap them gently on the shoulder . . .*/
3127 sts = sys$forcex(&info->pid,0,&abort);
3128 if (!(sts&1) && sts != SS$_NONEXPR) _ckvmssts_noperl(sts);
3131 _ckvmssts_noperl(sys$setast(1));
3135 /* again, wait for effect */
3137 for (j = 0; did_stuff && j < PIPE_COMPLETION_WAIT; j++) {
3142 _ckvmssts_noperl(sys$setast(0));
3143 if (info->waiting && info->done)
3145 nwait += info->waiting;
3146 _ckvmssts_noperl(sys$setast(1));
3155 _ckvmssts_noperl(sys$setast(0));
3156 if (!info->done) { /* We tried to be nice . . . */
3157 sts = sys$delprc(&info->pid,0);
3158 if (!(sts&1) && sts != SS$_NONEXPR) _ckvmssts_noperl(sts);
3159 info->done = 1; /* sys$delprc is as done as we're going to get. */
3161 _ckvmssts_noperl(sys$setast(1));
3167 #if defined(PERL_IMPLICIT_CONTEXT)
3168 /* We need to use the Perl context of the thread that created */
3171 if (open_pipes->err)
3172 aTHX = open_pipes->err->thx;
3173 else if (open_pipes->out)
3174 aTHX = open_pipes->out->thx;
3175 else if (open_pipes->in)
3176 aTHX = open_pipes->in->thx;
3178 if ((sts = my_pclose(open_pipes->fp)) == -1) retsts = vaxc$errno;
3179 else if (!(sts & 1)) retsts = sts;
3184 static struct exit_control_block pipe_exitblock =
3185 {(struct exit_control_block *) 0,
3186 pipe_exit_routine, 0, &pipe_exitblock.exit_status, 0};
3188 static void pipe_mbxtofd_ast(pPipe p);
3189 static void pipe_tochild1_ast(pPipe p);
3190 static void pipe_tochild2_ast(pPipe p);
3193 popen_completion_ast(pInfo info)
3195 pInfo i = open_pipes;
3200 info->completion &= 0x0FFFFFFF; /* strip off "control" field */
3201 closed_list[closed_index].pid = info->pid;
3202 closed_list[closed_index].completion = info->completion;
3204 if (closed_index == NKEEPCLOSED)
3209 if (i == info) break;
3212 if (!i) return; /* unlinked, probably freed too */
3217 Writing to subprocess ...
3218 if my_pclose'd: EOF already sent, should shutdown chan_in part of pipe
3220 chan_out may be waiting for "done" flag, or hung waiting
3221 for i/o completion to child...cancel the i/o. This will
3222 put it into "snarf mode" (done but no EOF yet) that discards
3225 Output from subprocess (stdout, stderr) needs to be flushed and
3226 shut down. We try sending an EOF, but if the mbx is full the pipe
3227 routine should still catch the "shut_on_empty" flag, telling it to
3228 use immediate-style reads so that "mbx empty" -> EOF.
3232 if (info->in && !info->in_done) { /* only for mode=w */
3233 if (info->in->shut_on_empty && info->in->need_wake) {
3234 info->in->need_wake = FALSE;
3235 _ckvmssts_noperl(sys$dclast(pipe_tochild2_ast,info->in,0));
3237 _ckvmssts_noperl(sys$cancel(info->in->chan_out));
3241 if (info->out && !info->out_done) { /* were we also piping output? */
3242 info->out->shut_on_empty = TRUE;
3243 iss = sys$qio(0,info->out->chan_in,IO$_WRITEOF|IO$M_NORSWAIT, 0, 0, 0, 0, 0, 0, 0, 0, 0);
3244 if (iss == SS$_MBFULL) iss = SS$_NORMAL;
3245 _ckvmssts_noperl(iss);
3248 if (info->err && !info->err_done) { /* we were piping stderr */
3249 info->err->shut_on_empty = TRUE;
3250 iss = sys$qio(0,info->err->chan_in,IO$_WRITEOF|IO$M_NORSWAIT, 0, 0, 0, 0, 0, 0, 0, 0, 0);
3251 if (iss == SS$_MBFULL) iss = SS$_NORMAL;
3252 _ckvmssts_noperl(iss);
3254 _ckvmssts_noperl(sys$setef(pipe_ef));
3258 static unsigned long int setup_cmddsc(pTHX_ const char *cmd, int check_img, int *suggest_quote, struct dsc$descriptor_s **pvmscmd);
3259 static void vms_execfree(struct dsc$descriptor_s *vmscmd);
3262 we actually differ from vmstrnenv since we use this to
3263 get the RMS IFI to check if SYS$OUTPUT and SYS$ERROR *really*
3264 are pointing to the same thing
3267 static unsigned short
3268 popen_translate(pTHX_ char *logical, char *result)
3271 $DESCRIPTOR(d_table,"LNM$PROCESS_TABLE");
3272 $DESCRIPTOR(d_log,"");
3274 unsigned short length;
3275 unsigned short code;
3277 unsigned short *retlenaddr;
3279 unsigned short l, ifi;
3281 d_log.dsc$a_pointer = logical;
3282 d_log.dsc$w_length = strlen(logical);
3284 itmlst[0].code = LNM$_STRING;
3285 itmlst[0].length = 255;
3286 itmlst[0].buffer_addr = result;
3287 itmlst[0].retlenaddr = &l;
3290 itmlst[1].length = 0;
3291 itmlst[1].buffer_addr = 0;
3292 itmlst[1].retlenaddr = 0;
3294 iss = sys$trnlnm(0, &d_table, &d_log, 0, itmlst);
3295 if (iss == SS$_NOLOGNAM) {
3299 if (!(iss&1)) lib$signal(iss);
3302 logicals for PPFs have a 4 byte prefix ESC+NUL+(RMS IFI)
3303 strip it off and return the ifi, if any
3306 if (result[0] == 0x1b && result[1] == 0x00) {
3307 memmove(&ifi,result+2,2);
3308 strcpy(result,result+4);
3310 return ifi; /* this is the RMS internal file id */
3313 static void pipe_infromchild_ast(pPipe p);
3316 I'm using LIB$(GET|FREE)_VM here so that we can allocate and deallocate
3317 inside an AST routine without worrying about reentrancy and which Perl
3318 memory allocator is being used.
3320 We read data and queue up the buffers, then spit them out one at a
3321 time to the output mailbox when the output mailbox is ready for one.
3324 #define INITIAL_TOCHILDQUEUE 2
3327 pipe_tochild_setup(pTHX_ char *rmbx, char *wmbx)
3331 char mbx1[64], mbx2[64];
3332 struct dsc$descriptor_s d_mbx1 = {sizeof mbx1, DSC$K_DTYPE_T,
3333 DSC$K_CLASS_S, mbx1},
3334 d_mbx2 = {sizeof mbx2, DSC$K_DTYPE_T,
3335 DSC$K_CLASS_S, mbx2};
3336 unsigned int dviitm = DVI$_DEVBUFSIZ;
3340 _ckvmssts_noperl(lib$get_vm(&n, &p));
3342 create_mbx(&p->chan_in , &d_mbx1);
3343 create_mbx(&p->chan_out, &d_mbx2);
3344 _ckvmssts_noperl(lib$getdvi(&dviitm, &p->chan_in, 0, &p->bufsize));
3347 p->shut_on_empty = FALSE;
3348 p->need_wake = FALSE;
3351 p->iosb.status = SS$_NORMAL;
3352 p->iosb2.status = SS$_NORMAL;
3358 #ifdef PERL_IMPLICIT_CONTEXT
3362 n = sizeof(CBuf) + p->bufsize;
3364 for (j = 0; j < INITIAL_TOCHILDQUEUE; j++) {
3365 _ckvmssts_noperl(lib$get_vm(&n, &b));
3366 b->buf = (char *) b + sizeof(CBuf);
3367 _ckvmssts_noperl(lib$insqhi(b, &p->free));
3370 pipe_tochild2_ast(p);
3371 pipe_tochild1_ast(p);
3377 /* reads the MBX Perl is writing, and queues */
3380 pipe_tochild1_ast(pPipe p)
3383 int iss = p->iosb.status;
3384 int eof = (iss == SS$_ENDOFFILE);
3386 #ifdef PERL_IMPLICIT_CONTEXT
3392 p->shut_on_empty = TRUE;
3394 _ckvmssts_noperl(sys$dassgn(p->chan_in));
3396 _ckvmssts_noperl(iss);
3400 b->size = p->iosb.count;
3401 _ckvmssts_noperl(sts = lib$insqhi(b, &p->wait));
3403 p->need_wake = FALSE;
3404 _ckvmssts_noperl(sys$dclast(pipe_tochild2_ast,p,0));
3407 p->retry = 1; /* initial call */
3410 if (eof) { /* flush the free queue, return when done */
3411 int n = sizeof(CBuf) + p->bufsize;
3413 iss = lib$remqti(&p->free, &b);
3414 if (iss == LIB$_QUEWASEMP) return;
3415 _ckvmssts_noperl(iss);
3416 _ckvmssts_noperl(lib$free_vm(&n, &b));
3420 iss = lib$remqti(&p->free, &b);
3421 if (iss == LIB$_QUEWASEMP) {
3422 int n = sizeof(CBuf) + p->bufsize;
3423 _ckvmssts_noperl(lib$get_vm(&n, &b));
3424 b->buf = (char *) b + sizeof(CBuf);
3426 _ckvmssts_noperl(iss);
3430 iss = sys$qio(0,p->chan_in,
3431 IO$_READVBLK|(p->shut_on_empty ? IO$M_NOWAIT : 0),
3433 pipe_tochild1_ast, p, b->buf, p->bufsize, 0, 0, 0, 0);
3434 if (iss == SS$_ENDOFFILE && p->shut_on_empty) iss = SS$_NORMAL;
3435 _ckvmssts_noperl(iss);
3439 /* writes queued buffers to output, waits for each to complete before
3443 pipe_tochild2_ast(pPipe p)
3446 int iss = p->iosb2.status;
3447 int n = sizeof(CBuf) + p->bufsize;
3448 int done = (p->info && p->info->done) ||
3449 iss == SS$_CANCEL || iss == SS$_ABORT;
3450 #if defined(PERL_IMPLICIT_CONTEXT)
3455 if (p->type) { /* type=1 has old buffer, dispose */
3456 if (p->shut_on_empty) {
3457 _ckvmssts_noperl(lib$free_vm(&n, &b));
3459 _ckvmssts_noperl(lib$insqhi(b, &p->free));
3464 iss = lib$remqti(&p->wait, &b);
3465 if (iss == LIB$_QUEWASEMP) {
3466 if (p->shut_on_empty) {
3468 _ckvmssts_noperl(sys$dassgn(p->chan_out));
3469 *p->pipe_done = TRUE;
3470 _ckvmssts_noperl(sys$setef(pipe_ef));
3472 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEOF,
3473 &p->iosb2, pipe_tochild2_ast, p, 0, 0, 0, 0, 0, 0));
3477 p->need_wake = TRUE;
3480 _ckvmssts_noperl(iss);
3487 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEOF,
3488 &p->iosb2, pipe_tochild2_ast, p, 0, 0, 0, 0, 0, 0));
3490 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEVBLK,
3491 &p->iosb2, pipe_tochild2_ast, p, b->buf, b->size, 0, 0, 0, 0));
3500 pipe_infromchild_setup(pTHX_ char *rmbx, char *wmbx)
3503 char mbx1[64], mbx2[64];
3504 struct dsc$descriptor_s d_mbx1 = {sizeof mbx1, DSC$K_DTYPE_T,
3505 DSC$K_CLASS_S, mbx1},
3506 d_mbx2 = {sizeof mbx2, DSC$K_DTYPE_T,
3507 DSC$K_CLASS_S, mbx2};
3508 unsigned int dviitm = DVI$_DEVBUFSIZ;
3510 int n = sizeof(Pipe);
3511 _ckvmssts_noperl(lib$get_vm(&n, &p));
3512 create_mbx(&p->chan_in , &d_mbx1);
3513 create_mbx(&p->chan_out, &d_mbx2);
3515 _ckvmssts_noperl(lib$getdvi(&dviitm, &p->chan_in, 0, &p->bufsize));
3516 n = p->bufsize * sizeof(char);
3517 _ckvmssts_noperl(lib$get_vm(&n, &p->buf));
3518 p->shut_on_empty = FALSE;
3521 p->iosb.status = SS$_NORMAL;
3522 #if defined(PERL_IMPLICIT_CONTEXT)
3525 pipe_infromchild_ast(p);
3533 pipe_infromchild_ast(pPipe p)
3535 int iss = p->iosb.status;
3536 int eof = (iss == SS$_ENDOFFILE);
3537 int myeof = (eof && (p->iosb.dvispec == mypid || p->iosb.dvispec == 0));
3538 int kideof = (eof && (p->iosb.dvispec == p->info->pid));
3539 #if defined(PERL_IMPLICIT_CONTEXT)
3543 if (p->info && p->info->closing && p->chan_out) { /* output shutdown */
3544 _ckvmssts_noperl(sys$dassgn(p->chan_out));
3549 input shutdown if EOF from self (done or shut_on_empty)
3550 output shutdown if closing flag set (my_pclose)
3551 send data/eof from child or eof from self
3552 otherwise, re-read (snarf of data from child)
3557 if (myeof && p->chan_in) { /* input shutdown */
3558 _ckvmssts_noperl(sys$dassgn(p->chan_in));
3563 if (myeof || kideof) { /* pass EOF to parent */
3564 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEOF, &p->iosb,
3565 pipe_infromchild_ast, p,
3568 } else if (eof) { /* eat EOF --- fall through to read*/
3570 } else { /* transmit data */
3571 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEVBLK,&p->iosb,
3572 pipe_infromchild_ast,p,
3573 p->buf, p->iosb.count, 0, 0, 0, 0));
3579 /* everything shut? flag as done */
3581 if (!p->chan_in && !p->chan_out) {
3582 *p->pipe_done = TRUE;
3583 _ckvmssts_noperl(sys$setef(pipe_ef));
3587 /* write completed (or read, if snarfing from child)
3588 if still have input active,
3589 queue read...immediate mode if shut_on_empty so we get EOF if empty
3591 check if Perl reading, generate EOFs as needed
3597 iss = sys$qio(0,p->chan_in,IO$_READVBLK|(p->shut_on_empty ? IO$M_NOW : 0),&p->iosb,
3598 pipe_infromchild_ast,p,
3599 p->buf, p->bufsize, 0, 0, 0, 0);
3600 if (p->shut_on_empty && iss == SS$_ENDOFFILE) iss = SS$_NORMAL;
3601 _ckvmssts_noperl(iss);
3602 } else { /* send EOFs for extra reads */
3603 p->iosb.status = SS$_ENDOFFILE;
3604 p->iosb.dvispec = 0;
3605 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_SETMODE|IO$M_READATTN,
3607 pipe_infromchild_ast, p, 0, 0, 0, 0));
3613 pipe_mbxtofd_setup(pTHX_ int fd, char *out)
3617 unsigned long dviitm = DVI$_DEVBUFSIZ;
3619 struct dsc$descriptor_s d_mbx = {sizeof mbx, DSC$K_DTYPE_T,
3620 DSC$K_CLASS_S, mbx};
3621 int n = sizeof(Pipe);
3623 /* things like terminals and mbx's don't need this filter */
3624 if (fd && fstat(fd,&s) == 0) {
3625 unsigned long dviitm = DVI$_DEVCHAR, devchar;
3627 unsigned short dev_len;
3628 struct dsc$descriptor_s d_dev;
3630 struct item_list_3 items[3];
3632 unsigned short dvi_iosb[4];
3634 cptr = getname(fd, out, 1);
3635 if (cptr == NULL) _ckvmssts_noperl(SS$_NOSUCHDEV);
3636 d_dev.dsc$a_pointer = out;
3637 d_dev.dsc$w_length = strlen(out);
3638 d_dev.dsc$b_dtype = DSC$K_DTYPE_T;
3639 d_dev.dsc$b_class = DSC$K_CLASS_S;
3642 items[0].code = DVI$_DEVCHAR;
3643 items[0].bufadr = &devchar;
3644 items[0].retadr = NULL;
3646 items[1].code = DVI$_FULLDEVNAM;
3647 items[1].bufadr = device;
3648 items[1].retadr = &dev_len;
3652 status = sys$getdviw
3653 (NO_EFN, 0, &d_dev, items, dvi_iosb, NULL, NULL, NULL);
3654 _ckvmssts_noperl(status);
3655 if ($VMS_STATUS_SUCCESS(dvi_iosb[0])) {
3656 device[dev_len] = 0;
3658 if (!(devchar & DEV$M_DIR)) {
3659 strcpy(out, device);
3665 _ckvmssts_noperl(lib$get_vm(&n, &p));
3666 p->fd_out = dup(fd);
3667 create_mbx(&p->chan_in, &d_mbx);
3668 _ckvmssts_noperl(lib$getdvi(&dviitm, &p->chan_in, 0, &p->bufsize));
3669 n = (p->bufsize+1) * sizeof(char);
3670 _ckvmssts_noperl(lib$get_vm(&n, &p->buf));
3671 p->shut_on_empty = FALSE;
3676 _ckvmssts_noperl(sys$qio(0, p->chan_in, IO$_READVBLK, &p->iosb,
3677 pipe_mbxtofd_ast, p,
3678 p->buf, p->bufsize, 0, 0, 0, 0));
3684 pipe_mbxtofd_ast(pPipe p)
3686 int iss = p->iosb.status;
3687 int done = p->info->done;
3689 int eof = (iss == SS$_ENDOFFILE);
3690 int myeof = eof && ((p->iosb.dvispec == mypid)||(p->iosb.dvispec == 0));
3691 int err = !(iss&1) && !eof;
3692 #if defined(PERL_IMPLICIT_CONTEXT)
3696 if (done && myeof) { /* end piping */
3698 sys$dassgn(p->chan_in);
3699 *p->pipe_done = TRUE;
3700 _ckvmssts_noperl(sys$setef(pipe_ef));
3704 if (!err && !eof) { /* good data to send to file */
3705 p->buf[p->iosb.count] = '\n';
3706 iss2 = write(p->fd_out, p->buf, p->iosb.count+1);
3709 if (p->retry < MAX_RETRY) {
3710 _ckvmssts_noperl(sys$setimr(0,delaytime,pipe_mbxtofd_ast,p));
3716 _ckvmssts_noperl(iss);
3720 iss = sys$qio(0, p->chan_in, IO$_READVBLK|(p->shut_on_empty ? IO$M_NOW : 0), &p->iosb,
3721 pipe_mbxtofd_ast, p,
3722 p->buf, p->bufsize, 0, 0, 0, 0);
3723 if (p->shut_on_empty && (iss == SS$_ENDOFFILE)) iss = SS$_NORMAL;
3724 _ckvmssts_noperl(iss);
3728 typedef struct _pipeloc PLOC;
3729 typedef struct _pipeloc* pPLOC;
3733 char dir[NAM$C_MAXRSS+1];
3735 static pPLOC head_PLOC = 0;
3738 free_pipelocs(pTHX_ void *head)
3741 pPLOC *pHead = (pPLOC *)head;
3753 store_pipelocs(pTHX)
3762 char temp[NAM$C_MAXRSS+1];
3766 free_pipelocs(aTHX_ &head_PLOC);
3768 /* the . directory from @INC comes last */
3770 p = (pPLOC) PerlMem_malloc(sizeof(PLOC));
3771 if (p == NULL) _ckvmssts_noperl(SS$_INSFMEM);
3772 p->next = head_PLOC;
3774 strcpy(p->dir,"./");
3776 /* get the directory from $^X */
3778 unixdir = PerlMem_malloc(VMS_MAXRSS);
3779 if (unixdir == NULL) _ckvmssts_noperl(SS$_INSFMEM);
3781 #ifdef PERL_IMPLICIT_CONTEXT
3782 if (aTHX && PL_origargv && PL_origargv[0]) { /* maybe nul if embedded Perl */
3784 if (PL_origargv && PL_origargv[0]) { /* maybe nul if embedded Perl */
3786 strcpy(temp, PL_origargv[0]);
3787 x = strrchr(temp,']');
3789 x = strrchr(temp,'>');
3791 /* It could be a UNIX path */
3792 x = strrchr(temp,'/');
3798 /* Got a bare name, so use default directory */
3803 if ((tounixpath_utf8(temp, unixdir, NULL)) != NULL) {
3804 p = (pPLOC) PerlMem_malloc(sizeof(PLOC));
3805 if (p == NULL) _ckvmssts_noperl(SS$_INSFMEM);
3806 p->next = head_PLOC;
3808 strncpy(p->dir,unixdir,sizeof(p->dir)-1);
3809 p->dir[NAM$C_MAXRSS] = '\0';
3813 /* reverse order of @INC entries, skip "." since entered above */
3815 #ifdef PERL_IMPLICIT_CONTEXT
3818 if (PL_incgv) av = GvAVn(PL_incgv);
3820 for (i = 0; av && i <= AvFILL(av); i++) {
3821 dirsv = *av_fetch(av,i,TRUE);
3823 if (SvROK(dirsv)) continue;
3824 dir = SvPVx(dirsv,n_a);
3825 if (strcmp(dir,".") == 0) continue;
3826 if ((tounixpath_utf8(dir, unixdir, NULL)) == NULL)
3829 p = (pPLOC) PerlMem_malloc(sizeof(PLOC));
3830 p->next = head_PLOC;
3832 strncpy(p->dir,unixdir,sizeof(p->dir)-1);
3833 p->dir[NAM$C_MAXRSS] = '\0';
3836 /* most likely spot (ARCHLIB) put first in the list */
3839 if ((tounixpath_utf8(ARCHLIB_EXP, unixdir, NULL)) != NULL) {
3840 p = (pPLOC) PerlMem_malloc(sizeof(PLOC));
3841 if (p == NULL) _ckvmssts_noperl(SS$_INSFMEM);
3842 p->next = head_PLOC;
3844 strncpy(p->dir,unixdir,sizeof(p->dir)-1);
3845 p->dir[NAM$C_MAXRSS] = '\0';
3848 PerlMem_free(unixdir);
3852 Perl_cando_by_name_int
3853 (pTHX_ I32 bit, bool effective, const char *fname, int opts);
3854 #if !defined(PERL_IMPLICIT_CONTEXT)
3855 #define cando_by_name_int Perl_cando_by_name_int
3857 #define cando_by_name_int(a,b,c,d) Perl_cando_by_name_int(aTHX_ a,b,c,d)
3863 static int vmspipe_file_status = 0;
3864 static char vmspipe_file[NAM$C_MAXRSS+1];
3866 /* already found? Check and use ... need read+execute permission */
3868 if (vmspipe_file_status == 1) {
3869 if (cando_by_name_int(S_IRUSR, 0, vmspipe_file, PERL_RMSEXPAND_M_VMS_IN)
3870 && cando_by_name_int
3871 (S_IXUSR, 0, vmspipe_file, PERL_RMSEXPAND_M_VMS_IN)) {
3872 return vmspipe_file;
3874 vmspipe_file_status = 0;
3877 /* scan through stored @INC, $^X */
3879 if (vmspipe_file_status == 0) {
3880 char file[NAM$C_MAXRSS+1];
3881 pPLOC p = head_PLOC;
3886 strcpy(file, p->dir);
3887 dirlen = strlen(file);
3888 strncat(file, "vmspipe.com",NAM$C_MAXRSS - dirlen);
3889 file[NAM$C_MAXRSS] = '\0';
3892 exp_res = int_rmsexpand_tovms(file, vmspipe_file, 0);
3893 if (!exp_res) continue;
3895 if (cando_by_name_int
3896 (S_IRUSR, 0, vmspipe_file, PERL_RMSEXPAND_M_VMS_IN)
3897 && cando_by_name_int
3898 (S_IXUSR, 0, vmspipe_file, PERL_RMSEXPAND_M_VMS_IN)) {
3899 vmspipe_file_status = 1;
3900 return vmspipe_file;
3903 vmspipe_file_status = -1; /* failed, use tempfiles */
3910 vmspipe_tempfile(pTHX)
3912 char file[NAM$C_MAXRSS+1];
3914 static int index = 0;
3918 /* create a tempfile */
3920 /* we can't go from W, shr=get to R, shr=get without
3921 an intermediate vulnerable state, so don't bother trying...
3923 and lib$spawn doesn't shr=put, so have to close the write
3925 So... match up the creation date/time and the FID to
3926 make sure we're dealing with the same file
3931 if (!decc_filename_unix_only) {
3932 sprintf(file,"sys$scratch:perlpipe_%08.8x_%d.com",mypid,index);
3933 fp = fopen(file,"w");
3935 sprintf(file,"sys$login:perlpipe_%08.8x_%d.com",mypid,index);
3936 fp = fopen(file,"w");
3938 sprintf(file,"sys$disk:[]perlpipe_%08.8x_%d.com",mypid,index);
3939 fp = fopen(file,"w");
3944 sprintf(file,"/tmp/perlpipe_%08.8x_%d.com",mypid,index);
3945 fp = fopen(file,"w");
3947 sprintf(file,"/sys$login/perlpipe_%08.8x_%d.com",mypid,index);
3948 fp = fopen(file,"w");
3950 sprintf(file,"./perlpipe_%08.8x_%d.com",mypid,index);
3951 fp = fopen(file,"w");
3955 if (!fp) return 0; /* we're hosed */
3957 fprintf(fp,"$! 'f$verify(0)'\n");
3958 fprintf(fp,"$! --- protect against nonstandard definitions ---\n");
3959 fprintf(fp,"$ perl_cfile = f$environment(\"procedure\")\n");
3960 fprintf(fp,"$ perl_define = \"define/nolog\"\n");
3961 fprintf(fp,"$ perl_on = \"set noon\"\n");
3962 fprintf(fp,"$ perl_exit = \"exit\"\n");
3963 fprintf(fp,"$ perl_del = \"delete\"\n");
3964 fprintf(fp,"$ pif = \"if\"\n");
3965 fprintf(fp,"$! --- define i/o redirection (sys$output set by lib$spawn)\n");
3966 fprintf(fp,"$ pif perl_popen_in .nes. \"\" then perl_define/user/name_attributes=confine sys$input 'perl_popen_in'\n");
3967 fprintf(fp,"$ pif perl_popen_err .nes. \"\" then perl_define/user/name_attributes=confine sys$error 'perl_popen_err'\n");
3968 fprintf(fp,"$ pif perl_popen_out .nes. \"\" then perl_define sys$output 'perl_popen_out'\n");
3969 fprintf(fp,"$! --- build command line to get max possible length\n");
3970 fprintf(fp,"$c=perl_popen_cmd0\n");
3971 fprintf(fp,"$c=c+perl_popen_cmd1\n");
3972 fprintf(fp,"$c=c+perl_popen_cmd2\n");
3973 fprintf(fp,"$x=perl_popen_cmd3\n");
3974 fprintf(fp,"$c=c+x\n");
3975 fprintf(fp,"$ perl_on\n");
3976 fprintf(fp,"$ 'c'\n");
3977 fprintf(fp,"$ perl_status = $STATUS\n");
3978 fprintf(fp,"$ perl_del 'perl_cfile'\n");
3979 fprintf(fp,"$ perl_exit 'perl_status'\n");
3982 fgetname(fp, file, 1);
3983 fstat(fileno(fp), &s0.crtl_stat);
3986 if (decc_filename_unix_only)
3987 int_tounixspec(file, file, NULL);
3988 fp = fopen(file,"r","shr=get");
3990 fstat(fileno(fp), &s1.crtl_stat);
3992 cmp_result = VMS_INO_T_COMPARE(s0.crtl_stat.st_ino, s1.crtl_stat.st_ino);
3993 if ((cmp_result != 0) && (s0.st_ctime != s1.st_ctime)) {
4002 static int vms_is_syscommand_xterm(void)
4004 const static struct dsc$descriptor_s syscommand_dsc =
4005 { 11, DSC$K_DTYPE_T, DSC$K_CLASS_S, "SYS$COMMAND" };
4007 const static struct dsc$descriptor_s decwdisplay_dsc =
4008 { 12, DSC$K_DTYPE_T, DSC$K_CLASS_S, "DECW$DISPLAY" };
4010 struct item_list_3 items[2];
4011 unsigned short dvi_iosb[4];
4012 unsigned long devchar;
4013 unsigned long devclass;
4016 /* Very simple check to guess if sys$command is a decterm? */
4017 /* First see if the DECW$DISPLAY: device exists */
4019 items[0].code = DVI$_DEVCHAR;
4020 items[0].bufadr = &devchar;
4021 items[0].retadr = NULL;
4025 status = sys$getdviw
4026 (NO_EFN, 0, &decwdisplay_dsc, items, dvi_iosb, NULL, NULL, NULL);
4028 if ($VMS_STATUS_SUCCESS(status)) {
4029 status = dvi_iosb[0];
4032 if (!$VMS_STATUS_SUCCESS(status)) {
4033 SETERRNO(EVMSERR, status);
4037 /* If it does, then for now assume that we are on a workstation */
4038 /* Now verify that SYS$COMMAND is a terminal */
4039 /* for creating the debugger DECTerm */
4042 items[0].code = DVI$_DEVCLASS;
4043 items[0].bufadr = &devclass;
4044 items[0].retadr = NULL;
4048 status = sys$getdviw
4049 (NO_EFN, 0, &syscommand_dsc, items, dvi_iosb, NULL, NULL, NULL);
4051 if ($VMS_STATUS_SUCCESS(status)) {
4052 status = dvi_iosb[0];
4055 if (!$VMS_STATUS_SUCCESS(status)) {
4056 SETERRNO(EVMSERR, status);
4060 if (devclass == DC$_TERM) {
4067 /* If we are on a DECTerm, we can pretend to fork xterms when requested */
4068 static PerlIO * create_forked_xterm(pTHX_ const char *cmd, const char *mode)
4073 char device_name[65];
4074 unsigned short device_name_len;
4075 struct dsc$descriptor_s customization_dsc;
4076 struct dsc$descriptor_s device_name_dsc;
4079 char customization[200];
4083 unsigned short p_chan;
4085 unsigned short iosb[4];
4086 struct item_list_3 items[2];
4087 const char * cust_str =
4088 "DECW$TERMINAL.iconName:\tPerl Dbg\nDECW$TERMINAL.title:\t%40s\n";
4089 struct dsc$descriptor_s d_mbx1 = {sizeof mbx1, DSC$K_DTYPE_T,
4090 DSC$K_CLASS_S, mbx1};
4092 /* LIB$FIND_IMAGE_SIGNAL needs a handler */
4093 /*---------------------------------------*/
4094 VAXC$ESTABLISH((__vms_handler)lib$sig_to_ret);
4097 /* Make sure that this is from the Perl debugger */
4098 ret_char = strstr(cmd," xterm ");
4099 if (ret_char == NULL)
4101 cptr = ret_char + 7;
4102 ret_char = strstr(cmd,"tty");
4103 if (ret_char == NULL)
4105 ret_char = strstr(cmd,"sleep");
4106 if (ret_char == NULL)
4109 if (decw_term_port == 0) {
4110 $DESCRIPTOR(filename1_dsc, "DECW$TERMINALSHR12");
4111 $DESCRIPTOR(filename2_dsc, "DECW$TERMINALSHR");
4112 $DESCRIPTOR(decw_term_port_dsc, "DECW$TERM_PORT");
4114 status = lib$find_image_symbol
4116 &decw_term_port_dsc,
4117 (void *)&decw_term_port,
4121 /* Try again with the other image name */
4122 if (!$VMS_STATUS_SUCCESS(status)) {
4124 status = lib$find_image_symbol
4126 &decw_term_port_dsc,
4127 (void *)&decw_term_port,
4136 /* No decw$term_port, give it up */
4137 if (!$VMS_STATUS_SUCCESS(status))
4140 /* Are we on a workstation? */
4141 /* to do: capture the rows / columns and pass their properties */
4142 ret_stat = vms_is_syscommand_xterm();
4146 /* Make the title: */
4147 ret_char = strstr(cptr,"-title");
4148 if (ret_char != NULL) {
4149 while ((*cptr != 0) && (*cptr != '\"')) {
4155 while ((*cptr != 0) && (*cptr != '\"')) {
4168 strcpy(title,"Perl Debug DECTerm");
4170 sprintf(customization, cust_str, title);
4172 customization_dsc.dsc$a_pointer = customization;
4173 customization_dsc.dsc$w_length = strlen(customization);
4174 customization_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
4175 customization_dsc.dsc$b_class = DSC$K_CLASS_S;
4177 device_name_dsc.dsc$a_pointer = device_name;
4178 device_name_dsc.dsc$w_length = sizeof device_name -1;
4179 device_name_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
4180 device_name_dsc.dsc$b_class = DSC$K_CLASS_S;
4182 device_name_len = 0;
4184 /* Try to create the window */
4185 status = (*decw_term_port)
4194 if (!$VMS_STATUS_SUCCESS(status)) {
4195 SETERRNO(EVMSERR, status);
4199 device_name[device_name_len] = '\0';
4201 /* Need to set this up to look like a pipe for cleanup */
4203 status = lib$get_vm(&n, &info);
4204 if (!$VMS_STATUS_SUCCESS(status)) {
4205 SETERRNO(ENOMEM, status);
4211 info->completion = 0;
4212 info->closing = FALSE;
4219 info->in_done = TRUE;
4220 info->out_done = TRUE;
4221 info->err_done = TRUE;
4223 /* Assign a channel on this so that it will persist, and not login */
4224 /* We stash this channel in the info structure for reference. */
4225 /* The created xterm self destructs when the last channel is removed */
4226 /* and it appears that perl5db.pl (perl debugger) does this routinely */
4227 /* So leave this assigned. */
4228 device_name_dsc.dsc$w_length = device_name_len;
4229 status = sys$assign(&device_name_dsc,&info->xchan,0,0);
4230 if (!$VMS_STATUS_SUCCESS(status)) {
4231 SETERRNO(EVMSERR, status);
4234 info->xchan_valid = 1;
4236 /* Now create a mailbox to be read by the application */
4238 create_mbx(&p_chan, &d_mbx1);
4240 /* write the name of the created terminal to the mailbox */
4241 status = sys$qiow(NO_EFN, p_chan, IO$_WRITEVBLK|IO$M_NOW,
4242 iosb, NULL, NULL, device_name, device_name_len, 0, 0, 0, 0);
4244 if (!$VMS_STATUS_SUCCESS(status)) {
4245 SETERRNO(EVMSERR, status);
4249 info->fp = PerlIO_open(mbx1, mode);
4251 /* Done with this channel */
4254 /* If any errors, then clean up */
4257 _ckvmssts_noperl(lib$free_vm(&n, &info));
4265 static I32 my_pclose_pinfo(pTHX_ pInfo info);
4268 safe_popen(pTHX_ const char *cmd, const char *in_mode, int *psts)
4270 static int handler_set_up = FALSE;
4272 unsigned long int sts, flags = CLI$M_NOWAIT;
4273 /* The use of a GLOBAL table (as was done previously) rendered
4274 * Perl's qx() or `` unusable from a C<$ SET SYMBOL/SCOPE=NOGLOBAL> DCL
4275 * environment. Hence we've switched to LOCAL symbol table.
4277 unsigned int table = LIB$K_CLI_LOCAL_SYM;
4279 char *p, mode[10], symbol[MAX_DCL_SYMBOL+1], *vmspipe;
4280 char *in, *out, *err, mbx[512];
4282 char tfilebuf[NAM$C_MAXRSS+1];
4284 char cmd_sym_name[20];
4285 struct dsc$descriptor_s d_symbol= {0, DSC$K_DTYPE_T,
4286 DSC$K_CLASS_S, symbol};
4287 struct dsc$descriptor_s vmspipedsc = {0, DSC$K_DTYPE_T,
4289 struct dsc$descriptor_s d_sym_cmd = {0, DSC$K_DTYPE_T,
4290 DSC$K_CLASS_S, cmd_sym_name};
4291 struct dsc$descriptor_s *vmscmd;
4292 $DESCRIPTOR(d_sym_in ,"PERL_POPEN_IN");
4293 $DESCRIPTOR(d_sym_out,"PERL_POPEN_OUT");
4294 $DESCRIPTOR(d_sym_err,"PERL_POPEN_ERR");
4296 /* Check here for Xterm create request. This means looking for
4297 * "3>&1 xterm\b" and "\btty 1>&3\b$" in the command, and that it
4298 * is possible to create an xterm.
4300 if (*in_mode == 'r') {
4303 #if defined(PERL_IMPLICIT_CONTEXT)
4304 /* Can not fork an xterm with a NULL context */
4305 /* This probably could never happen */
4309 xterm_fd = create_forked_xterm(aTHX_ cmd, in_mode);
4310 if (xterm_fd != NULL)
4314 if (!head_PLOC) store_pipelocs(aTHX); /* at least TRY to use a static vmspipe file */
4316 /* once-per-program initialization...
4317 note that the SETAST calls and the dual test of pipe_ef
4318 makes sure that only the FIRST thread through here does
4319 the initialization...all other threads wait until it's
4322 Yeah, uglier than a pthread call, it's got all the stuff inline
4323 rather than in a separate routine.
4327 _ckvmssts_noperl(sys$setast(0));
4329 unsigned long int pidcode = JPI$_PID;
4330 $DESCRIPTOR(d_delay, RETRY_DELAY);
4331 _ckvmssts_noperl(lib$get_ef(&pipe_ef));
4332 _ckvmssts_noperl(lib$getjpi(&pidcode,0,0,&mypid,0,0));
4333 _ckvmssts_noperl(sys$bintim(&d_delay, delaytime));
4335 if (!handler_set_up) {
4336 _ckvmssts_noperl(sys$dclexh(&pipe_exitblock));
4337 handler_set_up = TRUE;
4339 _ckvmssts_noperl(sys$setast(1));
4342 /* see if we can find a VMSPIPE.COM */
4345 vmspipe = find_vmspipe(aTHX);
4347 strcpy(tfilebuf+1,vmspipe);
4348 } else { /* uh, oh...we're in tempfile hell */
4349 tpipe = vmspipe_tempfile(aTHX);
4350 if (!tpipe) { /* a fish popular in Boston */
4351 if (ckWARN(WARN_PIPE)) {
4352 Perl_warner(aTHX_ packWARN(WARN_PIPE),"unable to find VMSPIPE.COM for i/o piping");
4356 fgetname(tpipe,tfilebuf+1,1);
4358 vmspipedsc.dsc$a_pointer = tfilebuf;
4359 vmspipedsc.dsc$w_length = strlen(tfilebuf);
4361 sts = setup_cmddsc(aTHX_ cmd,0,0,&vmscmd);
4364 case RMS$_FNF: case RMS$_DNF:
4365 set_errno(ENOENT); break;
4367 set_errno(ENOTDIR); break;
4369 set_errno(ENODEV); break;
4371 set_errno(EACCES); break;
4373 set_errno(EINVAL); break;
4374 case CLI$_BUFOVF: case RMS$_RTB: case CLI$_TKNOVF: case CLI$_RSLOVF:
4375 set_errno(E2BIG); break;
4376 case LIB$_INVARG: case LIB$_INVSTRDES: case SS$_ACCVIO: /* shouldn't happen */
4377 _ckvmssts_noperl(sts); /* fall through */
4378 default: /* SS$_DUPLNAM, SS$_CLI, resource exhaustion, etc. */
4381 set_vaxc_errno(sts);
4382 if (*in_mode != 'n' && ckWARN(WARN_PIPE)) {
4383 Perl_warner(aTHX_ packWARN(WARN_PIPE),"Can't pipe \"%*s\": %s", strlen(cmd), cmd, Strerror(errno));
4389 _ckvmssts_noperl(lib$get_vm(&n, &info));
4391 strcpy(mode,in_mode);
4394 info->completion = 0;
4395 info->closing = FALSE;
4402 info->in_done = TRUE;
4403 info->out_done = TRUE;
4404 info->err_done = TRUE;
4406 info->xchan_valid = 0;
4408 in = PerlMem_malloc(VMS_MAXRSS);
4409 if (in == NULL) _ckvmssts_noperl(SS$_INSFMEM);
4410 out = PerlMem_malloc(VMS_MAXRSS);
4411 if (out == NULL) _ckvmssts_noperl(SS$_INSFMEM);
4412 err = PerlMem_malloc(VMS_MAXRSS);
4413 if (err == NULL) _ckvmssts_noperl(SS$_INSFMEM);
4415 in[0] = out[0] = err[0] = '\0';
4417 if ((p = strchr(mode,'F')) != NULL) { /* F -> use FILE* */
4421 if ((p = strchr(mode,'W')) != NULL) { /* W -> wait for completion */
4426 if (*mode == 'r') { /* piping from subroutine */
4428 info->out = pipe_infromchild_setup(aTHX_ mbx,out);
4430 info->out->pipe_done = &info->out_done;
4431 info->out_done = FALSE;
4432 info->out->info = info;
4434 if (!info->useFILE) {
4435 info->fp = PerlIO_open(mbx, mode);
4437 info->fp = (PerlIO *) freopen(mbx, mode, stdin);
4438 Perl_vmssetuserlnm(aTHX_ "SYS$INPUT",mbx);
4441 if (!info->fp && info->out) {
4442 sys$cancel(info->out->chan_out);
4444 while (!info->out_done) {
4446 _ckvmssts_noperl(sys$setast(0));
4447 done = info->out_done;
4448 if (!done) _ckvmssts_noperl(sys$clref(pipe_ef));
4449 _ckvmssts_noperl(sys$setast(1));
4450 if (!done) _ckvmssts_noperl(sys$waitfr(pipe_ef));
4453 if (info->out->buf) {
4454 n = info->out->bufsize * sizeof(char);
4455 _ckvmssts_noperl(lib$free_vm(&n, &info->out->buf));
4458 _ckvmssts_noperl(lib$free_vm(&n, &info->out));
4460 _ckvmssts_noperl(lib$free_vm(&n, &info));
4465 info->err = pipe_mbxtofd_setup(aTHX_ fileno(stderr), err);
4467 info->err->pipe_done = &info->err_done;
4468 info->err_done = FALSE;
4469 info->err->info = info;
4472 } else if (*mode == 'w') { /* piping to subroutine */
4474 info->out = pipe_mbxtofd_setup(aTHX_ fileno(stdout), out);
4476 info->out->pipe_done = &info->out_done;
4477 info->out_done = FALSE;
4478 info->out->info = info;
4481 info->err = pipe_mbxtofd_setup(aTHX_ fileno(stderr), err);
4483 info->err->pipe_done = &info->err_done;
4484 info->err_done = FALSE;
4485 info->err->info = info;
4488 info->in = pipe_tochild_setup(aTHX_ in,mbx);
4489 if (!info->useFILE) {
4490 info->fp = PerlIO_open(mbx, mode);
4492 info->fp = (PerlIO *) freopen(mbx, mode, stdout);
4493 Perl_vmssetuserlnm(aTHX_ "SYS$OUTPUT",mbx);
4497 info->in->pipe_done = &info->in_done;
4498 info->in_done = FALSE;
4499 info->in->info = info;
4503 if (!info->fp && info->in) {
4505 _ckvmssts_noperl(sys$qiow(0,info->in->chan_in, IO$_WRITEOF, 0,
4506 0, 0, 0, 0, 0, 0, 0, 0));
4508 while (!info->in_done) {
4510 _ckvmssts_noperl(sys$setast(0));
4511 done = info->in_done;
4512 if (!done) _ckvmssts_noperl(sys$clref(pipe_ef));
4513 _ckvmssts_noperl(sys$setast(1));
4514 if (!done) _ckvmssts_noperl(sys$waitfr(pipe_ef));
4517 if (info->in->buf) {
4518 n = info->in->bufsize * sizeof(char);
4519 _ckvmssts_noperl(lib$free_vm(&n, &info->in->buf));
4522 _ckvmssts_noperl(lib$free_vm(&n, &info->in));
4524 _ckvmssts_noperl(lib$free_vm(&n, &info));
4530 } else if (*mode == 'n') { /* separate subprocess, no Perl i/o */
4531 info->out = pipe_mbxtofd_setup(aTHX_ fileno(stdout), out);
4533 info->out->pipe_done = &info->out_done;
4534 info->out_done = FALSE;
4535 info->out->info = info;
4538 info->err = pipe_mbxtofd_setup(aTHX_ fileno(stderr), err);
4540 info->err->pipe_done = &info->err_done;
4541 info->err_done = FALSE;
4542 info->err->info = info;
4546 symbol[MAX_DCL_SYMBOL] = '\0';
4548 strncpy(symbol, in, MAX_DCL_SYMBOL);
4549 d_symbol.dsc$w_length = strlen(symbol);
4550 _ckvmssts_noperl(lib$set_symbol(&d_sym_in, &d_symbol, &table));
4552 strncpy(symbol, err, MAX_DCL_SYMBOL);
4553 d_symbol.dsc$w_length = strlen(symbol);
4554 _ckvmssts_noperl(lib$set_symbol(&d_sym_err, &d_symbol, &table));
4556 strncpy(symbol, out, MAX_DCL_SYMBOL);
4557 d_symbol.dsc$w_length = strlen(symbol);
4558 _ckvmssts_noperl(lib$set_symbol(&d_sym_out, &d_symbol, &table));
4560 /* Done with the names for the pipes */
4565 p = vmscmd->dsc$a_pointer;
4566 while (*p == ' ' || *p == '\t') p++; /* remove leading whitespace */
4567 if (*p == '$') p++; /* remove leading $ */
4568 while (*p == ' ' || *p == '\t') p++;
4570 for (j = 0; j < 4; j++) {
4571 sprintf(cmd_sym_name,"PERL_POPEN_CMD%d",j);
4572 d_sym_cmd.dsc$w_length = strlen(cmd_sym_name);
4574 strncpy(symbol, p, MAX_DCL_SYMBOL);
4575 d_symbol.dsc$w_length = strlen(symbol);
4576 _ckvmssts_noperl(lib$set_symbol(&d_sym_cmd, &d_symbol, &table));
4578 if (strlen(p) > MAX_DCL_SYMBOL) {
4579 p += MAX_DCL_SYMBOL;
4584 _ckvmssts_noperl(sys$setast(0));
4585 info->next=open_pipes; /* prepend to list */
4587 _ckvmssts_noperl(sys$setast(1));
4588 /* Omit arg 2 (input file) so the child will get the parent's SYS$INPUT
4589 * and SYS$COMMAND. vmspipe.com will redefine SYS$INPUT, but we'll still
4590 * have SYS$COMMAND if we need it.
4592 _ckvmssts_noperl(lib$spawn(&vmspipedsc, 0, &nl_desc, &flags,
4593 0, &info->pid, &info->completion,
4594 0, popen_completion_ast,info,0,0,0));
4596 /* if we were using a tempfile, close it now */
4598 if (tpipe) fclose(tpipe);
4600 /* once the subprocess is spawned, it has copied the symbols and
4601 we can get rid of ours */
4603 for (j = 0; j < 4; j++) {
4604 sprintf(cmd_sym_name,"PERL_POPEN_CMD%d",j);
4605 d_sym_cmd.dsc$w_length = strlen(cmd_sym_name);
4606 _ckvmssts_noperl(lib$delete_symbol(&d_sym_cmd, &table));
4608 _ckvmssts_noperl(lib$delete_symbol(&d_sym_in, &table));
4609 _ckvmssts_noperl(lib$delete_symbol(&d_sym_err, &table));
4610 _ckvmssts_noperl(lib$delete_symbol(&d_sym_out, &table));
4611 vms_execfree(vmscmd);
4613 #ifdef PERL_IMPLICIT_CONTEXT
4616 PL_forkprocess = info->pid;
4623 _ckvmssts_noperl(sys$setast(0));
4625 if (!done) _ckvmssts_noperl(sys$clref(pipe_ef));
4626 _ckvmssts_noperl(sys$setast(1));
4627 if (!done) _ckvmssts_noperl(sys$waitfr(pipe_ef));
4629 *psts = info->completion;
4630 /* Caller thinks it is open and tries to close it. */
4631 /* This causes some problems, as it changes the error status */
4632 /* my_pclose(info->fp); */
4634 /* If we did not have a file pointer open, then we have to */
4635 /* clean up here or eventually we will run out of something */
4637 if (info->fp == NULL) {
4638 my_pclose_pinfo(aTHX_ info);
4646 } /* end of safe_popen */
4649 /*{{{ PerlIO *my_popen(char *cmd, char *mode)*/
4651 Perl_my_popen(pTHX_ const char *cmd, const char *mode)
4655 TAINT_PROPER("popen");
4656 PERL_FLUSHALL_FOR_CHILD;
4657 return safe_popen(aTHX_ cmd,mode,&sts);
4663 /* Routine to close and cleanup a pipe info structure */
4665 static I32 my_pclose_pinfo(pTHX_ pInfo info) {
4667 unsigned long int retsts;
4672 /* If we were writing to a subprocess, insure that someone reading from
4673 * the mailbox gets an EOF. It looks like a simple fclose() doesn't
4674 * produce an EOF record in the mailbox.
4676 * well, at least sometimes it *does*, so we have to watch out for
4677 * the first EOF closing the pipe (and DASSGN'ing the channel)...
4681 #if defined(USE_ITHREADS)
4684 && PL_perlio_fd_refcnt)
4685 PerlIO_flush(info->fp);
4687 fflush((FILE *)info->fp);
4690 _ckvmssts(sys$setast(0));
4691 info->closing = TRUE;
4692 done = info->done && info->in_done && info->out_done && info->err_done;
4693 /* hanging on write to Perl's input? cancel it */
4694 if (info->mode == 'r' && info->out && !info->out_done) {
4695 if (info->out->chan_out) {
4696 _ckvmssts(sys$cancel(info->out->chan_out));
4697 if (!info->out->chan_in) { /* EOF generation, need AST */
4698 _ckvmssts(sys$dclast(pipe_infromchild_ast,info->out,0));
4702 if (info->in && !info->in_done && !info->in->shut_on_empty) /* EOF if hasn't had one yet */
4703 _ckvmssts(sys$qio(0,info->in->chan_in,IO$_WRITEOF,0,0,0,
4705 _ckvmssts(sys$setast(1));
4708 #if defined(USE_ITHREADS)
4711 && PL_perlio_fd_refcnt)
4712 PerlIO_close(info->fp);
4714 fclose((FILE *)info->fp);
4717 we have to wait until subprocess completes, but ALSO wait until all
4718 the i/o completes...otherwise we'll be freeing the "info" structure
4719 that the i/o ASTs could still be using...
4723 _ckvmssts(sys$setast(0));
4724 done = info->done && info->in_done && info->out_done && info->err_done;
4725 if (!done) _ckvmssts(sys$clref(pipe_ef));
4726 _ckvmssts(sys$setast(1));
4727 if (!done) _ckvmssts(sys$waitfr(pipe_ef));
4729 retsts = info->completion;
4731 /* remove from list of open pipes */
4732 _ckvmssts(sys$setast(0));
4734 for (next = open_pipes; next != NULL; last = next, next = next->next) {
4740 last->next = info->next;
4742 open_pipes = info->next;
4743 _ckvmssts(sys$setast(1));
4745 /* free buffers and structures */
4748 if (info->in->buf) {
4749 n = info->in->bufsize * sizeof(char);
4750 _ckvmssts(lib$free_vm(&n, &info->in->buf));
4753 _ckvmssts(lib$free_vm(&n, &info->in));
4756 if (info->out->buf) {
4757 n = info->out->bufsize * sizeof(char);
4758 _ckvmssts(lib$free_vm(&n, &info->out->buf));
4761 _ckvmssts(lib$free_vm(&n, &info->out));
4764 if (info->err->buf) {
4765 n = info->err->bufsize * sizeof(char);
4766 _ckvmssts(lib$free_vm(&n, &info->err->buf));
4769 _ckvmssts(lib$free_vm(&n, &info->err));
4772 _ckvmssts(lib$free_vm(&n, &info));
4778 /*{{{ I32 my_pclose(PerlIO *fp)*/
4779 I32 Perl_my_pclose(pTHX_ PerlIO *fp)
4781 pInfo info, last = NULL;
4784 /* Fixme - need ast and mutex protection here */
4785 for (info = open_pipes; info != NULL; last = info, info = info->next)
4786 if (info->fp == fp) break;
4788 if (info == NULL) { /* no such pipe open */
4789 set_errno(ECHILD); /* quoth POSIX */
4790 set_vaxc_errno(SS$_NONEXPR);
4794 ret_status = my_pclose_pinfo(aTHX_ info);
4798 } /* end of my_pclose() */
4800 #if defined(__CRTL_VER) && __CRTL_VER >= 70200000
4801 /* Roll our own prototype because we want this regardless of whether
4802 * _VMS_WAIT is defined.
4804 __pid_t __vms_waitpid( __pid_t __pid, int *__stat_loc, int __options );
4806 /* sort-of waitpid; special handling of pipe clean-up for subprocesses
4807 created with popen(); otherwise partially emulate waitpid() unless
4808 we have a suitable one from the CRTL that came with VMS 7.2 and later.
4809 Also check processes not considered by the CRTL waitpid().
4811 /*{{{Pid_t my_waitpid(Pid_t pid, int *statusp, int flags)*/
4813 Perl_my_waitpid(pTHX_ Pid_t pid, int *statusp, int flags)
4820 if (statusp) *statusp = 0;
4822 for (info = open_pipes; info != NULL; info = info->next)
4823 if (info->pid == pid) break;
4825 if (info != NULL) { /* we know about this child */
4826 while (!info->done) {
4827 _ckvmssts(sys$setast(0));
4829 if (!done) _ckvmssts(sys$clref(pipe_ef));
4830 _ckvmssts(sys$setast(1));
4831 if (!done) _ckvmssts(sys$waitfr(pipe_ef));
4834 if (statusp) *statusp = info->completion;
4838 /* child that already terminated? */
4840 for (j = 0; j < NKEEPCLOSED && j < closed_num; j++) {
4841 if (closed_list[j].pid == pid) {
4842 if (statusp) *statusp = closed_list[j].completion;
4847 /* fall through if this child is not one of our own pipe children */
4849 #if defined(__CRTL_VER) && __CRTL_VER >= 70200000
4851 /* waitpid() became available in the CRTL as of VMS 7.0