3 * VMS-specific routines for perl5
5 * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
6 * 2002, 2003, 2004, 2005, 2006, 2007 by Charles Bailey and others.
8 * You may distribute under the terms of either the GNU General Public
9 * License or the Artistic License, as specified in the README file.
11 * Please see Changes*.* or the Perl Repository Browser for revision history.
15 * Yet small as was their hunted band
16 * still fell and fearless was each hand,
17 * and strong deeds they wrought yet oft,
18 * and loved the woods, whose ways more soft
19 * them seemed than thralls of that black throne
20 * to live and languish in halls of stone.
21 * "The Lay of Leithian", Canto II, lines 135-40
23 * [p.162 of _The Lays of Beleriand_]
32 #include <climsgdef.h>
43 #include <libclidef.h>
45 #include <lib$routines.h>
49 #if __CRTL_VER >= 70301000 && !defined(__VAX)
59 #include <str$routines.h>
66 #if __CRTL_VER >= 70000000 /* FIXME to earliest version */
68 #define NO_EFN EFN$C_ENF
73 #if __CRTL_VER < 70301000 && __CRTL_VER >= 70300000
74 int decc$feature_get_index(const char *name);
75 char* decc$feature_get_name(int index);
76 int decc$feature_get_value(int index, int mode);
77 int decc$feature_set_value(int index, int mode, int value);
82 #pragma member_alignment save
83 #pragma nomember_alignment longword
88 unsigned short * retadr;
90 #pragma member_alignment restore
92 /* More specific prototype than in starlet_c.h makes programming errors
100 const struct dsc$descriptor_s * devnam,
101 const struct item_list_3 * itmlst,
103 void * (astadr)(unsigned long),
108 #ifdef sys$get_security
109 #undef sys$get_security
111 (const struct dsc$descriptor_s * clsnam,
112 const struct dsc$descriptor_s * objnam,
113 const unsigned int *objhan,
115 const struct item_list_3 * itmlst,
116 unsigned int * contxt,
117 const unsigned int * acmode);
120 #ifdef sys$set_security
121 #undef sys$set_security
123 (const struct dsc$descriptor_s * clsnam,
124 const struct dsc$descriptor_s * objnam,
125 const unsigned int *objhan,
127 const struct item_list_3 * itmlst,
128 unsigned int * contxt,
129 const unsigned int * acmode);
132 #ifdef lib$find_image_symbol
133 #undef lib$find_image_symbol
134 int lib$find_image_symbol
135 (const struct dsc$descriptor_s * imgname,
136 const struct dsc$descriptor_s * symname,
138 const struct dsc$descriptor_s * defspec,
142 #ifdef lib$rename_file
143 #undef lib$rename_file
145 (const struct dsc$descriptor_s * old_file_dsc,
146 const struct dsc$descriptor_s * new_file_dsc,
147 const struct dsc$descriptor_s * default_file_dsc,
148 const struct dsc$descriptor_s * related_file_dsc,
149 const unsigned long * flags,
150 void * (success)(const struct dsc$descriptor_s * old_dsc,
151 const struct dsc$descriptor_s * new_dsc,
153 void * (error)(const struct dsc$descriptor_s * old_dsc,
154 const struct dsc$descriptor_s * new_dsc,
157 const int * error_src,
158 const void * usr_arg),
159 int (confirm)(const struct dsc$descriptor_s * old_dsc,
160 const struct dsc$descriptor_s * new_dsc,
161 const void * old_fab,
162 const void * usr_arg),
164 struct dsc$descriptor_s * old_result_name_dsc,
165 struct dsc$descriptor_s * new_result_name_dsc,
166 unsigned long * file_scan_context);
169 #if __CRTL_VER >= 70300000 && !defined(__VAX)
171 static int set_feature_default(const char *name, int value)
176 index = decc$feature_get_index(name);
178 status = decc$feature_set_value(index, 1, value);
179 if (index == -1 || (status == -1)) {
183 status = decc$feature_get_value(index, 1);
184 if (status != value) {
192 /* Older versions of ssdef.h don't have these */
193 #ifndef SS$_INVFILFOROP
194 # define SS$_INVFILFOROP 3930
196 #ifndef SS$_NOSUCHOBJECT
197 # define SS$_NOSUCHOBJECT 2696
200 /* We implement I/O here, so we will be mixing PerlIO and stdio calls. */
201 #define PERLIO_NOT_STDIO 0
203 /* Don't replace system definitions of vfork, getenv, lstat, and stat,
204 * code below needs to get to the underlying CRTL routines. */
205 #define DONT_MASK_RTL_CALLS
209 /* Anticipating future expansion in lexical warnings . . . */
210 #ifndef WARN_INTERNAL
211 # define WARN_INTERNAL WARN_MISC
214 #ifdef VMS_LONGNAME_SUPPORT
215 #include <libfildef.h>
218 #if defined(__VMS_VER) && __VMS_VER >= 70000000 && __DECC_VER >= 50200000
219 # define RTL_USES_UTC 1
222 /* Routine to create a decterm for use with the Perl debugger */
223 /* No headers, this information was found in the Programming Concepts Manual */
225 static int (*decw_term_port)
226 (const struct dsc$descriptor_s * display,
227 const struct dsc$descriptor_s * setup_file,
228 const struct dsc$descriptor_s * customization,
229 struct dsc$descriptor_s * result_device_name,
230 unsigned short * result_device_name_length,
233 void * char_change_buffer) = 0;
235 /* gcc's header files don't #define direct access macros
236 * corresponding to VAXC's variant structs */
238 # define uic$v_format uic$r_uic_form.uic$v_format
239 # define uic$v_group uic$r_uic_form.uic$v_group
240 # define uic$v_member uic$r_uic_form.uic$v_member
241 # define prv$v_bypass prv$r_prvdef_bits0.prv$v_bypass
242 # define prv$v_grpprv prv$r_prvdef_bits0.prv$v_grpprv
243 # define prv$v_readall prv$r_prvdef_bits0.prv$v_readall
244 # define prv$v_sysprv prv$r_prvdef_bits0.prv$v_sysprv
247 #if defined(NEED_AN_H_ERRNO)
252 #pragma message disable pragma
253 #pragma member_alignment save
254 #pragma nomember_alignment longword
256 #pragma message disable misalgndmem
259 unsigned short int buflen;
260 unsigned short int itmcode;
262 unsigned short int *retlen;
265 struct filescan_itmlst_2 {
266 unsigned short length;
267 unsigned short itmcode;
272 unsigned short length;
277 #pragma message restore
278 #pragma member_alignment restore
281 #define do_fileify_dirspec(a,b,c,d) mp_do_fileify_dirspec(aTHX_ a,b,c,d)
282 #define do_pathify_dirspec(a,b,c,d) mp_do_pathify_dirspec(aTHX_ a,b,c,d)
283 #define do_tovmsspec(a,b,c,d) mp_do_tovmsspec(aTHX_ a,b,c,0,d)
284 #define do_tovmspath(a,b,c,d) mp_do_tovmspath(aTHX_ a,b,c,d)
285 #define do_rmsexpand(a,b,c,d,e,f,g) mp_do_rmsexpand(aTHX_ a,b,c,d,e,f,g)
286 #define do_vms_realpath(a,b,c) mp_do_vms_realpath(aTHX_ a,b,c)
287 #define do_vms_realname(a,b,c) mp_do_vms_realname(aTHX_ a,b,c)
288 #define do_tounixspec(a,b,c,d) mp_do_tounixspec(aTHX_ a,b,c,d)
289 #define do_tounixpath(a,b,c,d) mp_do_tounixpath(aTHX_ a,b,c,d)
290 #define do_vms_case_tolerant(a) mp_do_vms_case_tolerant(a)
291 #define expand_wild_cards(a,b,c,d) mp_expand_wild_cards(aTHX_ a,b,c,d)
292 #define getredirection(a,b) mp_getredirection(aTHX_ a,b)
294 static char *mp_do_tovmspath(pTHX_ const char *path, char *buf, int ts, int *);
295 static char *mp_do_tounixpath(pTHX_ const char *path, char *buf, int ts, int *);
296 static char *mp_do_tounixspec(pTHX_ const char *, char *, int, int *);
297 static char *mp_do_pathify_dirspec(pTHX_ const char *dir,char *buf, int ts, int *);
299 /* see system service docs for $TRNLNM -- NOT the same as LNM$_MAX_INDEX */
300 #define PERL_LNM_MAX_ALLOWED_INDEX 127
302 /* OpenVMS User's Guide says at least 9 iterative translations will be performed,
303 * depending on the facility. SHOW LOGICAL does 10, so we'll imitate that for
306 #define PERL_LNM_MAX_ITER 10
308 /* New values with 7.3-2*/ /* why does max DCL have 4 byte subtracted from it? */
309 #if __CRTL_VER >= 70302000 && !defined(__VAX)
310 #define MAX_DCL_SYMBOL (8192)
311 #define MAX_DCL_LINE_LENGTH (4096 - 4)
313 #define MAX_DCL_SYMBOL (1024)
314 #define MAX_DCL_LINE_LENGTH (1024 - 4)
317 static char *__mystrtolower(char *str)
319 if (str) for (; *str; ++str) *str= tolower(*str);
323 static struct dsc$descriptor_s fildevdsc =
324 { 12, DSC$K_DTYPE_T, DSC$K_CLASS_S, "LNM$FILE_DEV" };
325 static struct dsc$descriptor_s crtlenvdsc =
326 { 8, DSC$K_DTYPE_T, DSC$K_CLASS_S, "CRTL_ENV" };
327 static struct dsc$descriptor_s *fildev[] = { &fildevdsc, NULL };
328 static struct dsc$descriptor_s *defenv[] = { &fildevdsc, &crtlenvdsc, NULL };
329 static struct dsc$descriptor_s **env_tables = defenv;
330 static bool will_taint = FALSE; /* tainting active, but no PL_curinterp yet */
332 /* True if we shouldn't treat barewords as logicals during directory */
334 static int no_translate_barewords;
337 static int tz_updated = 1;
340 /* DECC Features that may need to affect how Perl interprets
341 * displays filename information
343 static int decc_disable_to_vms_logname_translation = 1;
344 static int decc_disable_posix_root = 1;
345 int decc_efs_case_preserve = 0;
346 static int decc_efs_charset = 0;
347 static int decc_efs_charset_index = -1;
348 static int decc_filename_unix_no_version = 0;
349 static int decc_filename_unix_only = 0;
350 int decc_filename_unix_report = 0;
351 int decc_posix_compliant_pathnames = 0;
352 int decc_readdir_dropdotnotype = 0;
353 static int vms_process_case_tolerant = 1;
354 int vms_vtf7_filenames = 0;
355 int gnv_unix_shell = 0;
356 static int vms_unlink_all_versions = 0;
357 static int vms_posix_exit = 0;
359 /* bug workarounds if needed */
360 int decc_bug_devnull = 1;
361 int decc_dir_barename = 0;
362 int vms_bug_stat_filename = 0;
364 static int vms_debug_on_exception = 0;
365 static int vms_debug_fileify = 0;
367 /* Simple logical name translation */
368 static int simple_trnlnm
369 (const char * logname,
373 const $DESCRIPTOR(table_dsc, "LNM$FILE_DEV");
374 const unsigned long attr = LNM$M_CASE_BLIND;
375 struct dsc$descriptor_s name_dsc;
377 unsigned short result;
378 struct itmlst_3 itlst[2] = {{value_len, LNM$_STRING, value, &result},
381 name_dsc.dsc$w_length = strlen(logname);
382 name_dsc.dsc$a_pointer = (char *)logname;
383 name_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
384 name_dsc.dsc$b_class = DSC$K_CLASS_S;
386 status = sys$trnlnm(&attr, &table_dsc, &name_dsc, 0, itlst);
388 if ($VMS_STATUS_SUCCESS(status)) {
390 /* Null terminate and return the string */
391 /*--------------------------------------*/
400 /* Is this a UNIX file specification?
401 * No longer a simple check with EFS file specs
402 * For now, not a full check, but need to
403 * handle POSIX ^UP^ specifications
404 * Fixing to handle ^/ cases would require
405 * changes to many other conversion routines.
408 static int is_unix_filespec(const char *path)
414 if (strncmp(path,"\"^UP^",5) != 0) {
415 pch1 = strchr(path, '/');
420 /* If the user wants UNIX files, "." needs to be treated as in UNIX */
421 if (decc_filename_unix_report || decc_filename_unix_only) {
422 if (strcmp(path,".") == 0)
430 /* This routine converts a UCS-2 character to be VTF-7 encoded.
433 static void ucs2_to_vtf7
435 unsigned long ucs2_char,
438 unsigned char * ucs_ptr;
441 ucs_ptr = (unsigned char *)&ucs2_char;
445 hex = (ucs_ptr[1] >> 4) & 0xf;
447 outspec[2] = hex + '0';
449 outspec[2] = (hex - 9) + 'A';
450 hex = ucs_ptr[1] & 0xF;
452 outspec[3] = hex + '0';
454 outspec[3] = (hex - 9) + 'A';
456 hex = (ucs_ptr[0] >> 4) & 0xf;
458 outspec[4] = hex + '0';
460 outspec[4] = (hex - 9) + 'A';
461 hex = ucs_ptr[1] & 0xF;
463 outspec[5] = hex + '0';
465 outspec[5] = (hex - 9) + 'A';
471 /* This handles the conversion of a UNIX extended character set to a ^
472 * escaped VMS character.
473 * in a UNIX file specification.
475 * The output count variable contains the number of characters added
476 * to the output string.
478 * The return value is the number of characters read from the input string
480 static int copy_expand_unix_filename_escape
481 (char *outspec, const char *inspec, int *output_cnt, const int * utf8_fl)
489 utf8_flag = *utf8_fl;
493 if (*inspec >= 0x80) {
494 if (utf8_fl && vms_vtf7_filenames) {
495 unsigned long ucs_char;
499 if ((*inspec & 0xE0) == 0xC0) {
501 ucs_char = ((inspec[0] & 0x1F) << 6) + (inspec[1] & 0x3f);
502 if (ucs_char >= 0x80) {
503 ucs2_to_vtf7(outspec, ucs_char, output_cnt);
506 } else if ((*inspec & 0xF0) == 0xE0) {
508 ucs_char = ((inspec[0] & 0xF) << 12) +
509 ((inspec[1] & 0x3f) << 6) +
511 if (ucs_char >= 0x800) {
512 ucs2_to_vtf7(outspec, ucs_char, output_cnt);
516 #if 0 /* I do not see longer sequences supported by OpenVMS */
517 /* Maybe some one can fix this later */
518 } else if ((*inspec & 0xF8) == 0xF0) {
521 } else if ((*inspec & 0xFC) == 0xF8) {
524 } else if ((*inspec & 0xFE) == 0xFC) {
531 /* High bit set, but not a Unicode character! */
533 /* Non printing DECMCS or ISO Latin-1 character? */
534 if (*inspec <= 0x9F) {
538 hex = (*inspec >> 4) & 0xF;
540 outspec[1] = hex + '0';
542 outspec[1] = (hex - 9) + 'A';
546 outspec[2] = hex + '0';
548 outspec[2] = (hex - 9) + 'A';
552 } else if (*inspec == 0xA0) {
558 } else if (*inspec == 0xFF) {
570 /* Is this a macro that needs to be passed through?
571 * Macros start with $( and an alpha character, followed
572 * by a string of alpha numeric characters ending with a )
573 * If this does not match, then encode it as ODS-5.
575 if ((inspec[0] == '$') && (inspec[1] == '(')) {
578 if (isalnum(inspec[2]) || (inspec[2] == '.') || (inspec[2] == '_')) {
580 outspec[0] = inspec[0];
581 outspec[1] = inspec[1];
582 outspec[2] = inspec[2];
584 while(isalnum(inspec[tcnt]) ||
585 (inspec[2] == '.') || (inspec[2] == '_')) {
586 outspec[tcnt] = inspec[tcnt];
589 if (inspec[tcnt] == ')') {
590 outspec[tcnt] = inspec[tcnt];
607 if (decc_efs_charset == 0)
633 /* Don't escape again if following character is
634 * already something we escape.
636 if (strchr(".~!#&\'`()+@{},;[]%^=_", *(inspec+1))) {
642 /* But otherwise fall through and escape it. */
644 /* Assume that this is to be escaped */
646 outspec[1] = *inspec;
650 case ' ': /* space */
651 /* Assume that this is to be escaped */
666 /* This handles the expansion of a '^' prefix to the proper character
667 * in a UNIX file specification.
669 * The output count variable contains the number of characters added
670 * to the output string.
672 * The return value is the number of characters read from the input
675 static int copy_expand_vms_filename_escape
676 (char *outspec, const char *inspec, int *output_cnt)
683 if (*inspec == '^') {
686 /* Spaces and non-trailing dots should just be passed through,
687 * but eat the escape character.
694 case '_': /* space */
700 /* Hmm. Better leave the escape escaped. */
706 case 'U': /* Unicode - FIX-ME this is wrong. */
709 scnt = strspn(inspec, "0123456789ABCDEFabcdef");
712 scnt = sscanf(inspec, "%2x%2x", &c1, &c2);
713 outspec[0] == c1 & 0xff;
714 outspec[1] == c2 & 0xff;
721 /* Error - do best we can to continue */
731 scnt = strspn(inspec, "0123456789ABCDEFabcdef");
735 scnt = sscanf(inspec, "%2x", &c1);
736 outspec[0] = c1 & 0xff;
760 (const struct dsc$descriptor_s * srcstr,
761 struct filescan_itmlst_2 * valuelist,
762 unsigned long * fldflags,
763 struct dsc$descriptor_s *auxout,
764 unsigned short * retlen);
767 /* vms_split_path - Verify that the input file specification is a
768 * VMS format file specification, and provide pointers to the components of
769 * it. With EFS format filenames, this is virtually the only way to
770 * parse a VMS path specification into components.
772 * If the sum of the components do not add up to the length of the
773 * string, then the passed file specification is probably a UNIX style
776 static int vms_split_path
791 struct dsc$descriptor path_desc;
795 struct filescan_itmlst_2 item_list[9];
796 const int filespec = 0;
797 const int nodespec = 1;
798 const int devspec = 2;
799 const int rootspec = 3;
800 const int dirspec = 4;
801 const int namespec = 5;
802 const int typespec = 6;
803 const int verspec = 7;
805 /* Assume the worst for an easy exit */
820 path_desc.dsc$a_pointer = (char *)path; /* cast ok */
821 path_desc.dsc$w_length = strlen(path);
822 path_desc.dsc$b_dtype = DSC$K_DTYPE_T;
823 path_desc.dsc$b_class = DSC$K_CLASS_S;
825 /* Get the total length, if it is shorter than the string passed
826 * then this was probably not a VMS formatted file specification
828 item_list[filespec].itmcode = FSCN$_FILESPEC;
829 item_list[filespec].length = 0;
830 item_list[filespec].component = NULL;
832 /* If the node is present, then it gets considered as part of the
833 * volume name to hopefully make things simple.
835 item_list[nodespec].itmcode = FSCN$_NODE;
836 item_list[nodespec].length = 0;
837 item_list[nodespec].component = NULL;
839 item_list[devspec].itmcode = FSCN$_DEVICE;
840 item_list[devspec].length = 0;
841 item_list[devspec].component = NULL;
843 /* root is a special case, adding it to either the directory or
844 * the device components will probalby complicate things for the
845 * callers of this routine, so leave it separate.
847 item_list[rootspec].itmcode = FSCN$_ROOT;
848 item_list[rootspec].length = 0;
849 item_list[rootspec].component = NULL;
851 item_list[dirspec].itmcode = FSCN$_DIRECTORY;
852 item_list[dirspec].length = 0;
853 item_list[dirspec].component = NULL;
855 item_list[namespec].itmcode = FSCN$_NAME;
856 item_list[namespec].length = 0;
857 item_list[namespec].component = NULL;
859 item_list[typespec].itmcode = FSCN$_TYPE;
860 item_list[typespec].length = 0;
861 item_list[typespec].component = NULL;
863 item_list[verspec].itmcode = FSCN$_VERSION;
864 item_list[verspec].length = 0;
865 item_list[verspec].component = NULL;
867 item_list[8].itmcode = 0;
868 item_list[8].length = 0;
869 item_list[8].component = NULL;
871 status = sys$filescan
872 ((const struct dsc$descriptor_s *)&path_desc, item_list,
874 _ckvmssts_noperl(status); /* All failure status values indicate a coding error */
876 /* If we parsed it successfully these two lengths should be the same */
877 if (path_desc.dsc$w_length != item_list[filespec].length)
880 /* If we got here, then it is a VMS file specification */
883 /* set the volume name */
884 if (item_list[nodespec].length > 0) {
885 *volume = item_list[nodespec].component;
886 *vol_len = item_list[nodespec].length + item_list[devspec].length;
889 *volume = item_list[devspec].component;
890 *vol_len = item_list[devspec].length;
893 *root = item_list[rootspec].component;
894 *root_len = item_list[rootspec].length;
896 *dir = item_list[dirspec].component;
897 *dir_len = item_list[dirspec].length;
899 /* Now fun with versions and EFS file specifications
900 * The parser can not tell the difference when a "." is a version
901 * delimiter or a part of the file specification.
903 if ((decc_efs_charset) &&
904 (item_list[verspec].length > 0) &&
905 (item_list[verspec].component[0] == '.')) {
906 *name = item_list[namespec].component;
907 *name_len = item_list[namespec].length + item_list[typespec].length;
908 *ext = item_list[verspec].component;
909 *ext_len = item_list[verspec].length;
914 *name = item_list[namespec].component;
915 *name_len = item_list[namespec].length;
916 *ext = item_list[typespec].component;
917 *ext_len = item_list[typespec].length;
918 *version = item_list[verspec].component;
919 *ver_len = item_list[verspec].length;
926 * Routine to retrieve the maximum equivalence index for an input
927 * logical name. Some calls to this routine have no knowledge if
928 * the variable is a logical or not. So on error we return a max
931 /*{{{int my_maxidx(const char *lnm) */
933 my_maxidx(const char *lnm)
937 int attr = LNM$M_CASE_BLIND;
938 struct dsc$descriptor lnmdsc;
939 struct itmlst_3 itlst[2] = {{sizeof(midx), LNM$_MAX_INDEX, &midx, 0},
942 lnmdsc.dsc$w_length = strlen(lnm);
943 lnmdsc.dsc$b_dtype = DSC$K_DTYPE_T;
944 lnmdsc.dsc$b_class = DSC$K_CLASS_S;
945 lnmdsc.dsc$a_pointer = (char *) lnm; /* Cast ok for read only parameter */
947 status = sys$trnlnm(&attr, &fildevdsc, &lnmdsc, 0, itlst);
948 if ((status & 1) == 0)
955 /*{{{int vmstrnenv(const char *lnm, char *eqv, unsigned long int idx, struct dsc$descriptor_s **tabvec, unsigned long int flags) */
957 Perl_vmstrnenv(const char *lnm, char *eqv, unsigned long int idx,
958 struct dsc$descriptor_s **tabvec, unsigned long int flags)
961 char uplnm[LNM$C_NAMLENGTH+1], *cp2;
962 unsigned short int eqvlen, curtab, ivlnm = 0, ivsym = 0, ivenv = 0, secure;
963 unsigned long int retsts, attr = LNM$M_CASE_BLIND;
965 unsigned char acmode;
966 struct dsc$descriptor_s lnmdsc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0},
967 tmpdsc = {6,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
968 struct itmlst_3 lnmlst[3] = {{sizeof idx, LNM$_INDEX, &idx, 0},
969 {LNM$C_NAMLENGTH, LNM$_STRING, eqv, &eqvlen},
971 $DESCRIPTOR(crtlenv,"CRTL_ENV"); $DESCRIPTOR(clisym,"CLISYM");
972 #if defined(PERL_IMPLICIT_CONTEXT)
975 aTHX = PERL_GET_INTERP;
981 if (!lnm || !eqv || ((idx != 0) && ((idx-1) > PERL_LNM_MAX_ALLOWED_INDEX))) {
982 set_errno(EINVAL); set_vaxc_errno(SS$_BADPARAM); return 0;
984 for (cp1 = lnm, cp2 = uplnm; *cp1; cp1++, cp2++) {
985 *cp2 = _toupper(*cp1);
986 if (cp1 - lnm > LNM$C_NAMLENGTH) {
987 set_errno(EINVAL); set_vaxc_errno(SS$_IVLOGNAM);
991 lnmdsc.dsc$w_length = cp1 - lnm;
992 lnmdsc.dsc$a_pointer = uplnm;
993 uplnm[lnmdsc.dsc$w_length] = '\0';
994 secure = flags & PERL__TRNENV_SECURE;
995 acmode = secure ? PSL$C_EXEC : PSL$C_USER;
996 if (!tabvec || !*tabvec) tabvec = env_tables;
998 for (curtab = 0; tabvec[curtab]; curtab++) {
999 if (!str$case_blind_compare(tabvec[curtab],&crtlenv)) {
1000 if (!ivenv && !secure) {
1005 #if defined(PERL_IMPLICIT_CONTEXT)
1008 "%%PERL-W-VMS_INIT Can't read CRTL environ\n");
1011 Perl_warn(aTHX_ "Can't read CRTL environ\n");
1014 retsts = SS$_NOLOGNAM;
1015 for (i = 0; environ[i]; i++) {
1016 if ((eq = strchr(environ[i],'=')) &&
1017 lnmdsc.dsc$w_length == (eq - environ[i]) &&
1018 !strncmp(environ[i],uplnm,eq - environ[i])) {
1020 for (eqvlen = 0; eq[eqvlen]; eqvlen++) eqv[eqvlen] = eq[eqvlen];
1021 if (!eqvlen) continue;
1022 retsts = SS$_NORMAL;
1026 if (retsts != SS$_NOLOGNAM) break;
1029 else if ((tmpdsc.dsc$a_pointer = tabvec[curtab]->dsc$a_pointer) &&
1030 !str$case_blind_compare(&tmpdsc,&clisym)) {
1031 if (!ivsym && !secure) {
1032 unsigned short int deflen = LNM$C_NAMLENGTH;
1033 struct dsc$descriptor_d eqvdsc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_D,0};
1034 /* dynamic dsc to accomodate possible long value */
1035 _ckvmssts_noperl(lib$sget1_dd(&deflen,&eqvdsc));
1036 retsts = lib$get_symbol(&lnmdsc,&eqvdsc,&eqvlen,0);
1038 if (eqvlen > MAX_DCL_SYMBOL) {
1039 set_errno(EVMSERR); set_vaxc_errno(LIB$_STRTRU);
1040 eqvlen = MAX_DCL_SYMBOL;
1041 /* Special hack--we might be called before the interpreter's */
1042 /* fully initialized, in which case either thr or PL_curcop */
1043 /* might be bogus. We have to check, since ckWARN needs them */
1044 /* both to be valid if running threaded */
1045 if (ckWARN(WARN_MISC)) {
1046 Perl_warner(aTHX_ packWARN(WARN_MISC),"Value of CLI symbol \"%s\" too long",lnm);
1049 strncpy(eqv,eqvdsc.dsc$a_pointer,eqvlen);
1051 _ckvmssts_noperl(lib$sfree1_dd(&eqvdsc));
1052 if (retsts == LIB$_INVSYMNAM) { ivsym = 1; continue; }
1053 if (retsts == LIB$_NOSUCHSYM) continue;
1058 if ( (idx == 0) && (flags & PERL__TRNENV_JOIN_SEARCHLIST) ) {
1059 midx = my_maxidx(lnm);
1060 for (idx = 0, cp2 = eqv; idx <= midx; idx++) {
1061 lnmlst[1].bufadr = cp2;
1063 retsts = sys$trnlnm(&attr,tabvec[curtab],&lnmdsc,&acmode,lnmlst);
1064 if (retsts == SS$_IVLOGNAM) { ivlnm = 1; break; }
1065 if (retsts == SS$_NOLOGNAM) break;
1066 /* PPFs have a prefix */
1069 *((int *)uplnm) == *((int *)"SYS$") &&
1071 eqvlen >= 4 && eqv[0] == 0x1b && eqv[1] == 0x00 &&
1072 ( (uplnm[4] == 'O' && !strcmp(uplnm,"SYS$OUTPUT")) ||
1073 (uplnm[4] == 'I' && !strcmp(uplnm,"SYS$INPUT")) ||
1074 (uplnm[4] == 'E' && !strcmp(uplnm,"SYS$ERROR")) ||
1075 (uplnm[4] == 'C' && !strcmp(uplnm,"SYS$COMMAND")) ) ) {
1076 memmove(eqv,eqv+4,eqvlen-4);
1082 if ((retsts == SS$_IVLOGNAM) ||
1083 (retsts == SS$_NOLOGNAM)) { continue; }
1086 retsts = sys$trnlnm(&attr,tabvec[curtab],&lnmdsc,&acmode,lnmlst);
1087 if (retsts == SS$_IVLOGNAM) { ivlnm = 1; continue; }
1088 if (retsts == SS$_NOLOGNAM) continue;
1091 eqvlen = strlen(eqv);
1095 if (retsts & 1) { eqv[eqvlen] = '\0'; return eqvlen; }
1096 else if (retsts == LIB$_NOSUCHSYM || retsts == LIB$_INVSYMNAM ||
1097 retsts == SS$_IVLOGNAM || retsts == SS$_IVLOGTAB ||
1098 retsts == SS$_NOLOGNAM) {
1099 set_errno(EINVAL); set_vaxc_errno(retsts);
1101 else _ckvmssts_noperl(retsts);
1103 } /* end of vmstrnenv */
1106 /*{{{ int my_trnlnm(const char *lnm, char *eqv, unsigned long int idx)*/
1107 /* Define as a function so we can access statics. */
1108 int Perl_my_trnlnm(pTHX_ const char *lnm, char *eqv, unsigned long int idx)
1110 return vmstrnenv(lnm,eqv,idx,fildev,
1111 #ifdef SECURE_INTERNAL_GETENV
1112 (PL_curinterp ? PL_tainting : will_taint) ? PERL__TRNENV_SECURE : 0
1121 * Note: Uses Perl temp to store result so char * can be returned to
1122 * caller; this pointer will be invalidated at next Perl statement
1124 * We define this as a function rather than a macro in terms of my_getenv_len()
1125 * so that it'll work when PL_curinterp is undefined (and we therefore can't
1128 /*{{{ char *my_getenv(const char *lnm, bool sys)*/
1130 Perl_my_getenv(pTHX_ const char *lnm, bool sys)
1133 static char *__my_getenv_eqv = NULL;
1134 char uplnm[LNM$C_NAMLENGTH+1], *cp2, *eqv;
1135 unsigned long int idx = 0;
1136 int trnsuccess, success, secure, saverr, savvmserr;
1140 midx = my_maxidx(lnm) + 1;
1142 if (PL_curinterp) { /* Perl interpreter running -- may be threaded */
1143 /* Set up a temporary buffer for the return value; Perl will
1144 * clean it up at the next statement transition */
1145 tmpsv = sv_2mortal(newSVpv("",(LNM$C_NAMLENGTH*midx)+1));
1146 if (!tmpsv) return NULL;
1150 /* Assume no interpreter ==> single thread */
1151 if (__my_getenv_eqv != NULL) {
1152 Renew(__my_getenv_eqv,LNM$C_NAMLENGTH*midx+1,char);
1155 Newx(__my_getenv_eqv,LNM$C_NAMLENGTH*midx+1,char);
1157 eqv = __my_getenv_eqv;
1160 for (cp1 = lnm, cp2 = eqv; *cp1; cp1++,cp2++) *cp2 = _toupper(*cp1);
1161 if (cp1 - lnm == 7 && !strncmp(eqv,"DEFAULT",7)) {
1163 getcwd(eqv,LNM$C_NAMLENGTH);
1167 /* Get rid of "000000/ in rooted filespecs */
1170 zeros = strstr(eqv, "/000000/");
1171 if (zeros != NULL) {
1173 mlen = len - (zeros - eqv) - 7;
1174 memmove(zeros, &zeros[7], mlen);
1182 /* Impose security constraints only if tainting */
1184 /* Impose security constraints only if tainting */
1185 secure = PL_curinterp ? PL_tainting : will_taint;
1186 saverr = errno; savvmserr = vaxc$errno;
1193 #ifdef SECURE_INTERNAL_GETENV
1194 secure ? PERL__TRNENV_SECURE : 0
1200 /* For the getenv interface we combine all the equivalence names
1201 * of a search list logical into one value to acquire a maximum
1202 * value length of 255*128 (assuming %ENV is using logicals).
1204 flags |= PERL__TRNENV_JOIN_SEARCHLIST;
1206 /* If the name contains a semicolon-delimited index, parse it
1207 * off and make sure we only retrieve the equivalence name for
1209 if ((cp2 = strchr(lnm,';')) != NULL) {
1211 uplnm[cp2-lnm] = '\0';
1212 idx = strtoul(cp2+1,NULL,0);
1214 flags &= ~PERL__TRNENV_JOIN_SEARCHLIST;
1217 success = vmstrnenv(lnm,eqv,idx,secure ? fildev : NULL,flags);
1219 /* Discard NOLOGNAM on internal calls since we're often looking
1220 * for an optional name, and this "error" often shows up as the
1221 * (bogus) exit status for a die() call later on. */
1222 if (sys && vaxc$errno == SS$_NOLOGNAM) SETERRNO(saverr,savvmserr);
1223 return success ? eqv : NULL;
1226 } /* end of my_getenv() */
1230 /*{{{ SV *my_getenv_len(const char *lnm, bool sys)*/
1232 Perl_my_getenv_len(pTHX_ const char *lnm, unsigned long *len, bool sys)
1236 unsigned long idx = 0;
1238 static char *__my_getenv_len_eqv = NULL;
1239 int secure, saverr, savvmserr;
1242 midx = my_maxidx(lnm) + 1;
1244 if (PL_curinterp) { /* Perl interpreter running -- may be threaded */
1245 /* Set up a temporary buffer for the return value; Perl will
1246 * clean it up at the next statement transition */
1247 tmpsv = sv_2mortal(newSVpv("",(LNM$C_NAMLENGTH*midx)+1));
1248 if (!tmpsv) return NULL;
1252 /* Assume no interpreter ==> single thread */
1253 if (__my_getenv_len_eqv != NULL) {
1254 Renew(__my_getenv_len_eqv,LNM$C_NAMLENGTH*midx+1,char);
1257 Newx(__my_getenv_len_eqv,LNM$C_NAMLENGTH*midx+1,char);
1259 buf = __my_getenv_len_eqv;
1262 for (cp1 = lnm, cp2 = buf; *cp1; cp1++,cp2++) *cp2 = _toupper(*cp1);
1263 if (cp1 - lnm == 7 && !strncmp(buf,"DEFAULT",7)) {
1266 getcwd(buf,LNM$C_NAMLENGTH);
1269 /* Get rid of "000000/ in rooted filespecs */
1271 zeros = strstr(buf, "/000000/");
1272 if (zeros != NULL) {
1274 mlen = *len - (zeros - buf) - 7;
1275 memmove(zeros, &zeros[7], mlen);
1284 /* Impose security constraints only if tainting */
1285 secure = PL_curinterp ? PL_tainting : will_taint;
1286 saverr = errno; savvmserr = vaxc$errno;
1293 #ifdef SECURE_INTERNAL_GETENV
1294 secure ? PERL__TRNENV_SECURE : 0
1300 flags |= PERL__TRNENV_JOIN_SEARCHLIST;
1302 if ((cp2 = strchr(lnm,';')) != NULL) {
1304 buf[cp2-lnm] = '\0';
1305 idx = strtoul(cp2+1,NULL,0);
1307 flags &= ~PERL__TRNENV_JOIN_SEARCHLIST;
1310 *len = vmstrnenv(lnm,buf,idx,secure ? fildev : NULL,flags);
1312 /* Get rid of "000000/ in rooted filespecs */
1315 zeros = strstr(buf, "/000000/");
1316 if (zeros != NULL) {
1318 mlen = *len - (zeros - buf) - 7;
1319 memmove(zeros, &zeros[7], mlen);
1325 /* Discard NOLOGNAM on internal calls since we're often looking
1326 * for an optional name, and this "error" often shows up as the
1327 * (bogus) exit status for a die() call later on. */
1328 if (sys && vaxc$errno == SS$_NOLOGNAM) SETERRNO(saverr,savvmserr);
1329 return *len ? buf : NULL;
1332 } /* end of my_getenv_len() */
1335 static void create_mbx(pTHX_ unsigned short int *, struct dsc$descriptor_s *);
1337 static void riseandshine(unsigned long int dummy) { sys$wake(0,0); }
1339 /*{{{ void prime_env_iter() */
1341 prime_env_iter(void)
1342 /* Fill the %ENV associative array with all logical names we can
1343 * find, in preparation for iterating over it.
1346 static int primed = 0;
1347 HV *seenhv = NULL, *envhv;
1349 char cmd[LNM$C_NAMLENGTH+24], mbxnam[LNM$C_NAMLENGTH], *buf = NULL;
1350 unsigned short int chan;
1351 #ifndef CLI$M_TRUSTED
1352 # define CLI$M_TRUSTED 0x40 /* Missing from VAXC headers */
1354 unsigned long int defflags = CLI$M_NOWAIT | CLI$M_NOKEYPAD | CLI$M_TRUSTED;
1355 unsigned long int mbxbufsiz, flags, retsts, subpid = 0, substs = 0, wakect = 0;
1357 bool have_sym = FALSE, have_lnm = FALSE;
1358 struct dsc$descriptor_s tmpdsc = {6,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
1359 $DESCRIPTOR(cmddsc,cmd); $DESCRIPTOR(nldsc,"_NLA0:");
1360 $DESCRIPTOR(clidsc,"DCL"); $DESCRIPTOR(clitabdsc,"DCLTABLES");
1361 $DESCRIPTOR(crtlenv,"CRTL_ENV"); $DESCRIPTOR(clisym,"CLISYM");
1362 $DESCRIPTOR(local,"_LOCAL"); $DESCRIPTOR(mbxdsc,mbxnam);
1363 #if defined(PERL_IMPLICIT_CONTEXT)
1366 #if defined(USE_ITHREADS)
1367 static perl_mutex primenv_mutex;
1368 MUTEX_INIT(&primenv_mutex);
1371 #if defined(PERL_IMPLICIT_CONTEXT)
1372 /* We jump through these hoops because we can be called at */
1373 /* platform-specific initialization time, which is before anything is */
1374 /* set up--we can't even do a plain dTHX since that relies on the */
1375 /* interpreter structure to be initialized */
1377 aTHX = PERL_GET_INTERP;
1379 /* we never get here because the NULL pointer will cause the */
1380 /* several of the routines called by this routine to access violate */
1382 /* This routine is only called by hv.c/hv_iterinit which has a */
1383 /* context, so the real fix may be to pass it through instead of */
1384 /* the hoops above */
1389 if (primed || !PL_envgv) return;
1390 MUTEX_LOCK(&primenv_mutex);
1391 if (primed) { MUTEX_UNLOCK(&primenv_mutex); return; }
1392 envhv = GvHVn(PL_envgv);
1393 /* Perform a dummy fetch as an lval to insure that the hash table is
1394 * set up. Otherwise, the hv_store() will turn into a nullop. */
1395 (void) hv_fetch(envhv,"DEFAULT",7,TRUE);
1397 for (i = 0; env_tables[i]; i++) {
1398 if (!have_sym && (tmpdsc.dsc$a_pointer = env_tables[i]->dsc$a_pointer) &&
1399 !str$case_blind_compare(&tmpdsc,&clisym)) have_sym = 1;
1400 if (!have_lnm && str$case_blind_compare(env_tables[i],&crtlenv)) have_lnm = 1;
1402 if (have_sym || have_lnm) {
1403 long int syiitm = SYI$_MAXBUF, dviitm = DVI$_DEVNAM;
1404 _ckvmssts(lib$getsyi(&syiitm, &mbxbufsiz, 0, 0, 0, 0));
1405 _ckvmssts(sys$crembx(0,&chan,mbxbufsiz,mbxbufsiz,0xff0f,0,0));
1406 _ckvmssts(lib$getdvi(&dviitm, &chan, NULL, NULL, &mbxdsc, &mbxdsc.dsc$w_length));
1409 for (i--; i >= 0; i--) {
1410 if (!str$case_blind_compare(env_tables[i],&crtlenv)) {
1413 for (j = 0; environ[j]; j++) {
1414 if (!(start = strchr(environ[j],'='))) {
1415 if (ckWARN(WARN_INTERNAL))
1416 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"Ill-formed CRTL environ value \"%s\"\n",environ[j]);
1420 sv = newSVpv(start,0);
1422 (void) hv_store(envhv,environ[j],start - environ[j] - 1,sv,0);
1427 else if ((tmpdsc.dsc$a_pointer = env_tables[i]->dsc$a_pointer) &&
1428 !str$case_blind_compare(&tmpdsc,&clisym)) {
1429 strcpy(cmd,"Show Symbol/Global *");
1430 cmddsc.dsc$w_length = 20;
1431 if (env_tables[i]->dsc$w_length == 12 &&
1432 (tmpdsc.dsc$a_pointer = env_tables[i]->dsc$a_pointer + 6) &&
1433 !str$case_blind_compare(&tmpdsc,&local)) strcpy(cmd+12,"Local *");
1434 flags = defflags | CLI$M_NOLOGNAM;
1437 strcpy(cmd,"Show Logical *");
1438 if (str$case_blind_compare(env_tables[i],&fildevdsc)) {
1439 strcat(cmd," /Table=");
1440 strncat(cmd,env_tables[i]->dsc$a_pointer,env_tables[i]->dsc$w_length);
1441 cmddsc.dsc$w_length = strlen(cmd);
1443 else cmddsc.dsc$w_length = 14; /* N.B. We test this below */
1444 flags = defflags | CLI$M_NOCLISYM;
1447 /* Create a new subprocess to execute each command, to exclude the
1448 * remote possibility that someone could subvert a mbx or file used
1449 * to write multiple commands to a single subprocess.
1452 retsts = lib$spawn(&cmddsc,&nldsc,&mbxdsc,&flags,0,&subpid,&substs,
1453 0,&riseandshine,0,0,&clidsc,&clitabdsc);
1454 flags &= ~CLI$M_TRUSTED; /* Just in case we hit a really old version */
1455 defflags &= ~CLI$M_TRUSTED;
1456 } while (retsts == LIB$_INVARG && (flags | CLI$M_TRUSTED));
1458 if (!buf) Newx(buf,mbxbufsiz + 1,char);
1459 if (seenhv) SvREFCNT_dec(seenhv);
1462 char *cp1, *cp2, *key;
1463 unsigned long int sts, iosb[2], retlen, keylen;
1466 sts = sys$qiow(0,chan,IO$_READVBLK,iosb,0,0,buf,mbxbufsiz,0,0,0,0);
1467 if (sts & 1) sts = iosb[0] & 0xffff;
1468 if (sts == SS$_ENDOFFILE) {
1470 while (substs == 0) { sys$hiber(); wakect++;}
1471 if (wakect > 1) sys$wake(0,0); /* Stole someone else's wake */
1476 retlen = iosb[0] >> 16;
1477 if (!retlen) continue; /* blank line */
1479 if (iosb[1] != subpid) {
1481 Perl_croak(aTHX_ "Unknown process %x sent message to prime_env_iter: %s",buf);
1485 if (sts == SS$_BUFFEROVF && ckWARN(WARN_INTERNAL))
1486 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"Buffer overflow in prime_env_iter: %s",buf);
1488 for (cp1 = buf; *cp1 && isspace(*cp1); cp1++) ;
1489 if (*cp1 == '(' || /* Logical name table name */
1490 *cp1 == '=' /* Next eqv of searchlist */) continue;
1491 if (*cp1 == '"') cp1++;
1492 for (cp2 = cp1; *cp2 && *cp2 != '"' && *cp2 != ' '; cp2++) ;
1493 key = cp1; keylen = cp2 - cp1;
1494 if (keylen && hv_exists(seenhv,key,keylen)) continue;
1495 while (*cp2 && *cp2 != '=') cp2++;
1496 while (*cp2 && *cp2 == '=') cp2++;
1497 while (*cp2 && *cp2 == ' ') cp2++;
1498 if (*cp2 == '"') { /* String translation; may embed "" */
1499 for (cp1 = buf + retlen; *cp1 != '"'; cp1--) ;
1500 cp2++; cp1--; /* Skip "" surrounding translation */
1502 else { /* Numeric translation */
1503 for (cp1 = cp2; *cp1 && *cp1 != ' '; cp1++) ;
1504 cp1--; /* stop on last non-space char */
1506 if ((!keylen || (cp1 - cp2 < -1)) && ckWARN(WARN_INTERNAL)) {
1507 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"Ill-formed message in prime_env_iter: |%s|",buf);
1510 PERL_HASH(hash,key,keylen);
1512 if (cp1 == cp2 && *cp2 == '.') {
1513 /* A single dot usually means an unprintable character, such as a null
1514 * to indicate a zero-length value. Get the actual value to make sure.
1516 char lnm[LNM$C_NAMLENGTH+1];
1517 char eqv[MAX_DCL_SYMBOL+1];
1519 strncpy(lnm, key, keylen);
1520 trnlen = vmstrnenv(lnm, eqv, 0, fildev, 0);
1521 sv = newSVpvn(eqv, strlen(eqv));
1524 sv = newSVpvn(cp2,cp1 - cp2 + 1);
1528 hv_store(envhv,key,keylen,sv,hash);
1529 hv_store(seenhv,key,keylen,&PL_sv_yes,hash);
1531 if (cmddsc.dsc$w_length == 14) { /* We just read LNM$FILE_DEV */
1532 /* get the PPFs for this process, not the subprocess */
1533 const char *ppfs[] = {"SYS$COMMAND", "SYS$INPUT", "SYS$OUTPUT", "SYS$ERROR", NULL};
1534 char eqv[LNM$C_NAMLENGTH+1];
1536 for (i = 0; ppfs[i]; i++) {
1537 trnlen = vmstrnenv(ppfs[i],eqv,0,fildev,0);
1538 sv = newSVpv(eqv,trnlen);
1540 hv_store(envhv,ppfs[i],strlen(ppfs[i]),sv,0);
1545 if (have_sym || have_lnm) _ckvmssts(sys$dassgn(chan));
1546 if (buf) Safefree(buf);
1547 if (seenhv) SvREFCNT_dec(seenhv);
1548 MUTEX_UNLOCK(&primenv_mutex);
1551 } /* end of prime_env_iter */
1555 /*{{{ int vmssetenv(const char *lnm, const char *eqv)*/
1556 /* Define or delete an element in the same "environment" as
1557 * vmstrnenv(). If an element is to be deleted, it's removed from
1558 * the first place it's found. If it's to be set, it's set in the
1559 * place designated by the first element of the table vector.
1560 * Like setenv() returns 0 for success, non-zero on error.
1563 Perl_vmssetenv(pTHX_ const char *lnm, const char *eqv, struct dsc$descriptor_s **tabvec)
1566 char uplnm[LNM$C_NAMLENGTH], *cp2, *c;
1567 unsigned short int curtab, ivlnm = 0, ivsym = 0, ivenv = 0;
1569 unsigned long int retsts, usermode = PSL$C_USER;
1570 struct itmlst_3 *ile, *ilist;
1571 struct dsc$descriptor_s lnmdsc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,uplnm},
1572 eqvdsc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0},
1573 tmpdsc = {6,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
1574 $DESCRIPTOR(crtlenv,"CRTL_ENV"); $DESCRIPTOR(clisym,"CLISYM");
1575 $DESCRIPTOR(local,"_LOCAL");
1578 set_errno(EINVAL); set_vaxc_errno(SS$_IVLOGNAM);
1579 return SS$_IVLOGNAM;
1582 for (cp1 = lnm, cp2 = uplnm; *cp1; cp1++, cp2++) {
1583 *cp2 = _toupper(*cp1);
1584 if (cp1 - lnm > LNM$C_NAMLENGTH) {
1585 set_errno(EINVAL); set_vaxc_errno(SS$_IVLOGNAM);
1586 return SS$_IVLOGNAM;
1589 lnmdsc.dsc$w_length = cp1 - lnm;
1590 if (!tabvec || !*tabvec) tabvec = env_tables;
1592 if (!eqv) { /* we're deleting n element */
1593 for (curtab = 0; tabvec[curtab]; curtab++) {
1594 if (!ivenv && !str$case_blind_compare(tabvec[curtab],&crtlenv)) {
1596 for (i = 0; environ[i]; i++) { /* If it's an environ elt, reset */
1597 if ((cp1 = strchr(environ[i],'=')) &&
1598 lnmdsc.dsc$w_length == (cp1 - environ[i]) &&
1599 !strncmp(environ[i],lnm,cp1 - environ[i])) {
1601 return setenv(lnm,"",1) ? vaxc$errno : 0;
1604 ivenv = 1; retsts = SS$_NOLOGNAM;
1606 if (ckWARN(WARN_INTERNAL))
1607 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"This Perl can't reset CRTL environ elements (%s)",lnm);
1608 ivenv = 1; retsts = SS$_NOSUCHPGM;
1614 else if ((tmpdsc.dsc$a_pointer = tabvec[curtab]->dsc$a_pointer) &&
1615 !str$case_blind_compare(&tmpdsc,&clisym)) {
1616 unsigned int symtype;
1617 if (tabvec[curtab]->dsc$w_length == 12 &&
1618 (tmpdsc.dsc$a_pointer = tabvec[curtab]->dsc$a_pointer + 6) &&
1619 !str$case_blind_compare(&tmpdsc,&local))
1620 symtype = LIB$K_CLI_LOCAL_SYM;
1621 else symtype = LIB$K_CLI_GLOBAL_SYM;
1622 retsts = lib$delete_symbol(&lnmdsc,&symtype);
1623 if (retsts == LIB$_INVSYMNAM) { ivsym = 1; continue; }
1624 if (retsts == LIB$_NOSUCHSYM) continue;
1628 retsts = sys$dellnm(tabvec[curtab],&lnmdsc,&usermode); /* try user mode first */
1629 if (retsts == SS$_IVLOGNAM) { ivlnm = 1; continue; }
1630 if (retsts != SS$_NOLOGNAM && retsts != SS$_NOLOGTAB) break;
1631 retsts = lib$delete_logical(&lnmdsc,tabvec[curtab]); /* then supervisor mode */
1632 if (retsts != SS$_NOLOGNAM && retsts != SS$_NOLOGTAB) break;
1636 else { /* we're defining a value */
1637 if (!ivenv && !str$case_blind_compare(tabvec[0],&crtlenv)) {
1639 return setenv(lnm,eqv,1) ? vaxc$errno : 0;
1641 if (ckWARN(WARN_INTERNAL))
1642 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"This Perl can't set CRTL environ elements (%s=%s)",lnm,eqv);
1643 retsts = SS$_NOSUCHPGM;
1647 eqvdsc.dsc$a_pointer = (char *) eqv; /* cast ok to readonly parameter */
1648 eqvdsc.dsc$w_length = strlen(eqv);
1649 if ((tmpdsc.dsc$a_pointer = tabvec[0]->dsc$a_pointer) &&
1650 !str$case_blind_compare(&tmpdsc,&clisym)) {
1651 unsigned int symtype;
1652 if (tabvec[0]->dsc$w_length == 12 &&
1653 (tmpdsc.dsc$a_pointer = tabvec[0]->dsc$a_pointer + 6) &&
1654 !str$case_blind_compare(&tmpdsc,&local))
1655 symtype = LIB$K_CLI_LOCAL_SYM;
1656 else symtype = LIB$K_CLI_GLOBAL_SYM;
1657 retsts = lib$set_symbol(&lnmdsc,&eqvdsc,&symtype);
1660 if (!*eqv) eqvdsc.dsc$w_length = 1;
1661 if (eqvdsc.dsc$w_length > LNM$C_NAMLENGTH) {
1663 nseg = (eqvdsc.dsc$w_length + LNM$C_NAMLENGTH - 1) / LNM$C_NAMLENGTH;
1664 if (nseg > PERL_LNM_MAX_ALLOWED_INDEX + 1) {
1665 Perl_warner(aTHX_ packWARN(WARN_MISC),"Value of logical \"%s\" too long. Truncating to %i bytes",
1666 lnm, LNM$C_NAMLENGTH * (PERL_LNM_MAX_ALLOWED_INDEX+1));
1667 eqvdsc.dsc$w_length = LNM$C_NAMLENGTH * (PERL_LNM_MAX_ALLOWED_INDEX+1);
1668 nseg = PERL_LNM_MAX_ALLOWED_INDEX + 1;
1671 Newx(ilist,nseg+1,struct itmlst_3);
1674 set_errno(ENOMEM); set_vaxc_errno(SS$_INSFMEM);
1677 memset(ilist, 0, (sizeof(struct itmlst_3) * (nseg+1)));
1679 for (j = 0, c = eqvdsc.dsc$a_pointer; j < nseg; j++, ile++, c += LNM$C_NAMLENGTH) {
1680 ile->itmcode = LNM$_STRING;
1682 if ((j+1) == nseg) {
1683 ile->buflen = strlen(c);
1684 /* in case we are truncating one that's too long */
1685 if (ile->buflen > LNM$C_NAMLENGTH) ile->buflen = LNM$C_NAMLENGTH;
1688 ile->buflen = LNM$C_NAMLENGTH;
1692 retsts = lib$set_logical(&lnmdsc,0,tabvec[0],0,ilist);
1696 retsts = lib$set_logical(&lnmdsc,&eqvdsc,tabvec[0],0,0);
1701 if (!(retsts & 1)) {
1703 case LIB$_AMBSYMDEF: case LIB$_INSCLIMEM:
1704 case SS$_NOLOGTAB: case SS$_TOOMANYLNAM: case SS$_IVLOGTAB:
1705 set_errno(EVMSERR); break;
1706 case LIB$_INVARG: case LIB$_INVSYMNAM: case SS$_IVLOGNAM:
1707 case LIB$_NOSUCHSYM: case SS$_NOLOGNAM:
1708 set_errno(EINVAL); break;
1710 set_errno(EACCES); break;
1715 set_vaxc_errno(retsts);
1716 return (int) retsts || 44; /* retsts should never be 0, but just in case */
1719 /* We reset error values on success because Perl does an hv_fetch()
1720 * before each hv_store(), and if the thing we're setting didn't
1721 * previously exist, we've got a leftover error message. (Of course,
1722 * this fails in the face of
1723 * $foo = $ENV{nonexistent}; $ENV{existent} = 'foo';
1724 * in that the error reported in $! isn't spurious,
1725 * but it's right more often than not.)
1727 set_errno(0); set_vaxc_errno(retsts);
1731 } /* end of vmssetenv() */
1734 /*{{{ void my_setenv(const char *lnm, const char *eqv)*/
1735 /* This has to be a function since there's a prototype for it in proto.h */
1737 Perl_my_setenv(pTHX_ const char *lnm, const char *eqv)
1740 int len = strlen(lnm);
1744 for (i = 0; lnm[i]; i++) uplnm[i] = _toupper(lnm[i]);
1745 if (!strcmp(uplnm,"DEFAULT")) {
1746 if (eqv && *eqv) my_chdir(eqv);
1750 #ifndef RTL_USES_UTC
1751 if (len == 6 || len == 2) {
1754 for (i = 0; lnm[i]; i++) uplnm[i] = _toupper(lnm[i]);
1756 if (!strcmp(uplnm,"UCX$TZ")) tz_updated = 1;
1757 if (!strcmp(uplnm,"TZ")) tz_updated = 1;
1761 (void) vmssetenv(lnm,eqv,NULL);
1765 /*{{{static void vmssetuserlnm(char *name, char *eqv); */
1767 * sets a user-mode logical in the process logical name table
1768 * used for redirection of sys$error
1771 Perl_vmssetuserlnm(pTHX_ const char *name, const char *eqv)
1773 $DESCRIPTOR(d_tab, "LNM$PROCESS");
1774 struct dsc$descriptor_d d_name = {0,DSC$K_DTYPE_T,DSC$K_CLASS_D,0};
1775 unsigned long int iss, attr = LNM$M_CONFINE;
1776 unsigned char acmode = PSL$C_USER;
1777 struct itmlst_3 lnmlst[2] = {{0, LNM$_STRING, 0, 0},
1779 d_name.dsc$a_pointer = (char *)name; /* Cast OK for read only parameter */
1780 d_name.dsc$w_length = strlen(name);
1782 lnmlst[0].buflen = strlen(eqv);
1783 lnmlst[0].bufadr = (char *)eqv; /* Cast OK for read only parameter */
1785 iss = sys$crelnm(&attr,&d_tab,&d_name,&acmode,lnmlst);
1786 if (!(iss&1)) lib$signal(iss);
1791 /*{{{ char *my_crypt(const char *textpasswd, const char *usrname)*/
1792 /* my_crypt - VMS password hashing
1793 * my_crypt() provides an interface compatible with the Unix crypt()
1794 * C library function, and uses sys$hash_password() to perform VMS
1795 * password hashing. The quadword hashed password value is returned
1796 * as a NUL-terminated 8 character string. my_crypt() does not change
1797 * the case of its string arguments; in order to match the behavior
1798 * of LOGINOUT et al., alphabetic characters in both arguments must
1799 * be upcased by the caller.
1801 * - fix me to call ACM services when available
1804 Perl_my_crypt(pTHX_ const char *textpasswd, const char *usrname)
1806 # ifndef UAI$C_PREFERRED_ALGORITHM
1807 # define UAI$C_PREFERRED_ALGORITHM 127
1809 unsigned char alg = UAI$C_PREFERRED_ALGORITHM;
1810 unsigned short int salt = 0;
1811 unsigned long int sts;
1813 unsigned short int dsc$w_length;
1814 unsigned char dsc$b_type;
1815 unsigned char dsc$b_class;
1816 const char * dsc$a_pointer;
1817 } usrdsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0},
1818 txtdsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
1819 struct itmlst_3 uailst[3] = {
1820 { sizeof alg, UAI$_ENCRYPT, &alg, 0},
1821 { sizeof salt, UAI$_SALT, &salt, 0},
1822 { 0, 0, NULL, NULL}};
1823 static char hash[9];
1825 usrdsc.dsc$w_length = strlen(usrname);
1826 usrdsc.dsc$a_pointer = usrname;
1827 if (!((sts = sys$getuai(0, 0, &usrdsc, uailst, 0, 0, 0)) & 1)) {
1829 case SS$_NOGRPPRV: case SS$_NOSYSPRV:
1833 set_errno(ESRCH); /* There isn't a Unix no-such-user error */
1838 set_vaxc_errno(sts);
1839 if (sts != RMS$_RNF) return NULL;
1842 txtdsc.dsc$w_length = strlen(textpasswd);
1843 txtdsc.dsc$a_pointer = textpasswd;
1844 if (!((sts = sys$hash_password(&txtdsc, alg, salt, &usrdsc, &hash)) & 1)) {
1845 set_errno(EVMSERR); set_vaxc_errno(sts); return NULL;
1848 return (char *) hash;
1850 } /* end of my_crypt() */
1854 static char *mp_do_rmsexpand(pTHX_ const char *, char *, int, const char *, unsigned, int *, int *);
1855 static char *mp_do_fileify_dirspec(pTHX_ const char *, char *, int, int *);
1856 static char *mp_do_tovmsspec(pTHX_ const char *, char *, int, int, int *);
1858 /* fixup barenames that are directories for internal use.
1859 * There have been problems with the consistent handling of UNIX
1860 * style directory names when routines are presented with a name that
1861 * has no directory delimitors at all. So this routine will eventually
1864 static char * fixup_bare_dirnames(const char * name)
1866 if (decc_disable_to_vms_logname_translation) {
1872 /* 8.3, remove() is now broken on symbolic links */
1873 static int rms_erase(const char * vmsname);
1877 * A little hack to get around a bug in some implemenation of remove()
1878 * that do not know how to delete a directory
1880 * Delete any file to which user has control access, regardless of whether
1881 * delete access is explicitly allowed.
1882 * Limitations: User must have write access to parent directory.
1883 * Does not block signals or ASTs; if interrupted in midstream
1884 * may leave file with an altered ACL.
1887 /*{{{int mp_do_kill_file(const char *name, int dirflag)*/
1889 mp_do_kill_file(pTHX_ const char *name, int dirflag)
1893 unsigned long int jpicode = JPI$_UIC, type = ACL$C_FILE;
1894 unsigned long int cxt = 0, aclsts, fndsts, rmsts = -1;
1895 struct dsc$descriptor_s fildsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
1897 unsigned char myace$b_length;
1898 unsigned char myace$b_type;
1899 unsigned short int myace$w_flags;
1900 unsigned long int myace$l_access;
1901 unsigned long int myace$l_ident;
1902 } newace = { sizeof(struct myacedef), ACE$C_KEYID, 0,
1903 ACE$M_READ | ACE$M_WRITE | ACE$M_DELETE | ACE$M_CONTROL, 0},
1904 oldace = { sizeof(struct myacedef), ACE$C_KEYID, 0, 0, 0};
1906 findlst[3] = {{sizeof oldace, ACL$C_FNDACLENT, &oldace, 0},
1907 {sizeof oldace, ACL$C_READACE, &oldace, 0},{0,0,0,0}},
1908 addlst[2] = {{sizeof newace, ACL$C_ADDACLENT, &newace, 0},{0,0,0,0}},
1909 dellst[2] = {{sizeof newace, ACL$C_DELACLENT, &newace, 0},{0,0,0,0}},
1910 lcklst[2] = {{sizeof newace, ACL$C_WLOCK_ACL, &newace, 0},{0,0,0,0}},
1911 ulklst[2] = {{sizeof newace, ACL$C_UNLOCK_ACL, &newace, 0},{0,0,0,0}};
1913 /* Expand the input spec using RMS, since the CRTL remove() and
1914 * system services won't do this by themselves, so we may miss
1915 * a file "hiding" behind a logical name or search list. */
1916 vmsname = PerlMem_malloc(NAM$C_MAXRSS+1);
1917 if (vmsname == NULL) _ckvmssts_noperl(SS$_INSFMEM);
1919 rslt = do_rmsexpand(name,
1923 PERL_RMSEXPAND_M_VMS | PERL_RMSEXPAND_M_SYMLINK,
1927 PerlMem_free(vmsname);
1931 /* Erase the file */
1932 rmsts = rms_erase(vmsname);
1934 /* Did it succeed */
1935 if ($VMS_STATUS_SUCCESS(rmsts)) {
1936 PerlMem_free(vmsname);
1940 /* If not, can changing protections help? */
1941 if (rmsts != RMS$_PRV) {
1942 set_vaxc_errno(rmsts);
1943 PerlMem_free(vmsname);
1947 /* No, so we get our own UIC to use as a rights identifier,
1948 * and the insert an ACE at the head of the ACL which allows us
1949 * to delete the file.
1951 _ckvmssts_noperl(lib$getjpi(&jpicode,0,0,&(oldace.myace$l_ident),0,0));
1952 fildsc.dsc$w_length = strlen(vmsname);
1953 fildsc.dsc$a_pointer = vmsname;
1955 newace.myace$l_ident = oldace.myace$l_ident;
1957 if (!((aclsts = sys$change_acl(0,&type,&fildsc,lcklst,0,0,0)) & 1)) {
1959 case RMS$_FNF: case RMS$_DNF: case SS$_NOSUCHOBJECT:
1960 set_errno(ENOENT); break;
1962 set_errno(ENOTDIR); break;
1964 set_errno(ENODEV); break;
1965 case RMS$_SYN: case SS$_INVFILFOROP:
1966 set_errno(EINVAL); break;
1968 set_errno(EACCES); break;
1970 _ckvmssts_noperl(aclsts);
1972 set_vaxc_errno(aclsts);
1973 PerlMem_free(vmsname);
1976 /* Grab any existing ACEs with this identifier in case we fail */
1977 aclsts = fndsts = sys$change_acl(0,&type,&fildsc,findlst,0,0,&cxt);
1978 if ( fndsts & 1 || fndsts == SS$_ACLEMPTY || fndsts == SS$_NOENTRY
1979 || fndsts == SS$_NOMOREACE ) {
1980 /* Add the new ACE . . . */
1981 if (!((aclsts = sys$change_acl(0,&type,&fildsc,addlst,0,0,0)) & 1))
1984 rmsts = rms_erase(vmsname);
1985 if ($VMS_STATUS_SUCCESS(rmsts)) {
1990 /* We blew it - dir with files in it, no write priv for
1991 * parent directory, etc. Put things back the way they were. */
1992 if (!((aclsts = sys$change_acl(0,&type,&fildsc,dellst,0,0,0)) & 1))
1995 addlst[0].bufadr = &oldace;
1996 if (!((aclsts = sys$change_acl(0,&type,&fildsc,addlst,0,0,&cxt)) & 1))
2003 fndsts = sys$change_acl(0,&type,&fildsc,ulklst,0,0,0);
2004 /* We just deleted it, so of course it's not there. Some versions of
2005 * VMS seem to return success on the unlock operation anyhow (after all
2006 * the unlock is successful), but others don't.
2008 if (fndsts == RMS$_FNF || fndsts == SS$_NOSUCHOBJECT) fndsts = SS$_NORMAL;
2009 if (aclsts & 1) aclsts = fndsts;
2010 if (!(aclsts & 1)) {
2012 set_vaxc_errno(aclsts);
2015 PerlMem_free(vmsname);
2018 } /* end of kill_file() */
2022 /*{{{int do_rmdir(char *name)*/
2024 Perl_do_rmdir(pTHX_ const char *name)
2030 dirfile = PerlMem_malloc(VMS_MAXRSS + 1);
2031 if (dirfile == NULL)
2032 _ckvmssts(SS$_INSFMEM);
2034 /* Force to a directory specification */
2035 if (do_fileify_dirspec(name, dirfile, 0, NULL) == NULL) {
2036 PerlMem_free(dirfile);
2039 if (Perl_flex_lstat(aTHX_ dirfile, &st) || !S_ISDIR(st.st_mode)) {
2044 retval = mp_do_kill_file(aTHX_ dirfile, 1);
2046 PerlMem_free(dirfile);
2049 } /* end of do_rmdir */
2053 * Delete any file to which user has control access, regardless of whether
2054 * delete access is explicitly allowed.
2055 * Limitations: User must have write access to parent directory.
2056 * Does not block signals or ASTs; if interrupted in midstream
2057 * may leave file with an altered ACL.
2060 /*{{{int kill_file(char *name)*/
2062 Perl_kill_file(pTHX_ const char *name)
2064 char rspec[NAM$C_MAXRSS+1];
2069 /* Remove() is allowed to delete directories, according to the X/Open
2071 * This may need special handling to work with the ACL hacks.
2073 if ((flex_lstat(name, &st) == 0) && S_ISDIR(st.st_mode)) {
2074 rmsts = Perl_do_rmdir(aTHX_ name);
2078 rmsts = mp_do_kill_file(aTHX_ name, 0);
2082 } /* end of kill_file() */
2086 /*{{{int my_mkdir(char *,Mode_t)*/
2088 Perl_my_mkdir(pTHX_ const char *dir, Mode_t mode)
2090 STRLEN dirlen = strlen(dir);
2092 /* zero length string sometimes gives ACCVIO */
2093 if (dirlen == 0) return -1;
2095 /* CRTL mkdir() doesn't tolerate trailing /, since that implies
2096 * null file name/type. However, it's commonplace under Unix,
2097 * so we'll allow it for a gain in portability.
2099 if (dir[dirlen-1] == '/') {
2100 char *newdir = savepvn(dir,dirlen-1);
2101 int ret = mkdir(newdir,mode);
2105 else return mkdir(dir,mode);
2106 } /* end of my_mkdir */
2109 /*{{{int my_chdir(char *)*/
2111 Perl_my_chdir(pTHX_ const char *dir)
2113 STRLEN dirlen = strlen(dir);
2115 /* zero length string sometimes gives ACCVIO */
2116 if (dirlen == 0) return -1;
2119 /* Perl is passing the output of the DCL SHOW DEFAULT with leading spaces.
2120 * This does not work if DECC$EFS_CHARSET is active. Hack it here
2121 * so that existing scripts do not need to be changed.
2124 while ((dirlen > 0) && (*dir1 == ' ')) {
2129 /* some versions of CRTL chdir() doesn't tolerate trailing /, since
2131 * null file name/type. However, it's commonplace under Unix,
2132 * so we'll allow it for a gain in portability.
2134 * - Preview- '/' will be valid soon on VMS
2136 if ((dirlen > 1) && (dir1[dirlen-1] == '/')) {
2137 char *newdir = savepvn(dir1,dirlen-1);
2138 int ret = chdir(newdir);
2142 else return chdir(dir1);
2143 } /* end of my_chdir */
2147 /*{{{int my_chmod(char *, mode_t)*/
2149 Perl_my_chmod(pTHX_ const char *file_spec, mode_t mode)
2151 STRLEN speclen = strlen(file_spec);
2153 /* zero length string sometimes gives ACCVIO */
2154 if (speclen == 0) return -1;
2156 /* some versions of CRTL chmod() doesn't tolerate trailing /, since
2157 * that implies null file name/type. However, it's commonplace under Unix,
2158 * so we'll allow it for a gain in portability.
2160 * Tests are showing that chmod() on VMS 8.3 is only accepting directories
2161 * in VMS file.dir notation.
2163 if ((speclen > 1) && (file_spec[speclen-1] == '/')) {
2164 char *vms_src, *vms_dir, *rslt;
2168 /* First convert this to a VMS format specification */
2169 vms_src = PerlMem_malloc(VMS_MAXRSS);
2170 if (vms_src == NULL)
2171 _ckvmssts_noperl(SS$_INSFMEM);
2173 rslt = do_tovmsspec(file_spec, vms_src, 0, NULL);
2175 /* If we fail, then not a file specification */
2176 PerlMem_free(vms_src);
2181 /* Now make it a directory spec so chmod is happy */
2182 vms_dir = PerlMem_malloc(VMS_MAXRSS + 1);
2183 if (vms_dir == NULL)
2184 _ckvmssts_noperl(SS$_INSFMEM);
2185 rslt = do_fileify_dirspec(vms_src, vms_dir, 0, NULL);
2186 PerlMem_free(vms_src);
2190 ret = chmod(vms_dir, mode);
2194 PerlMem_free(vms_dir);
2197 else return chmod(file_spec, mode);
2198 } /* end of my_chmod */
2202 /*{{{FILE *my_tmpfile()*/
2209 if ((fp = tmpfile())) return fp;
2211 cp = PerlMem_malloc(L_tmpnam+24);
2212 if (cp == NULL) _ckvmssts_noperl(SS$_INSFMEM);
2214 if (decc_filename_unix_only == 0)
2215 strcpy(cp,"Sys$Scratch:");
2218 tmpnam(cp+strlen(cp));
2219 strcat(cp,".Perltmp");
2220 fp = fopen(cp,"w+","fop=dlt");
2227 #ifndef HOMEGROWN_POSIX_SIGNALS
2229 * The C RTL's sigaction fails to check for invalid signal numbers so we
2230 * help it out a bit. The docs are correct, but the actual routine doesn't
2231 * do what the docs say it will.
2233 /*{{{int Perl_my_sigaction (pTHX_ int, const struct sigaction*, struct sigaction*);*/
2235 Perl_my_sigaction (pTHX_ int sig, const struct sigaction* act,
2236 struct sigaction* oact)
2238 if (sig == SIGKILL || sig == SIGSTOP || sig == SIGCONT) {
2239 SETERRNO(EINVAL, SS$_INVARG);
2242 return sigaction(sig, act, oact);
2247 #ifdef KILL_BY_SIGPRC
2248 #include <errnodef.h>
2250 /* We implement our own kill() using the undocumented system service
2251 sys$sigprc for one of two reasons:
2253 1.) If the kill() in an older CRTL uses sys$forcex, causing the
2254 target process to do a sys$exit, which usually can't be handled
2255 gracefully...certainly not by Perl and the %SIG{} mechanism.
2257 2.) If the kill() in the CRTL can't be called from a signal
2258 handler without disappearing into the ether, i.e., the signal
2259 it purportedly sends is never trapped. Still true as of VMS 7.3.
2261 sys$sigprc has the same parameters as sys$forcex, but throws an exception
2262 in the target process rather than calling sys$exit.
2264 Note that distinguishing SIGSEGV from SIGBUS requires an extra arg
2265 on the ACCVIO condition, which sys$sigprc (and sys$forcex) don't
2266 provide. On VMS 7.0+ this is taken care of by doing sys$sigprc
2267 with condition codes C$_SIG0+nsig*8, catching the exception on the
2268 target process and resignaling with appropriate arguments.
2270 But we don't have that VMS 7.0+ exception handler, so if you
2271 Perl_my_kill(.., SIGSEGV) it will show up as a SIGBUS. Oh well.
2273 Also note that SIGTERM is listed in the docs as being "unimplemented",
2274 yet always seems to be signaled with a VMS condition code of 4 (and
2275 correctly handled for that code). So we hardwire it in.
2277 Unlike the VMS 7.0+ CRTL kill() function, we actually check the signal
2278 number to see if it's valid. So Perl_my_kill(pid,0) returns -1 rather
2279 than signalling with an unrecognized (and unhandled by CRTL) code.
2282 #define _MY_SIG_MAX 28
2285 Perl_sig_to_vmscondition_int(int sig)
2287 static unsigned int sig_code[_MY_SIG_MAX+1] =
2290 SS$_HANGUP, /* 1 SIGHUP */
2291 SS$_CONTROLC, /* 2 SIGINT */
2292 SS$_CONTROLY, /* 3 SIGQUIT */
2293 SS$_RADRMOD, /* 4 SIGILL */
2294 SS$_BREAK, /* 5 SIGTRAP */
2295 SS$_OPCCUS, /* 6 SIGABRT */
2296 SS$_COMPAT, /* 7 SIGEMT */
2298 SS$_FLTOVF, /* 8 SIGFPE VAX */
2300 SS$_HPARITH, /* 8 SIGFPE AXP */
2302 SS$_ABORT, /* 9 SIGKILL */
2303 SS$_ACCVIO, /* 10 SIGBUS */
2304 SS$_ACCVIO, /* 11 SIGSEGV */
2305 SS$_BADPARAM, /* 12 SIGSYS */
2306 SS$_NOMBX, /* 13 SIGPIPE */
2307 SS$_ASTFLT, /* 14 SIGALRM */
2324 #if __VMS_VER >= 60200000
2325 static int initted = 0;
2328 sig_code[16] = C$_SIGUSR1;
2329 sig_code[17] = C$_SIGUSR2;
2330 #if __CRTL_VER >= 70000000
2331 sig_code[20] = C$_SIGCHLD;
2333 #if __CRTL_VER >= 70300000
2334 sig_code[28] = C$_SIGWINCH;
2339 if (sig < _SIG_MIN) return 0;
2340 if (sig > _MY_SIG_MAX) return 0;
2341 return sig_code[sig];
2345 Perl_sig_to_vmscondition(int sig)
2348 if (vms_debug_on_exception != 0)
2349 lib$signal(SS$_DEBUG);
2351 return Perl_sig_to_vmscondition_int(sig);
2356 Perl_my_kill(int pid, int sig)
2361 int sys$sigprc(unsigned int *pidadr,
2362 struct dsc$descriptor_s *prcname,
2365 /* sig 0 means validate the PID */
2366 /*------------------------------*/
2368 const unsigned long int jpicode = JPI$_PID;
2371 status = lib$getjpi(&jpicode, &pid, NULL, &ret_pid, NULL, NULL);
2372 if ($VMS_STATUS_SUCCESS(status))
2375 case SS$_NOSUCHNODE:
2376 case SS$_UNREACHABLE:
2390 code = Perl_sig_to_vmscondition_int(sig);
2393 SETERRNO(EINVAL, SS$_BADPARAM);
2397 /* Fixme: Per official UNIX specification: If pid = 0, or negative then
2398 * signals are to be sent to multiple processes.
2399 * pid = 0 - all processes in group except ones that the system exempts
2400 * pid = -1 - all processes except ones that the system exempts
2401 * pid = -n - all processes in group (abs(n)) except ...
2402 * For now, just report as not supported.
2406 SETERRNO(ENOTSUP, SS$_UNSUPPORTED);
2410 iss = sys$sigprc((unsigned int *)&pid,0,code);
2411 if (iss&1) return 0;
2415 set_errno(EPERM); break;
2417 case SS$_NOSUCHNODE:
2418 case SS$_UNREACHABLE:
2419 set_errno(ESRCH); break;
2421 set_errno(ENOMEM); break;
2423 _ckvmssts_noperl(iss);
2426 set_vaxc_errno(iss);
2432 /* Routine to convert a VMS status code to a UNIX status code.
2433 ** More tricky than it appears because of conflicting conventions with
2436 ** VMS status codes are a bit mask, with the least significant bit set for
2439 ** Special UNIX status of EVMSERR indicates that no translation is currently
2440 ** available, and programs should check the VMS status code.
2442 ** Programs compiled with _POSIX_EXIT have a special encoding that requires
2446 #ifndef C_FACILITY_NO
2447 #define C_FACILITY_NO 0x350000
2450 #define DCL_IVVERB 0x38090
2453 int Perl_vms_status_to_unix(int vms_status, int child_flag)
2461 /* Assume the best or the worst */
2462 if (vms_status & STS$M_SUCCESS)
2465 unix_status = EVMSERR;
2467 msg_status = vms_status & ~STS$M_CONTROL;
2469 facility = vms_status & STS$M_FAC_NO;
2470 fac_sp = vms_status & STS$M_FAC_SP;
2471 msg_no = vms_status & (STS$M_MSG_NO | STS$M_SEVERITY);
2473 if (((facility == 0) || (fac_sp == 0)) && (child_flag == 0)) {
2479 unix_status = EFAULT;
2481 case SS$_DEVOFFLINE:
2482 unix_status = EBUSY;
2485 unix_status = ENOTCONN;
2493 case SS$_INVFILFOROP:
2497 unix_status = EINVAL;
2499 case SS$_UNSUPPORTED:
2500 unix_status = ENOTSUP;
2505 unix_status = EACCES;
2507 case SS$_DEVICEFULL:
2508 unix_status = ENOSPC;
2511 unix_status = ENODEV;
2513 case SS$_NOSUCHFILE:
2514 case SS$_NOSUCHOBJECT:
2515 unix_status = ENOENT;
2517 case SS$_ABORT: /* Fatal case */
2518 case ((SS$_ABORT & STS$M_COND_ID) | STS$K_ERROR): /* Error case */
2519 case ((SS$_ABORT & STS$M_COND_ID) | STS$K_WARNING): /* Warning case */
2520 unix_status = EINTR;
2523 unix_status = E2BIG;
2526 unix_status = ENOMEM;
2529 unix_status = EPERM;
2531 case SS$_NOSUCHNODE:
2532 case SS$_UNREACHABLE:
2533 unix_status = ESRCH;
2536 unix_status = ECHILD;
2539 if ((facility == 0) && (msg_no < 8)) {
2540 /* These are not real VMS status codes so assume that they are
2541 ** already UNIX status codes
2543 unix_status = msg_no;
2549 /* Translate a POSIX exit code to a UNIX exit code */
2550 if ((facility == C_FACILITY_NO) && ((msg_no & 0xA000) == 0xA000)) {
2551 unix_status = (msg_no & 0x07F8) >> 3;
2555 /* Documented traditional behavior for handling VMS child exits */
2556 /*--------------------------------------------------------------*/
2557 if (child_flag != 0) {
2559 /* Success / Informational return 0 */
2560 /*----------------------------------*/
2561 if (msg_no & STS$K_SUCCESS)
2564 /* Warning returns 1 */
2565 /*-------------------*/
2566 if ((msg_no & (STS$K_ERROR | STS$K_SEVERE)) == 0)
2569 /* Everything else pass through the severity bits */
2570 /*------------------------------------------------*/
2571 return (msg_no & STS$M_SEVERITY);
2574 /* Normal VMS status to ERRNO mapping attempt */
2575 /*--------------------------------------------*/
2576 switch(msg_status) {
2577 /* case RMS$_EOF: */ /* End of File */
2578 case RMS$_FNF: /* File Not Found */
2579 case RMS$_DNF: /* Dir Not Found */
2580 unix_status = ENOENT;
2582 case RMS$_RNF: /* Record Not Found */
2583 unix_status = ESRCH;
2586 unix_status = ENOTDIR;
2589 unix_status = ENODEV;
2594 unix_status = EBADF;
2597 unix_status = EEXIST;
2601 case LIB$_INVSTRDES:
2603 case LIB$_NOSUCHSYM:
2604 case LIB$_INVSYMNAM:
2606 unix_status = EINVAL;
2612 unix_status = E2BIG;
2614 case RMS$_PRV: /* No privilege */
2615 case RMS$_ACC: /* ACP file access failed */
2616 case RMS$_WLK: /* Device write locked */
2617 unix_status = EACCES;
2619 case RMS$_MKD: /* Failed to mark for delete */
2620 unix_status = EPERM;
2622 /* case RMS$_NMF: */ /* No more files */
2630 /* Try to guess at what VMS error status should go with a UNIX errno
2631 * value. This is hard to do as there could be many possible VMS
2632 * error statuses that caused the errno value to be set.
2635 int Perl_unix_status_to_vms(int unix_status)
2637 int test_unix_status;
2639 /* Trivial cases first */
2640 /*---------------------*/
2641 if (unix_status == EVMSERR)
2644 /* Is vaxc$errno sane? */
2645 /*---------------------*/
2646 test_unix_status = Perl_vms_status_to_unix(vaxc$errno, 0);
2647 if (test_unix_status == unix_status)
2650 /* If way out of range, must be VMS code already */
2651 /*-----------------------------------------------*/
2652 if (unix_status > EVMSERR)
2655 /* If out of range, punt */
2656 /*-----------------------*/
2657 if (unix_status > __ERRNO_MAX)
2661 /* Ok, now we have to do it the hard way. */
2662 /*----------------------------------------*/
2663 switch(unix_status) {
2664 case 0: return SS$_NORMAL;
2665 case EPERM: return SS$_NOPRIV;
2666 case ENOENT: return SS$_NOSUCHOBJECT;
2667 case ESRCH: return SS$_UNREACHABLE;
2668 case EINTR: return SS$_ABORT;
2671 case E2BIG: return SS$_BUFFEROVF;
2673 case EBADF: return RMS$_IFI;
2674 case ECHILD: return SS$_NONEXPR;
2676 case ENOMEM: return SS$_INSFMEM;
2677 case EACCES: return SS$_FILACCERR;
2678 case EFAULT: return SS$_ACCVIO;
2680 case EBUSY: return SS$_DEVOFFLINE;
2681 case EEXIST: return RMS$_FEX;
2683 case ENODEV: return SS$_NOSUCHDEV;
2684 case ENOTDIR: return RMS$_DIR;
2686 case EINVAL: return SS$_INVARG;
2692 case ENOSPC: return SS$_DEVICEFULL;
2693 case ESPIPE: return LIB$_INVARG;
2698 case ERANGE: return LIB$_INVARG;
2699 /* case EWOULDBLOCK */
2700 /* case EINPROGRESS */
2703 /* case EDESTADDRREQ */
2705 /* case EPROTOTYPE */
2706 /* case ENOPROTOOPT */
2707 /* case EPROTONOSUPPORT */
2708 /* case ESOCKTNOSUPPORT */
2709 /* case EOPNOTSUPP */
2710 /* case EPFNOSUPPORT */
2711 /* case EAFNOSUPPORT */
2712 /* case EADDRINUSE */
2713 /* case EADDRNOTAVAIL */
2715 /* case ENETUNREACH */
2716 /* case ENETRESET */
2717 /* case ECONNABORTED */
2718 /* case ECONNRESET */
2721 case ENOTCONN: return SS$_CLEARED;
2722 /* case ESHUTDOWN */
2723 /* case ETOOMANYREFS */
2724 /* case ETIMEDOUT */
2725 /* case ECONNREFUSED */
2727 /* case ENAMETOOLONG */
2728 /* case EHOSTDOWN */
2729 /* case EHOSTUNREACH */
2730 /* case ENOTEMPTY */
2742 /* case ECANCELED */
2746 return SS$_UNSUPPORTED;
2752 /* case EABANDONED */
2754 return SS$_ABORT; /* punt */
2757 return SS$_ABORT; /* Should not get here */
2761 /* default piping mailbox size */
2762 #define PERL_BUFSIZ 512
2766 create_mbx(pTHX_ unsigned short int *chan, struct dsc$descriptor_s *namdsc)
2768 unsigned long int mbxbufsiz;
2769 static unsigned long int syssize = 0;
2770 unsigned long int dviitm = DVI$_DEVNAM;
2771 char csize[LNM$C_NAMLENGTH+1];
2775 unsigned long syiitm = SYI$_MAXBUF;
2777 * Get the SYSGEN parameter MAXBUF
2779 * If the logical 'PERL_MBX_SIZE' is defined
2780 * use the value of the logical instead of PERL_BUFSIZ, but
2781 * keep the size between 128 and MAXBUF.
2784 _ckvmssts_noperl(lib$getsyi(&syiitm, &syssize, 0, 0, 0, 0));
2787 if (vmstrnenv("PERL_MBX_SIZE", csize, 0, fildev, 0)) {
2788 mbxbufsiz = atoi(csize);
2790 mbxbufsiz = PERL_BUFSIZ;
2792 if (mbxbufsiz < 128) mbxbufsiz = 128;
2793 if (mbxbufsiz > syssize) mbxbufsiz = syssize;
2795 _ckvmssts_noperl(sts = sys$crembx(0,chan,mbxbufsiz,mbxbufsiz,0,0,0));
2797 sts = lib$getdvi(&dviitm, chan, NULL, NULL, namdsc, &namdsc->dsc$w_length);
2798 _ckvmssts_noperl(sts);
2799 namdsc->dsc$a_pointer[namdsc->dsc$w_length] = '\0';
2801 } /* end of create_mbx() */
2804 /*{{{ my_popen and my_pclose*/
2806 typedef struct _iosb IOSB;
2807 typedef struct _iosb* pIOSB;
2808 typedef struct _pipe Pipe;
2809 typedef struct _pipe* pPipe;
2810 typedef struct pipe_details Info;
2811 typedef struct pipe_details* pInfo;
2812 typedef struct _srqp RQE;
2813 typedef struct _srqp* pRQE;
2814 typedef struct _tochildbuf CBuf;
2815 typedef struct _tochildbuf* pCBuf;
2818 unsigned short status;
2819 unsigned short count;
2820 unsigned long dvispec;
2823 #pragma member_alignment save
2824 #pragma nomember_alignment quadword
2825 struct _srqp { /* VMS self-relative queue entry */
2826 unsigned long qptr[2];
2828 #pragma member_alignment restore
2829 static RQE RQE_ZERO = {0,0};
2831 struct _tochildbuf {
2834 unsigned short size;
2842 unsigned short chan_in;
2843 unsigned short chan_out;
2845 unsigned int bufsize;
2857 #if defined(PERL_IMPLICIT_CONTEXT)
2858 void *thx; /* Either a thread or an interpreter */
2859 /* pointer, depending on how we're built */
2867 PerlIO *fp; /* file pointer to pipe mailbox */
2868 int useFILE; /* using stdio, not perlio */
2869 int pid; /* PID of subprocess */
2870 int mode; /* == 'r' if pipe open for reading */
2871 int done; /* subprocess has completed */
2872 int waiting; /* waiting for completion/closure */
2873 int closing; /* my_pclose is closing this pipe */
2874 unsigned long completion; /* termination status of subprocess */
2875 pPipe in; /* pipe in to sub */
2876 pPipe out; /* pipe out of sub */
2877 pPipe err; /* pipe of sub's sys$error */
2878 int in_done; /* true when in pipe finished */
2881 unsigned short xchan; /* channel to debug xterm */
2882 unsigned short xchan_valid; /* channel is assigned */
2885 struct exit_control_block
2887 struct exit_control_block *flink;
2888 unsigned long int (*exit_routine)();
2889 unsigned long int arg_count;
2890 unsigned long int *status_address;
2891 unsigned long int exit_status;
2894 typedef struct _closed_pipes Xpipe;
2895 typedef struct _closed_pipes* pXpipe;
2897 struct _closed_pipes {
2898 int pid; /* PID of subprocess */
2899 unsigned long completion; /* termination status of subprocess */
2901 #define NKEEPCLOSED 50
2902 static Xpipe closed_list[NKEEPCLOSED];
2903 static int closed_index = 0;
2904 static int closed_num = 0;
2906 #define RETRY_DELAY "0 ::0.20"
2907 #define MAX_RETRY 50
2909 static int pipe_ef = 0; /* first call to safe_popen inits these*/
2910 static unsigned long mypid;
2911 static unsigned long delaytime[2];
2913 static pInfo open_pipes = NULL;
2914 static $DESCRIPTOR(nl_desc, "NL:");
2916 #define PIPE_COMPLETION_WAIT 30 /* seconds, for EOF/FORCEX wait */
2920 static unsigned long int
2924 unsigned long int retsts = SS$_NORMAL, abort = SS$_TIMEOUT;
2925 int sts, did_stuff, need_eof, j;
2928 * Flush any pending i/o, but since we are in process run-down, be
2929 * careful about referencing PerlIO structures that may already have
2930 * been deallocated. We may not even have an interpreter anymore.
2935 #if defined(PERL_IMPLICIT_CONTEXT)
2936 /* We need to use the Perl context of the thread that created */
2940 aTHX = info->err->thx;
2942 aTHX = info->out->thx;
2944 aTHX = info->in->thx;
2947 #if defined(USE_ITHREADS)
2950 && PL_perlio_fd_refcnt)
2951 PerlIO_flush(info->fp);
2953 fflush((FILE *)info->fp);
2959 next we try sending an EOF...ignore if doesn't work, make sure we
2967 _ckvmssts_noperl(sys$setast(0));
2968 if (info->in && !info->in->shut_on_empty) {
2969 _ckvmssts_noperl(sys$qio(0,info->in->chan_in,IO$_WRITEOF,0,0,0,
2974 _ckvmssts_noperl(sys$setast(1));
2978 /* wait for EOF to have effect, up to ~ 30 sec [default] */
2980 for (j = 0; did_stuff && j < PIPE_COMPLETION_WAIT; j++) {
2985 _ckvmssts_noperl(sys$setast(0));
2986 if (info->waiting && info->done)
2988 nwait += info->waiting;
2989 _ckvmssts_noperl(sys$setast(1));
2999 _ckvmssts_noperl(sys$setast(0));
3000 if (!info->done) { /* Tap them gently on the shoulder . . .*/
3001 sts = sys$forcex(&info->pid,0,&abort);
3002 if (!(sts&1) && sts != SS$_NONEXPR) _ckvmssts_noperl(sts);
3005 _ckvmssts_noperl(sys$setast(1));
3009 /* again, wait for effect */
3011 for (j = 0; did_stuff && j < PIPE_COMPLETION_WAIT; j++) {
3016 _ckvmssts_noperl(sys$setast(0));
3017 if (info->waiting && info->done)
3019 nwait += info->waiting;
3020 _ckvmssts_noperl(sys$setast(1));
3029 _ckvmssts_noperl(sys$setast(0));
3030 if (!info->done) { /* We tried to be nice . . . */
3031 sts = sys$delprc(&info->pid,0);
3032 if (!(sts&1) && sts != SS$_NONEXPR) _ckvmssts_noperl(sts);
3033 info->done = 1; /* sys$delprc is as done as we're going to get. */
3035 _ckvmssts_noperl(sys$setast(1));
3041 #if defined(PERL_IMPLICIT_CONTEXT)
3042 /* We need to use the Perl context of the thread that created */
3046 aTHX = info->err->thx;
3048 aTHX = info->out->thx;
3050 aTHX = info->in->thx;
3052 if ((sts = my_pclose(open_pipes->fp)) == -1) retsts = vaxc$errno;
3053 else if (!(sts & 1)) retsts = sts;
3058 static struct exit_control_block pipe_exitblock =
3059 {(struct exit_control_block *) 0,
3060 pipe_exit_routine, 0, &pipe_exitblock.exit_status, 0};
3062 static void pipe_mbxtofd_ast(pPipe p);
3063 static void pipe_tochild1_ast(pPipe p);
3064 static void pipe_tochild2_ast(pPipe p);
3067 popen_completion_ast(pInfo info)
3069 pInfo i = open_pipes;
3074 info->completion &= 0x0FFFFFFF; /* strip off "control" field */
3075 closed_list[closed_index].pid = info->pid;
3076 closed_list[closed_index].completion = info->completion;
3078 if (closed_index == NKEEPCLOSED)
3083 if (i == info) break;
3086 if (!i) return; /* unlinked, probably freed too */
3091 Writing to subprocess ...
3092 if my_pclose'd: EOF already sent, should shutdown chan_in part of pipe
3094 chan_out may be waiting for "done" flag, or hung waiting
3095 for i/o completion to child...cancel the i/o. This will
3096 put it into "snarf mode" (done but no EOF yet) that discards
3099 Output from subprocess (stdout, stderr) needs to be flushed and
3100 shut down. We try sending an EOF, but if the mbx is full the pipe
3101 routine should still catch the "shut_on_empty" flag, telling it to
3102 use immediate-style reads so that "mbx empty" -> EOF.
3106 if (info->in && !info->in_done) { /* only for mode=w */
3107 if (info->in->shut_on_empty && info->in->need_wake) {
3108 info->in->need_wake = FALSE;
3109 _ckvmssts_noperl(sys$dclast(pipe_tochild2_ast,info->in,0));
3111 _ckvmssts_noperl(sys$cancel(info->in->chan_out));
3115 if (info->out && !info->out_done) { /* were we also piping output? */
3116 info->out->shut_on_empty = TRUE;
3117 iss = sys$qio(0,info->out->chan_in,IO$_WRITEOF|IO$M_NORSWAIT, 0, 0, 0, 0, 0, 0, 0, 0, 0);
3118 if (iss == SS$_MBFULL) iss = SS$_NORMAL;
3119 _ckvmssts_noperl(iss);
3122 if (info->err && !info->err_done) { /* we were piping stderr */
3123 info->err->shut_on_empty = TRUE;
3124 iss = sys$qio(0,info->err->chan_in,IO$_WRITEOF|IO$M_NORSWAIT, 0, 0, 0, 0, 0, 0, 0, 0, 0);
3125 if (iss == SS$_MBFULL) iss = SS$_NORMAL;
3126 _ckvmssts_noperl(iss);
3128 _ckvmssts_noperl(sys$setef(pipe_ef));
3132 static unsigned long int setup_cmddsc(pTHX_ const char *cmd, int check_img, int *suggest_quote, struct dsc$descriptor_s **pvmscmd);
3133 static void vms_execfree(struct dsc$descriptor_s *vmscmd);
3136 we actually differ from vmstrnenv since we use this to
3137 get the RMS IFI to check if SYS$OUTPUT and SYS$ERROR *really*
3138 are pointing to the same thing
3141 static unsigned short
3142 popen_translate(pTHX_ char *logical, char *result)
3145 $DESCRIPTOR(d_table,"LNM$PROCESS_TABLE");
3146 $DESCRIPTOR(d_log,"");
3148 unsigned short length;
3149 unsigned short code;
3151 unsigned short *retlenaddr;
3153 unsigned short l, ifi;
3155 d_log.dsc$a_pointer = logical;
3156 d_log.dsc$w_length = strlen(logical);
3158 itmlst[0].code = LNM$_STRING;
3159 itmlst[0].length = 255;
3160 itmlst[0].buffer_addr = result;
3161 itmlst[0].retlenaddr = &l;
3164 itmlst[1].length = 0;
3165 itmlst[1].buffer_addr = 0;
3166 itmlst[1].retlenaddr = 0;
3168 iss = sys$trnlnm(0, &d_table, &d_log, 0, itmlst);
3169 if (iss == SS$_NOLOGNAM) {
3173 if (!(iss&1)) lib$signal(iss);
3176 logicals for PPFs have a 4 byte prefix ESC+NUL+(RMS IFI)
3177 strip it off and return the ifi, if any
3180 if (result[0] == 0x1b && result[1] == 0x00) {
3181 memmove(&ifi,result+2,2);
3182 strcpy(result,result+4);
3184 return ifi; /* this is the RMS internal file id */
3187 static void pipe_infromchild_ast(pPipe p);
3190 I'm using LIB$(GET|FREE)_VM here so that we can allocate and deallocate
3191 inside an AST routine without worrying about reentrancy and which Perl
3192 memory allocator is being used.
3194 We read data and queue up the buffers, then spit them out one at a
3195 time to the output mailbox when the output mailbox is ready for one.
3198 #define INITIAL_TOCHILDQUEUE 2
3201 pipe_tochild_setup(pTHX_ char *rmbx, char *wmbx)
3205 char mbx1[64], mbx2[64];
3206 struct dsc$descriptor_s d_mbx1 = {sizeof mbx1, DSC$K_DTYPE_T,
3207 DSC$K_CLASS_S, mbx1},
3208 d_mbx2 = {sizeof mbx2, DSC$K_DTYPE_T,
3209 DSC$K_CLASS_S, mbx2};
3210 unsigned int dviitm = DVI$_DEVBUFSIZ;
3214 _ckvmssts_noperl(lib$get_vm(&n, &p));
3216 create_mbx(aTHX_ &p->chan_in , &d_mbx1);
3217 create_mbx(aTHX_ &p->chan_out, &d_mbx2);
3218 _ckvmssts_noperl(lib$getdvi(&dviitm, &p->chan_in, 0, &p->bufsize));
3221 p->shut_on_empty = FALSE;
3222 p->need_wake = FALSE;
3225 p->iosb.status = SS$_NORMAL;
3226 p->iosb2.status = SS$_NORMAL;
3232 #ifdef PERL_IMPLICIT_CONTEXT
3236 n = sizeof(CBuf) + p->bufsize;
3238 for (j = 0; j < INITIAL_TOCHILDQUEUE; j++) {
3239 _ckvmssts_noperl(lib$get_vm(&n, &b));
3240 b->buf = (char *) b + sizeof(CBuf);
3241 _ckvmssts_noperl(lib$insqhi(b, &p->free));
3244 pipe_tochild2_ast(p);
3245 pipe_tochild1_ast(p);
3251 /* reads the MBX Perl is writing, and queues */
3254 pipe_tochild1_ast(pPipe p)
3257 int iss = p->iosb.status;
3258 int eof = (iss == SS$_ENDOFFILE);
3260 #ifdef PERL_IMPLICIT_CONTEXT
3266 p->shut_on_empty = TRUE;
3268 _ckvmssts_noperl(sys$dassgn(p->chan_in));
3270 _ckvmssts_noperl(iss);
3274 b->size = p->iosb.count;
3275 _ckvmssts_noperl(sts = lib$insqhi(b, &p->wait));
3277 p->need_wake = FALSE;
3278 _ckvmssts_noperl(sys$dclast(pipe_tochild2_ast,p,0));
3281 p->retry = 1; /* initial call */
3284 if (eof) { /* flush the free queue, return when done */
3285 int n = sizeof(CBuf) + p->bufsize;
3287 iss = lib$remqti(&p->free, &b);
3288 if (iss == LIB$_QUEWASEMP) return;
3289 _ckvmssts_noperl(iss);
3290 _ckvmssts_noperl(lib$free_vm(&n, &b));
3294 iss = lib$remqti(&p->free, &b);
3295 if (iss == LIB$_QUEWASEMP) {
3296 int n = sizeof(CBuf) + p->bufsize;
3297 _ckvmssts_noperl(lib$get_vm(&n, &b));
3298 b->buf = (char *) b + sizeof(CBuf);
3300 _ckvmssts_noperl(iss);
3304 iss = sys$qio(0,p->chan_in,
3305 IO$_READVBLK|(p->shut_on_empty ? IO$M_NOWAIT : 0),
3307 pipe_tochild1_ast, p, b->buf, p->bufsize, 0, 0, 0, 0);
3308 if (iss == SS$_ENDOFFILE && p->shut_on_empty) iss = SS$_NORMAL;
3309 _ckvmssts_noperl(iss);
3313 /* writes queued buffers to output, waits for each to complete before
3317 pipe_tochild2_ast(pPipe p)
3320 int iss = p->iosb2.status;
3321 int n = sizeof(CBuf) + p->bufsize;
3322 int done = (p->info && p->info->done) ||
3323 iss == SS$_CANCEL || iss == SS$_ABORT;
3324 #if defined(PERL_IMPLICIT_CONTEXT)
3329 if (p->type) { /* type=1 has old buffer, dispose */
3330 if (p->shut_on_empty) {
3331 _ckvmssts_noperl(lib$free_vm(&n, &b));
3333 _ckvmssts_noperl(lib$insqhi(b, &p->free));
3338 iss = lib$remqti(&p->wait, &b);
3339 if (iss == LIB$_QUEWASEMP) {
3340 if (p->shut_on_empty) {
3342 _ckvmssts_noperl(sys$dassgn(p->chan_out));
3343 *p->pipe_done = TRUE;
3344 _ckvmssts_noperl(sys$setef(pipe_ef));
3346 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEOF,
3347 &p->iosb2, pipe_tochild2_ast, p, 0, 0, 0, 0, 0, 0));
3351 p->need_wake = TRUE;
3354 _ckvmssts_noperl(iss);
3361 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEOF,
3362 &p->iosb2, pipe_tochild2_ast, p, 0, 0, 0, 0, 0, 0));
3364 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEVBLK,
3365 &p->iosb2, pipe_tochild2_ast, p, b->buf, b->size, 0, 0, 0, 0));
3374 pipe_infromchild_setup(pTHX_ char *rmbx, char *wmbx)
3377 char mbx1[64], mbx2[64];
3378 struct dsc$descriptor_s d_mbx1 = {sizeof mbx1, DSC$K_DTYPE_T,
3379 DSC$K_CLASS_S, mbx1},
3380 d_mbx2 = {sizeof mbx2, DSC$K_DTYPE_T,
3381 DSC$K_CLASS_S, mbx2};
3382 unsigned int dviitm = DVI$_DEVBUFSIZ;
3384 int n = sizeof(Pipe);
3385 _ckvmssts_noperl(lib$get_vm(&n, &p));
3386 create_mbx(aTHX_ &p->chan_in , &d_mbx1);
3387 create_mbx(aTHX_ &p->chan_out, &d_mbx2);
3389 _ckvmssts_noperl(lib$getdvi(&dviitm, &p->chan_in, 0, &p->bufsize));
3390 n = p->bufsize * sizeof(char);
3391 _ckvmssts_noperl(lib$get_vm(&n, &p->buf));
3392 p->shut_on_empty = FALSE;
3395 p->iosb.status = SS$_NORMAL;
3396 #if defined(PERL_IMPLICIT_CONTEXT)
3399 pipe_infromchild_ast(p);
3407 pipe_infromchild_ast(pPipe p)
3409 int iss = p->iosb.status;
3410 int eof = (iss == SS$_ENDOFFILE);
3411 int myeof = (eof && (p->iosb.dvispec == mypid || p->iosb.dvispec == 0));
3412 int kideof = (eof && (p->iosb.dvispec == p->info->pid));
3413 #if defined(PERL_IMPLICIT_CONTEXT)
3417 if (p->info && p->info->closing && p->chan_out) { /* output shutdown */
3418 _ckvmssts_noperl(sys$dassgn(p->chan_out));
3423 input shutdown if EOF from self (done or shut_on_empty)
3424 output shutdown if closing flag set (my_pclose)
3425 send data/eof from child or eof from self
3426 otherwise, re-read (snarf of data from child)
3431 if (myeof && p->chan_in) { /* input shutdown */
3432 _ckvmssts_noperl(sys$dassgn(p->chan_in));
3437 if (myeof || kideof) { /* pass EOF to parent */
3438 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEOF, &p->iosb,
3439 pipe_infromchild_ast, p,
3442 } else if (eof) { /* eat EOF --- fall through to read*/
3444 } else { /* transmit data */
3445 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEVBLK,&p->iosb,
3446 pipe_infromchild_ast,p,
3447 p->buf, p->iosb.count, 0, 0, 0, 0));
3453 /* everything shut? flag as done */
3455 if (!p->chan_in && !p->chan_out) {
3456 *p->pipe_done = TRUE;
3457 _ckvmssts_noperl(sys$setef(pipe_ef));
3461 /* write completed (or read, if snarfing from child)
3462 if still have input active,
3463 queue read...immediate mode if shut_on_empty so we get EOF if empty
3465 check if Perl reading, generate EOFs as needed
3471 iss = sys$qio(0,p->chan_in,IO$_READVBLK|(p->shut_on_empty ? IO$M_NOW : 0),&p->iosb,
3472 pipe_infromchild_ast,p,
3473 p->buf, p->bufsize, 0, 0, 0, 0);
3474 if (p->shut_on_empty && iss == SS$_ENDOFFILE) iss = SS$_NORMAL;
3475 _ckvmssts_noperl(iss);
3476 } else { /* send EOFs for extra reads */
3477 p->iosb.status = SS$_ENDOFFILE;
3478 p->iosb.dvispec = 0;
3479 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_SETMODE|IO$M_READATTN,
3481 pipe_infromchild_ast, p, 0, 0, 0, 0));
3487 pipe_mbxtofd_setup(pTHX_ int fd, char *out)
3491 unsigned long dviitm = DVI$_DEVBUFSIZ;
3493 struct dsc$descriptor_s d_mbx = {sizeof mbx, DSC$K_DTYPE_T,
3494 DSC$K_CLASS_S, mbx};
3495 int n = sizeof(Pipe);
3497 /* things like terminals and mbx's don't need this filter */
3498 if (fd && fstat(fd,&s) == 0) {
3499 unsigned long dviitm = DVI$_DEVCHAR, devchar;
3501 unsigned short dev_len;
3502 struct dsc$descriptor_s d_dev;
3504 struct item_list_3 items[3];
3506 unsigned short dvi_iosb[4];
3508 cptr = getname(fd, out, 1);
3509 if (cptr == NULL) _ckvmssts_noperl(SS$_NOSUCHDEV);
3510 d_dev.dsc$a_pointer = out;
3511 d_dev.dsc$w_length = strlen(out);
3512 d_dev.dsc$b_dtype = DSC$K_DTYPE_T;
3513 d_dev.dsc$b_class = DSC$K_CLASS_S;
3516 items[0].code = DVI$_DEVCHAR;
3517 items[0].bufadr = &devchar;
3518 items[0].retadr = NULL;
3520 items[1].code = DVI$_FULLDEVNAM;
3521 items[1].bufadr = device;
3522 items[1].retadr = &dev_len;
3526 status = sys$getdviw
3527 (NO_EFN, 0, &d_dev, items, dvi_iosb, NULL, NULL, NULL);
3528 _ckvmssts_noperl(status);
3529 if ($VMS_STATUS_SUCCESS(dvi_iosb[0])) {
3530 device[dev_len] = 0;
3532 if (!(devchar & DEV$M_DIR)) {
3533 strcpy(out, device);
3539 _ckvmssts_noperl(lib$get_vm(&n, &p));
3540 p->fd_out = dup(fd);
3541 create_mbx(aTHX_ &p->chan_in, &d_mbx);
3542 _ckvmssts_noperl(lib$getdvi(&dviitm, &p->chan_in, 0, &p->bufsize));
3543 n = (p->bufsize+1) * sizeof(char);
3544 _ckvmssts_noperl(lib$get_vm(&n, &p->buf));
3545 p->shut_on_empty = FALSE;
3550 _ckvmssts_noperl(sys$qio(0, p->chan_in, IO$_READVBLK, &p->iosb,
3551 pipe_mbxtofd_ast, p,
3552 p->buf, p->bufsize, 0, 0, 0, 0));
3558 pipe_mbxtofd_ast(pPipe p)
3560 int iss = p->iosb.status;
3561 int done = p->info->done;
3563 int eof = (iss == SS$_ENDOFFILE);
3564 int myeof = eof && ((p->iosb.dvispec == mypid)||(p->iosb.dvispec == 0));
3565 int err = !(iss&1) && !eof;
3566 #if defined(PERL_IMPLICIT_CONTEXT)
3570 if (done && myeof) { /* end piping */
3572 sys$dassgn(p->chan_in);
3573 *p->pipe_done = TRUE;
3574 _ckvmssts_noperl(sys$setef(pipe_ef));
3578 if (!err && !eof) { /* good data to send to file */
3579 p->buf[p->iosb.count] = '\n';
3580 iss2 = write(p->fd_out, p->buf, p->iosb.count+1);
3583 if (p->retry < MAX_RETRY) {
3584 _ckvmssts_noperl(sys$setimr(0,delaytime,pipe_mbxtofd_ast,p));
3590 _ckvmssts_noperl(iss);
3594 iss = sys$qio(0, p->chan_in, IO$_READVBLK|(p->shut_on_empty ? IO$M_NOW : 0), &p->iosb,
3595 pipe_mbxtofd_ast, p,
3596 p->buf, p->bufsize, 0, 0, 0, 0);
3597 if (p->shut_on_empty && (iss == SS$_ENDOFFILE)) iss = SS$_NORMAL;
3598 _ckvmssts_noperl(iss);
3602 typedef struct _pipeloc PLOC;
3603 typedef struct _pipeloc* pPLOC;
3607 char dir[NAM$C_MAXRSS+1];
3609 static pPLOC head_PLOC = 0;
3612 free_pipelocs(pTHX_ void *head)
3615 pPLOC *pHead = (pPLOC *)head;
3627 store_pipelocs(pTHX)
3636 char temp[NAM$C_MAXRSS+1];
3640 free_pipelocs(aTHX_ &head_PLOC);
3642 /* the . directory from @INC comes last */
3644 p = (pPLOC) PerlMem_malloc(sizeof(PLOC));
3645 if (p == NULL) _ckvmssts_noperl(SS$_INSFMEM);
3646 p->next = head_PLOC;
3648 strcpy(p->dir,"./");
3650 /* get the directory from $^X */
3652 unixdir = PerlMem_malloc(VMS_MAXRSS);
3653 if (unixdir == NULL) _ckvmssts_noperl(SS$_INSFMEM);
3655 #ifdef PERL_IMPLICIT_CONTEXT
3656 if (aTHX && PL_origargv && PL_origargv[0]) { /* maybe nul if embedded Perl */
3658 if (PL_origargv && PL_origargv[0]) { /* maybe nul if embedded Perl */
3660 strcpy(temp, PL_origargv[0]);
3661 x = strrchr(temp,']');
3663 x = strrchr(temp,'>');
3665 /* It could be a UNIX path */
3666 x = strrchr(temp,'/');
3672 /* Got a bare name, so use default directory */
3677 if ((tounixpath_utf8(temp, unixdir, NULL)) != NULL) {
3678 p = (pPLOC) PerlMem_malloc(sizeof(PLOC));
3679 if (p == NULL) _ckvmssts_noperl(SS$_INSFMEM);
3680 p->next = head_PLOC;
3682 strncpy(p->dir,unixdir,sizeof(p->dir)-1);
3683 p->dir[NAM$C_MAXRSS] = '\0';
3687 /* reverse order of @INC entries, skip "." since entered above */
3689 #ifdef PERL_IMPLICIT_CONTEXT
3692 if (PL_incgv) av = GvAVn(PL_incgv);
3694 for (i = 0; av && i <= AvFILL(av); i++) {
3695 dirsv = *av_fetch(av,i,TRUE);
3697 if (SvROK(dirsv)) continue;
3698 dir = SvPVx(dirsv,n_a);
3699 if (strcmp(dir,".") == 0) continue;
3700 if ((tounixpath_utf8(dir, unixdir, NULL)) == NULL)
3703 p = (pPLOC) PerlMem_malloc(sizeof(PLOC));
3704 p->next = head_PLOC;
3706 strncpy(p->dir,unixdir,sizeof(p->dir)-1);
3707 p->dir[NAM$C_MAXRSS] = '\0';
3710 /* most likely spot (ARCHLIB) put first in the list */
3713 if ((tounixpath_utf8(ARCHLIB_EXP, unixdir, NULL)) != NULL) {
3714 p = (pPLOC) PerlMem_malloc(sizeof(PLOC));
3715 if (p == NULL) _ckvmssts_noperl(SS$_INSFMEM);
3716 p->next = head_PLOC;
3718 strncpy(p->dir,unixdir,sizeof(p->dir)-1);
3719 p->dir[NAM$C_MAXRSS] = '\0';
3722 PerlMem_free(unixdir);
3726 Perl_cando_by_name_int
3727 (pTHX_ I32 bit, bool effective, const char *fname, int opts);
3728 #if !defined(PERL_IMPLICIT_CONTEXT)
3729 #define cando_by_name_int Perl_cando_by_name_int
3731 #define cando_by_name_int(a,b,c,d) Perl_cando_by_name_int(aTHX_ a,b,c,d)
3737 static int vmspipe_file_status = 0;
3738 static char vmspipe_file[NAM$C_MAXRSS+1];
3740 /* already found? Check and use ... need read+execute permission */
3742 if (vmspipe_file_status == 1) {
3743 if (cando_by_name_int(S_IRUSR, 0, vmspipe_file, PERL_RMSEXPAND_M_VMS_IN)
3744 && cando_by_name_int
3745 (S_IXUSR, 0, vmspipe_file, PERL_RMSEXPAND_M_VMS_IN)) {
3746 return vmspipe_file;
3748 vmspipe_file_status = 0;
3751 /* scan through stored @INC, $^X */
3753 if (vmspipe_file_status == 0) {
3754 char file[NAM$C_MAXRSS+1];
3755 pPLOC p = head_PLOC;
3760 strcpy(file, p->dir);
3761 dirlen = strlen(file);
3762 strncat(file, "vmspipe.com",NAM$C_MAXRSS - dirlen);
3763 file[NAM$C_MAXRSS] = '\0';
3766 exp_res = do_rmsexpand
3767 (file, vmspipe_file, 0, NULL, PERL_RMSEXPAND_M_VMS, NULL, NULL);
3768 if (!exp_res) continue;
3770 if (cando_by_name_int
3771 (S_IRUSR, 0, vmspipe_file, PERL_RMSEXPAND_M_VMS_IN)
3772 && cando_by_name_int
3773 (S_IXUSR, 0, vmspipe_file, PERL_RMSEXPAND_M_VMS_IN)) {
3774 vmspipe_file_status = 1;
3775 return vmspipe_file;
3778 vmspipe_file_status = -1; /* failed, use tempfiles */
3785 vmspipe_tempfile(pTHX)
3787 char file[NAM$C_MAXRSS+1];
3789 static int index = 0;
3793 /* create a tempfile */
3795 /* we can't go from W, shr=get to R, shr=get without
3796 an intermediate vulnerable state, so don't bother trying...
3798 and lib$spawn doesn't shr=put, so have to close the write
3800 So... match up the creation date/time and the FID to
3801 make sure we're dealing with the same file
3806 if (!decc_filename_unix_only) {
3807 sprintf(file,"sys$scratch:perlpipe_%08.8x_%d.com",mypid,index);
3808 fp = fopen(file,"w");
3810 sprintf(file,"sys$login:perlpipe_%08.8x_%d.com",mypid,index);
3811 fp = fopen(file,"w");
3813 sprintf(file,"sys$disk:[]perlpipe_%08.8x_%d.com",mypid,index);
3814 fp = fopen(file,"w");
3819 sprintf(file,"/tmp/perlpipe_%08.8x_%d.com",mypid,index);
3820 fp = fopen(file,"w");
3822 sprintf(file,"/sys$login/perlpipe_%08.8x_%d.com",mypid,index);
3823 fp = fopen(file,"w");
3825 sprintf(file,"./perlpipe_%08.8x_%d.com",mypid,index);
3826 fp = fopen(file,"w");
3830 if (!fp) return 0; /* we're hosed */
3832 fprintf(fp,"$! 'f$verify(0)'\n");
3833 fprintf(fp,"$! --- protect against nonstandard definitions ---\n");
3834 fprintf(fp,"$ perl_cfile = f$environment(\"procedure\")\n");
3835 fprintf(fp,"$ perl_define = \"define/nolog\"\n");
3836 fprintf(fp,"$ perl_on = \"set noon\"\n");
3837 fprintf(fp,"$ perl_exit = \"exit\"\n");
3838 fprintf(fp,"$ perl_del = \"delete\"\n");
3839 fprintf(fp,"$ pif = \"if\"\n");
3840 fprintf(fp,"$! --- define i/o redirection (sys$output set by lib$spawn)\n");
3841 fprintf(fp,"$ pif perl_popen_in .nes. \"\" then perl_define/user/name_attributes=confine sys$input 'perl_popen_in'\n");
3842 fprintf(fp,"$ pif perl_popen_err .nes. \"\" then perl_define/user/name_attributes=confine sys$error 'perl_popen_err'\n");
3843 fprintf(fp,"$ pif perl_popen_out .nes. \"\" then perl_define sys$output 'perl_popen_out'\n");
3844 fprintf(fp,"$! --- build command line to get max possible length\n");
3845 fprintf(fp,"$c=perl_popen_cmd0\n");
3846 fprintf(fp,"$c=c+perl_popen_cmd1\n");
3847 fprintf(fp,"$c=c+perl_popen_cmd2\n");
3848 fprintf(fp,"$x=perl_popen_cmd3\n");
3849 fprintf(fp,"$c=c+x\n");
3850 fprintf(fp,"$ perl_on\n");
3851 fprintf(fp,"$ 'c'\n");
3852 fprintf(fp,"$ perl_status = $STATUS\n");
3853 fprintf(fp,"$ perl_del 'perl_cfile'\n");
3854 fprintf(fp,"$ perl_exit 'perl_status'\n");
3857 fgetname(fp, file, 1);
3858 fstat(fileno(fp), (struct stat *)&s0);
3861 if (decc_filename_unix_only)
3862 do_tounixspec(file, file, 0, NULL);
3863 fp = fopen(file,"r","shr=get");
3865 fstat(fileno(fp), (struct stat *)&s1);
3867 cmp_result = VMS_INO_T_COMPARE(s0.crtl_stat.st_ino, s1.crtl_stat.st_ino);
3868 if ((cmp_result != 0) && (s0.st_ctime != s1.st_ctime)) {
3877 static int vms_is_syscommand_xterm(void)
3879 const static struct dsc$descriptor_s syscommand_dsc =
3880 { 11, DSC$K_DTYPE_T, DSC$K_CLASS_S, "SYS$COMMAND" };
3882 const static struct dsc$descriptor_s decwdisplay_dsc =
3883 { 12, DSC$K_DTYPE_T, DSC$K_CLASS_S, "DECW$DISPLAY" };
3885 struct item_list_3 items[2];
3886 unsigned short dvi_iosb[4];
3887 unsigned long devchar;
3888 unsigned long devclass;
3891 /* Very simple check to guess if sys$command is a decterm? */
3892 /* First see if the DECW$DISPLAY: device exists */
3894 items[0].code = DVI$_DEVCHAR;
3895 items[0].bufadr = &devchar;
3896 items[0].retadr = NULL;
3900 status = sys$getdviw
3901 (NO_EFN, 0, &decwdisplay_dsc, items, dvi_iosb, NULL, NULL, NULL);
3903 if ($VMS_STATUS_SUCCESS(status)) {
3904 status = dvi_iosb[0];
3907 if (!$VMS_STATUS_SUCCESS(status)) {
3908 SETERRNO(EVMSERR, status);
3912 /* If it does, then for now assume that we are on a workstation */
3913 /* Now verify that SYS$COMMAND is a terminal */
3914 /* for creating the debugger DECTerm */
3917 items[0].code = DVI$_DEVCLASS;
3918 items[0].bufadr = &devclass;
3919 items[0].retadr = NULL;
3923 status = sys$getdviw
3924 (NO_EFN, 0, &syscommand_dsc, items, dvi_iosb, NULL, NULL, NULL);
3926 if ($VMS_STATUS_SUCCESS(status)) {
3927 status = dvi_iosb[0];
3930 if (!$VMS_STATUS_SUCCESS(status)) {
3931 SETERRNO(EVMSERR, status);
3935 if (devclass == DC$_TERM) {
3942 /* If we are on a DECTerm, we can pretend to fork xterms when requested */
3943 static PerlIO * create_forked_xterm(pTHX_ const char *cmd, const char *mode)
3948 char device_name[65];
3949 unsigned short device_name_len;
3950 struct dsc$descriptor_s customization_dsc;
3951 struct dsc$descriptor_s device_name_dsc;
3954 char customization[200];
3958 unsigned short p_chan;
3960 unsigned short iosb[4];
3961 struct item_list_3 items[2];
3962 const char * cust_str =
3963 "DECW$TERMINAL.iconName:\tPerl Dbg\nDECW$TERMINAL.title:\t%40s\n";
3964 struct dsc$descriptor_s d_mbx1 = {sizeof mbx1, DSC$K_DTYPE_T,
3965 DSC$K_CLASS_S, mbx1};
3967 /* LIB$FIND_IMAGE_SIGNAL needs a handler */
3968 /*---------------------------------------*/
3969 VAXC$ESTABLISH((__vms_handler)lib$sig_to_ret);
3972 /* Make sure that this is from the Perl debugger */
3973 ret_char = strstr(cmd," xterm ");
3974 if (ret_char == NULL)
3976 cptr = ret_char + 7;
3977 ret_char = strstr(cmd,"tty");
3978 if (ret_char == NULL)
3980 ret_char = strstr(cmd,"sleep");
3981 if (ret_char == NULL)
3984 if (decw_term_port == 0) {
3985 $DESCRIPTOR(filename1_dsc, "DECW$TERMINALSHR12");
3986 $DESCRIPTOR(filename2_dsc, "DECW$TERMINALSHR");
3987 $DESCRIPTOR(decw_term_port_dsc, "DECW$TERM_PORT");
3989 status = lib$find_image_symbol
3991 &decw_term_port_dsc,
3992 (void *)&decw_term_port,
3996 /* Try again with the other image name */
3997 if (!$VMS_STATUS_SUCCESS(status)) {
3999 status = lib$find_image_symbol
4001 &decw_term_port_dsc,
4002 (void *)&decw_term_port,
4011 /* No decw$term_port, give it up */
4012 if (!$VMS_STATUS_SUCCESS(status))
4015 /* Are we on a workstation? */
4016 /* to do: capture the rows / columns and pass their properties */
4017 ret_stat = vms_is_syscommand_xterm();
4021 /* Make the title: */
4022 ret_char = strstr(cptr,"-title");
4023 if (ret_char != NULL) {
4024 while ((*cptr != 0) && (*cptr != '\"')) {
4030 while ((*cptr != 0) && (*cptr != '\"')) {
4043 strcpy(title,"Perl Debug DECTerm");
4045 sprintf(customization, cust_str, title);
4047 customization_dsc.dsc$a_pointer = customization;
4048 customization_dsc.dsc$w_length = strlen(customization);
4049 customization_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
4050 customization_dsc.dsc$b_class = DSC$K_CLASS_S;
4052 device_name_dsc.dsc$a_pointer = device_name;
4053 device_name_dsc.dsc$w_length = sizeof device_name -1;
4054 device_name_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
4055 device_name_dsc.dsc$b_class = DSC$K_CLASS_S;
4057 device_name_len = 0;
4059 /* Try to create the window */
4060 status = (*decw_term_port)
4069 if (!$VMS_STATUS_SUCCESS(status)) {
4070 SETERRNO(EVMSERR, status);
4074 device_name[device_name_len] = '\0';
4076 /* Need to set this up to look like a pipe for cleanup */
4078 status = lib$get_vm(&n, &info);
4079 if (!$VMS_STATUS_SUCCESS(status)) {
4080 SETERRNO(ENOMEM, status);
4086 info->completion = 0;
4087 info->closing = FALSE;
4094 info->in_done = TRUE;
4095 info->out_done = TRUE;
4096 info->err_done = TRUE;
4098 /* Assign a channel on this so that it will persist, and not login */
4099 /* We stash this channel in the info structure for reference. */
4100 /* The created xterm self destructs when the last channel is removed */
4101 /* and it appears that perl5db.pl (perl debugger) does this routinely */
4102 /* So leave this assigned. */
4103 device_name_dsc.dsc$w_length = device_name_len;
4104 status = sys$assign(&device_name_dsc,&info->xchan,0,0);
4105 if (!$VMS_STATUS_SUCCESS(status)) {
4106 SETERRNO(EVMSERR, status);
4109 info->xchan_valid = 1;
4111 /* Now create a mailbox to be read by the application */
4113 create_mbx(aTHX_ &p_chan, &d_mbx1);
4115 /* write the name of the created terminal to the mailbox */
4116 status = sys$qiow(NO_EFN, p_chan, IO$_WRITEVBLK|IO$M_NOW,
4117 iosb, NULL, NULL, device_name, device_name_len, 0, 0, 0, 0);
4119 if (!$VMS_STATUS_SUCCESS(status)) {
4120 SETERRNO(EVMSERR, status);
4124 info->fp = PerlIO_open(mbx1, mode);
4126 /* Done with this channel */
4129 /* If any errors, then clean up */
4132 _ckvmssts_noperl(lib$free_vm(&n, &info));
4140 static I32 my_pclose_pinfo(pTHX_ pInfo info);
4143 safe_popen(pTHX_ const char *cmd, const char *in_mode, int *psts)
4145 static int handler_set_up = FALSE;
4147 unsigned long int sts, flags = CLI$M_NOWAIT;
4148 /* The use of a GLOBAL table (as was done previously) rendered
4149 * Perl's qx() or `` unusable from a C<$ SET SYMBOL/SCOPE=NOGLOBAL> DCL
4150 * environment. Hence we've switched to LOCAL symbol table.
4152 unsigned int table = LIB$K_CLI_LOCAL_SYM;
4154 char *p, mode[10], symbol[MAX_DCL_SYMBOL+1], *vmspipe;
4155 char *in, *out, *err, mbx[512];
4157 char tfilebuf[NAM$C_MAXRSS+1];
4159 char cmd_sym_name[20];
4160 struct dsc$descriptor_s d_symbol= {0, DSC$K_DTYPE_T,
4161 DSC$K_CLASS_S, symbol};
4162 struct dsc$descriptor_s vmspipedsc = {0, DSC$K_DTYPE_T,
4164 struct dsc$descriptor_s d_sym_cmd = {0, DSC$K_DTYPE_T,
4165 DSC$K_CLASS_S, cmd_sym_name};
4166 struct dsc$descriptor_s *vmscmd;
4167 $DESCRIPTOR(d_sym_in ,"PERL_POPEN_IN");
4168 $DESCRIPTOR(d_sym_out,"PERL_POPEN_OUT");
4169 $DESCRIPTOR(d_sym_err,"PERL_POPEN_ERR");
4171 /* Check here for Xterm create request. This means looking for
4172 * "3>&1 xterm\b" and "\btty 1>&3\b$" in the command, and that it
4173 * is possible to create an xterm.
4175 if (*in_mode == 'r') {
4178 xterm_fd = create_forked_xterm(aTHX_ cmd, in_mode);
4179 if (xterm_fd != NULL)
4183 if (!head_PLOC) store_pipelocs(aTHX); /* at least TRY to use a static vmspipe file */
4185 /* once-per-program initialization...
4186 note that the SETAST calls and the dual test of pipe_ef
4187 makes sure that only the FIRST thread through here does
4188 the initialization...all other threads wait until it's
4191 Yeah, uglier than a pthread call, it's got all the stuff inline
4192 rather than in a separate routine.
4196 _ckvmssts_noperl(sys$setast(0));
4198 unsigned long int pidcode = JPI$_PID;
4199 $DESCRIPTOR(d_delay, RETRY_DELAY);
4200 _ckvmssts_noperl(lib$get_ef(&pipe_ef));
4201 _ckvmssts_noperl(lib$getjpi(&pidcode,0,0,&mypid,0,0));
4202 _ckvmssts_noperl(sys$bintim(&d_delay, delaytime));
4204 if (!handler_set_up) {
4205 _ckvmssts_noperl(sys$dclexh(&pipe_exitblock));
4206 handler_set_up = TRUE;
4208 _ckvmssts_noperl(sys$setast(1));
4211 /* see if we can find a VMSPIPE.COM */
4214 vmspipe = find_vmspipe(aTHX);
4216 strcpy(tfilebuf+1,vmspipe);
4217 } else { /* uh, oh...we're in tempfile hell */
4218 tpipe = vmspipe_tempfile(aTHX);
4219 if (!tpipe) { /* a fish popular in Boston */
4220 if (ckWARN(WARN_PIPE)) {
4221 Perl_warner(aTHX_ packWARN(WARN_PIPE),"unable to find VMSPIPE.COM for i/o piping");
4225 fgetname(tpipe,tfilebuf+1,1);
4227 vmspipedsc.dsc$a_pointer = tfilebuf;
4228 vmspipedsc.dsc$w_length = strlen(tfilebuf);
4230 sts = setup_cmddsc(aTHX_ cmd,0,0,&vmscmd);
4233 case RMS$_FNF: case RMS$_DNF:
4234 set_errno(ENOENT); break;
4236 set_errno(ENOTDIR); break;
4238 set_errno(ENODEV); break;
4240 set_errno(EACCES); break;
4242 set_errno(EINVAL); break;
4243 case CLI$_BUFOVF: case RMS$_RTB: case CLI$_TKNOVF: case CLI$_RSLOVF:
4244 set_errno(E2BIG); break;
4245 case LIB$_INVARG: case LIB$_INVSTRDES: case SS$_ACCVIO: /* shouldn't happen */
4246 _ckvmssts_noperl(sts); /* fall through */
4247 default: /* SS$_DUPLNAM, SS$_CLI, resource exhaustion, etc. */
4250 set_vaxc_errno(sts);
4251 if (*in_mode != 'n' && ckWARN(WARN_PIPE)) {
4252 Perl_warner(aTHX_ packWARN(WARN_PIPE),"Can't pipe \"%*s\": %s", strlen(cmd), cmd, Strerror(errno));
4258 _ckvmssts_noperl(lib$get_vm(&n, &info));
4260 strcpy(mode,in_mode);
4263 info->completion = 0;
4264 info->closing = FALSE;
4271 info->in_done = TRUE;
4272 info->out_done = TRUE;
4273 info->err_done = TRUE;
4275 info->xchan_valid = 0;
4277 in = PerlMem_malloc(VMS_MAXRSS);
4278 if (in == NULL) _ckvmssts_noperl(SS$_INSFMEM);
4279 out = PerlMem_malloc(VMS_MAXRSS);
4280 if (out == NULL) _ckvmssts_noperl(SS$_INSFMEM);
4281 err = PerlMem_malloc(VMS_MAXRSS);
4282 if (err == NULL) _ckvmssts_noperl(SS$_INSFMEM);
4284 in[0] = out[0] = err[0] = '\0';
4286 if ((p = strchr(mode,'F')) != NULL) { /* F -> use FILE* */
4290 if ((p = strchr(mode,'W')) != NULL) { /* W -> wait for completion */
4295 if (*mode == 'r') { /* piping from subroutine */
4297 info->out = pipe_infromchild_setup(aTHX_ mbx,out);
4299 info->out->pipe_done = &info->out_done;
4300 info->out_done = FALSE;
4301 info->out->info = info;
4303 if (!info->useFILE) {
4304 info->fp = PerlIO_open(mbx, mode);
4306 info->fp = (PerlIO *) freopen(mbx, mode, stdin);
4307 Perl_vmssetuserlnm(aTHX_ "SYS$INPUT",mbx);
4310 if (!info->fp && info->out) {
4311 sys$cancel(info->out->chan_out);
4313 while (!info->out_done) {
4315 _ckvmssts_noperl(sys$setast(0));
4316 done = info->out_done;
4317 if (!done) _ckvmssts_noperl(sys$clref(pipe_ef));
4318 _ckvmssts_noperl(sys$setast(1));
4319 if (!done) _ckvmssts_noperl(sys$waitfr(pipe_ef));
4322 if (info->out->buf) {
4323 n = info->out->bufsize * sizeof(char);
4324 _ckvmssts_noperl(lib$free_vm(&n, &info->out->buf));
4327 _ckvmssts_noperl(lib$free_vm(&n, &info->out));
4329 _ckvmssts_noperl(lib$free_vm(&n, &info));
4334 info->err = pipe_mbxtofd_setup(aTHX_ fileno(stderr), err);
4336 info->err->pipe_done = &info->err_done;
4337 info->err_done = FALSE;
4338 info->err->info = info;
4341 } else if (*mode == 'w') { /* piping to subroutine */
4343 info->out = pipe_mbxtofd_setup(aTHX_ fileno(stdout), out);
4345 info->out->pipe_done = &info->out_done;
4346 info->out_done = FALSE;
4347 info->out->info = info;
4350 info->err = pipe_mbxtofd_setup(aTHX_ fileno(stderr), err);
4352 info->err->pipe_done = &info->err_done;
4353 info->err_done = FALSE;
4354 info->err->info = info;
4357 info->in = pipe_tochild_setup(aTHX_ in,mbx);
4358 if (!info->useFILE) {
4359 info->fp = PerlIO_open(mbx, mode);
4361 info->fp = (PerlIO *) freopen(mbx, mode, stdout);
4362 Perl_vmssetuserlnm(aTHX_ "SYS$OUTPUT",mbx);
4366 info->in->pipe_done = &info->in_done;
4367 info->in_done = FALSE;
4368 info->in->info = info;
4372 if (!info->fp && info->in) {
4374 _ckvmssts_noperl(sys$qiow(0,info->in->chan_in, IO$_WRITEOF, 0,
4375 0, 0, 0, 0, 0, 0, 0, 0));
4377 while (!info->in_done) {
4379 _ckvmssts_noperl(sys$setast(0));
4380 done = info->in_done;
4381 if (!done) _ckvmssts_noperl(sys$clref(pipe_ef));
4382 _ckvmssts_noperl(sys$setast(1));
4383 if (!done) _ckvmssts_noperl(sys$waitfr(pipe_ef));
4386 if (info->in->buf) {
4387 n = info->in->bufsize * sizeof(char);
4388 _ckvmssts_noperl(lib$free_vm(&n, &info->in->buf));
4391 _ckvmssts_noperl(lib$free_vm(&n, &info->in));
4393 _ckvmssts_noperl(lib$free_vm(&n, &info));
4399 } else if (*mode == 'n') { /* separate subprocess, no Perl i/o */
4400 info->out = pipe_mbxtofd_setup(aTHX_ fileno(stdout), out);
4402 info->out->pipe_done = &info->out_done;
4403 info->out_done = FALSE;
4404 info->out->info = info;
4407 info->err = pipe_mbxtofd_setup(aTHX_ fileno(stderr), err);
4409 info->err->pipe_done = &info->err_done;
4410 info->err_done = FALSE;
4411 info->err->info = info;
4415 symbol[MAX_DCL_SYMBOL] = '\0';
4417 strncpy(symbol, in, MAX_DCL_SYMBOL);
4418 d_symbol.dsc$w_length = strlen(symbol);
4419 _ckvmssts_noperl(lib$set_symbol(&d_sym_in, &d_symbol, &table));
4421 strncpy(symbol, err, MAX_DCL_SYMBOL);
4422 d_symbol.dsc$w_length = strlen(symbol);
4423 _ckvmssts_noperl(lib$set_symbol(&d_sym_err, &d_symbol, &table));
4425 strncpy(symbol, out, MAX_DCL_SYMBOL);
4426 d_symbol.dsc$w_length = strlen(symbol);
4427 _ckvmssts_noperl(lib$set_symbol(&d_sym_out, &d_symbol, &table));
4429 /* Done with the names for the pipes */
4434 p = vmscmd->dsc$a_pointer;
4435 while (*p == ' ' || *p == '\t') p++; /* remove leading whitespace */
4436 if (*p == '$') p++; /* remove leading $ */
4437 while (*p == ' ' || *p == '\t') p++;
4439 for (j = 0; j < 4; j++) {
4440 sprintf(cmd_sym_name,"PERL_POPEN_CMD%d",j);
4441 d_sym_cmd.dsc$w_length = strlen(cmd_sym_name);
4443 strncpy(symbol, p, MAX_DCL_SYMBOL);
4444 d_symbol.dsc$w_length = strlen(symbol);
4445 _ckvmssts_noperl(lib$set_symbol(&d_sym_cmd, &d_symbol, &table));
4447 if (strlen(p) > MAX_DCL_SYMBOL) {
4448 p += MAX_DCL_SYMBOL;
4453 _ckvmssts_noperl(sys$setast(0));
4454 info->next=open_pipes; /* prepend to list */
4456 _ckvmssts_noperl(sys$setast(1));
4457 /* Omit arg 2 (input file) so the child will get the parent's SYS$INPUT
4458 * and SYS$COMMAND. vmspipe.com will redefine SYS$INPUT, but we'll still
4459 * have SYS$COMMAND if we need it.
4461 _ckvmssts_noperl(lib$spawn(&vmspipedsc, 0, &nl_desc, &flags,
4462 0, &info->pid, &info->completion,
4463 0, popen_completion_ast,info,0,0,0));
4465 /* if we were using a tempfile, close it now */
4467 if (tpipe) fclose(tpipe);
4469 /* once the subprocess is spawned, it has copied the symbols and
4470 we can get rid of ours */
4472 for (j = 0; j < 4; j++) {
4473 sprintf(cmd_sym_name,"PERL_POPEN_CMD%d",j);
4474 d_sym_cmd.dsc$w_length = strlen(cmd_sym_name);
4475 _ckvmssts_noperl(lib$delete_symbol(&d_sym_cmd, &table));
4477 _ckvmssts_noperl(lib$delete_symbol(&d_sym_in, &table));
4478 _ckvmssts_noperl(lib$delete_symbol(&d_sym_err, &table));
4479 _ckvmssts_noperl(lib$delete_symbol(&d_sym_out, &table));
4480 vms_execfree(vmscmd);
4482 #ifdef PERL_IMPLICIT_CONTEXT
4485 PL_forkprocess = info->pid;
4492 _ckvmssts_noperl(sys$setast(0));
4494 if (!done) _ckvmssts_noperl(sys$clref(pipe_ef));
4495 _ckvmssts_noperl(sys$setast(1));
4496 if (!done) _ckvmssts_noperl(sys$waitfr(pipe_ef));
4498 *psts = info->completion;
4499 /* Caller thinks it is open and tries to close it. */
4500 /* This causes some problems, as it changes the error status */
4501 /* my_pclose(info->fp); */
4503 /* If we did not have a file pointer open, then we have to */
4504 /* clean up here or eventually we will run out of something */
4506 if (info->fp == NULL) {
4507 my_pclose_pinfo(aTHX_ info);
4515 } /* end of safe_popen */
4518 /*{{{ PerlIO *my_popen(char *cmd, char *mode)*/
4520 Perl_my_popen(pTHX_ const char *cmd, const char *mode)
4524 TAINT_PROPER("popen");
4525 PERL_FLUSHALL_FOR_CHILD;
4526 return safe_popen(aTHX_ cmd,mode,&sts);
4532 /* Routine to close and cleanup a pipe info structure */
4534 static I32 my_pclose_pinfo(pTHX_ pInfo info) {
4536 unsigned long int retsts;
4541 /* If we were writing to a subprocess, insure that someone reading from
4542 * the mailbox gets an EOF. It looks like a simple fclose() doesn't
4543 * produce an EOF record in the mailbox.
4545 * well, at least sometimes it *does*, so we have to watch out for
4546 * the first EOF closing the pipe (and DASSGN'ing the channel)...
4550 #if defined(USE_ITHREADS)
4553 && PL_perlio_fd_refcnt)
4554 PerlIO_flush(info->fp);
4556 fflush((FILE *)info->fp);
4559 _ckvmssts(sys$setast(0));
4560 info->closing = TRUE;
4561 done = info->done && info->in_done && info->out_done && info->err_done;
4562 /* hanging on write to Perl's input? cancel it */
4563 if (info->mode == 'r' && info->out && !info->out_done) {
4564 if (info->out->chan_out) {
4565 _ckvmssts(sys$cancel(info->out->chan_out));
4566 if (!info->out->chan_in) { /* EOF generation, need AST */
4567 _ckvmssts(sys$dclast(pipe_infromchild_ast,info->out,0));
4571 if (info->in && !info->in_done && !info->in->shut_on_empty) /* EOF if hasn't had one yet */
4572 _ckvmssts(sys$qio(0,info->in->chan_in,IO$_WRITEOF,0,0,0,
4574 _ckvmssts(sys$setast(1));
4577 #if defined(USE_ITHREADS)
4580 && PL_perlio_fd_refcnt)
4581 PerlIO_close(info->fp);
4583 fclose((FILE *)info->fp);
4586 we have to wait until subprocess completes, but ALSO wait until all
4587 the i/o completes...otherwise we'll be freeing the "info" structure
4588 that the i/o ASTs could still be using...
4592 _ckvmssts(sys$setast(0));
4593 done = info->done && info->in_done && info->out_done && info->err_done;
4594 if (!done) _ckvmssts(sys$clref(pipe_ef));
4595 _ckvmssts(sys$setast(1));
4596 if (!done) _ckvmssts(sys$waitfr(pipe_ef));
4598 retsts = info->completion;
4600 /* remove from list of open pipes */
4601 _ckvmssts(sys$setast(0));
4603 for (next = open_pipes; next != NULL; last = next, next = next->next) {
4609 last->next = info->next;
4611 open_pipes = info->next;
4612 _ckvmssts(sys$setast(1));
4614 /* free buffers and structures */
4617 if (info->in->buf) {
4618 n = info->in->bufsize * sizeof(char);
4619 _ckvmssts(lib$free_vm(&n, &info->in->buf));
4622 _ckvmssts(lib$free_vm(&n, &info->in));
4625 if (info->out->buf) {
4626 n = info->out->bufsize * sizeof(char);
4627 _ckvmssts(lib$free_vm(&n, &info->out->buf));
4630 _ckvmssts(lib$free_vm(&n, &info->out));
4633 if (info->err->buf) {
4634 n = info->err->bufsize * sizeof(char);
4635 _ckvmssts(lib$free_vm(&n, &info->err->buf));
4638 _ckvmssts(lib$free_vm(&n, &info->err));
4641 _ckvmssts(lib$free_vm(&n, &info));
4647 /*{{{ I32 my_pclose(PerlIO *fp)*/
4648 I32 Perl_my_pclose(pTHX_ PerlIO *fp)
4650 pInfo info, last = NULL;
4653 /* Fixme - need ast and mutex protection here */
4654 for (info = open_pipes; info != NULL; last = info, info = info->next)
4655 if (info->fp == fp) break;
4657 if (info == NULL) { /* no such pipe open */
4658 set_errno(ECHILD); /* quoth POSIX */
4659 set_vaxc_errno(SS$_NONEXPR);
4663 ret_status = my_pclose_pinfo(aTHX_ info);
4667 } /* end of my_pclose() */
4669 #if defined(__CRTL_VER) && __CRTL_VER >= 70200000
4670 /* Roll our own prototype because we want this regardless of whether
4671 * _VMS_WAIT is defined.
4673 __pid_t __vms_waitpid( __pid_t __pid, int *__stat_loc, int __options );
4675 /* sort-of waitpid; special handling of pipe clean-up for subprocesses
4676 created with popen(); otherwise partially emulate waitpid() unless
4677 we have a suitable one from the CRTL that came with VMS 7.2 and later.
4678 Also check processes not considered by the CRTL waitpid().
4680 /*{{{Pid_t my_waitpid(Pid_t pid, int *statusp, int flags)*/
4682 Perl_my_waitpid(pTHX_ Pid_t pid, int *statusp, int flags)
4689 if (statusp) *statusp = 0;
4691 for (info = open_pipes; info != NULL; info = info->next)
4692 if (info->pid == pid) break;
4694 if (info != NULL) { /* we know about this child */
4695 while (!info->done) {
4696 _ckvmssts(sys$setast(0));
4698 if (!done) _ckvmssts(sys$clref(pipe_ef));
4699 _ckvmssts(sys$setast(1));
4700 if (!done) _ckvmssts(sys$waitfr(pipe_ef));
4703 if (statusp) *statusp = info->completion;
4707 /* child that already terminated? */
4709 for (j = 0; j < NKEEPCLOSED && j < closed_num; j++) {
4710 if (closed_list[j].pid == pid) {
4711 if (statusp) *statusp = closed_list[j].completion;
4716 /* fall through if this child is not one of our own pipe children */
4718 #if defined(__CRTL_VER) && __CRTL_VER >= 70200000
4720 /* waitpid() became available in the CRTL as of VMS 7.0, but only
4721 * in 7.2 did we get a version that fills in the VMS completion
4722 * status as Perl has always tried to do.
4725 sts = __vms_waitpid( pid, statusp, flags );
4727 if ( sts == 0 || !(sts == -1 && errno == ECHILD) )
4730 /* If the real waitpid tells us the child does not exist, we
4731 * fall through here to implement waiting for a child that
4732 * was created by some means other than exec() (say, spawned
4733 * from DCL) or to wait for a process that is not a subprocess
4734 * of the current process.
4737 #endif /* defined(__CRTL_VER) && __CRTL_VER >= 70200000 */
4740 $DESCRIPTOR(intdsc,"0 00:00:01");
4741 unsigned long int ownercode = JPI$_OWNER, ownerpid;
4742 unsigned long int pidcode = JPI$_PID, mypid;
4743 unsigned long int interval[2];
4744 unsigned int jpi_iosb[2];
4745 struct itmlst_3 jpilist[2] = {
4746 {sizeof(ownerpid), JPI$_OWNER, &ownerpid, 0},
4751 /* Sorry folks, we don't presently implement rooting around for
4752 the first child we can find, and we definitely don't want to
4753 pass a pid of -1 to $getjpi, where it is a wildcard operation.
4759 /* Get the owner of the child so I can warn if it's not mine. If the
4760 * process doesn't exist or I don't have the privs to look at it,
4761 * I can go home early.
4763 sts = sys$getjpiw(0,&pid,NULL,&jpilist,&jpi_iosb,NULL,NULL);
4764 if (sts & 1) sts = jpi_iosb[0];
4776 set_vaxc_errno(sts);
4780 if (ckWARN(WARN_EXEC)) {
4781 /* remind folks they are asking for non-standard waitpid behavior */
4782 _ckvmssts(lib$getjpi(&pidcode,0,0,&mypid,0,0));
4783 if (ownerpid != mypid)
4784 Perl_warner(aTHX_ packWARN(WARN_EXEC),
4785 "waitpid: process %x is not a child of process %x",
4789 /* simply check on it once a second until it's not there anymore. */
4791 _ckvmssts(sys$bintim(&intdsc,interval));
4792 while ((sts=lib$getjpi(&ownercode,&pid,0,&ownerpid,0,0)) & 1) {
4793 _ckvmssts(sys$schdwk(0,0,interval,0));
4794 _ckvmssts(sys$hiber());
4796 if (sts == SS$_NONEXPR) sts = SS$_NORMAL;
4801 } /* end of waitpid() */
4806 /*{{{ char *my_gconvert(double val, int ndig, int trail, char *buf) */
4808 my_gconvert(double val, int ndig, int trail, char *buf)
4810 static char __gcvtbuf[DBL_DIG+1];
4813 loc = buf ? buf : __gcvtbuf;
4815 #ifndef __DECC /* VAXCRTL gcvt uses E format for numbers < 1 */
4817 sprintf(loc,"%.*g",ndig,val);
4823 if (!buf && ndig > DBL_DIG) ndig = DBL_DIG;
4824 return gcvt(val,ndig,loc);
4827 loc[0] = '0'; loc[1] = '\0';
4834 #if defined(__VAX) || !defined(NAML$C_MAXRSS)
4835 static int rms_free_search_context(struct FAB * fab)
4839 nam = fab->fab$l_nam;
4840 nam->nam$b_nop |= NAM$M_SYNCHK;
4841 nam->nam$l_rlf = NULL;
4843 return sys$parse(fab, NULL, NULL);
4846 #define rms_setup_nam(nam) struct NAM nam = cc$rms_nam
4847 #define rms_clear_nam_nop(nam) nam.nam$b_nop = 0;
4848 #define rms_set_nam_nop(nam, opt) nam.nam$b_nop |= (opt)
4849 #define rms_set_nam_fnb(nam, opt) nam.nam$l_fnb |= (opt)
4850 #define rms_is_nam_fnb(nam, opt) (nam.nam$l_fnb & (opt))
4851 #define rms_nam_esll(nam) nam.nam$b_esl
4852 #define rms_nam_esl(nam) nam.nam$b_esl
4853 #define rms_nam_name(nam) nam.nam$l_name
4854 #define rms_nam_namel(nam) nam.nam$l_name
4855 #define rms_nam_type(nam) nam.nam$l_type
4856 #define rms_nam_typel(nam) nam.nam$l_type