3 * VMS-specific routines for perl5
5 * Copyright (C) 1993-2015 by Charles Bailey and others.
7 * You may distribute under the terms of either the GNU General Public
8 * License or the Artistic License, as specified in the README file.
12 * Yet small as was their hunted band
13 * still fell and fearless was each hand,
14 * and strong deeds they wrought yet oft,
15 * and loved the woods, whose ways more soft
16 * them seemed than thralls of that black throne
17 * to live and languish in halls of stone.
18 * "The Lay of Leithian", Canto II, lines 135-40
20 * [p.162 of _The Lays of Beleriand_]
28 #include <climsgdef.h>
38 #include <libclidef.h>
40 #include <lib$routines.h>
52 #include <str$routines.h>
58 #define NO_EFN EFN$C_ENF
62 #pragma member_alignment save
63 #pragma nomember_alignment longword
68 unsigned short * retadr;
70 #pragma member_alignment restore
72 /* Older versions of ssdef.h don't have these */
73 #ifndef SS$_INVFILFOROP
74 # define SS$_INVFILFOROP 3930
76 #ifndef SS$_NOSUCHOBJECT
77 # define SS$_NOSUCHOBJECT 2696
80 /* We implement I/O here, so we will be mixing PerlIO and stdio calls. */
81 #define PERLIO_NOT_STDIO 0
83 /* Don't replace system definitions of vfork, getenv, lstat, and stat,
84 * code below needs to get to the underlying CRTL routines. */
85 #define DONT_MASK_RTL_CALLS
89 /* Anticipating future expansion in lexical warnings . . . */
91 # define WARN_INTERNAL WARN_MISC
94 #ifdef VMS_LONGNAME_SUPPORT
95 #include <libfildef.h>
98 #if __CRTL_VER >= 80200000
106 #define lstat(_x, _y) stat(_x, _y)
109 /* Routine to create a decterm for use with the Perl debugger */
110 /* No headers, this information was found in the Programming Concepts Manual */
112 static int (*decw_term_port)
113 (const struct dsc$descriptor_s * display,
114 const struct dsc$descriptor_s * setup_file,
115 const struct dsc$descriptor_s * customization,
116 struct dsc$descriptor_s * result_device_name,
117 unsigned short * result_device_name_length,
120 void * char_change_buffer) = 0;
122 #if defined(NEED_AN_H_ERRNO)
126 #if defined(__DECC) || defined(__DECCXX)
127 #pragma member_alignment save
128 #pragma nomember_alignment longword
130 #pragma message disable misalgndmem
133 unsigned short int buflen;
134 unsigned short int itmcode;
136 unsigned short int *retlen;
139 struct filescan_itmlst_2 {
140 unsigned short length;
141 unsigned short itmcode;
146 unsigned short length;
147 char str[VMS_MAXRSS];
148 unsigned short pad; /* for longword struct alignment */
151 #if defined(__DECC) || defined(__DECCXX)
152 #pragma message restore
153 #pragma member_alignment restore
156 #define do_fileify_dirspec(a,b,c,d) mp_do_fileify_dirspec(aTHX_ a,b,c,d)
157 #define do_pathify_dirspec(a,b,c,d) mp_do_pathify_dirspec(aTHX_ a,b,c,d)
158 #define do_tovmsspec(a,b,c,d) mp_do_tovmsspec(aTHX_ a,b,c,0,d)
159 #define do_tovmspath(a,b,c,d) mp_do_tovmspath(aTHX_ a,b,c,d)
160 #define do_rmsexpand(a,b,c,d,e,f,g) mp_do_rmsexpand(aTHX_ a,b,c,d,e,f,g)
161 #define do_vms_realpath(a,b,c) mp_do_vms_realpath(aTHX_ a,b,c)
162 #define do_vms_realname(a,b,c) mp_do_vms_realname(aTHX_ a,b,c)
163 #define do_tounixspec(a,b,c,d) mp_do_tounixspec(aTHX_ a,b,c,d)
164 #define do_tounixpath(a,b,c,d) mp_do_tounixpath(aTHX_ a,b,c,d)
165 #define do_vms_case_tolerant(a) mp_do_vms_case_tolerant(a)
166 #define expand_wild_cards(a,b,c,d) mp_expand_wild_cards(aTHX_ a,b,c,d)
167 #define getredirection(a,b) mp_getredirection(aTHX_ a,b)
169 static char *mp_do_tovmspath(pTHX_ const char *path, char *buf, int ts, int *);
170 static char *mp_do_tounixpath(pTHX_ const char *path, char *buf, int ts, int *);
171 static char *mp_do_tounixspec(pTHX_ const char *, char *, int, int *);
172 static char *mp_do_pathify_dirspec(pTHX_ const char *dir,char *buf, int ts, int *);
174 static char * int_rmsexpand_vms(
175 const char * filespec, char * outbuf, unsigned opts);
176 static char * int_rmsexpand_tovms(
177 const char * filespec, char * outbuf, unsigned opts);
178 static char *int_tovmsspec
179 (const char *path, char *buf, int dir_flag, int * utf8_flag);
180 static char * int_fileify_dirspec(const char *dir, char *buf, int *utf8_fl);
181 static char * int_tounixspec(const char *spec, char *buf, int * utf8_fl);
182 static char * int_tovmspath(const char *path, char *buf, int * utf8_fl);
184 /* see system service docs for $TRNLNM -- NOT the same as LNM$_MAX_INDEX */
185 #define PERL_LNM_MAX_ALLOWED_INDEX 127
187 /* OpenVMS User's Guide says at least 9 iterative translations will be performed,
188 * depending on the facility. SHOW LOGICAL does 10, so we'll imitate that for
191 #define PERL_LNM_MAX_ITER 10
193 /* New values with 7.3-2*/ /* why does max DCL have 4 byte subtracted from it? */
194 #define MAX_DCL_SYMBOL (8192)
195 #define MAX_DCL_LINE_LENGTH (4096 - 4)
197 static char *__mystrtolower(char *str)
199 if (str) for (; *str; ++str) *str= toLOWER_L1(*str);
203 static struct dsc$descriptor_s fildevdsc =
204 { 12, DSC$K_DTYPE_T, DSC$K_CLASS_S, "LNM$FILE_DEV" };
205 static struct dsc$descriptor_s crtlenvdsc =
206 { 8, DSC$K_DTYPE_T, DSC$K_CLASS_S, "CRTL_ENV" };
207 static struct dsc$descriptor_s *fildev[] = { &fildevdsc, NULL };
208 static struct dsc$descriptor_s *defenv[] = { &fildevdsc, &crtlenvdsc, NULL };
209 static struct dsc$descriptor_s **env_tables = defenv;
210 static bool will_taint = FALSE; /* tainting active, but no PL_curinterp yet */
212 /* True if we shouldn't treat barewords as logicals during directory */
214 static int no_translate_barewords;
216 /* DECC Features that may need to affect how Perl interprets
217 * displays filename information
219 static int decc_disable_to_vms_logname_translation = 1;
220 static int decc_disable_posix_root = 1;
221 int decc_efs_case_preserve = 0;
222 static int decc_efs_charset = 0;
223 static int decc_efs_charset_index = -1;
224 static int decc_filename_unix_no_version = 0;
225 static int decc_filename_unix_only = 0;
226 int decc_filename_unix_report = 0;
227 int decc_posix_compliant_pathnames = 0;
228 int decc_readdir_dropdotnotype = 0;
229 static int vms_process_case_tolerant = 1;
230 int vms_vtf7_filenames = 0;
231 int gnv_unix_shell = 0;
232 static int vms_unlink_all_versions = 0;
233 static int vms_posix_exit = 0;
235 /* bug workarounds if needed */
236 int decc_bug_devnull = 1;
237 int vms_bug_stat_filename = 0;
239 static int vms_debug_on_exception = 0;
240 static int vms_debug_fileify = 0;
242 /* Simple logical name translation */
244 simple_trnlnm(const char * logname, char * value, int value_len)
246 const $DESCRIPTOR(table_dsc, "LNM$FILE_DEV");
247 const unsigned long attr = LNM$M_CASE_BLIND;
248 struct dsc$descriptor_s name_dsc;
250 unsigned short result;
251 struct itmlst_3 itlst[2] = {{value_len, LNM$_STRING, value, &result},
254 name_dsc.dsc$w_length = strlen(logname);
255 name_dsc.dsc$a_pointer = (char *)logname;
256 name_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
257 name_dsc.dsc$b_class = DSC$K_CLASS_S;
259 status = sys$trnlnm(&attr, &table_dsc, &name_dsc, 0, itlst);
261 if ($VMS_STATUS_SUCCESS(status)) {
263 /* Null terminate and return the string */
264 /*--------------------------------------*/
273 /* Is this a UNIX file specification?
274 * No longer a simple check with EFS file specs
275 * For now, not a full check, but need to
276 * handle POSIX ^UP^ specifications
277 * Fixing to handle ^/ cases would require
278 * changes to many other conversion routines.
282 is_unix_filespec(const char *path)
288 if (strncmp(path,"\"^UP^",5) != 0) {
289 pch1 = strchr(path, '/');
294 /* If the user wants UNIX files, "." needs to be treated as in UNIX */
295 if (decc_filename_unix_report || decc_filename_unix_only) {
296 if (strcmp(path,".") == 0)
304 /* This routine converts a UCS-2 character to be VTF-7 encoded.
308 ucs2_to_vtf7(char *outspec, unsigned long ucs2_char, int * output_cnt)
310 unsigned char * ucs_ptr;
313 ucs_ptr = (unsigned char *)&ucs2_char;
317 hex = (ucs_ptr[1] >> 4) & 0xf;
319 outspec[2] = hex + '0';
321 outspec[2] = (hex - 9) + 'A';
322 hex = ucs_ptr[1] & 0xF;
324 outspec[3] = hex + '0';
326 outspec[3] = (hex - 9) + 'A';
328 hex = (ucs_ptr[0] >> 4) & 0xf;
330 outspec[4] = hex + '0';
332 outspec[4] = (hex - 9) + 'A';
333 hex = ucs_ptr[1] & 0xF;
335 outspec[5] = hex + '0';
337 outspec[5] = (hex - 9) + 'A';
343 /* This handles the conversion of a UNIX extended character set to a ^
344 * escaped VMS character.
345 * in a UNIX file specification.
347 * The output count variable contains the number of characters added
348 * to the output string.
350 * The return value is the number of characters read from the input string
353 copy_expand_unix_filename_escape(char *outspec, const char *inspec, int *output_cnt, const int * utf8_fl)
360 utf8_flag = *utf8_fl;
364 if (*inspec >= 0x80) {
365 if (utf8_fl && vms_vtf7_filenames) {
366 unsigned long ucs_char;
370 if ((*inspec & 0xE0) == 0xC0) {
372 ucs_char = ((inspec[0] & 0x1F) << 6) + (inspec[1] & 0x3f);
373 if (ucs_char >= 0x80) {
374 ucs2_to_vtf7(outspec, ucs_char, output_cnt);
377 } else if ((*inspec & 0xF0) == 0xE0) {
379 ucs_char = ((inspec[0] & 0xF) << 12) +
380 ((inspec[1] & 0x3f) << 6) +
382 if (ucs_char >= 0x800) {
383 ucs2_to_vtf7(outspec, ucs_char, output_cnt);
387 #if 0 /* I do not see longer sequences supported by OpenVMS */
388 /* Maybe some one can fix this later */
389 } else if ((*inspec & 0xF8) == 0xF0) {
392 } else if ((*inspec & 0xFC) == 0xF8) {
395 } else if ((*inspec & 0xFE) == 0xFC) {
402 /* High bit set, but not a Unicode character! */
404 /* Non printing DECMCS or ISO Latin-1 character? */
405 if ((unsigned char)*inspec <= 0x9F) {
409 hex = (*inspec >> 4) & 0xF;
411 outspec[1] = hex + '0';
413 outspec[1] = (hex - 9) + 'A';
417 outspec[2] = hex + '0';
419 outspec[2] = (hex - 9) + 'A';
423 } else if ((unsigned char)*inspec == 0xA0) {
429 } else if ((unsigned char)*inspec == 0xFF) {
441 /* Is this a macro that needs to be passed through?
442 * Macros start with $( and an alpha character, followed
443 * by a string of alpha numeric characters ending with a )
444 * If this does not match, then encode it as ODS-5.
446 if ((inspec[0] == '$') && (inspec[1] == '(')) {
449 if (isALPHA_L1(inspec[2]) || (inspec[2] == '.') || (inspec[2] == '_')) {
451 outspec[0] = inspec[0];
452 outspec[1] = inspec[1];
453 outspec[2] = inspec[2];
455 while(isALPHA_L1(inspec[tcnt]) ||
456 (inspec[2] == '.') || (inspec[2] == '_')) {
457 outspec[tcnt] = inspec[tcnt];
460 if (inspec[tcnt] == ')') {
461 outspec[tcnt] = inspec[tcnt];
478 if (decc_efs_charset == 0)
504 /* Don't escape again if following character is
505 * already something we escape.
507 if (strchr(".!#&\'`()+@{},;[]%^=_\\", *(inspec+1))) {
513 /* But otherwise fall through and escape it. */
515 /* Assume that this is to be escaped */
517 outspec[1] = *inspec;
521 case ' ': /* space */
522 /* Assume that this is to be escaped */
538 /* This handles the expansion of a '^' prefix to the proper character
539 * in a UNIX file specification.
541 * The output count variable contains the number of characters added
542 * to the output string.
544 * The return value is the number of characters read from the input
548 copy_expand_vms_filename_escape(char *outspec, const char *inspec, int *output_cnt)
555 if (*inspec == '^') {
558 /* Spaces and non-trailing dots should just be passed through,
559 * but eat the escape character.
566 case '_': /* space */
572 /* Hmm. Better leave the escape escaped. */
578 case 'U': /* Unicode - FIX-ME this is wrong. */
581 scnt = strspn(inspec, "0123456789ABCDEFabcdef");
584 scnt = sscanf(inspec, "%2x%2x", &c1, &c2);
585 outspec[0] = c1 & 0xff;
586 outspec[1] = c2 & 0xff;
593 /* Error - do best we can to continue */
603 scnt = strspn(inspec, "0123456789ABCDEFabcdef");
607 scnt = sscanf(inspec, "%2x", &c1);
608 outspec[0] = c1 & 0xff;
629 /* vms_split_path - Verify that the input file specification is a
630 * VMS format file specification, and provide pointers to the components of
631 * it. With EFS format filenames, this is virtually the only way to
632 * parse a VMS path specification into components.
634 * If the sum of the components do not add up to the length of the
635 * string, then the passed file specification is probably a UNIX style
639 vms_split_path(const char * path, char * * volume, int * vol_len, char * * root, int * root_len,
640 char * * dir, int * dir_len, char * * name, int * name_len,
641 char * * ext, int * ext_len, char * * version, int * ver_len)
643 struct dsc$descriptor path_desc;
647 struct filescan_itmlst_2 item_list[9];
648 const int filespec = 0;
649 const int nodespec = 1;
650 const int devspec = 2;
651 const int rootspec = 3;
652 const int dirspec = 4;
653 const int namespec = 5;
654 const int typespec = 6;
655 const int verspec = 7;
657 /* Assume the worst for an easy exit */
671 path_desc.dsc$a_pointer = (char *)path; /* cast ok */
672 path_desc.dsc$w_length = strlen(path);
673 path_desc.dsc$b_dtype = DSC$K_DTYPE_T;
674 path_desc.dsc$b_class = DSC$K_CLASS_S;
676 /* Get the total length, if it is shorter than the string passed
677 * then this was probably not a VMS formatted file specification
679 item_list[filespec].itmcode = FSCN$_FILESPEC;
680 item_list[filespec].length = 0;
681 item_list[filespec].component = NULL;
683 /* If the node is present, then it gets considered as part of the
684 * volume name to hopefully make things simple.
686 item_list[nodespec].itmcode = FSCN$_NODE;
687 item_list[nodespec].length = 0;
688 item_list[nodespec].component = NULL;
690 item_list[devspec].itmcode = FSCN$_DEVICE;
691 item_list[devspec].length = 0;
692 item_list[devspec].component = NULL;
694 /* root is a special case, adding it to either the directory or
695 * the device components will probably complicate things for the
696 * callers of this routine, so leave it separate.
698 item_list[rootspec].itmcode = FSCN$_ROOT;
699 item_list[rootspec].length = 0;
700 item_list[rootspec].component = NULL;
702 item_list[dirspec].itmcode = FSCN$_DIRECTORY;
703 item_list[dirspec].length = 0;
704 item_list[dirspec].component = NULL;
706 item_list[namespec].itmcode = FSCN$_NAME;
707 item_list[namespec].length = 0;
708 item_list[namespec].component = NULL;
710 item_list[typespec].itmcode = FSCN$_TYPE;
711 item_list[typespec].length = 0;
712 item_list[typespec].component = NULL;
714 item_list[verspec].itmcode = FSCN$_VERSION;
715 item_list[verspec].length = 0;
716 item_list[verspec].component = NULL;
718 item_list[8].itmcode = 0;
719 item_list[8].length = 0;
720 item_list[8].component = NULL;
722 status = sys$filescan
723 ((const struct dsc$descriptor_s *)&path_desc, item_list,
725 _ckvmssts_noperl(status); /* All failure status values indicate a coding error */
727 /* If we parsed it successfully these two lengths should be the same */
728 if (path_desc.dsc$w_length != item_list[filespec].length)
731 /* If we got here, then it is a VMS file specification */
734 /* set the volume name */
735 if (item_list[nodespec].length > 0) {
736 *volume = item_list[nodespec].component;
737 *vol_len = item_list[nodespec].length + item_list[devspec].length;
740 *volume = item_list[devspec].component;
741 *vol_len = item_list[devspec].length;
744 *root = item_list[rootspec].component;
745 *root_len = item_list[rootspec].length;
747 *dir = item_list[dirspec].component;
748 *dir_len = item_list[dirspec].length;
750 /* Now fun with versions and EFS file specifications
751 * The parser can not tell the difference when a "." is a version
752 * delimiter or a part of the file specification.
754 if ((decc_efs_charset) &&
755 (item_list[verspec].length > 0) &&
756 (item_list[verspec].component[0] == '.')) {
757 *name = item_list[namespec].component;
758 *name_len = item_list[namespec].length + item_list[typespec].length;
759 *ext = item_list[verspec].component;
760 *ext_len = item_list[verspec].length;
765 *name = item_list[namespec].component;
766 *name_len = item_list[namespec].length;
767 *ext = item_list[typespec].component;
768 *ext_len = item_list[typespec].length;
769 *version = item_list[verspec].component;
770 *ver_len = item_list[verspec].length;
775 /* Routine to determine if the file specification ends with .dir */
777 is_dir_ext(char * e_spec, int e_len, char * vs_spec, int vs_len)
780 /* e_len must be 4, and version must be <= 2 characters */
781 if (e_len != 4 || vs_len > 2)
784 /* If a version number is present, it needs to be one */
785 if ((vs_len == 2) && (vs_spec[1] != '1'))
788 /* Look for the DIR on the extension */
789 if (vms_process_case_tolerant) {
790 if ((toUPPER_A(e_spec[1]) == 'D') &&
791 (toUPPER_A(e_spec[2]) == 'I') &&
792 (toUPPER_A(e_spec[3]) == 'R')) {
796 /* Directory extensions are supposed to be in upper case only */
797 /* I would not be surprised if this rule can not be enforced */
798 /* if and when someone fully debugs the case sensitive mode */
799 if ((e_spec[1] == 'D') &&
800 (e_spec[2] == 'I') &&
801 (e_spec[3] == 'R')) {
810 * Routine to retrieve the maximum equivalence index for an input
811 * logical name. Some calls to this routine have no knowledge if
812 * the variable is a logical or not. So on error we return a max
815 /*{{{int my_maxidx(const char *lnm) */
817 my_maxidx(const char *lnm)
821 int attr = LNM$M_CASE_BLIND;
822 struct dsc$descriptor lnmdsc;
823 struct itmlst_3 itlst[2] = {{sizeof(midx), LNM$_MAX_INDEX, &midx, 0},
826 lnmdsc.dsc$w_length = strlen(lnm);
827 lnmdsc.dsc$b_dtype = DSC$K_DTYPE_T;
828 lnmdsc.dsc$b_class = DSC$K_CLASS_S;
829 lnmdsc.dsc$a_pointer = (char *) lnm; /* Cast ok for read only parameter */
831 status = sys$trnlnm(&attr, &fildevdsc, &lnmdsc, 0, itlst);
832 if ((status & 1) == 0)
839 /* Routine to remove the 2-byte prefix from the translation of a
840 * process-permanent file (PPF).
842 static inline unsigned short int
843 S_remove_ppf_prefix(const char *lnm, char *eqv, unsigned short int eqvlen)
845 if (*((int *)lnm) == *((int *)"SYS$") &&
846 eqvlen >= 4 && eqv[0] == 0x1b && eqv[1] == 0x00 &&
847 ( (lnm[4] == 'O' && !strcmp(lnm,"SYS$OUTPUT")) ||
848 (lnm[4] == 'I' && !strcmp(lnm,"SYS$INPUT")) ||
849 (lnm[4] == 'E' && !strcmp(lnm,"SYS$ERROR")) ||
850 (lnm[4] == 'C' && !strcmp(lnm,"SYS$COMMAND")) ) ) {
852 memmove(eqv, eqv+4, eqvlen-4);
858 /*{{{int vmstrnenv(const char *lnm, char *eqv, unsigned long int idx, struct dsc$descriptor_s **tabvec, unsigned long int flags) */
860 Perl_vmstrnenv(const char *lnm, char *eqv, unsigned long int idx,
861 struct dsc$descriptor_s **tabvec, unsigned long int flags)
864 char uplnm[LNM$C_NAMLENGTH+1], *cp2;
865 unsigned short int eqvlen, curtab, ivlnm = 0, ivsym = 0, ivenv = 0, secure;
866 bool found_in_crtlenv = 0, found_in_clisym = 0;
867 unsigned long int retsts, attr = LNM$M_CASE_BLIND;
869 unsigned char acmode;
870 struct dsc$descriptor_s lnmdsc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0},
871 tmpdsc = {6,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
872 struct itmlst_3 lnmlst[3] = {{sizeof idx, LNM$_INDEX, &idx, 0},
873 {LNM$C_NAMLENGTH, LNM$_STRING, eqv, &eqvlen},
875 $DESCRIPTOR(crtlenv,"CRTL_ENV"); $DESCRIPTOR(clisym,"CLISYM");
876 #if defined(PERL_IMPLICIT_CONTEXT)
879 aTHX = PERL_GET_INTERP;
885 if (!lnm || !eqv || ((idx != 0) && ((idx-1) > PERL_LNM_MAX_ALLOWED_INDEX))) {
886 set_errno(EINVAL); set_vaxc_errno(SS$_BADPARAM); return 0;
888 for (cp1 = lnm, cp2 = uplnm; *cp1; cp1++, cp2++) {
889 *cp2 = toUPPER_A(*cp1);
890 if (cp1 - lnm > LNM$C_NAMLENGTH) {
891 set_errno(EINVAL); set_vaxc_errno(SS$_IVLOGNAM);
895 lnmdsc.dsc$w_length = cp1 - lnm;
896 lnmdsc.dsc$a_pointer = uplnm;
897 uplnm[lnmdsc.dsc$w_length] = '\0';
898 secure = flags & PERL__TRNENV_SECURE;
899 acmode = secure ? PSL$C_EXEC : PSL$C_USER;
900 if (!tabvec || !*tabvec) tabvec = env_tables;
902 for (curtab = 0; tabvec[curtab]; curtab++) {
903 if (!str$case_blind_compare(tabvec[curtab],&crtlenv)) {
904 if (!ivenv && !secure) {
909 #if defined(PERL_IMPLICIT_CONTEXT)
912 "Can't read CRTL environ\n");
915 Perl_warn(aTHX_ "Can't read CRTL environ\n");
918 retsts = SS$_NOLOGNAM;
919 for (i = 0; environ[i]; i++) {
920 if ((eq = strchr(environ[i],'=')) &&
921 lnmdsc.dsc$w_length == (eq - environ[i]) &&
922 !strncmp(environ[i],lnm,eq - environ[i])) {
924 for (eqvlen = 0; eq[eqvlen]; eqvlen++) eqv[eqvlen] = eq[eqvlen];
925 if (!eqvlen) continue;
930 if (retsts != SS$_NOLOGNAM) {
931 found_in_crtlenv = 1;
936 else if ((tmpdsc.dsc$a_pointer = tabvec[curtab]->dsc$a_pointer) &&
937 !str$case_blind_compare(&tmpdsc,&clisym)) {
938 if (!ivsym && !secure) {
939 unsigned short int deflen = LNM$C_NAMLENGTH;
940 struct dsc$descriptor_d eqvdsc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_D,0};
941 /* dynamic dsc to accommodate possible long value */
942 _ckvmssts_noperl(lib$sget1_dd(&deflen,&eqvdsc));
943 retsts = lib$get_symbol(&lnmdsc,&eqvdsc,&eqvlen,0);
945 if (eqvlen > MAX_DCL_SYMBOL) {
946 set_errno(EVMSERR); set_vaxc_errno(LIB$_STRTRU);
947 eqvlen = MAX_DCL_SYMBOL;
948 /* Special hack--we might be called before the interpreter's */
949 /* fully initialized, in which case either thr or PL_curcop */
950 /* might be bogus. We have to check, since ckWARN needs them */
951 /* both to be valid if running threaded */
952 #if defined(PERL_IMPLICIT_CONTEXT)
955 "Value of CLI symbol \"%s\" too long",lnm);
958 if (ckWARN(WARN_MISC)) {
959 Perl_warner(aTHX_ packWARN(WARN_MISC),"Value of CLI symbol \"%s\" too long",lnm);
962 strncpy(eqv,eqvdsc.dsc$a_pointer,eqvlen);
964 _ckvmssts_noperl(lib$sfree1_dd(&eqvdsc));
965 if (retsts == LIB$_INVSYMNAM) { ivsym = 1; continue; }
966 if (retsts == LIB$_NOSUCHSYM) continue;
972 if ( (idx == 0) && (flags & PERL__TRNENV_JOIN_SEARCHLIST) ) {
973 midx = my_maxidx(lnm);
974 for (idx = 0, cp2 = eqv; idx <= midx; idx++) {
975 lnmlst[1].bufadr = cp2;
977 retsts = sys$trnlnm(&attr,tabvec[curtab],&lnmdsc,&acmode,lnmlst);
978 if (retsts == SS$_IVLOGNAM) { ivlnm = 1; break; }
979 if (retsts == SS$_NOLOGNAM) break;
980 eqvlen = S_remove_ppf_prefix(uplnm, eqv, eqvlen);
984 if ((retsts == SS$_IVLOGNAM) ||
985 (retsts == SS$_NOLOGNAM)) { continue; }
986 eqvlen = strlen(eqv);
989 retsts = sys$trnlnm(&attr,tabvec[curtab],&lnmdsc,&acmode,lnmlst);
990 if (retsts == SS$_IVLOGNAM) { ivlnm = 1; continue; }
991 if (retsts == SS$_NOLOGNAM) continue;
992 eqvlen = S_remove_ppf_prefix(uplnm, eqv, eqvlen);
998 /* An index only makes sense for logical names, so make sure we aren't
999 * iterating over an index for an environ var or DCL symbol and getting
1000 * the same answer ad infinitum.
1002 if (idx > 0 && (found_in_crtlenv || found_in_clisym)) {
1005 else if (retsts & 1) { eqv[eqvlen] = '\0'; return eqvlen; }
1006 else if (retsts == LIB$_NOSUCHSYM ||
1007 retsts == SS$_NOLOGNAM) {
1008 /* Unsuccessful lookup is normal -- no need to set errno */
1011 else if (retsts == LIB$_INVSYMNAM ||
1012 retsts == SS$_IVLOGNAM ||
1013 retsts == SS$_IVLOGTAB) {
1014 set_errno(EINVAL); set_vaxc_errno(retsts);
1016 else _ckvmssts_noperl(retsts);
1018 } /* end of vmstrnenv */
1021 /*{{{ int my_trnlnm(const char *lnm, char *eqv, unsigned long int idx)*/
1022 /* Define as a function so we can access statics. */
1024 Perl_my_trnlnm(pTHX_ const char *lnm, char *eqv, unsigned long int idx)
1028 #if defined(PERL_IMPLICIT_CONTEXT)
1031 #ifdef SECURE_INTERNAL_GETENV
1032 flags = (PL_curinterp ? TAINTING_get : will_taint) ?
1033 PERL__TRNENV_SECURE : 0;
1036 return vmstrnenv(lnm, eqv, idx, fildev, flags);
1041 * Note: Uses Perl temp to store result so char * can be returned to
1042 * caller; this pointer will be invalidated at next Perl statement
1044 * We define this as a function rather than a macro in terms of my_getenv_len()
1045 * so that it'll work when PL_curinterp is undefined (and we therefore can't
1048 /*{{{ char *my_getenv(const char *lnm, bool sys)*/
1050 Perl_my_getenv(pTHX_ const char *lnm, bool sys)
1053 static char *__my_getenv_eqv = NULL;
1054 char uplnm[LNM$C_NAMLENGTH+1], *cp2, *eqv;
1055 unsigned long int idx = 0;
1056 int success, secure;
1060 midx = my_maxidx(lnm) + 1;
1062 if (PL_curinterp) { /* Perl interpreter running -- may be threaded */
1063 /* Set up a temporary buffer for the return value; Perl will
1064 * clean it up at the next statement transition */
1065 tmpsv = sv_2mortal(newSVpv("",(LNM$C_NAMLENGTH*midx)+1));
1066 if (!tmpsv) return NULL;
1070 /* Assume no interpreter ==> single thread */
1071 if (__my_getenv_eqv != NULL) {
1072 Renew(__my_getenv_eqv,LNM$C_NAMLENGTH*midx+1,char);
1075 Newx(__my_getenv_eqv,LNM$C_NAMLENGTH*midx+1,char);
1077 eqv = __my_getenv_eqv;
1080 for (cp1 = lnm, cp2 = eqv; *cp1; cp1++,cp2++) *cp2 = toUPPER_A(*cp1);
1081 if (cp1 - lnm == 7 && !strncmp(eqv,"DEFAULT",7)) {
1083 getcwd(eqv,LNM$C_NAMLENGTH);
1087 /* Get rid of "000000/ in rooted filespecs */
1090 zeros = strstr(eqv, "/000000/");
1091 if (zeros != NULL) {
1093 mlen = len - (zeros - eqv) - 7;
1094 memmove(zeros, &zeros[7], mlen);
1102 /* Impose security constraints only if tainting */
1104 /* Impose security constraints only if tainting */
1105 secure = PL_curinterp ? TAINTING_get : will_taint;
1112 #ifdef SECURE_INTERNAL_GETENV
1113 secure ? PERL__TRNENV_SECURE : 0
1119 /* For the getenv interface we combine all the equivalence names
1120 * of a search list logical into one value to acquire a maximum
1121 * value length of 255*128 (assuming %ENV is using logicals).
1123 flags |= PERL__TRNENV_JOIN_SEARCHLIST;
1125 /* If the name contains a semicolon-delimited index, parse it
1126 * off and make sure we only retrieve the equivalence name for
1128 if ((cp2 = strchr(lnm,';')) != NULL) {
1129 my_strlcpy(uplnm, lnm, cp2 - lnm + 1);
1130 idx = strtoul(cp2+1,NULL,0);
1132 flags &= ~PERL__TRNENV_JOIN_SEARCHLIST;
1135 success = vmstrnenv(lnm,eqv,idx,secure ? fildev : NULL,flags);
1137 return success ? eqv : NULL;
1140 } /* end of my_getenv() */
1144 /*{{{ SV *my_getenv_len(const char *lnm, bool sys)*/
1146 Perl_my_getenv_len(pTHX_ const char *lnm, unsigned long *len, bool sys)
1150 unsigned long idx = 0;
1152 static char *__my_getenv_len_eqv = NULL;
1156 midx = my_maxidx(lnm) + 1;
1158 if (PL_curinterp) { /* Perl interpreter running -- may be threaded */
1159 /* Set up a temporary buffer for the return value; Perl will
1160 * clean it up at the next statement transition */
1161 tmpsv = sv_2mortal(newSVpv("",(LNM$C_NAMLENGTH*midx)+1));
1162 if (!tmpsv) return NULL;
1166 /* Assume no interpreter ==> single thread */
1167 if (__my_getenv_len_eqv != NULL) {
1168 Renew(__my_getenv_len_eqv,LNM$C_NAMLENGTH*midx+1,char);
1171 Newx(__my_getenv_len_eqv,LNM$C_NAMLENGTH*midx+1,char);
1173 buf = __my_getenv_len_eqv;
1176 for (cp1 = lnm, cp2 = buf; *cp1; cp1++,cp2++) *cp2 = toUPPER_A(*cp1);
1177 if (cp1 - lnm == 7 && !strncmp(buf,"DEFAULT",7)) {
1180 getcwd(buf,LNM$C_NAMLENGTH);
1183 /* Get rid of "000000/ in rooted filespecs */
1185 zeros = strstr(buf, "/000000/");
1186 if (zeros != NULL) {
1188 mlen = *len - (zeros - buf) - 7;
1189 memmove(zeros, &zeros[7], mlen);
1198 /* Impose security constraints only if tainting */
1199 secure = PL_curinterp ? TAINTING_get : will_taint;
1206 #ifdef SECURE_INTERNAL_GETENV
1207 secure ? PERL__TRNENV_SECURE : 0
1213 flags |= PERL__TRNENV_JOIN_SEARCHLIST;
1215 if ((cp2 = strchr(lnm,';')) != NULL) {
1216 my_strlcpy(buf, lnm, cp2 - lnm + 1);
1217 idx = strtoul(cp2+1,NULL,0);
1219 flags &= ~PERL__TRNENV_JOIN_SEARCHLIST;
1222 *len = vmstrnenv(lnm,buf,idx,secure ? fildev : NULL,flags);
1224 /* Get rid of "000000/ in rooted filespecs */
1227 zeros = strstr(buf, "/000000/");
1228 if (zeros != NULL) {
1230 mlen = *len - (zeros - buf) - 7;
1231 memmove(zeros, &zeros[7], mlen);
1237 return *len ? buf : NULL;
1240 } /* end of my_getenv_len() */
1243 static void create_mbx(unsigned short int *, struct dsc$descriptor_s *);
1245 static void riseandshine(unsigned long int dummy) { sys$wake(0,0); }
1247 /*{{{ void prime_env_iter() */
1249 prime_env_iter(void)
1250 /* Fill the %ENV associative array with all logical names we can
1251 * find, in preparation for iterating over it.
1254 static int primed = 0;
1255 HV *seenhv = NULL, *envhv;
1257 char cmd[LNM$C_NAMLENGTH+24], mbxnam[LNM$C_NAMLENGTH], *buf = NULL;
1258 unsigned short int chan;
1259 #ifndef CLI$M_TRUSTED
1260 # define CLI$M_TRUSTED 0x40 /* Missing from VAXC headers */
1262 unsigned long int defflags = CLI$M_NOWAIT | CLI$M_NOKEYPAD | CLI$M_TRUSTED;
1263 unsigned long int mbxbufsiz, flags, retsts, subpid = 0, substs = 0;
1265 bool have_sym = FALSE, have_lnm = FALSE;
1266 struct dsc$descriptor_s tmpdsc = {6,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
1267 $DESCRIPTOR(cmddsc,cmd); $DESCRIPTOR(nldsc,"_NLA0:");
1268 $DESCRIPTOR(clidsc,"DCL"); $DESCRIPTOR(clitabdsc,"DCLTABLES");
1269 $DESCRIPTOR(crtlenv,"CRTL_ENV"); $DESCRIPTOR(clisym,"CLISYM");
1270 $DESCRIPTOR(local,"_LOCAL"); $DESCRIPTOR(mbxdsc,mbxnam);
1271 #if defined(PERL_IMPLICIT_CONTEXT)
1274 #if defined(USE_ITHREADS)
1275 static perl_mutex primenv_mutex;
1276 MUTEX_INIT(&primenv_mutex);
1279 #if defined(PERL_IMPLICIT_CONTEXT)
1280 /* We jump through these hoops because we can be called at */
1281 /* platform-specific initialization time, which is before anything is */
1282 /* set up--we can't even do a plain dTHX since that relies on the */
1283 /* interpreter structure to be initialized */
1285 aTHX = PERL_GET_INTERP;
1287 /* we never get here because the NULL pointer will cause the */
1288 /* several of the routines called by this routine to access violate */
1290 /* This routine is only called by hv.c/hv_iterinit which has a */
1291 /* context, so the real fix may be to pass it through instead of */
1292 /* the hoops above */
1297 if (primed || !PL_envgv) return;
1298 MUTEX_LOCK(&primenv_mutex);
1299 if (primed) { MUTEX_UNLOCK(&primenv_mutex); return; }
1300 envhv = GvHVn(PL_envgv);
1301 /* Perform a dummy fetch as an lval to insure that the hash table is
1302 * set up. Otherwise, the hv_store() will turn into a nullop. */
1303 (void) hv_fetchs(envhv,"DEFAULT",TRUE);
1305 for (i = 0; env_tables[i]; i++) {
1306 if (!have_sym && (tmpdsc.dsc$a_pointer = env_tables[i]->dsc$a_pointer) &&
1307 !str$case_blind_compare(&tmpdsc,&clisym)) have_sym = 1;
1308 if (!have_lnm && str$case_blind_compare(env_tables[i],&crtlenv)) have_lnm = 1;
1310 if (have_sym || have_lnm) {
1311 long int syiitm = SYI$_MAXBUF, dviitm = DVI$_DEVNAM;
1312 _ckvmssts(lib$getsyi(&syiitm, &mbxbufsiz, 0, 0, 0, 0));
1313 _ckvmssts(sys$crembx(0,&chan,mbxbufsiz,mbxbufsiz,0xff0f,0,0));
1314 _ckvmssts(lib$getdvi(&dviitm, &chan, NULL, NULL, &mbxdsc, &mbxdsc.dsc$w_length));
1317 for (i--; i >= 0; i--) {
1318 if (!str$case_blind_compare(env_tables[i],&crtlenv)) {
1321 /* Start at the end, so if there is a duplicate we keep the first one. */
1322 for (j = 0; environ[j]; j++);
1323 for (j--; j >= 0; j--) {
1324 if (!(start = strchr(environ[j],'='))) {
1325 if (ckWARN(WARN_INTERNAL))
1326 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"Ill-formed CRTL environ value \"%s\"\n",environ[j]);
1330 sv = newSVpv(start,0);
1332 (void) hv_store(envhv,environ[j],start - environ[j] - 1,sv,0);
1337 else if ((tmpdsc.dsc$a_pointer = env_tables[i]->dsc$a_pointer) &&
1338 !str$case_blind_compare(&tmpdsc,&clisym)) {
1339 my_strlcpy(cmd, "Show Symbol/Global *", sizeof(cmd));
1340 cmddsc.dsc$w_length = 20;
1341 if (env_tables[i]->dsc$w_length == 12 &&
1342 (tmpdsc.dsc$a_pointer = env_tables[i]->dsc$a_pointer + 6) &&
1343 !str$case_blind_compare(&tmpdsc,&local)) my_strlcpy(cmd+12, "Local *", sizeof(cmd)-12);
1344 flags = defflags | CLI$M_NOLOGNAM;
1347 my_strlcpy(cmd, "Show Logical *", sizeof(cmd));
1348 if (str$case_blind_compare(env_tables[i],&fildevdsc)) {
1349 my_strlcat(cmd," /Table=", sizeof(cmd));
1350 cmddsc.dsc$w_length = my_strlcat(cmd, env_tables[i]->dsc$a_pointer, sizeof(cmd));
1352 else cmddsc.dsc$w_length = 14; /* N.B. We test this below */
1353 flags = defflags | CLI$M_NOCLISYM;
1356 /* Create a new subprocess to execute each command, to exclude the
1357 * remote possibility that someone could subvert a mbx or file used
1358 * to write multiple commands to a single subprocess.
1361 retsts = lib$spawn(&cmddsc,&nldsc,&mbxdsc,&flags,0,&subpid,&substs,
1362 0,&riseandshine,0,0,&clidsc,&clitabdsc);
1363 flags &= ~CLI$M_TRUSTED; /* Just in case we hit a really old version */
1364 defflags &= ~CLI$M_TRUSTED;
1365 } while (retsts == LIB$_INVARG && (flags | CLI$M_TRUSTED));
1367 if (!buf) Newx(buf,mbxbufsiz + 1,char);
1368 if (seenhv) SvREFCNT_dec(seenhv);
1371 char *cp1, *cp2, *key;
1372 unsigned long int sts, iosb[2], retlen, keylen;
1375 sts = sys$qiow(0,chan,IO$_READVBLK,iosb,0,0,buf,mbxbufsiz,0,0,0,0);
1376 if (sts & 1) sts = iosb[0] & 0xffff;
1377 if (sts == SS$_ENDOFFILE) {
1379 while (substs == 0) { sys$hiber(); wakect++;}
1380 if (wakect > 1) sys$wake(0,0); /* Stole someone else's wake */
1385 retlen = iosb[0] >> 16;
1386 if (!retlen) continue; /* blank line */
1388 if (iosb[1] != subpid) {
1390 Perl_croak(aTHX_ "Unknown process %x sent message to prime_env_iter: %s",buf);
1394 if (sts == SS$_BUFFEROVF && ckWARN(WARN_INTERNAL))
1395 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"Buffer overflow in prime_env_iter: %s",buf);
1397 for (cp1 = buf; *cp1 && isSPACE_L1(*cp1); cp1++) ;
1398 if (*cp1 == '(' || /* Logical name table name */
1399 *cp1 == '=' /* Next eqv of searchlist */) continue;
1400 if (*cp1 == '"') cp1++;
1401 for (cp2 = cp1; *cp2 && *cp2 != '"' && *cp2 != ' '; cp2++) ;
1402 key = cp1; keylen = cp2 - cp1;
1403 if (keylen && hv_exists(seenhv,key,keylen)) continue;
1404 while (*cp2 && *cp2 != '=') cp2++;
1405 while (*cp2 && *cp2 == '=') cp2++;
1406 while (*cp2 && *cp2 == ' ') cp2++;
1407 if (*cp2 == '"') { /* String translation; may embed "" */
1408 for (cp1 = buf + retlen; *cp1 != '"'; cp1--) ;
1409 cp2++; cp1--; /* Skip "" surrounding translation */
1411 else { /* Numeric translation */
1412 for (cp1 = cp2; *cp1 && *cp1 != ' '; cp1++) ;
1413 cp1--; /* stop on last non-space char */
1415 if ((!keylen || (cp1 - cp2 < -1)) && ckWARN(WARN_INTERNAL)) {
1416 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"Ill-formed message in prime_env_iter: |%s|",buf);
1419 PERL_HASH(hash,key,keylen);
1421 if (cp1 == cp2 && *cp2 == '.') {
1422 /* A single dot usually means an unprintable character, such as a null
1423 * to indicate a zero-length value. Get the actual value to make sure.
1425 char lnm[LNM$C_NAMLENGTH+1];
1426 char eqv[MAX_DCL_SYMBOL+1];
1428 strncpy(lnm, key, keylen);
1429 trnlen = vmstrnenv(lnm, eqv, 0, fildev, 0);
1430 sv = newSVpvn(eqv, strlen(eqv));
1433 sv = newSVpvn(cp2,cp1 - cp2 + 1);
1437 hv_store(envhv,key,keylen,sv,hash);
1438 hv_store(seenhv,key,keylen,&PL_sv_yes,hash);
1440 if (cmddsc.dsc$w_length == 14) { /* We just read LNM$FILE_DEV */
1441 /* get the PPFs for this process, not the subprocess */
1442 const char *ppfs[] = {"SYS$COMMAND", "SYS$INPUT", "SYS$OUTPUT", "SYS$ERROR", NULL};
1443 char eqv[LNM$C_NAMLENGTH+1];
1445 for (i = 0; ppfs[i]; i++) {
1446 trnlen = vmstrnenv(ppfs[i],eqv,0,fildev,0);
1447 sv = newSVpv(eqv,trnlen);
1449 hv_store(envhv,ppfs[i],strlen(ppfs[i]),sv,0);
1454 if (have_sym || have_lnm) _ckvmssts(sys$dassgn(chan));
1455 if (buf) Safefree(buf);
1456 if (seenhv) SvREFCNT_dec(seenhv);
1457 MUTEX_UNLOCK(&primenv_mutex);
1460 } /* end of prime_env_iter */
1464 /*{{{ int vmssetenv(const char *lnm, const char *eqv)*/
1465 /* Define or delete an element in the same "environment" as
1466 * vmstrnenv(). If an element is to be deleted, it's removed from
1467 * the first place it's found. If it's to be set, it's set in the
1468 * place designated by the first element of the table vector.
1469 * Like setenv() returns 0 for success, non-zero on error.
1472 Perl_vmssetenv(pTHX_ const char *lnm, const char *eqv, struct dsc$descriptor_s **tabvec)
1475 char uplnm[LNM$C_NAMLENGTH], *cp2, *c;
1476 unsigned short int curtab, ivlnm = 0, ivsym = 0, ivenv = 0;
1478 unsigned long int retsts, usermode = PSL$C_USER;
1479 struct itmlst_3 *ile, *ilist;
1480 struct dsc$descriptor_s lnmdsc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,uplnm},
1481 eqvdsc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0},
1482 tmpdsc = {6,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
1483 $DESCRIPTOR(crtlenv,"CRTL_ENV"); $DESCRIPTOR(clisym,"CLISYM");
1484 $DESCRIPTOR(local,"_LOCAL");
1487 set_errno(EINVAL); set_vaxc_errno(SS$_IVLOGNAM);
1488 return SS$_IVLOGNAM;
1491 for (cp1 = lnm, cp2 = uplnm; *cp1; cp1++, cp2++) {
1492 *cp2 = toUPPER_A(*cp1);
1493 if (cp1 - lnm > LNM$C_NAMLENGTH) {
1494 set_errno(EINVAL); set_vaxc_errno(SS$_IVLOGNAM);
1495 return SS$_IVLOGNAM;
1498 lnmdsc.dsc$w_length = cp1 - lnm;
1499 if (!tabvec || !*tabvec) tabvec = env_tables;
1501 if (!eqv) { /* we're deleting n element */
1502 for (curtab = 0; tabvec[curtab]; curtab++) {
1503 if (!ivenv && !str$case_blind_compare(tabvec[curtab],&crtlenv)) {
1505 for (i = 0; environ[i]; i++) { /* If it's an environ elt, reset */
1506 if ((cp1 = strchr(environ[i],'=')) &&
1507 lnmdsc.dsc$w_length == (cp1 - environ[i]) &&
1508 !strncmp(environ[i],lnm,cp1 - environ[i])) {
1513 ivenv = 1; retsts = SS$_NOLOGNAM;
1515 else if ((tmpdsc.dsc$a_pointer = tabvec[curtab]->dsc$a_pointer) &&
1516 !str$case_blind_compare(&tmpdsc,&clisym)) {
1517 unsigned int symtype;
1518 if (tabvec[curtab]->dsc$w_length == 12 &&
1519 (tmpdsc.dsc$a_pointer = tabvec[curtab]->dsc$a_pointer + 6) &&
1520 !str$case_blind_compare(&tmpdsc,&local))
1521 symtype = LIB$K_CLI_LOCAL_SYM;
1522 else symtype = LIB$K_CLI_GLOBAL_SYM;
1523 retsts = lib$delete_symbol(&lnmdsc,&symtype);
1524 if (retsts == LIB$_INVSYMNAM) { ivsym = 1; continue; }
1525 if (retsts == LIB$_NOSUCHSYM) continue;
1529 retsts = sys$dellnm(tabvec[curtab],&lnmdsc,&usermode); /* try user mode first */
1530 if (retsts == SS$_IVLOGNAM) { ivlnm = 1; continue; }
1531 if (retsts != SS$_NOLOGNAM && retsts != SS$_NOLOGTAB) break;
1532 retsts = lib$delete_logical(&lnmdsc,tabvec[curtab]); /* then supervisor mode */
1533 if (retsts != SS$_NOLOGNAM && retsts != SS$_NOLOGTAB) break;
1537 else { /* we're defining a value */
1538 if (!ivenv && !str$case_blind_compare(tabvec[0],&crtlenv)) {
1539 return setenv(lnm,eqv,1) ? vaxc$errno : 0;
1542 eqvdsc.dsc$a_pointer = (char *) eqv; /* cast ok to readonly parameter */
1543 eqvdsc.dsc$w_length = strlen(eqv);
1544 if ((tmpdsc.dsc$a_pointer = tabvec[0]->dsc$a_pointer) &&
1545 !str$case_blind_compare(&tmpdsc,&clisym)) {
1546 unsigned int symtype;
1547 if (tabvec[0]->dsc$w_length == 12 &&
1548 (tmpdsc.dsc$a_pointer = tabvec[0]->dsc$a_pointer + 6) &&
1549 !str$case_blind_compare(&tmpdsc,&local))
1550 symtype = LIB$K_CLI_LOCAL_SYM;
1551 else symtype = LIB$K_CLI_GLOBAL_SYM;
1552 retsts = lib$set_symbol(&lnmdsc,&eqvdsc,&symtype);
1555 if (!*eqv) eqvdsc.dsc$w_length = 1;
1556 if (eqvdsc.dsc$w_length > LNM$C_NAMLENGTH) {
1558 nseg = (eqvdsc.dsc$w_length + LNM$C_NAMLENGTH - 1) / LNM$C_NAMLENGTH;
1559 if (nseg > PERL_LNM_MAX_ALLOWED_INDEX + 1) {
1560 Perl_warner(aTHX_ packWARN(WARN_MISC),"Value of logical \"%s\" too long. Truncating to %i bytes",
1561 lnm, LNM$C_NAMLENGTH * (PERL_LNM_MAX_ALLOWED_INDEX+1));
1562 eqvdsc.dsc$w_length = LNM$C_NAMLENGTH * (PERL_LNM_MAX_ALLOWED_INDEX+1);
1563 nseg = PERL_LNM_MAX_ALLOWED_INDEX + 1;
1566 Newx(ilist,nseg+1,struct itmlst_3);
1569 set_errno(ENOMEM); set_vaxc_errno(SS$_INSFMEM);
1572 memset(ilist, 0, (sizeof(struct itmlst_3) * (nseg+1)));
1574 for (j = 0, c = eqvdsc.dsc$a_pointer; j < nseg; j++, ile++, c += LNM$C_NAMLENGTH) {
1575 ile->itmcode = LNM$_STRING;
1577 if ((j+1) == nseg) {
1578 ile->buflen = strlen(c);
1579 /* in case we are truncating one that's too long */
1580 if (ile->buflen > LNM$C_NAMLENGTH) ile->buflen = LNM$C_NAMLENGTH;
1583 ile->buflen = LNM$C_NAMLENGTH;
1587 retsts = lib$set_logical(&lnmdsc,0,tabvec[0],0,ilist);
1591 retsts = lib$set_logical(&lnmdsc,&eqvdsc,tabvec[0],0,0);
1596 if (!(retsts & 1)) {
1598 case LIB$_AMBSYMDEF: case LIB$_INSCLIMEM:
1599 case SS$_NOLOGTAB: case SS$_TOOMANYLNAM: case SS$_IVLOGTAB:
1600 set_errno(EVMSERR); break;
1601 case LIB$_INVARG: case LIB$_INVSYMNAM: case SS$_IVLOGNAM:
1602 case LIB$_NOSUCHSYM: case SS$_NOLOGNAM:
1603 set_errno(EINVAL); break;
1605 set_errno(EACCES); break;
1610 set_vaxc_errno(retsts);
1611 return (int) retsts || 44; /* retsts should never be 0, but just in case */
1614 /* We reset error values on success because Perl does an hv_fetch()
1615 * before each hv_store(), and if the thing we're setting didn't
1616 * previously exist, we've got a leftover error message. (Of course,
1617 * this fails in the face of
1618 * $foo = $ENV{nonexistent}; $ENV{existent} = 'foo';
1619 * in that the error reported in $! isn't spurious,
1620 * but it's right more often than not.)
1622 set_errno(0); set_vaxc_errno(retsts);
1626 } /* end of vmssetenv() */
1629 /*{{{ void my_setenv(const char *lnm, const char *eqv)*/
1630 /* This has to be a function since there's a prototype for it in proto.h */
1632 Perl_my_setenv(pTHX_ const char *lnm, const char *eqv)
1635 int len = strlen(lnm);
1639 for (i = 0; lnm[i]; i++) uplnm[i] = toUPPER_A(lnm[i]);
1640 if (!strcmp(uplnm,"DEFAULT")) {
1641 if (eqv && *eqv) my_chdir(eqv);
1646 (void) vmssetenv(lnm,eqv,NULL);
1650 /*{{{static void vmssetuserlnm(char *name, char *eqv); */
1652 * sets a user-mode logical in the process logical name table
1653 * used for redirection of sys$error
1656 Perl_vmssetuserlnm(const char *name, const char *eqv)
1658 $DESCRIPTOR(d_tab, "LNM$PROCESS");
1659 struct dsc$descriptor_d d_name = {0,DSC$K_DTYPE_T,DSC$K_CLASS_D,0};
1660 unsigned long int iss, attr = LNM$M_CONFINE;
1661 unsigned char acmode = PSL$C_USER;
1662 struct itmlst_3 lnmlst[2] = {{0, LNM$_STRING, 0, 0},
1664 d_name.dsc$a_pointer = (char *)name; /* Cast OK for read only parameter */
1665 d_name.dsc$w_length = strlen(name);
1667 lnmlst[0].buflen = strlen(eqv);
1668 lnmlst[0].bufadr = (char *)eqv; /* Cast OK for read only parameter */
1670 iss = sys$crelnm(&attr,&d_tab,&d_name,&acmode,lnmlst);
1671 if (!(iss&1)) lib$signal(iss);
1676 /*{{{ char *my_crypt(const char *textpasswd, const char *usrname)*/
1677 /* my_crypt - VMS password hashing
1678 * my_crypt() provides an interface compatible with the Unix crypt()
1679 * C library function, and uses sys$hash_password() to perform VMS
1680 * password hashing. The quadword hashed password value is returned
1681 * as a NUL-terminated 8 character string. my_crypt() does not change
1682 * the case of its string arguments; in order to match the behavior
1683 * of LOGINOUT et al., alphabetic characters in both arguments must
1684 * be upcased by the caller.
1686 * - fix me to call ACM services when available
1689 Perl_my_crypt(pTHX_ const char *textpasswd, const char *usrname)
1691 # ifndef UAI$C_PREFERRED_ALGORITHM
1692 # define UAI$C_PREFERRED_ALGORITHM 127
1694 unsigned char alg = UAI$C_PREFERRED_ALGORITHM;
1695 unsigned short int salt = 0;
1696 unsigned long int sts;
1698 unsigned short int dsc$w_length;
1699 unsigned char dsc$b_type;
1700 unsigned char dsc$b_class;
1701 const char * dsc$a_pointer;
1702 } usrdsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0},
1703 txtdsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
1704 struct itmlst_3 uailst[3] = {
1705 { sizeof alg, UAI$_ENCRYPT, &alg, 0},
1706 { sizeof salt, UAI$_SALT, &salt, 0},
1707 { 0, 0, NULL, NULL}};
1708 static char hash[9];
1710 usrdsc.dsc$w_length = strlen(usrname);
1711 usrdsc.dsc$a_pointer = usrname;
1712 if (!((sts = sys$getuai(0, 0, &usrdsc, uailst, 0, 0, 0)) & 1)) {
1714 case SS$_NOGRPPRV: case SS$_NOSYSPRV:
1718 set_errno(ESRCH); /* There isn't a Unix no-such-user error */
1723 set_vaxc_errno(sts);
1724 if (sts != RMS$_RNF) return NULL;
1727 txtdsc.dsc$w_length = strlen(textpasswd);
1728 txtdsc.dsc$a_pointer = textpasswd;
1729 if (!((sts = sys$hash_password(&txtdsc, alg, salt, &usrdsc, &hash)) & 1)) {
1730 set_errno(EVMSERR); set_vaxc_errno(sts); return NULL;
1733 return (char *) hash;
1735 } /* end of my_crypt() */
1739 static char *mp_do_rmsexpand(pTHX_ const char *, char *, int, const char *, unsigned, int *, int *);
1740 static char *mp_do_fileify_dirspec(pTHX_ const char *, char *, int, int *);
1741 static char *mp_do_tovmsspec(pTHX_ const char *, char *, int, int, int *);
1743 /* 8.3, remove() is now broken on symbolic links */
1744 static int rms_erase(const char * vmsname);
1748 * A little hack to get around a bug in some implementation of remove()
1749 * that do not know how to delete a directory
1751 * Delete any file to which user has control access, regardless of whether
1752 * delete access is explicitly allowed.
1753 * Limitations: User must have write access to parent directory.
1754 * Does not block signals or ASTs; if interrupted in midstream
1755 * may leave file with an altered ACL.
1758 /*{{{int mp_do_kill_file(const char *name, int dirflag)*/
1760 mp_do_kill_file(pTHX_ const char *name, int dirflag)
1764 unsigned long int jpicode = JPI$_UIC, type = ACL$C_FILE;
1765 unsigned long int cxt = 0, aclsts, fndsts;
1767 struct dsc$descriptor_s fildsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
1769 unsigned char myace$b_length;
1770 unsigned char myace$b_type;
1771 unsigned short int myace$w_flags;
1772 unsigned long int myace$l_access;
1773 unsigned long int myace$l_ident;
1774 } newace = { sizeof(struct myacedef), ACE$C_KEYID, 0,
1775 ACE$M_READ | ACE$M_WRITE | ACE$M_DELETE | ACE$M_CONTROL, 0},
1776 oldace = { sizeof(struct myacedef), ACE$C_KEYID, 0, 0, 0};
1778 findlst[3] = {{sizeof oldace, ACL$C_FNDACLENT, &oldace, 0},
1779 {sizeof oldace, ACL$C_READACE, &oldace, 0},{0,0,0,0}},
1780 addlst[2] = {{sizeof newace, ACL$C_ADDACLENT, &newace, 0},{0,0,0,0}},
1781 dellst[2] = {{sizeof newace, ACL$C_DELACLENT, &newace, 0},{0,0,0,0}},
1782 lcklst[2] = {{sizeof newace, ACL$C_WLOCK_ACL, &newace, 0},{0,0,0,0}},
1783 ulklst[2] = {{sizeof newace, ACL$C_UNLOCK_ACL, &newace, 0},{0,0,0,0}};
1785 /* Expand the input spec using RMS, since the CRTL remove() and
1786 * system services won't do this by themselves, so we may miss
1787 * a file "hiding" behind a logical name or search list. */
1788 vmsname = (char *)PerlMem_malloc(NAM$C_MAXRSS+1);
1789 if (vmsname == NULL) _ckvmssts_noperl(SS$_INSFMEM);
1791 rslt = int_rmsexpand_tovms(name, vmsname, PERL_RMSEXPAND_M_SYMLINK);
1793 PerlMem_free(vmsname);
1797 /* Erase the file */
1798 rmsts = rms_erase(vmsname);
1800 /* Did it succeed */
1801 if ($VMS_STATUS_SUCCESS(rmsts)) {
1802 PerlMem_free(vmsname);
1806 /* If not, can changing protections help? */
1807 if (rmsts != RMS$_PRV) {
1808 set_vaxc_errno(rmsts);
1809 PerlMem_free(vmsname);
1813 /* No, so we get our own UIC to use as a rights identifier,
1814 * and the insert an ACE at the head of the ACL which allows us
1815 * to delete the file.
1817 _ckvmssts_noperl(lib$getjpi(&jpicode,0,0,&(oldace.myace$l_ident),0,0));
1818 fildsc.dsc$w_length = strlen(vmsname);
1819 fildsc.dsc$a_pointer = vmsname;
1821 newace.myace$l_ident = oldace.myace$l_ident;
1823 if (!((aclsts = sys$change_acl(0,&type,&fildsc,lcklst,0,0,0)) & 1)) {
1825 case RMS$_FNF: case RMS$_DNF: case SS$_NOSUCHOBJECT:
1826 set_errno(ENOENT); break;
1828 set_errno(ENOTDIR); break;
1830 set_errno(ENODEV); break;
1831 case RMS$_SYN: case SS$_INVFILFOROP:
1832 set_errno(EINVAL); break;
1834 set_errno(EACCES); break;
1836 _ckvmssts_noperl(aclsts);
1838 set_vaxc_errno(aclsts);
1839 PerlMem_free(vmsname);
1842 /* Grab any existing ACEs with this identifier in case we fail */
1843 aclsts = fndsts = sys$change_acl(0,&type,&fildsc,findlst,0,0,&cxt);
1844 if ( fndsts & 1 || fndsts == SS$_ACLEMPTY || fndsts == SS$_NOENTRY
1845 || fndsts == SS$_NOMOREACE ) {
1846 /* Add the new ACE . . . */
1847 if (!((aclsts = sys$change_acl(0,&type,&fildsc,addlst,0,0,0)) & 1))
1850 rmsts = rms_erase(vmsname);
1851 if ($VMS_STATUS_SUCCESS(rmsts)) {
1856 /* We blew it - dir with files in it, no write priv for
1857 * parent directory, etc. Put things back the way they were. */
1858 if (!((aclsts = sys$change_acl(0,&type,&fildsc,dellst,0,0,0)) & 1))
1861 addlst[0].bufadr = &oldace;
1862 if (!((aclsts = sys$change_acl(0,&type,&fildsc,addlst,0,0,&cxt)) & 1))
1869 fndsts = sys$change_acl(0,&type,&fildsc,ulklst,0,0,0);
1870 /* We just deleted it, so of course it's not there. Some versions of
1871 * VMS seem to return success on the unlock operation anyhow (after all
1872 * the unlock is successful), but others don't.
1874 if (fndsts == RMS$_FNF || fndsts == SS$_NOSUCHOBJECT) fndsts = SS$_NORMAL;
1875 if (aclsts & 1) aclsts = fndsts;
1876 if (!(aclsts & 1)) {
1878 set_vaxc_errno(aclsts);
1881 PerlMem_free(vmsname);
1884 } /* end of kill_file() */
1888 /*{{{int do_rmdir(char *name)*/
1890 Perl_do_rmdir(pTHX_ const char *name)
1896 /* lstat returns a VMS fileified specification of the name */
1897 /* that is looked up, and also lets verifies that this is a directory */
1899 retval = flex_lstat(name, &st);
1903 /* Due to a historical feature, flex_stat/lstat can not see some */
1904 /* Unix format file names that the rest of the CRTL can see */
1905 /* Fixing that feature will cause some perl tests to fail */
1906 /* So try this one more time. */
1908 retval = lstat(name, &st.crtl_stat);
1912 /* force it to a file spec for the kill file to work. */
1913 ret_spec = do_fileify_dirspec(name, st.st_devnam, 0, NULL);
1914 if (ret_spec == NULL) {
1920 if (!S_ISDIR(st.st_mode)) {
1925 dirfile = st.st_devnam;
1927 /* It may be possible for flex_stat to find a file and vmsify() to */
1928 /* fail with ODS-2 specifications. mp_do_kill_file can not deal */
1929 /* with that case, so fail it */
1930 if (dirfile[0] == 0) {
1935 retval = mp_do_kill_file(aTHX_ dirfile, 1);
1940 } /* end of do_rmdir */
1944 * Delete any file to which user has control access, regardless of whether
1945 * delete access is explicitly allowed.
1946 * Limitations: User must have write access to parent directory.
1947 * Does not block signals or ASTs; if interrupted in midstream
1948 * may leave file with an altered ACL.
1951 /*{{{int kill_file(char *name)*/
1953 Perl_kill_file(pTHX_ const char *name)
1959 /* Convert the filename to VMS format and see if it is a directory */
1960 /* flex_lstat returns a vmsified file specification */
1961 rmsts = flex_lstat(name, &st);
1964 /* Due to a historical feature, flex_stat/lstat can not see some */
1965 /* Unix format file names that the rest of the CRTL can see when */
1966 /* ODS-2 file specifications are in use. */
1967 /* Fixing that feature will cause some perl tests to fail */
1968 /* [.lib.ExtUtils.t]Manifest.t is one of them */
1970 vmsfile = (char *) name; /* cast ok */
1973 vmsfile = st.st_devnam;
1974 if (vmsfile[0] == 0) {
1975 /* It may be possible for flex_stat to find a file and vmsify() */
1976 /* to fail with ODS-2 specifications. mp_do_kill_file can not */
1977 /* deal with that case, so fail it */
1983 /* Remove() is allowed to delete directories, according to the X/Open
1985 * This may need special handling to work with the ACL hacks.
1987 if (S_ISDIR(st.st_mode)) {
1988 rmsts = mp_do_kill_file(aTHX_ vmsfile, 1);
1992 rmsts = mp_do_kill_file(aTHX_ vmsfile, 0);
1994 /* Need to delete all versions ? */
1995 if ((rmsts == 0) && (vms_unlink_all_versions == 1)) {
1998 /* Just use lstat() here as do not need st_dev */
1999 /* and we know that the file is in VMS format or that */
2000 /* because of a historical bug, flex_stat can not see the file */
2001 while (lstat(vmsfile, (stat_t *)&st) == 0) {
2002 rmsts = mp_do_kill_file(aTHX_ vmsfile, 0);
2007 /* Make sure that we do not loop forever */
2018 } /* end of kill_file() */
2022 /*{{{int my_mkdir(char *,Mode_t)*/
2024 Perl_my_mkdir(pTHX_ const char *dir, Mode_t mode)
2026 STRLEN dirlen = strlen(dir);
2028 /* zero length string sometimes gives ACCVIO */
2029 if (dirlen == 0) return -1;
2031 /* CRTL mkdir() doesn't tolerate trailing /, since that implies
2032 * null file name/type. However, it's commonplace under Unix,
2033 * so we'll allow it for a gain in portability.
2035 if (dir[dirlen-1] == '/') {
2036 char *newdir = savepvn(dir,dirlen-1);
2037 int ret = mkdir(newdir,mode);
2041 else return mkdir(dir,mode);
2042 } /* end of my_mkdir */
2045 /*{{{int my_chdir(char *)*/
2047 Perl_my_chdir(pTHX_ const char *dir)
2049 STRLEN dirlen = strlen(dir);
2050 const char *dir1 = dir;
2052 /* POSIX says we should set ENOENT for zero length string. */
2054 SETERRNO(ENOENT, RMS$_DNF);
2058 /* Perl is passing the output of the DCL SHOW DEFAULT with leading spaces.
2059 * This does not work if DECC$EFS_CHARSET is active. Hack it here
2060 * so that existing scripts do not need to be changed.
2062 while ((dirlen > 0) && (*dir1 == ' ')) {
2067 /* some versions of CRTL chdir() doesn't tolerate trailing /, since
2069 * null file name/type. However, it's commonplace under Unix,
2070 * so we'll allow it for a gain in portability.
2072 * '/' is valid when SYS$POSIX_ROOT or POSIX compliant pathnames are active.
2074 if ((dirlen > 1) && (dir1[dirlen-1] == '/')) {
2077 newdir = (char *)PerlMem_malloc(dirlen);
2079 _ckvmssts_noperl(SS$_INSFMEM);
2080 memcpy(newdir, dir1, dirlen-1);
2081 newdir[dirlen-1] = '\0';
2082 ret = chdir(newdir);
2083 PerlMem_free(newdir);
2086 else return chdir(dir1);
2087 } /* end of my_chdir */
2091 /*{{{int my_chmod(char *, mode_t)*/
2093 Perl_my_chmod(pTHX_ const char *file_spec, mode_t mode)
2098 STRLEN speclen = strlen(file_spec);
2100 /* zero length string sometimes gives ACCVIO */
2101 if (speclen == 0) return -1;
2103 /* some versions of CRTL chmod() doesn't tolerate trailing /, since
2104 * that implies null file name/type. However, it's commonplace under Unix,
2105 * so we'll allow it for a gain in portability.
2107 * Tests are showing that chmod() on VMS 8.3 is only accepting directories
2108 * in VMS file.dir notation.
2110 changefile = (char *) file_spec; /* cast ok */
2111 ret = flex_lstat(file_spec, &st);
2114 /* Due to a historical feature, flex_stat/lstat can not see some */
2115 /* Unix format file names that the rest of the CRTL can see when */
2116 /* ODS-2 file specifications are in use. */
2117 /* Fixing that feature will cause some perl tests to fail */
2118 /* [.lib.ExtUtils.t]Manifest.t is one of them */
2122 /* It may be possible to get here with nothing in st_devname */
2123 /* chmod still may work though */
2124 if (st.st_devnam[0] != 0) {
2125 changefile = st.st_devnam;
2128 ret = chmod(changefile, mode);
2130 } /* end of my_chmod */
2134 /*{{{FILE *my_tmpfile()*/
2141 if ((fp = tmpfile())) return fp;
2143 cp = (char *)PerlMem_malloc(L_tmpnam+24);
2144 if (cp == NULL) _ckvmssts_noperl(SS$_INSFMEM);
2146 if (decc_filename_unix_only == 0)
2147 strcpy(cp,"Sys$Scratch:");
2150 tmpnam(cp+strlen(cp));
2151 strcat(cp,".Perltmp");
2152 fp = fopen(cp,"w+","fop=dlt");
2160 * The C RTL's sigaction fails to check for invalid signal numbers so we
2161 * help it out a bit. The docs are correct, but the actual routine doesn't
2162 * do what the docs say it will.
2164 /*{{{int Perl_my_sigaction (pTHX_ int, const struct sigaction*, struct sigaction*);*/
2166 Perl_my_sigaction (pTHX_ int sig, const struct sigaction* act,
2167 struct sigaction* oact)
2169 if (sig == SIGKILL || sig == SIGSTOP || sig == SIGCONT) {
2170 SETERRNO(EINVAL, SS$_INVARG);
2173 return sigaction(sig, act, oact);
2177 #include <errnodef.h>
2179 /* We implement our own kill() using the undocumented system service
2180 sys$sigprc for one of two reasons:
2182 1.) If the kill() in an older CRTL uses sys$forcex, causing the
2183 target process to do a sys$exit, which usually can't be handled
2184 gracefully...certainly not by Perl and the %SIG{} mechanism.
2186 2.) If the kill() in the CRTL can't be called from a signal
2187 handler without disappearing into the ether, i.e., the signal
2188 it purportedly sends is never trapped. Still true as of VMS 7.3.
2190 sys$sigprc has the same parameters as sys$forcex, but throws an exception
2191 in the target process rather than calling sys$exit.
2193 Note that distinguishing SIGSEGV from SIGBUS requires an extra arg
2194 on the ACCVIO condition, which sys$sigprc (and sys$forcex) don't
2195 provide. On VMS 7.0+ this is taken care of by doing sys$sigprc
2196 with condition codes C$_SIG0+nsig*8, catching the exception on the
2197 target process and resignaling with appropriate arguments.
2199 But we don't have that VMS 7.0+ exception handler, so if you
2200 Perl_my_kill(.., SIGSEGV) it will show up as a SIGBUS. Oh well.
2202 Also note that SIGTERM is listed in the docs as being "unimplemented",
2203 yet always seems to be signaled with a VMS condition code of 4 (and
2204 correctly handled for that code). So we hardwire it in.
2206 Unlike the VMS 7.0+ CRTL kill() function, we actually check the signal
2207 number to see if it's valid. So Perl_my_kill(pid,0) returns -1 rather
2208 than signalling with an unrecognized (and unhandled by CRTL) code.
2211 #define _MY_SIG_MAX 28
2214 Perl_sig_to_vmscondition_int(int sig)
2216 static unsigned int sig_code[_MY_SIG_MAX+1] =
2219 SS$_HANGUP, /* 1 SIGHUP */
2220 SS$_CONTROLC, /* 2 SIGINT */
2221 SS$_CONTROLY, /* 3 SIGQUIT */
2222 SS$_RADRMOD, /* 4 SIGILL */
2223 SS$_BREAK, /* 5 SIGTRAP */
2224 SS$_OPCCUS, /* 6 SIGABRT */
2225 SS$_COMPAT, /* 7 SIGEMT */
2226 SS$_HPARITH, /* 8 SIGFPE AXP */
2227 SS$_ABORT, /* 9 SIGKILL */
2228 SS$_ACCVIO, /* 10 SIGBUS */
2229 SS$_ACCVIO, /* 11 SIGSEGV */
2230 SS$_BADPARAM, /* 12 SIGSYS */
2231 SS$_NOMBX, /* 13 SIGPIPE */
2232 SS$_ASTFLT, /* 14 SIGALRM */
2249 static int initted = 0;
2252 sig_code[16] = C$_SIGUSR1;
2253 sig_code[17] = C$_SIGUSR2;
2254 sig_code[20] = C$_SIGCHLD;
2255 sig_code[28] = C$_SIGWINCH;
2258 if (sig < _SIG_MIN) return 0;
2259 if (sig > _MY_SIG_MAX) return 0;
2260 return sig_code[sig];
2264 Perl_sig_to_vmscondition(int sig)
2267 if (vms_debug_on_exception != 0)
2268 lib$signal(SS$_DEBUG);
2270 return Perl_sig_to_vmscondition_int(sig);
2274 #ifdef KILL_BY_SIGPRC
2275 #define sys$sigprc SYS$SIGPRC
2279 int sys$sigprc(unsigned int *pidadr,
2280 struct dsc$descriptor_s *prcname,
2287 Perl_my_kill(int pid, int sig)
2292 /* sig 0 means validate the PID */
2293 /*------------------------------*/
2295 const unsigned long int jpicode = JPI$_PID;
2298 status = lib$getjpi(&jpicode, &pid, NULL, &ret_pid, NULL, NULL);
2299 if ($VMS_STATUS_SUCCESS(status))
2302 case SS$_NOSUCHNODE:
2303 case SS$_UNREACHABLE:
2317 code = Perl_sig_to_vmscondition_int(sig);
2320 SETERRNO(EINVAL, SS$_BADPARAM);
2324 /* Per official UNIX specification: If pid = 0, or negative then
2325 * signals are to be sent to multiple processes.
2326 * pid = 0 - all processes in group except ones that the system exempts
2327 * pid = -1 - all processes except ones that the system exempts
2328 * pid = -n - all processes in group (abs(n)) except ...
2330 * Handle these via killpg, which is redundant for the -n case, since OP_KILL
2331 * in doio.c already does that. killpg currently does not support the -1 case.
2335 return killpg(-pid, sig);
2338 iss = sys$sigprc((unsigned int *)&pid,0,code);
2339 if (iss&1) return 0;
2343 set_errno(EPERM); break;
2345 case SS$_NOSUCHNODE:
2346 case SS$_UNREACHABLE:
2347 set_errno(ESRCH); break;
2349 set_errno(ENOMEM); break;
2351 _ckvmssts_noperl(iss);
2354 set_vaxc_errno(iss);
2361 Perl_my_killpg(pid_t master_pid, int signum)
2364 unsigned long int jpi_context;
2365 unsigned short int iosb[4];
2366 struct itmlst_3 il3[3];
2368 /* All processes on the system? Seems dangerous, but it looks
2369 * like we could implement this pretty easily with a wildcard
2370 * input to sys$process_scan.
2372 if (master_pid == -1) {
2373 SETERRNO(ENOTSUP, SS$_UNSUPPORTED);
2377 /* All processes in the current process group; find the master
2378 * pid for the current process.
2380 if (master_pid == 0) {
2382 il3[i].buflen = sizeof( int );
2383 il3[i].itmcode = JPI$_MASTER_PID;
2384 il3[i].bufadr = &master_pid;
2385 il3[i++].retlen = NULL;
2389 il3[i].bufadr = NULL;
2390 il3[i++].retlen = NULL;
2392 status = sys$getjpiw(EFN$C_ENF, NULL, NULL, il3, iosb, NULL, 0);
2393 if ($VMS_STATUS_SUCCESS(status))
2401 SETERRNO(EPERM, status);
2403 case SS$_NOMOREPROC:
2405 case SS$_NOSUCHNODE:
2406 case SS$_UNREACHABLE:
2407 SETERRNO(ESRCH, status);
2411 SETERRNO(EINVAL, status);
2414 SETERRNO(EVMSERR, status);
2416 if (!$VMS_STATUS_SUCCESS(status))
2420 /* Set up a process context for those processes we will scan
2421 * with sys$getjpiw. Ask for all processes belonging to the
2427 il3[i].itmcode = PSCAN$_MASTER_PID;
2428 il3[i].bufadr = (void *)master_pid;
2429 il3[i++].retlen = NULL;
2433 il3[i].bufadr = NULL;
2434 il3[i++].retlen = NULL;
2436 status = sys$process_scan(&jpi_context, il3);
2444 SETERRNO(EINVAL, status);
2447 SETERRNO(EVMSERR, status);
2449 if (!$VMS_STATUS_SUCCESS(status))
2453 il3[i].buflen = sizeof(int);
2454 il3[i].itmcode = JPI$_PID;
2455 il3[i].bufadr = &pid;
2456 il3[i++].retlen = NULL;
2460 il3[i].bufadr = NULL;
2461 il3[i++].retlen = NULL;
2463 /* Loop through the processes matching our specified criteria
2467 /* Find the next process...
2469 status = sys$getjpiw( EFN$C_ENF, &jpi_context, NULL, il3, iosb, NULL, 0);
2470 if ($VMS_STATUS_SUCCESS(status)) status = iosb[0];
2474 if (kill(pid, signum) == -1)
2477 continue; /* next process */
2480 SETERRNO(EPERM, status);
2482 case SS$_NOMOREPROC:
2485 case SS$_NOSUCHNODE:
2486 case SS$_UNREACHABLE:
2487 SETERRNO(ESRCH, status);
2491 SETERRNO(EINVAL, status);
2494 SETERRNO(EVMSERR, status);
2497 if (!$VMS_STATUS_SUCCESS(status))
2501 /* Release context-related resources.
2503 (void) sys$process_scan(&jpi_context);
2505 if (status != SS$_NOMOREPROC)
2511 /* Routine to convert a VMS status code to a UNIX status code.
2512 ** More tricky than it appears because of conflicting conventions with
2515 ** VMS status codes are a bit mask, with the least significant bit set for
2518 ** Special UNIX status of EVMSERR indicates that no translation is currently
2519 ** available, and programs should check the VMS status code.
2521 ** Programs compiled with _POSIX_EXIT have a special encoding that requires
2525 #ifndef C_FACILITY_NO
2526 #define C_FACILITY_NO 0x350000
2529 #define DCL_IVVERB 0x38090
2533 Perl_vms_status_to_unix(int vms_status, int child_flag)
2541 /* Assume the best or the worst */
2542 if (vms_status & STS$M_SUCCESS)
2545 unix_status = EVMSERR;
2547 msg_status = vms_status & ~STS$M_CONTROL;
2549 facility = vms_status & STS$M_FAC_NO;
2550 fac_sp = vms_status & STS$M_FAC_SP;
2551 msg_no = vms_status & (STS$M_MSG_NO | STS$M_SEVERITY);
2553 if (((facility == 0) || (fac_sp == 0)) && (child_flag == 0)) {
2559 unix_status = EFAULT;
2561 case SS$_DEVOFFLINE:
2562 unix_status = EBUSY;
2565 unix_status = ENOTCONN;
2573 case SS$_INVFILFOROP:
2577 unix_status = EINVAL;
2579 case SS$_UNSUPPORTED:
2580 unix_status = ENOTSUP;
2585 unix_status = EACCES;
2587 case SS$_DEVICEFULL:
2588 unix_status = ENOSPC;
2591 unix_status = ENODEV;
2593 case SS$_NOSUCHFILE:
2594 case SS$_NOSUCHOBJECT:
2595 unix_status = ENOENT;
2597 case SS$_ABORT: /* Fatal case */
2598 case ((SS$_ABORT & STS$M_COND_ID) | STS$K_ERROR): /* Error case */
2599 case ((SS$_ABORT & STS$M_COND_ID) | STS$K_WARNING): /* Warning case */
2600 unix_status = EINTR;
2603 unix_status = E2BIG;
2606 unix_status = ENOMEM;
2609 unix_status = EPERM;
2611 case SS$_NOSUCHNODE:
2612 case SS$_UNREACHABLE:
2613 unix_status = ESRCH;
2616 unix_status = ECHILD;
2619 if ((facility == 0) && (msg_no < 8)) {
2620 /* These are not real VMS status codes so assume that they are
2621 ** already UNIX status codes
2623 unix_status = msg_no;
2629 /* Translate a POSIX exit code to a UNIX exit code */
2630 if ((facility == C_FACILITY_NO) && ((msg_no & 0xA000) == 0xA000)) {
2631 unix_status = (msg_no & 0x07F8) >> 3;
2635 /* Documented traditional behavior for handling VMS child exits */
2636 /*--------------------------------------------------------------*/
2637 if (child_flag != 0) {
2639 /* Success / Informational return 0 */
2640 /*----------------------------------*/
2641 if (msg_no & STS$K_SUCCESS)
2644 /* Warning returns 1 */
2645 /*-------------------*/
2646 if ((msg_no & (STS$K_ERROR | STS$K_SEVERE)) == 0)
2649 /* Everything else pass through the severity bits */
2650 /*------------------------------------------------*/
2651 return (msg_no & STS$M_SEVERITY);
2654 /* Normal VMS status to ERRNO mapping attempt */
2655 /*--------------------------------------------*/
2656 switch(msg_status) {
2657 /* case RMS$_EOF: */ /* End of File */
2658 case RMS$_FNF: /* File Not Found */
2659 case RMS$_DNF: /* Dir Not Found */
2660 unix_status = ENOENT;
2662 case RMS$_RNF: /* Record Not Found */
2663 unix_status = ESRCH;
2666 unix_status = ENOTDIR;
2669 unix_status = ENODEV;
2674 unix_status = EBADF;
2677 unix_status = EEXIST;
2681 case LIB$_INVSTRDES:
2683 case LIB$_NOSUCHSYM:
2684 case LIB$_INVSYMNAM:
2686 unix_status = EINVAL;
2692 unix_status = E2BIG;
2694 case RMS$_PRV: /* No privilege */
2695 case RMS$_ACC: /* ACP file access failed */
2696 case RMS$_WLK: /* Device write locked */
2697 unix_status = EACCES;
2699 case RMS$_MKD: /* Failed to mark for delete */
2700 unix_status = EPERM;
2702 /* case RMS$_NMF: */ /* No more files */
2710 /* Try to guess at what VMS error status should go with a UNIX errno
2711 * value. This is hard to do as there could be many possible VMS
2712 * error statuses that caused the errno value to be set.
2716 Perl_unix_status_to_vms(int unix_status)
2718 int test_unix_status;
2720 /* Trivial cases first */
2721 /*---------------------*/
2722 if (unix_status == EVMSERR)
2725 /* Is vaxc$errno sane? */
2726 /*---------------------*/
2727 test_unix_status = Perl_vms_status_to_unix(vaxc$errno, 0);
2728 if (test_unix_status == unix_status)
2731 /* If way out of range, must be VMS code already */
2732 /*-----------------------------------------------*/
2733 if (unix_status > EVMSERR)
2736 /* If out of range, punt */
2737 /*-----------------------*/
2738 if (unix_status > __ERRNO_MAX)
2742 /* Ok, now we have to do it the hard way. */
2743 /*----------------------------------------*/
2744 switch(unix_status) {
2745 case 0: return SS$_NORMAL;
2746 case EPERM: return SS$_NOPRIV;
2747 case ENOENT: return SS$_NOSUCHOBJECT;
2748 case ESRCH: return SS$_UNREACHABLE;
2749 case EINTR: return SS$_ABORT;
2752 case E2BIG: return SS$_BUFFEROVF;
2754 case EBADF: return RMS$_IFI;
2755 case ECHILD: return SS$_NONEXPR;
2757 case ENOMEM: return SS$_INSFMEM;
2758 case EACCES: return SS$_FILACCERR;
2759 case EFAULT: return SS$_ACCVIO;
2761 case EBUSY: return SS$_DEVOFFLINE;
2762 case EEXIST: return RMS$_FEX;
2764 case ENODEV: return SS$_NOSUCHDEV;
2765 case ENOTDIR: return RMS$_DIR;
2767 case EINVAL: return SS$_INVARG;
2773 case ENOSPC: return SS$_DEVICEFULL;
2774 case ESPIPE: return LIB$_INVARG;
2779 case ERANGE: return LIB$_INVARG;
2780 /* case EWOULDBLOCK */
2781 /* case EINPROGRESS */
2784 /* case EDESTADDRREQ */
2786 /* case EPROTOTYPE */
2787 /* case ENOPROTOOPT */
2788 /* case EPROTONOSUPPORT */
2789 /* case ESOCKTNOSUPPORT */
2790 /* case EOPNOTSUPP */
2791 /* case EPFNOSUPPORT */
2792 /* case EAFNOSUPPORT */
2793 /* case EADDRINUSE */
2794 /* case EADDRNOTAVAIL */
2796 /* case ENETUNREACH */
2797 /* case ENETRESET */
2798 /* case ECONNABORTED */
2799 /* case ECONNRESET */
2802 case ENOTCONN: return SS$_CLEARED;
2803 /* case ESHUTDOWN */
2804 /* case ETOOMANYREFS */
2805 /* case ETIMEDOUT */
2806 /* case ECONNREFUSED */
2808 /* case ENAMETOOLONG */
2809 /* case EHOSTDOWN */
2810 /* case EHOSTUNREACH */
2811 /* case ENOTEMPTY */
2823 /* case ECANCELED */
2827 return SS$_UNSUPPORTED;
2833 /* case EABANDONED */
2835 return SS$_ABORT; /* punt */
2840 /* default piping mailbox size */
2841 #define PERL_BUFSIZ 8192
2845 create_mbx(unsigned short int *chan, struct dsc$descriptor_s *namdsc)
2847 unsigned long int mbxbufsiz;
2848 static unsigned long int syssize = 0;
2849 unsigned long int dviitm = DVI$_DEVNAM;
2850 char csize[LNM$C_NAMLENGTH+1];
2854 unsigned long syiitm = SYI$_MAXBUF;
2856 * Get the SYSGEN parameter MAXBUF
2858 * If the logical 'PERL_MBX_SIZE' is defined
2859 * use the value of the logical instead of PERL_BUFSIZ, but
2860 * keep the size between 128 and MAXBUF.
2863 _ckvmssts_noperl(lib$getsyi(&syiitm, &syssize, 0, 0, 0, 0));
2866 if (vmstrnenv("PERL_MBX_SIZE", csize, 0, fildev, 0)) {
2867 mbxbufsiz = atoi(csize);
2869 mbxbufsiz = PERL_BUFSIZ;
2871 if (mbxbufsiz < 128) mbxbufsiz = 128;
2872 if (mbxbufsiz > syssize) mbxbufsiz = syssize;
2874 _ckvmssts_noperl(sts = sys$crembx(0,chan,mbxbufsiz,mbxbufsiz,0,0,0));
2876 sts = lib$getdvi(&dviitm, chan, NULL, NULL, namdsc, &namdsc->dsc$w_length);
2877 _ckvmssts_noperl(sts);
2878 namdsc->dsc$a_pointer[namdsc->dsc$w_length] = '\0';
2880 } /* end of create_mbx() */
2883 /*{{{ my_popen and my_pclose*/
2885 typedef struct _iosb IOSB;
2886 typedef struct _iosb* pIOSB;
2887 typedef struct _pipe Pipe;
2888 typedef struct _pipe* pPipe;
2889 typedef struct pipe_details Info;
2890 typedef struct pipe_details* pInfo;
2891 typedef struct _srqp RQE;
2892 typedef struct _srqp* pRQE;
2893 typedef struct _tochildbuf CBuf;
2894 typedef struct _tochildbuf* pCBuf;
2897 unsigned short status;
2898 unsigned short count;
2899 unsigned long dvispec;
2902 #pragma member_alignment save
2903 #pragma nomember_alignment quadword
2904 struct _srqp { /* VMS self-relative queue entry */
2905 unsigned long qptr[2];
2907 #pragma member_alignment restore
2908 static RQE RQE_ZERO = {0,0};
2910 struct _tochildbuf {
2913 unsigned short size;
2921 unsigned short chan_in;
2922 unsigned short chan_out;
2924 unsigned int bufsize;
2936 #if defined(PERL_IMPLICIT_CONTEXT)
2937 void *thx; /* Either a thread or an interpreter */
2938 /* pointer, depending on how we're built */
2946 PerlIO *fp; /* file pointer to pipe mailbox */
2947 int useFILE; /* using stdio, not perlio */
2948 int pid; /* PID of subprocess */
2949 int mode; /* == 'r' if pipe open for reading */
2950 int done; /* subprocess has completed */
2951 int waiting; /* waiting for completion/closure */
2952 int closing; /* my_pclose is closing this pipe */
2953 unsigned long completion; /* termination status of subprocess */
2954 pPipe in; /* pipe in to sub */
2955 pPipe out; /* pipe out of sub */
2956 pPipe err; /* pipe of sub's sys$error */
2957 int in_done; /* true when in pipe finished */
2960 unsigned short xchan; /* channel to debug xterm */
2961 unsigned short xchan_valid; /* channel is assigned */
2964 struct exit_control_block
2966 struct exit_control_block *flink;
2967 unsigned long int (*exit_routine)(void);
2968 unsigned long int arg_count;
2969 unsigned long int *status_address;
2970 unsigned long int exit_status;
2973 typedef struct _closed_pipes Xpipe;
2974 typedef struct _closed_pipes* pXpipe;
2976 struct _closed_pipes {
2977 int pid; /* PID of subprocess */
2978 unsigned long completion; /* termination status of subprocess */
2980 #define NKEEPCLOSED 50
2981 static Xpipe closed_list[NKEEPCLOSED];
2982 static int closed_index = 0;
2983 static int closed_num = 0;
2985 #define RETRY_DELAY "0 ::0.20"
2986 #define MAX_RETRY 50
2988 static int pipe_ef = 0; /* first call to safe_popen inits these*/
2989 static unsigned long mypid;
2990 static unsigned long delaytime[2];
2992 static pInfo open_pipes = NULL;
2993 static $DESCRIPTOR(nl_desc, "NL:");
2995 #define PIPE_COMPLETION_WAIT 30 /* seconds, for EOF/FORCEX wait */
2999 static unsigned long int
3000 pipe_exit_routine(void)
3003 unsigned long int retsts = SS$_NORMAL, abort = SS$_TIMEOUT;
3004 int sts, did_stuff, j;
3007 * Flush any pending i/o, but since we are in process run-down, be
3008 * careful about referencing PerlIO structures that may already have
3009 * been deallocated. We may not even have an interpreter anymore.
3014 #if defined(PERL_IMPLICIT_CONTEXT)
3015 /* We need to use the Perl context of the thread that created */
3019 aTHX = info->err->thx;
3021 aTHX = info->out->thx;
3023 aTHX = info->in->thx;
3026 #if defined(USE_ITHREADS)
3030 && PL_perlio_fd_refcnt
3033 PerlIO_flush(info->fp);
3035 fflush((FILE *)info->fp);
3041 next we try sending an EOF...ignore if doesn't work, make sure we
3048 _ckvmssts_noperl(sys$setast(0));
3049 if (info->in && !info->in->shut_on_empty) {
3050 _ckvmssts_noperl(sys$qio(0,info->in->chan_in,IO$_WRITEOF,0,0,0,
3055 _ckvmssts_noperl(sys$setast(1));
3059 /* wait for EOF to have effect, up to ~ 30 sec [default] */
3061 for (j = 0; did_stuff && j < PIPE_COMPLETION_WAIT; j++) {
3066 _ckvmssts_noperl(sys$setast(0));
3067 if (info->waiting && info->done)
3069 nwait += info->waiting;
3070 _ckvmssts_noperl(sys$setast(1));
3080 _ckvmssts_noperl(sys$setast(0));
3081 if (!info->done) { /* Tap them gently on the shoulder . . .*/
3082 sts = sys$forcex(&info->pid,0,&abort);
3083 if (!(sts&1) && sts != SS$_NONEXPR) _ckvmssts_noperl(sts);
3086 _ckvmssts_noperl(sys$setast(1));
3090 /* again, wait for effect */
3092 for (j = 0; did_stuff && j < PIPE_COMPLETION_WAIT; j++) {
3097 _ckvmssts_noperl(sys$setast(0));
3098 if (info->waiting && info->done)
3100 nwait += info->waiting;
3101 _ckvmssts_noperl(sys$setast(1));
3110 _ckvmssts_noperl(sys$setast(0));
3111 if (!info->done) { /* We tried to be nice . . . */
3112 sts = sys$delprc(&info->pid,0);
3113 if (!(sts&1) && sts != SS$_NONEXPR) _ckvmssts_noperl(sts);
3114 info->done = 1; /* sys$delprc is as done as we're going to get. */
3116 _ckvmssts_noperl(sys$setast(1));
3122 #if defined(PERL_IMPLICIT_CONTEXT)
3123 /* We need to use the Perl context of the thread that created */
3126 if (open_pipes->err)
3127 aTHX = open_pipes->err->thx;
3128 else if (open_pipes->out)
3129 aTHX = open_pipes->out->thx;
3130 else if (open_pipes->in)
3131 aTHX = open_pipes->in->thx;
3133 if ((sts = my_pclose(open_pipes->fp)) == -1) retsts = vaxc$errno;
3134 else if (!(sts & 1)) retsts = sts;
3139 static struct exit_control_block pipe_exitblock =
3140 {(struct exit_control_block *) 0,
3141 pipe_exit_routine, 0, &pipe_exitblock.exit_status, 0};
3143 static void pipe_mbxtofd_ast(pPipe p);
3144 static void pipe_tochild1_ast(pPipe p);
3145 static void pipe_tochild2_ast(pPipe p);
3148 popen_completion_ast(pInfo info)
3150 pInfo i = open_pipes;
3153 info->completion &= 0x0FFFFFFF; /* strip off "control" field */
3154 closed_list[closed_index].pid = info->pid;
3155 closed_list[closed_index].completion = info->completion;
3157 if (closed_index == NKEEPCLOSED)
3162 if (i == info) break;
3165 if (!i) return; /* unlinked, probably freed too */
3170 Writing to subprocess ...
3171 if my_pclose'd: EOF already sent, should shutdown chan_in part of pipe
3173 chan_out may be waiting for "done" flag, or hung waiting
3174 for i/o completion to child...cancel the i/o. This will
3175 put it into "snarf mode" (done but no EOF yet) that discards
3178 Output from subprocess (stdout, stderr) needs to be flushed and
3179 shut down. We try sending an EOF, but if the mbx is full the pipe
3180 routine should still catch the "shut_on_empty" flag, telling it to
3181 use immediate-style reads so that "mbx empty" -> EOF.
3185 if (info->in && !info->in_done) { /* only for mode=w */
3186 if (info->in->shut_on_empty && info->in->need_wake) {
3187 info->in->need_wake = FALSE;
3188 _ckvmssts_noperl(sys$dclast(pipe_tochild2_ast,info->in,0));
3190 _ckvmssts_noperl(sys$cancel(info->in->chan_out));
3194 if (info->out && !info->out_done) { /* were we also piping output? */
3195 info->out->shut_on_empty = TRUE;
3196 iss = sys$qio(0,info->out->chan_in,IO$_WRITEOF|IO$M_NORSWAIT, 0, 0, 0, 0, 0, 0, 0, 0, 0);
3197 if (iss == SS$_MBFULL) iss = SS$_NORMAL;
3198 _ckvmssts_noperl(iss);
3201 if (info->err && !info->err_done) { /* we were piping stderr */
3202 info->err->shut_on_empty = TRUE;
3203 iss = sys$qio(0,info->err->chan_in,IO$_WRITEOF|IO$M_NORSWAIT, 0, 0, 0, 0, 0, 0, 0, 0, 0);
3204 if (iss == SS$_MBFULL) iss = SS$_NORMAL;
3205 _ckvmssts_noperl(iss);
3207 _ckvmssts_noperl(sys$setef(pipe_ef));
3211 static unsigned long int setup_cmddsc(pTHX_ const char *cmd, int check_img, int *suggest_quote, struct dsc$descriptor_s **pvmscmd);
3212 static void vms_execfree(struct dsc$descriptor_s *vmscmd);
3213 static void pipe_infromchild_ast(pPipe p);
3216 I'm using LIB$(GET|FREE)_VM here so that we can allocate and deallocate
3217 inside an AST routine without worrying about reentrancy and which Perl
3218 memory allocator is being used.
3220 We read data and queue up the buffers, then spit them out one at a
3221 time to the output mailbox when the output mailbox is ready for one.
3224 #define INITIAL_TOCHILDQUEUE 2
3227 pipe_tochild_setup(pTHX_ char *rmbx, char *wmbx)
3231 char mbx1[64], mbx2[64];
3232 struct dsc$descriptor_s d_mbx1 = {sizeof mbx1, DSC$K_DTYPE_T,
3233 DSC$K_CLASS_S, mbx1},
3234 d_mbx2 = {sizeof mbx2, DSC$K_DTYPE_T,
3235 DSC$K_CLASS_S, mbx2};
3236 unsigned int dviitm = DVI$_DEVBUFSIZ;
3240 _ckvmssts_noperl(lib$get_vm(&n, &p));
3242 create_mbx(&p->chan_in , &d_mbx1);
3243 create_mbx(&p->chan_out, &d_mbx2);
3244 _ckvmssts_noperl(lib$getdvi(&dviitm, &p->chan_in, 0, &p->bufsize));
3247 p->shut_on_empty = FALSE;
3248 p->need_wake = FALSE;
3251 p->iosb.status = SS$_NORMAL;
3252 p->iosb2.status = SS$_NORMAL;
3258 #ifdef PERL_IMPLICIT_CONTEXT
3262 n = sizeof(CBuf) + p->bufsize;
3264 for (j = 0; j < INITIAL_TOCHILDQUEUE; j++) {
3265 _ckvmssts_noperl(lib$get_vm(&n, &b));
3266 b->buf = (char *) b + sizeof(CBuf);
3267 _ckvmssts_noperl(lib$insqhi(b, &p->free));
3270 pipe_tochild2_ast(p);
3271 pipe_tochild1_ast(p);
3277 /* reads the MBX Perl is writing, and queues */
3280 pipe_tochild1_ast(pPipe p)
3283 int iss = p->iosb.status;
3284 int eof = (iss == SS$_ENDOFFILE);
3286 #ifdef PERL_IMPLICIT_CONTEXT
3292 p->shut_on_empty = TRUE;
3294 _ckvmssts_noperl(sys$dassgn(p->chan_in));
3296 _ckvmssts_noperl(iss);
3300 b->size = p->iosb.count;
3301 _ckvmssts_noperl(sts = lib$insqhi(b, &p->wait));
3303 p->need_wake = FALSE;
3304 _ckvmssts_noperl(sys$dclast(pipe_tochild2_ast,p,0));
3307 p->retry = 1; /* initial call */
3310 if (eof) { /* flush the free queue, return when done */
3311 int n = sizeof(CBuf) + p->bufsize;
3313 iss = lib$remqti(&p->free, &b);
3314 if (iss == LIB$_QUEWASEMP) return;
3315 _ckvmssts_noperl(iss);
3316 _ckvmssts_noperl(lib$free_vm(&n, &b));
3320 iss = lib$remqti(&p->free, &b);
3321 if (iss == LIB$_QUEWASEMP) {
3322 int n = sizeof(CBuf) + p->bufsize;
3323 _ckvmssts_noperl(lib$get_vm(&n, &b));
3324 b->buf = (char *) b + sizeof(CBuf);
3326 _ckvmssts_noperl(iss);
3330 iss = sys$qio(0,p->chan_in,
3331 IO$_READVBLK|(p->shut_on_empty ? IO$M_NOWAIT : 0),
3333 pipe_tochild1_ast, p, b->buf, p->bufsize, 0, 0, 0, 0);
3334 if (iss == SS$_ENDOFFILE && p->shut_on_empty) iss = SS$_NORMAL;
3335 _ckvmssts_noperl(iss);
3339 /* writes queued buffers to output, waits for each to complete before
3343 pipe_tochild2_ast(pPipe p)
3346 int iss = p->iosb2.status;
3347 int n = sizeof(CBuf) + p->bufsize;
3348 int done = (p->info && p->info->done) ||
3349 iss == SS$_CANCEL || iss == SS$_ABORT;
3350 #if defined(PERL_IMPLICIT_CONTEXT)
3355 if (p->type) { /* type=1 has old buffer, dispose */
3356 if (p->shut_on_empty) {
3357 _ckvmssts_noperl(lib$free_vm(&n, &b));
3359 _ckvmssts_noperl(lib$insqhi(b, &p->free));
3364 iss = lib$remqti(&p->wait, &b);
3365 if (iss == LIB$_QUEWASEMP) {
3366 if (p->shut_on_empty) {
3368 _ckvmssts_noperl(sys$dassgn(p->chan_out));
3369 *p->pipe_done = TRUE;
3370 _ckvmssts_noperl(sys$setef(pipe_ef));
3372 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEOF,
3373 &p->iosb2, pipe_tochild2_ast, p, 0, 0, 0, 0, 0, 0));
3377 p->need_wake = TRUE;
3380 _ckvmssts_noperl(iss);
3387 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEOF,
3388 &p->iosb2, pipe_tochild2_ast, p, 0, 0, 0, 0, 0, 0));
3390 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEVBLK,
3391 &p->iosb2, pipe_tochild2_ast, p, b->buf, b->size, 0, 0, 0, 0));
3400 pipe_infromchild_setup(pTHX_ char *rmbx, char *wmbx)
3403 char mbx1[64], mbx2[64];
3404 struct dsc$descriptor_s d_mbx1 = {sizeof mbx1, DSC$K_DTYPE_T,
3405 DSC$K_CLASS_S, mbx1},
3406 d_mbx2 = {sizeof mbx2, DSC$K_DTYPE_T,
3407 DSC$K_CLASS_S, mbx2};
3408 unsigned int dviitm = DVI$_DEVBUFSIZ;
3410 int n = sizeof(Pipe);
3411 _ckvmssts_noperl(lib$get_vm(&n, &p));
3412 create_mbx(&p->chan_in , &d_mbx1);
3413 create_mbx(&p->chan_out, &d_mbx2);
3415 _ckvmssts_noperl(lib$getdvi(&dviitm, &p->chan_in, 0, &p->bufsize));
3416 n = p->bufsize * sizeof(char);
3417 _ckvmssts_noperl(lib$get_vm(&n, &p->buf));
3418 p->shut_on_empty = FALSE;
3421 p->iosb.status = SS$_NORMAL;
3422 #if defined(PERL_IMPLICIT_CONTEXT)
3425 pipe_infromchild_ast(p);
3433 pipe_infromchild_ast(pPipe p)
3435 int iss = p->iosb.status;
3436 int eof = (iss == SS$_ENDOFFILE);
3437 int myeof = (eof && (p->iosb.dvispec == mypid || p->iosb.dvispec == 0));
3438 int kideof = (eof && (p->iosb.dvispec == p->info->pid));
3439 #if defined(PERL_IMPLICIT_CONTEXT)
3443 if (p->info && p->info->closing && p->chan_out) { /* output shutdown */
3444 _ckvmssts_noperl(sys$dassgn(p->chan_out));
3449 input shutdown if EOF from self (done or shut_on_empty)
3450 output shutdown if closing flag set (my_pclose)
3451 send data/eof from child or eof from self
3452 otherwise, re-read (snarf of data from child)
3457 if (myeof && p->chan_in) { /* input shutdown */
3458 _ckvmssts_noperl(sys$dassgn(p->chan_in));
3463 if (myeof || kideof) { /* pass EOF to parent */
3464 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEOF, &p->iosb,
3465 pipe_infromchild_ast, p,
3468 } else if (eof) { /* eat EOF --- fall through to read*/
3470 } else { /* transmit data */
3471 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEVBLK,&p->iosb,
3472 pipe_infromchild_ast,p,
3473 p->buf, p->iosb.count, 0, 0, 0, 0));
3479 /* everything shut? flag as done */
3481 if (!p->chan_in && !p->chan_out) {
3482 *p->pipe_done = TRUE;
3483 _ckvmssts_noperl(sys$setef(pipe_ef));
3487 /* write completed (or read, if snarfing from child)
3488 if still have input active,
3489 queue read...immediate mode if shut_on_empty so we get EOF if empty
3491 check if Perl reading, generate EOFs as needed
3497 iss = sys$qio(0,p->chan_in,IO$_READVBLK|(p->shut_on_empty ? IO$M_NOW : 0),&p->iosb,
3498 pipe_infromchild_ast,p,
3499 p->buf, p->bufsize, 0, 0, 0, 0);
3500 if (p->shut_on_empty && iss == SS$_ENDOFFILE) iss = SS$_NORMAL;
3501 _ckvmssts_noperl(iss);
3502 } else { /* send EOFs for extra reads */
3503 p->iosb.status = SS$_ENDOFFILE;
3504 p->iosb.dvispec = 0;
3505 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_SETMODE|IO$M_READATTN,
3507 pipe_infromchild_ast, p, 0, 0, 0, 0));
3513 pipe_mbxtofd_setup(pTHX_ int fd, char *out)
3517 unsigned long dviitm = DVI$_DEVBUFSIZ;
3519 struct dsc$descriptor_s d_mbx = {sizeof mbx, DSC$K_DTYPE_T,
3520 DSC$K_CLASS_S, mbx};
3521 int n = sizeof(Pipe);
3523 /* things like terminals and mbx's don't need this filter */
3524 if (fd && fstat(fd,&s) == 0) {
3525 unsigned long devchar;
3527 unsigned short dev_len;
3528 struct dsc$descriptor_s d_dev;
3530 struct item_list_3 items[3];
3532 unsigned short dvi_iosb[4];
3534 cptr = getname(fd, out, 1);
3535 if (cptr == NULL) _ckvmssts_noperl(SS$_NOSUCHDEV);
3536 d_dev.dsc$a_pointer = out;
3537 d_dev.dsc$w_length = strlen(out);
3538 d_dev.dsc$b_dtype = DSC$K_DTYPE_T;
3539 d_dev.dsc$b_class = DSC$K_CLASS_S;
3542 items[0].code = DVI$_DEVCHAR;
3543 items[0].bufadr = &devchar;
3544 items[0].retadr = NULL;
3546 items[1].code = DVI$_FULLDEVNAM;
3547 items[1].bufadr = device;
3548 items[1].retadr = &dev_len;
3552 status = sys$getdviw
3553 (NO_EFN, 0, &d_dev, items, dvi_iosb, NULL, NULL, NULL);
3554 _ckvmssts_noperl(status);
3555 if ($VMS_STATUS_SUCCESS(dvi_iosb[0])) {
3556 device[dev_len] = 0;
3558 if (!(devchar & DEV$M_DIR)) {
3559 strcpy(out, device);
3565 _ckvmssts_noperl(lib$get_vm(&n, &p));
3566 p->fd_out = dup(fd);
3567 create_mbx(&p->chan_in, &d_mbx);
3568 _ckvmssts_noperl(lib$getdvi(&dviitm, &p->chan_in, 0, &p->bufsize));
3569 n = (p->bufsize+1) * sizeof(char);
3570 _ckvmssts_noperl(lib$get_vm(&n, &p->buf));
3571 p->shut_on_empty = FALSE;
3576 _ckvmssts_noperl(sys$qio(0, p->chan_in, IO$_READVBLK, &p->iosb,
3577 pipe_mbxtofd_ast, p,
3578 p->buf, p->bufsize, 0, 0, 0, 0));
3584 pipe_mbxtofd_ast(pPipe p)
3586 int iss = p->iosb.status;
3587 int done = p->info->done;
3589 int eof = (iss == SS$_ENDOFFILE);
3590 int myeof = eof && ((p->iosb.dvispec == mypid)||(p->iosb.dvispec == 0));
3591 int err = !(iss&1) && !eof;
3592 #if defined(PERL_IMPLICIT_CONTEXT)
3596 if (done && myeof) { /* end piping */
3598 sys$dassgn(p->chan_in);
3599 *p->pipe_done = TRUE;
3600 _ckvmssts_noperl(sys$setef(pipe_ef));
3604 if (!err && !eof) { /* good data to send to file */
3605 p->buf[p->iosb.count] = '\n';
3606 iss2 = write(p->fd_out, p->buf, p->iosb.count+1);
3609 if (p->retry < MAX_RETRY) {
3610 _ckvmssts_noperl(sys$setimr(0,delaytime,pipe_mbxtofd_ast,p));
3616 _ckvmssts_noperl(iss);
3620 iss = sys$qio(0, p->chan_in, IO$_READVBLK|(p->shut_on_empty ? IO$M_NOW : 0), &p->iosb,
3621 pipe_mbxtofd_ast, p,
3622 p->buf, p->bufsize, 0, 0, 0, 0);
3623 if (p->shut_on_empty && (iss == SS$_ENDOFFILE)) iss = SS$_NORMAL;
3624 _ckvmssts_noperl(iss);
3628 typedef struct _pipeloc PLOC;
3629 typedef struct _pipeloc* pPLOC;
3633 char dir[NAM$C_MAXRSS+1];
3635 static pPLOC head_PLOC = 0;
3638 free_pipelocs(pTHX_ void *head)
3641 pPLOC *pHead = (pPLOC *)head;
3653 store_pipelocs(pTHX)
3661 char temp[NAM$C_MAXRSS+1];
3665 free_pipelocs(aTHX_ &head_PLOC);
3667 /* the . directory from @INC comes last */
3669 p = (pPLOC) PerlMem_malloc(sizeof(PLOC));
3670 if (p == NULL) _ckvmssts_noperl(SS$_INSFMEM);
3671 p->next = head_PLOC;
3673 strcpy(p->dir,"./");
3675 /* get the directory from $^X */
3677 unixdir = (char *)PerlMem_malloc(VMS_MAXRSS);
3678 if (unixdir == NULL) _ckvmssts_noperl(SS$_INSFMEM);
3680 #ifdef PERL_IMPLICIT_CONTEXT
3681 if (aTHX && PL_origargv && PL_origargv[0]) { /* maybe nul if embedded Perl */
3683 if (PL_origargv && PL_origargv[0]) { /* maybe nul if embedded Perl */
3685 my_strlcpy(temp, PL_origargv[0], sizeof(temp));
3686 x = strrchr(temp,']');
3688 x = strrchr(temp,'>');
3690 /* It could be a UNIX path */
3691 x = strrchr(temp,'/');
3697 /* Got a bare name, so use default directory */
3702 if ((tounixpath_utf8(temp, unixdir, NULL)) != NULL) {
3703 p = (pPLOC) PerlMem_malloc(sizeof(PLOC));
3704 if (p == NULL) _ckvmssts_noperl(SS$_INSFMEM);
3705 p->next = head_PLOC;
3707 my_strlcpy(p->dir, unixdir, sizeof(p->dir));
3711 /* reverse order of @INC entries, skip "." since entered above */
3713 #ifdef PERL_IMPLICIT_CONTEXT
3716 if (PL_incgv) av = GvAVn(PL_incgv);
3718 for (i = 0; av && i <= AvFILL(av); i++) {
3719 dirsv = *av_fetch(av,i,TRUE);
3721 if (SvROK(dirsv)) continue;
3722 dir = SvPVx(dirsv,n_a);
3723 if (strcmp(dir,".") == 0) continue;
3724 if ((tounixpath_utf8(dir, unixdir, NULL)) == NULL)
3727 p = (pPLOC) PerlMem_malloc(sizeof(PLOC));
3728 p->next = head_PLOC;
3730 my_strlcpy(p->dir, unixdir, sizeof(p->dir));
3733 /* most likely spot (ARCHLIB) put first in the list */
3736 if ((tounixpath_utf8(ARCHLIB_EXP, unixdir, NULL)) != NULL) {
3737 p = (pPLOC) PerlMem_malloc(sizeof(PLOC));
3738 if (p == NULL) _ckvmssts_noperl(SS$_INSFMEM);
3739 p->next = head_PLOC;
3741 my_strlcpy(p->dir, unixdir, sizeof(p->dir));
3744 PerlMem_free(unixdir);
3747 static I32 Perl_cando_by_name_int(pTHX_ I32 bit, bool effective,
3748 const char *fname, int opts);
3749 #if !defined(PERL_IMPLICIT_CONTEXT)
3750 #define cando_by_name_int Perl_cando_by_name_int
3752 #define cando_by_name_int(a,b,c,d) Perl_cando_by_name_int(aTHX_ a,b,c,d)
3758 static int vmspipe_file_status = 0;
3759 static char vmspipe_file[NAM$C_MAXRSS+1];
3761 /* already found? Check and use ... need read+execute permission */
3763 if (vmspipe_file_status == 1) {
3764 if (cando_by_name_int(S_IRUSR, 0, vmspipe_file, PERL_RMSEXPAND_M_VMS_IN)
3765 && cando_by_name_int
3766 (S_IXUSR, 0, vmspipe_file, PERL_RMSEXPAND_M_VMS_IN)) {
3767 return vmspipe_file;
3769 vmspipe_file_status = 0;
3772 /* scan through stored @INC, $^X */
3774 if (vmspipe_file_status == 0) {
3775 char file[NAM$C_MAXRSS+1];
3776 pPLOC p = head_PLOC;
3781 dirlen = my_strlcpy(file, p->dir, sizeof(file));
3782 my_strlcat(file, "vmspipe.com", sizeof(file));
3785 exp_res = int_rmsexpand_tovms(file, vmspipe_file, 0);
3786 if (!exp_res) continue;
3788 if (cando_by_name_int
3789 (S_IRUSR, 0, vmspipe_file, PERL_RMSEXPAND_M_VMS_IN)
3790 && cando_by_name_int
3791 (S_IXUSR, 0, vmspipe_file, PERL_RMSEXPAND_M_VMS_IN)) {
3792 vmspipe_file_status = 1;
3793 return vmspipe_file;
3796 vmspipe_file_status = -1; /* failed, use tempfiles */
3803 vmspipe_tempfile(pTHX)
3805 char file[NAM$C_MAXRSS+1];
3807 static int index = 0;
3811 /* create a tempfile */
3813 /* we can't go from W, shr=get to R, shr=get without
3814 an intermediate vulnerable state, so don't bother trying...
3816 and lib$spawn doesn't shr=put, so have to close the write
3818 So... match up the creation date/time and the FID to
3819 make sure we're dealing with the same file
3824 if (!decc_filename_unix_only) {
3825 sprintf(file,"sys$scratch:perlpipe_%08.8x_%d.com",mypid,index);
3826 fp = fopen(file,"w");
3828 sprintf(file,"sys$login:perlpipe_%08.8x_%d.com",mypid,index);
3829 fp = fopen(file,"w");
3831 sprintf(file,"sys$disk:[]perlpipe_%08.8x_%d.com",mypid,index);
3832 fp = fopen(file,"w");
3837 sprintf(file,"/tmp/perlpipe_%08.8x_%d.com",mypid,index);
3838 fp = fopen(file,"w");
3840 sprintf(file,"/sys$login/perlpipe_%08.8x_%d.com",mypid,index);
3841 fp = fopen(file,"w");
3843 sprintf(file,"./perlpipe_%08.8x_%d.com",mypid,index);
3844 fp = fopen(file,"w");
3848 if (!fp) return 0; /* we're hosed */
3850 fprintf(fp,"$! 'f$verify(0)'\n");
3851 fprintf(fp,"$! --- protect against nonstandard definitions ---\n");
3852 fprintf(fp,"$ perl_cfile = f$environment(\"procedure\")\n");
3853 fprintf(fp,"$ perl_define = \"define/nolog\"\n");
3854 fprintf(fp,"$ perl_on = \"set noon\"\n");
3855 fprintf(fp,"$ perl_exit = \"exit\"\n");
3856 fprintf(fp,"$ perl_del = \"delete\"\n");
3857 fprintf(fp,"$ pif = \"if\"\n");
3858 fprintf(fp,"$! --- define i/o redirection (sys$output set by lib$spawn)\n");
3859 fprintf(fp,"$ pif perl_popen_in .nes. \"\" then perl_define/user/name_attributes=confine sys$input 'perl_popen_in'\n");
3860 fprintf(fp,"$ pif perl_popen_err .nes. \"\" then perl_define/user/name_attributes=confine sys$error 'perl_popen_err'\n");
3861 fprintf(fp,"$ pif perl_popen_out .nes. \"\" then perl_define sys$output 'perl_popen_out'\n");
3862 fprintf(fp,"$! --- build command line to get max possible length\n");
3863 fprintf(fp,"$c=perl_popen_cmd0\n");
3864 fprintf(fp,"$c=c+perl_popen_cmd1\n");
3865 fprintf(fp,"$c=c+perl_popen_cmd2\n");
3866 fprintf(fp,"$x=perl_popen_cmd3\n");
3867 fprintf(fp,"$c=c+x\n");
3868 fprintf(fp,"$ perl_on\n");
3869 fprintf(fp,"$ 'c'\n");
3870 fprintf(fp,"$ perl_status = $STATUS\n");
3871 fprintf(fp,"$ perl_del 'perl_cfile'\n");
3872 fprintf(fp,"$ perl_exit 'perl_status'\n");
3875 fgetname(fp, file, 1);
3876 fstat(fileno(fp), &s0.crtl_stat);
3879 if (decc_filename_unix_only)
3880 int_tounixspec(file, file, NULL);
3881 fp = fopen(file,"r","shr=get");
3883 fstat(fileno(fp), &s1.crtl_stat);
3885 cmp_result = VMS_INO_T_COMPARE(s0.crtl_stat.st_ino, s1.crtl_stat.st_ino);
3886 if ((cmp_result != 0) && (s0.st_ctime != s1.st_ctime)) {
3896 vms_is_syscommand_xterm(void)
3898 const static struct dsc$descriptor_s syscommand_dsc =
3899 { 11, DSC$K_DTYPE_T, DSC$K_CLASS_S, "SYS$COMMAND" };
3901 const static struct dsc$descriptor_s decwdisplay_dsc =
3902 { 12, DSC$K_DTYPE_T, DSC$K_CLASS_S, "DECW$DISPLAY" };
3904 struct item_list_3 items[2];
3905 unsigned short dvi_iosb[4];
3906 unsigned long devchar;
3907 unsigned long devclass;
3910 /* Very simple check to guess if sys$command is a decterm? */
3911 /* First see if the DECW$DISPLAY: device exists */
3913 items[0].code = DVI$_DEVCHAR;
3914 items[0].bufadr = &devchar;
3915 items[0].retadr = NULL;
3919 status = sys$getdviw
3920 (NO_EFN, 0, &decwdisplay_dsc, items, dvi_iosb, NULL, NULL, NULL);
3922 if ($VMS_STATUS_SUCCESS(status)) {
3923 status = dvi_iosb[0];
3926 if (!$VMS_STATUS_SUCCESS(status)) {
3927 SETERRNO(EVMSERR, status);
3931 /* If it does, then for now assume that we are on a workstation */
3932 /* Now verify that SYS$COMMAND is a terminal */
3933 /* for creating the debugger DECTerm */
3936 items[0].code = DVI$_DEVCLASS;
3937 items[0].bufadr = &devclass;
3938 items[0].retadr = NULL;
3942 status = sys$getdviw
3943 (NO_EFN, 0, &syscommand_dsc, items, dvi_iosb, NULL, NULL, NULL);
3945 if ($VMS_STATUS_SUCCESS(status)) {
3946 status = dvi_iosb[0];
3949 if (!$VMS_STATUS_SUCCESS(status)) {
3950 SETERRNO(EVMSERR, status);
3954 if (devclass == DC$_TERM) {
3961 /* If we are on a DECTerm, we can pretend to fork xterms when requested */
3963 create_forked_xterm(pTHX_ const char *cmd, const char *mode)
3968 char device_name[65];
3969 unsigned short device_name_len;
3970 struct dsc$descriptor_s customization_dsc;
3971 struct dsc$descriptor_s device_name_dsc;
3973 char customization[200];
3977 unsigned short p_chan;
3979 unsigned short iosb[4];
3980 const char * cust_str =
3981 "DECW$TERMINAL.iconName:\tPerl Dbg\nDECW$TERMINAL.title:\t%40s\n";
3982 struct dsc$descriptor_s d_mbx1 = {sizeof mbx1, DSC$K_DTYPE_T,
3983 DSC$K_CLASS_S, mbx1};
3985 /* LIB$FIND_IMAGE_SIGNAL needs a handler */
3986 /*---------------------------------------*/
3987 VAXC$ESTABLISH((__vms_handler)lib$sig_to_ret);
3990 /* Make sure that this is from the Perl debugger */
3991 ret_char = strstr(cmd," xterm ");
3992 if (ret_char == NULL)
3994 cptr = ret_char + 7;
3995 ret_char = strstr(cmd,"tty");
3996 if (ret_char == NULL)
3998 ret_char = strstr(cmd,"sleep");
3999 if (ret_char == NULL)
4002 if (decw_term_port == 0) {
4003 $DESCRIPTOR(filename1_dsc, "DECW$TERMINALSHR12");
4004 $DESCRIPTOR(filename2_dsc, "DECW$TERMINALSHR");
4005 $DESCRIPTOR(decw_term_port_dsc, "DECW$TERM_PORT");
4007 status = lib$find_image_symbol
4009 &decw_term_port_dsc,
4010 (void *)&decw_term_port,
4014 /* Try again with the other image name */
4015 if (!$VMS_STATUS_SUCCESS(status)) {
4017 status = lib$find_image_symbol
4019 &decw_term_port_dsc,
4020 (void *)&decw_term_port,
4029 /* No decw$term_port, give it up */
4030 if (!$VMS_STATUS_SUCCESS(status))
4033 /* Are we on a workstation? */
4034 /* to do: capture the rows / columns and pass their properties */
4035 ret_stat = vms_is_syscommand_xterm();
4039 /* Make the title: */
4040 ret_char = strstr(cptr,"-title");
4041 if (ret_char != NULL) {
4042 while ((*cptr != 0) && (*cptr != '\"')) {
4048 while ((*cptr != 0) && (*cptr != '\"')) {
4061 strcpy(title,"Perl Debug DECTerm");
4063 sprintf(customization, cust_str, title);
4065 customization_dsc.dsc$a_pointer = customization;
4066 customization_dsc.dsc$w_length = strlen(customization);
4067 customization_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
4068 customization_dsc.dsc$b_class = DSC$K_CLASS_S;
4070 device_name_dsc.dsc$a_pointer = device_name;
4071 device_name_dsc.dsc$w_length = sizeof device_name -1;
4072 device_name_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
4073 device_name_dsc.dsc$b_class = DSC$K_CLASS_S;
4075 device_name_len = 0;
4077 /* Try to create the window */
4078 status = (*decw_term_port)
4087 if (!$VMS_STATUS_SUCCESS(status)) {
4088 SETERRNO(EVMSERR, status);
4092 device_name[device_name_len] = '\0';
4094 /* Need to set this up to look like a pipe for cleanup */
4096 status = lib$get_vm(&n, &info);
4097 if (!$VMS_STATUS_SUCCESS(status)) {
4098 SETERRNO(ENOMEM, status);
4104 info->completion = 0;
4105 info->closing = FALSE;
4112 info->in_done = TRUE;
4113 info->out_done = TRUE;
4114 info->err_done = TRUE;
4116 /* Assign a channel on this so that it will persist, and not login */
4117 /* We stash this channel in the info structure for reference. */
4118 /* The created xterm self destructs when the last channel is removed */
4119 /* and it appears that perl5db.pl (perl debugger) does this routinely */
4120 /* So leave this assigned. */
4121 device_name_dsc.dsc$w_length = device_name_len;
4122 status = sys$assign(&device_name_dsc,&info->xchan,0,0);
4123 if (!$VMS_STATUS_SUCCESS(status)) {
4124 SETERRNO(EVMSERR, status);
4127 info->xchan_valid = 1;
4129 /* Now create a mailbox to be read by the application */
4131 create_mbx(&p_chan, &d_mbx1);
4133 /* write the name of the created terminal to the mailbox */
4134 status = sys$qiow(NO_EFN, p_chan, IO$_WRITEVBLK|IO$M_NOW,
4135 iosb, NULL, NULL, device_name, device_name_len, 0, 0, 0, 0);
4137 if (!$VMS_STATUS_SUCCESS(status)) {
4138 SETERRNO(EVMSERR, status);
4142 info->fp = PerlIO_open(mbx1, mode);
4144 /* Done with this channel */
4147 /* If any errors, then clean up */
4150 _ckvmssts_noperl(lib$free_vm(&n, &info));
4158 static I32 my_pclose_pinfo(pTHX_ pInfo info);
4161 safe_popen(pTHX_ const char *cmd, const char *in_mode, int *psts)
4163 static int handler_set_up = FALSE;
4165 unsigned long int sts, flags = CLI$M_NOWAIT;
4166 /* The use of a GLOBAL table (as was done previously) rendered
4167 * Perl's qx() or `` unusable from a C<$ SET SYMBOL/SCOPE=NOGLOBAL> DCL
4168 * environment. Hence we've switched to LOCAL symbol table.
4170 unsigned int table = LIB$K_CLI_LOCAL_SYM;
4172 char *p, mode[10], symbol[MAX_DCL_SYMBOL+1], *vmspipe;
4173 char *in, *out, *err, mbx[512];
4175 char tfilebuf[NAM$C_MAXRSS+1];
4177 char cmd_sym_name[20];
4178 struct dsc$descriptor_s d_symbol= {0, DSC$K_DTYPE_T,
4179 DSC$K_CLASS_S, symbol};
4180 struct dsc$descriptor_s vmspipedsc = {0, DSC$K_DTYPE_T,
4182 struct dsc$descriptor_s d_sym_cmd = {0, DSC$K_DTYPE_T,
4183 DSC$K_CLASS_S, cmd_sym_name};
4184 struct dsc$descriptor_s *vmscmd;
4185 $DESCRIPTOR(d_sym_in ,"PERL_POPEN_IN");
4186 $DESCRIPTOR(d_sym_out,"PERL_POPEN_OUT");
4187 $DESCRIPTOR(d_sym_err,"PERL_POPEN_ERR");
4189 /* Check here for Xterm create request. This means looking for
4190 * "3>&1 xterm\b" and "\btty 1>&3\b$" in the command, and that it
4191 * is possible to create an xterm.
4193 if (*in_mode == 'r') {
4196 #if defined(PERL_IMPLICIT_CONTEXT)
4197 /* Can not fork an xterm with a NULL context */
4198 /* This probably could never happen */
4202 xterm_fd = create_forked_xterm(aTHX_ cmd, in_mode);
4203 if (xterm_fd != NULL)
4207 if (!head_PLOC) store_pipelocs(aTHX); /* at least TRY to use a static vmspipe file */
4209 /* once-per-program initialization...
4210 note that the SETAST calls and the dual test of pipe_ef
4211 makes sure that only the FIRST thread through here does
4212 the initialization...all other threads wait until it's
4215 Yeah, uglier than a pthread call, it's got all the stuff inline
4216 rather than in a separate routine.
4220 _ckvmssts_noperl(sys$setast(0));
4222 unsigned long int pidcode = JPI$_PID;
4223 $DESCRIPTOR(d_delay, RETRY_DELAY);
4224 _ckvmssts_noperl(lib$get_ef(&pipe_ef));
4225 _ckvmssts_noperl(lib$getjpi(&pidcode,0,0,&mypid,0,0));
4226 _ckvmssts_noperl(sys$bintim(&d_delay, delaytime));
4228 if (!handler_set_up) {
4229 _ckvmssts_noperl(sys$dclexh(&pipe_exitblock));
4230 handler_set_up = TRUE;
4232 _ckvmssts_noperl(sys$setast(1));
4235 /* see if we can find a VMSPIPE.COM */
4238 vmspipe = find_vmspipe(aTHX);
4240 vmspipedsc.dsc$w_length = my_strlcpy(tfilebuf+1, vmspipe, sizeof(tfilebuf)-1) + 1;
4241 } else { /* uh, oh...we're in tempfile hell */
4242 tpipe = vmspipe_tempfile(aTHX);
4243 if (!tpipe) { /* a fish popular in Boston */
4244 if (ckWARN(WARN_PIPE)) {
4245 Perl_warner(aTHX_ packWARN(WARN_PIPE),"unable to find VMSPIPE.COM for i/o piping");
4249 fgetname(tpipe,tfilebuf+1,1);
4250 vmspipedsc.dsc$w_length = strlen(tfilebuf);
4252 vmspipedsc.dsc$a_pointer = tfilebuf;
4254 sts = setup_cmddsc(aTHX_ cmd,0,0,&vmscmd);
4257 case RMS$_FNF: case RMS$_DNF:
4258 set_errno(ENOENT); break;
4260 set_errno(ENOTDIR); break;
4262 set_errno(ENODEV); break;
4264 set_errno(EACCES); break;
4266 set_errno(EINVAL); break;
4267 case CLI$_BUFOVF: case RMS$_RTB: case CLI$_TKNOVF: case CLI$_RSLOVF:
4268 set_errno(E2BIG); break;
4269 case LIB$_INVARG: case LIB$_INVSTRDES: case SS$_ACCVIO: /* shouldn't happen */
4270 _ckvmssts_noperl(sts); /* fall through */
4271 default: /* SS$_DUPLNAM, SS$_CLI, resource exhaustion, etc. */
4274 set_vaxc_errno(sts);
4275 if (*in_mode != 'n' && ckWARN(WARN_PIPE)) {
4276 Perl_warner(aTHX_ packWARN(WARN_PIPE),"Can't pipe \"%*s\": %s", strlen(cmd), cmd, Strerror(errno));
4282 _ckvmssts_noperl(lib$get_vm(&n, &info));
4284 my_strlcpy(mode, in_mode, sizeof(mode));
4287 info->completion = 0;
4288 info->closing = FALSE;
4295 info->in_done = TRUE;
4296 info->out_done = TRUE;
4297 info->err_done = TRUE;
4299 info->xchan_valid = 0;
4301 in = (char *)PerlMem_malloc(VMS_MAXRSS);
4302 if (in == NULL) _ckvmssts_noperl(SS$_INSFMEM);
4303 out = (char *)PerlMem_malloc(VMS_MAXRSS);
4304 if (out == NULL) _ckvmssts_noperl(SS$_INSFMEM);
4305 err = (char *)PerlMem_malloc(VMS_MAXRSS);
4306 if (err == NULL) _ckvmssts_noperl(SS$_INSFMEM);
4308 in[0] = out[0] = err[0] = '\0';
4310 if ((p = strchr(mode,'F')) != NULL) { /* F -> use FILE* */
4314 if ((p = strchr(mode,'W')) != NULL) { /* W -> wait for completion */
4319 if (*mode == 'r') { /* piping from subroutine */
4321 info->out = pipe_infromchild_setup(aTHX_ mbx,out);
4323 info->out->pipe_done = &info->out_done;
4324 info->out_done = FALSE;
4325 info->out->info = info;
4327 if (!info->useFILE) {
4328 info->fp = PerlIO_open(mbx, mode);
4330 info->fp = (PerlIO *) freopen(mbx, mode, stdin);
4331 vmssetuserlnm("SYS$INPUT", mbx);
4334 if (!info->fp && info->out) {
4335 sys$cancel(info->out->chan_out);
4337 while (!info->out_done) {
4339 _ckvmssts_noperl(sys$setast(0));
4340 done = info->out_done;
4341 if (!done) _ckvmssts_noperl(sys$clref(pipe_ef));
4342 _ckvmssts_noperl(sys$setast(1));
4343 if (!done) _ckvmssts_noperl(sys$waitfr(pipe_ef));
4346 if (info->out->buf) {
4347 n = info->out->bufsize * sizeof(char);
4348 _ckvmssts_noperl(lib$free_vm(&n, &info->out->buf));
4351 _ckvmssts_noperl(lib$free_vm(&n, &info->out));
4353 _ckvmssts_noperl(lib$free_vm(&n, &info));
4358 info->err = pipe_mbxtofd_setup(aTHX_ fileno(stderr), err);
4360 info->err->pipe_done = &info->err_done;
4361 info->err_done = FALSE;
4362 info->err->info = info;
4365 } else if (*mode == 'w') { /* piping to subroutine */
4367 info->out = pipe_mbxtofd_setup(aTHX_ fileno(stdout), out);
4369 info->out->pipe_done = &info->out_done;
4370 info->out_done = FALSE;
4371 info->out->info = info;
4374 info->err = pipe_mbxtofd_setup(aTHX_ fileno(stderr), err);
4376 info->err->pipe_done = &info->err_done;
4377 info->err_done = FALSE;
4378 info->err->info = info;
4381 info->in = pipe_tochild_setup(aTHX_ in,mbx);
4382 if (!info->useFILE) {
4383 info->fp = PerlIO_open(mbx, mode);
4385 info->fp = (PerlIO *) freopen(mbx, mode, stdout);
4386 vmssetuserlnm("SYS$OUTPUT", mbx);
4390 info->in->pipe_done = &info->in_done;
4391 info->in_done = FALSE;
4392 info->in->info = info;
4396 if (!info->fp && info->in) {
4398 _ckvmssts_noperl(sys$qiow(0,info->in->chan_in, IO$_WRITEOF, 0,
4399 0, 0, 0, 0, 0, 0, 0, 0));
4401 while (!info->in_done) {
4403 _ckvmssts_noperl(sys$setast(0));
4404 done = info->in_done;
4405 if (!done) _ckvmssts_noperl(sys$clref(pipe_ef));
4406 _ckvmssts_noperl(sys$setast(1));
4407 if (!done) _ckvmssts_noperl(sys$waitfr(pipe_ef));
4410 if (info->in->buf) {
4411 n = info->in->bufsize * sizeof(char);
4412 _ckvmssts_noperl(lib$free_vm(&n, &info->in->buf));
4415 _ckvmssts_noperl(lib$free_vm(&n, &info->in));
4417 _ckvmssts_noperl(lib$free_vm(&n, &info));
4423 } else if (*mode == 'n') { /* separate subprocess, no Perl i/o */
4424 /* Let the child inherit standard input, unless it's a directory. */
4426 if (my_trnlnm("SYS$INPUT", in, 0)) {
4427 if (flex_stat(in, &st) != 0 || S_ISDIR(st.st_mode))
4431 info->out = pipe_mbxtofd_setup(aTHX_ fileno(stdout), out);
4433 info->out->pipe_done = &info->out_done;
4434 info->out_done = FALSE;
4435 info->out->info = info;
4438 info->err = pipe_mbxtofd_setup(aTHX_ fileno(stderr), err);
4440 info->err->pipe_done = &info->err_done;
4441 info->err_done = FALSE;
4442 info->err->info = info;
4446 d_symbol.dsc$w_length = my_strlcpy(symbol, in, sizeof(symbol));
4447 _ckvmssts_noperl(lib$set_symbol(&d_sym_in, &d_symbol, &table));
4449 d_symbol.dsc$w_length = my_strlcpy(symbol, err, sizeof(symbol));
4450 _ckvmssts_noperl(lib$set_symbol(&d_sym_err, &d_symbol, &table));
4452 d_symbol.dsc$w_length = my_strlcpy(symbol, out, sizeof(symbol));
4453 _ckvmssts_noperl(lib$set_symbol(&d_sym_out, &d_symbol, &table));
4455 /* Done with the names for the pipes */
4460 p = vmscmd->dsc$a_pointer;
4461 while (*p == ' ' || *p == '\t') p++; /* remove leading whitespace */
4462 if (*p == '$') p++; /* remove leading $ */
4463 while (*p == ' ' || *p == '\t') p++;
4465 for (j = 0; j < 4; j++) {
4466 sprintf(cmd_sym_name,"PERL_POPEN_CMD%d",j);
4467 d_sym_cmd.dsc$w_length = strlen(cmd_sym_name);
4469 d_symbol.dsc$w_length = my_strlcpy(symbol, p, sizeof(symbol));
4470 _ckvmssts_noperl(lib$set_symbol(&d_sym_cmd, &d_symbol, &table));
4472 if (strlen(p) > MAX_DCL_SYMBOL) {
4473 p += MAX_DCL_SYMBOL;
4478 _ckvmssts_noperl(sys$setast(0));
4479 info->next=open_pipes; /* prepend to list */
4481 _ckvmssts_noperl(sys$setast(1));
4482 /* Omit arg 2 (input file) so the child will get the parent's SYS$INPUT
4483 * and SYS$COMMAND. vmspipe.com will redefine SYS$INPUT, but we'll still
4484 * have SYS$COMMAND if we need it.
4486 _ckvmssts_noperl(lib$spawn(&vmspipedsc, 0, &nl_desc, &flags,
4487 0, &info->pid, &info->completion,
4488 0, popen_completion_ast,info,0,0,0));
4490 /* if we were using a tempfile, close it now */
4492 if (tpipe) fclose(tpipe);
4494 /* once the subprocess is spawned, it has copied the symbols and
4495 we can get rid of ours */
4497 for (j = 0; j < 4; j++) {
4498 sprintf(cmd_sym_name,"PERL_POPEN_CMD%d",j);
4499 d_sym_cmd.dsc$w_length = strlen(cmd_sym_name);
4500 _ckvmssts_noperl(lib$delete_symbol(&d_sym_cmd, &table));
4502 _ckvmssts_noperl(lib$delete_symbol(&d_sym_in, &table));
4503 _ckvmssts_noperl(lib$delete_symbol(&d_sym_err, &table));
4504 _ckvmssts_noperl(lib$delete_symbol(&d_sym_out, &table));
4505 vms_execfree(vmscmd);
4507 #ifdef PERL_IMPLICIT_CONTEXT
4510 PL_forkprocess = info->pid;
4517 _ckvmssts_noperl(sys$setast(0));
4519 if (!done) _ckvmssts_noperl(sys$clref(pipe_ef));
4520 _ckvmssts_noperl(sys$setast(1));
4521 if (!done) _ckvmssts_noperl(sys$waitfr(pipe_ef));
4523 *psts = info->completion;
4524 /* Caller thinks it is open and tries to close it. */
4525 /* This causes some problems, as it changes the error status */
4526 /* my_pclose(info->fp); */
4528 /* If we did not have a file pointer open, then we have to */
4529 /* clean up here or eventually we will run out of something */
4531 if (info->fp == NULL) {
4532 my_pclose_pinfo(aTHX_ info);
4540 } /* end of safe_popen */
4543 /*{{{ PerlIO *my_popen(char *cmd, char *mode)*/
4545 Perl_my_popen(pTHX_ const char *cmd, const char *mode)
4549 TAINT_PROPER("popen");
4550 PERL_FLUSHALL_FOR_CHILD;
4551 return safe_popen(aTHX_ cmd,mode,&sts);
4557 /* Routine to close and cleanup a pipe info structure */
4560 my_pclose_pinfo(pTHX_ pInfo info) {
4562 unsigned long int retsts;
4566 /* If we were writing to a subprocess, insure that someone reading from
4567 * the mailbox gets an EOF. It looks like a simple fclose() doesn't
4568 * produce an EOF record in the mailbox.
4570 * well, at least sometimes it *does*, so we have to watch out for
4571 * the first EOF closing the pipe (and DASSGN'ing the channel)...
4575 #if defined(USE_ITHREADS)
4579 && PL_perlio_fd_refcnt
4582 PerlIO_flush(info->fp);
4584 fflush((FILE *)info->fp);
4587 _ckvmssts(sys$setast(0));
4588 info->closing = TRUE;
4589 done = info->done && info->in_done && info->out_done && info->err_done;
4590 /* hanging on write to Perl's input? cancel it */
4591 if (info->mode == 'r' && info->out && !info->out_done) {
4592 if (info->out->chan_out) {
4593 _ckvmssts(sys$cancel(info->out->chan_out));
4594 if (!info->out->chan_in) { /* EOF generation, need AST */
4595 _ckvmssts(sys$dclast(pipe_infromchild_ast,info->out,0));
4599 if (info->in && !info->in_done && !info->in->shut_on_empty) /* EOF if hasn't had one yet */
4600 _ckvmssts(sys$qio(0,info->in->chan_in,IO$_WRITEOF,0,0,0,
4602 _ckvmssts(sys$setast(1));
4605 #if defined(USE_ITHREADS)
4609 && PL_perlio_fd_refcnt
4612 PerlIO_close(info->fp);
4614 fclose((FILE *)info->fp);
4617 we have to wait until subprocess completes, but ALSO wait until all
4618 the i/o completes...otherwise we'll be freeing the "info" structure
4619 that the i/o ASTs could still be using...
4623 _ckvmssts(sys$setast(0));
4624 done = info->done && info->in_done && info->out_done && info->err_done;
4625 if (!done) _ckvmssts(sys$clref(pipe_ef));
4626 _ckvmssts(sys$setast(1));
4627 if (!done) _ckvmssts(sys$waitfr(pipe_ef));
4629 retsts = info->completion;
4631 /* remove from list of open pipes */
4632 _ckvmssts(sys$setast(0));
4634 for (next = open_pipes; next != NULL; last = next, next = next->next) {
4640 last->next = info->next;
4642 open_pipes = info->next;
4643 _ckvmssts(sys$setast(1));
4645 /* free buffers and structures */
4648 if (info->in->buf) {
4649 n = info->in->bufsize * sizeof(char);
4650 _ckvmssts(lib$free_vm(&n, &info->in->buf));
4653 _ckvmssts(lib$free_vm(&n, &info->in));
4656 if (info->out->buf) {
4657 n = info->out->bufsize * sizeof(char);
4658 _ckvmssts(lib$free_vm(&n, &info->out->buf));
4661 _ckvmssts(lib$free_vm(&n, &info->out));
4664 if (info->err->buf) {
4665 n = info->err->bufsize * sizeof(char);
4666 _ckvmssts(lib$free_vm(&n, &info->err->buf));
4669 _ckvmssts(lib$free_vm(&n, &info->err));
4672 _ckvmssts(lib$free_vm(&n, &info));
4678 /*{{{ I32 my_pclose(PerlIO *fp)*/
4679 I32 Perl_my_pclose(pTHX_ PerlIO *fp)
4681 pInfo info, last = NULL;
4684 /* Fixme - need ast and mutex protection here */
4685 for (info = open_pipes; info != NULL; last = info, info = info->next)
4686 if (info->fp == fp) break;
4688 if (info == NULL) { /* no such pipe open */
4689 set_errno(ECHILD); /* quoth POSIX */
4690 set_vaxc_errno(SS$_NONEXPR);
4694 ret_status = my_pclose_pinfo(aTHX_ info);
4698 } /* end of my_pclose() */
4700 /* Roll our own prototype because we want this regardless of whether
4701 * _VMS_WAIT is defined.
4707 __pid_t __vms_waitpid( __pid_t __pid, int *__stat_loc, int __options );
4712 /* sort-of waitpid; special handling of pipe clean-up for subprocesses
4713 created with popen(); otherwise partially emulate waitpid() unless
4714 we have a suitable one from the CRTL that came with VMS 7.2 and later.
4715 Also check processes not considered by the CRTL waitpid().
4717 /*{{{Pid_t my_waitpid(Pid_t pid, int *statusp, int flags)*/
4719 Perl_my_waitpid(pTHX_ Pid_t pid, int *statusp, int flags)
4726 if (statusp) *statusp = 0;
4728 for (info = open_pipes; info != NULL; info = info->next)
4729 if (info->pid == pid) break;
4731 if (info != NULL) { /* we know about this child */
4732 while (!info->done) {
4733 _ckvmssts(sys$setast(0));
4735 if (!done) _ckvmssts(sys$clref(pipe_ef));
4736 _ckvmssts(sys$setast(1));
4737 if (!done) _ckvmssts(sys$waitfr(pipe_ef));
4740 if (statusp) *statusp = info->completion;
4744 /* child that already terminated? */
4746 for (j = 0; j < NKEEPCLOSED && j < closed_num; j++) {
4747 if (closed_list[j].pid == pid) {
4748 if (statusp) *statusp = closed_list[j].completion;
4753 /* fall through if this child is not one of our own pipe children */
4755 /* waitpid() became available in the CRTL as of VMS 7.0, but only
4756 * in 7.2 did we get a version that fills in the VMS completion
4757 * status as Perl has always tried to do.
4760 sts = __vms_waitpid( pid, statusp, flags );
4762 if ( sts == 0 || !(sts == -1 && errno == ECHILD) )
4765 /* If the real waitpid tells us the child does not exist, we
4766 * fall through here to implement waiting for a child that
4767 * was created by some means other than exec() (say, spawned
4768 * from DCL) or to wait for a process that is not a subprocess
4769 * of the current process.
4773 $DESCRIPTOR(intdsc,"0 00:00:01");
4774 unsigned long int ownercode = JPI$_OWNER, ownerpid;
4775 unsigned long int pidcode = JPI$_PID, mypid;
4776 unsigned long int interval[2];
4777 unsigned int jpi_iosb[2];
4778 struct itmlst_3 jpilist[2] = {
4779 {sizeof(ownerpid), JPI$_OWNER, &ownerpid, 0},
4784 /* Sorry folks, we don't presently implement rooting around for
4785 the first child we can find, and we definitely don't want to
4786 pass a pid of -1 to $getjpi, where it is a wildcard operation.
4792 /* Get the owner of the child so I can warn if it's not mine. If the
4793 * process doesn't exist or I don't have the privs to look at it,
4794 * I can go home early.
4796 sts = sys$getjpiw(0,&pid,NULL,&jpilist,&jpi_iosb,NULL,NULL);
4797 if (sts & 1) sts = jpi_iosb[0];
4809 set_vaxc_errno(sts);
4813 if (ckWARN(WARN_EXEC)) {
4814 /* remind folks they are asking for non-standard waitpid behavior */
4815 _ckvmssts(lib$getjpi(&pidcode,0,0,&mypid,0,0));
4816 if (ownerpid != mypid)