3 * VMS-specific routines for perl5
5 * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
6 * 2002, 2003, 2004, 2005, 2006, 2007 by Charles Bailey and others.
8 * You may distribute under the terms of either the GNU General Public
9 * License or the Artistic License, as specified in the README file.
11 * Please see Changes*.* or the Perl Repository Browser for revision history.
15 * Yet small as was their hunted band
16 * still fell and fearless was each hand,
17 * and strong deeds they wrought yet oft,
18 * and loved the woods, whose ways more soft
19 * them seemed than thralls of that black throne
20 * to live and languish in halls of stone.
21 * "The Lay of Leithian", Canto II, lines 135-40
23 * [p.162 of _The Lays of Beleriand_]
29 #if __CRTL_VER < 70300000
30 /* needed for home-rolled utime() */
36 #include <climsgdef.h>
46 #include <libclidef.h>
48 #include <lib$routines.h>
51 #if __CRTL_VER >= 70301000 && !defined(__VAX)
61 #include <str$routines.h>
67 #define NO_EFN EFN$C_ENF
69 #if __CRTL_VER < 70301000 && __CRTL_VER >= 70300000
70 int decc$feature_get_index(const char *name);
71 char* decc$feature_get_name(int index);
72 int decc$feature_get_value(int index, int mode);
73 int decc$feature_set_value(int index, int mode, int value);
78 #pragma member_alignment save
79 #pragma nomember_alignment longword
84 unsigned short * retadr;
86 #pragma member_alignment restore
88 #if __CRTL_VER >= 70300000 && !defined(__VAX)
90 static int set_feature_default(const char *name, int value)
95 index = decc$feature_get_index(name);
97 status = decc$feature_set_value(index, 1, value);
98 if (index == -1 || (status == -1)) {
102 status = decc$feature_get_value(index, 1);
103 if (status != value) {
107 /* Various things may check for an environment setting
108 * rather than the feature directly, so set that too.
110 vmssetuserlnm(name, value ? "ENABLE" : "DISABLE");
116 /* Older versions of ssdef.h don't have these */
117 #ifndef SS$_INVFILFOROP
118 # define SS$_INVFILFOROP 3930
120 #ifndef SS$_NOSUCHOBJECT
121 # define SS$_NOSUCHOBJECT 2696
124 /* We implement I/O here, so we will be mixing PerlIO and stdio calls. */
125 #define PERLIO_NOT_STDIO 0
127 /* Don't replace system definitions of vfork, getenv, lstat, and stat,
128 * code below needs to get to the underlying CRTL routines. */
129 #define DONT_MASK_RTL_CALLS
133 /* Anticipating future expansion in lexical warnings . . . */
134 #ifndef WARN_INTERNAL
135 # define WARN_INTERNAL WARN_MISC
138 #ifdef VMS_LONGNAME_SUPPORT
139 #include <libfildef.h>
142 #if !defined(__VAX) && __CRTL_VER >= 80200000
150 #define lstat(_x, _y) stat(_x, _y)
153 /* Routine to create a decterm for use with the Perl debugger */
154 /* No headers, this information was found in the Programming Concepts Manual */
156 static int (*decw_term_port)
157 (const struct dsc$descriptor_s * display,
158 const struct dsc$descriptor_s * setup_file,
159 const struct dsc$descriptor_s * customization,
160 struct dsc$descriptor_s * result_device_name,
161 unsigned short * result_device_name_length,
164 void * char_change_buffer) = 0;
166 /* gcc's header files don't #define direct access macros
167 * corresponding to VAXC's variant structs */
169 # define uic$v_format uic$r_uic_form.uic$v_format
170 # define uic$v_group uic$r_uic_form.uic$v_group
171 # define uic$v_member uic$r_uic_form.uic$v_member
172 # define prv$v_bypass prv$r_prvdef_bits0.prv$v_bypass
173 # define prv$v_grpprv prv$r_prvdef_bits0.prv$v_grpprv
174 # define prv$v_readall prv$r_prvdef_bits0.prv$v_readall
175 # define prv$v_sysprv prv$r_prvdef_bits0.prv$v_sysprv
178 #if defined(NEED_AN_H_ERRNO)
182 #if defined(__DECC) || defined(__DECCXX)
183 #pragma member_alignment save
184 #pragma nomember_alignment longword
186 #pragma message disable misalgndmem
189 unsigned short int buflen;
190 unsigned short int itmcode;
192 unsigned short int *retlen;
195 struct filescan_itmlst_2 {
196 unsigned short length;
197 unsigned short itmcode;
202 unsigned short length;
203 char str[VMS_MAXRSS];
204 unsigned short pad; /* for longword struct alignment */
207 #if defined(__DECC) || defined(__DECCXX)
208 #pragma message restore
209 #pragma member_alignment restore
212 #define do_fileify_dirspec(a,b,c,d) mp_do_fileify_dirspec(aTHX_ a,b,c,d)
213 #define do_pathify_dirspec(a,b,c,d) mp_do_pathify_dirspec(aTHX_ a,b,c,d)
214 #define do_tovmsspec(a,b,c,d) mp_do_tovmsspec(aTHX_ a,b,c,0,d)
215 #define do_tovmspath(a,b,c,d) mp_do_tovmspath(aTHX_ a,b,c,d)
216 #define do_rmsexpand(a,b,c,d,e,f,g) mp_do_rmsexpand(aTHX_ a,b,c,d,e,f,g)
217 #define do_vms_realpath(a,b,c) mp_do_vms_realpath(aTHX_ a,b,c)
218 #define do_vms_realname(a,b,c) mp_do_vms_realname(aTHX_ a,b,c)
219 #define do_tounixspec(a,b,c,d) mp_do_tounixspec(aTHX_ a,b,c,d)
220 #define do_tounixpath(a,b,c,d) mp_do_tounixpath(aTHX_ a,b,c,d)
221 #define do_vms_case_tolerant(a) mp_do_vms_case_tolerant(a)
222 #define expand_wild_cards(a,b,c,d) mp_expand_wild_cards(aTHX_ a,b,c,d)
223 #define getredirection(a,b) mp_getredirection(aTHX_ a,b)
225 static char *mp_do_tovmspath(pTHX_ const char *path, char *buf, int ts, int *);
226 static char *mp_do_tounixpath(pTHX_ const char *path, char *buf, int ts, int *);
227 static char *mp_do_tounixspec(pTHX_ const char *, char *, int, int *);
228 static char *mp_do_pathify_dirspec(pTHX_ const char *dir,char *buf, int ts, int *);
230 static char * int_rmsexpand_vms(
231 const char * filespec, char * outbuf, unsigned opts);
232 static char * int_rmsexpand_tovms(
233 const char * filespec, char * outbuf, unsigned opts);
234 static char *int_tovmsspec
235 (const char *path, char *buf, int dir_flag, int * utf8_flag);
236 static char * int_fileify_dirspec(const char *dir, char *buf, int *utf8_fl);
237 static char * int_tounixspec(const char *spec, char *buf, int * utf8_fl);
238 static char * int_tovmspath(const char *path, char *buf, int * utf8_fl);
240 /* see system service docs for $TRNLNM -- NOT the same as LNM$_MAX_INDEX */
241 #define PERL_LNM_MAX_ALLOWED_INDEX 127
243 /* OpenVMS User's Guide says at least 9 iterative translations will be performed,
244 * depending on the facility. SHOW LOGICAL does 10, so we'll imitate that for
247 #define PERL_LNM_MAX_ITER 10
249 /* New values with 7.3-2*/ /* why does max DCL have 4 byte subtracted from it? */
250 #if __CRTL_VER >= 70302000 && !defined(__VAX)
251 #define MAX_DCL_SYMBOL (8192)
252 #define MAX_DCL_LINE_LENGTH (4096 - 4)
254 #define MAX_DCL_SYMBOL (1024)
255 #define MAX_DCL_LINE_LENGTH (1024 - 4)
258 static char *__mystrtolower(char *str)
260 if (str) for (; *str; ++str) *str= tolower(*str);
264 static struct dsc$descriptor_s fildevdsc =
265 { 12, DSC$K_DTYPE_T, DSC$K_CLASS_S, "LNM$FILE_DEV" };
266 static struct dsc$descriptor_s crtlenvdsc =
267 { 8, DSC$K_DTYPE_T, DSC$K_CLASS_S, "CRTL_ENV" };
268 static struct dsc$descriptor_s *fildev[] = { &fildevdsc, NULL };
269 static struct dsc$descriptor_s *defenv[] = { &fildevdsc, &crtlenvdsc, NULL };
270 static struct dsc$descriptor_s **env_tables = defenv;
271 static bool will_taint = FALSE; /* tainting active, but no PL_curinterp yet */
273 /* True if we shouldn't treat barewords as logicals during directory */
275 static int no_translate_barewords;
277 /* DECC Features that may need to affect how Perl interprets
278 * displays filename information
280 static int decc_disable_to_vms_logname_translation = 1;
281 static int decc_disable_posix_root = 1;
282 int decc_efs_case_preserve = 0;
283 static int decc_efs_charset = 0;
284 static int decc_efs_charset_index = -1;
285 static int decc_filename_unix_no_version = 0;
286 static int decc_filename_unix_only = 0;
287 int decc_filename_unix_report = 0;
288 int decc_posix_compliant_pathnames = 0;
289 int decc_readdir_dropdotnotype = 0;
290 static int vms_process_case_tolerant = 1;
291 int vms_vtf7_filenames = 0;
292 int gnv_unix_shell = 0;
293 static int vms_unlink_all_versions = 0;
294 static int vms_posix_exit = 0;
296 /* bug workarounds if needed */
297 int decc_bug_devnull = 1;
298 int decc_dir_barename = 0;
299 int vms_bug_stat_filename = 0;
301 static int vms_debug_on_exception = 0;
302 static int vms_debug_fileify = 0;
304 /* Simple logical name translation */
305 static int simple_trnlnm
306 (const char * logname,
310 const $DESCRIPTOR(table_dsc, "LNM$FILE_DEV");
311 const unsigned long attr = LNM$M_CASE_BLIND;
312 struct dsc$descriptor_s name_dsc;
314 unsigned short result;
315 struct itmlst_3 itlst[2] = {{value_len, LNM$_STRING, value, &result},
318 name_dsc.dsc$w_length = strlen(logname);
319 name_dsc.dsc$a_pointer = (char *)logname;
320 name_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
321 name_dsc.dsc$b_class = DSC$K_CLASS_S;
323 status = sys$trnlnm(&attr, &table_dsc, &name_dsc, 0, itlst);
325 if ($VMS_STATUS_SUCCESS(status)) {
327 /* Null terminate and return the string */
328 /*--------------------------------------*/
337 /* Is this a UNIX file specification?
338 * No longer a simple check with EFS file specs
339 * For now, not a full check, but need to
340 * handle POSIX ^UP^ specifications
341 * Fixing to handle ^/ cases would require
342 * changes to many other conversion routines.
345 static int is_unix_filespec(const char *path)
351 if (strncmp(path,"\"^UP^",5) != 0) {
352 pch1 = strchr(path, '/');
357 /* If the user wants UNIX files, "." needs to be treated as in UNIX */
358 if (decc_filename_unix_report || decc_filename_unix_only) {
359 if (strcmp(path,".") == 0)
367 /* This routine converts a UCS-2 character to be VTF-7 encoded.
370 static void ucs2_to_vtf7
372 unsigned long ucs2_char,
375 unsigned char * ucs_ptr;
378 ucs_ptr = (unsigned char *)&ucs2_char;
382 hex = (ucs_ptr[1] >> 4) & 0xf;
384 outspec[2] = hex + '0';
386 outspec[2] = (hex - 9) + 'A';
387 hex = ucs_ptr[1] & 0xF;
389 outspec[3] = hex + '0';
391 outspec[3] = (hex - 9) + 'A';
393 hex = (ucs_ptr[0] >> 4) & 0xf;
395 outspec[4] = hex + '0';
397 outspec[4] = (hex - 9) + 'A';
398 hex = ucs_ptr[1] & 0xF;
400 outspec[5] = hex + '0';
402 outspec[5] = (hex - 9) + 'A';
408 /* This handles the conversion of a UNIX extended character set to a ^
409 * escaped VMS character.
410 * in a UNIX file specification.
412 * The output count variable contains the number of characters added
413 * to the output string.
415 * The return value is the number of characters read from the input string
417 static int copy_expand_unix_filename_escape
418 (char *outspec, const char *inspec, int *output_cnt, const int * utf8_fl)
425 utf8_flag = *utf8_fl;
429 if (*inspec >= 0x80) {
430 if (utf8_fl && vms_vtf7_filenames) {
431 unsigned long ucs_char;
435 if ((*inspec & 0xE0) == 0xC0) {
437 ucs_char = ((inspec[0] & 0x1F) << 6) + (inspec[1] & 0x3f);
438 if (ucs_char >= 0x80) {
439 ucs2_to_vtf7(outspec, ucs_char, output_cnt);
442 } else if ((*inspec & 0xF0) == 0xE0) {
444 ucs_char = ((inspec[0] & 0xF) << 12) +
445 ((inspec[1] & 0x3f) << 6) +
447 if (ucs_char >= 0x800) {
448 ucs2_to_vtf7(outspec, ucs_char, output_cnt);
452 #if 0 /* I do not see longer sequences supported by OpenVMS */
453 /* Maybe some one can fix this later */
454 } else if ((*inspec & 0xF8) == 0xF0) {
457 } else if ((*inspec & 0xFC) == 0xF8) {
460 } else if ((*inspec & 0xFE) == 0xFC) {
467 /* High bit set, but not a Unicode character! */
469 /* Non printing DECMCS or ISO Latin-1 character? */
470 if ((unsigned char)*inspec <= 0x9F) {
474 hex = (*inspec >> 4) & 0xF;
476 outspec[1] = hex + '0';
478 outspec[1] = (hex - 9) + 'A';
482 outspec[2] = hex + '0';
484 outspec[2] = (hex - 9) + 'A';
488 } else if ((unsigned char)*inspec == 0xA0) {
494 } else if ((unsigned char)*inspec == 0xFF) {
506 /* Is this a macro that needs to be passed through?
507 * Macros start with $( and an alpha character, followed
508 * by a string of alpha numeric characters ending with a )
509 * If this does not match, then encode it as ODS-5.
511 if ((inspec[0] == '$') && (inspec[1] == '(')) {
514 if (isalnum(inspec[2]) || (inspec[2] == '.') || (inspec[2] == '_')) {
516 outspec[0] = inspec[0];
517 outspec[1] = inspec[1];
518 outspec[2] = inspec[2];
520 while(isalnum(inspec[tcnt]) ||
521 (inspec[2] == '.') || (inspec[2] == '_')) {
522 outspec[tcnt] = inspec[tcnt];
525 if (inspec[tcnt] == ')') {
526 outspec[tcnt] = inspec[tcnt];
543 if (decc_efs_charset == 0)
570 /* Don't escape again if following character is
571 * already something we escape.
573 if (strchr(".~!#&\'`()+@{},;[]%^=_\\", *(inspec+1))) {
579 /* But otherwise fall through and escape it. */
581 /* Assume that this is to be escaped */
583 outspec[1] = *inspec;
587 case ' ': /* space */
588 /* Assume that this is to be escaped */
604 /* This handles the expansion of a '^' prefix to the proper character
605 * in a UNIX file specification.
607 * The output count variable contains the number of characters added
608 * to the output string.
610 * The return value is the number of characters read from the input
613 static int copy_expand_vms_filename_escape
614 (char *outspec, const char *inspec, int *output_cnt)
621 if (*inspec == '^') {
624 /* Spaces and non-trailing dots should just be passed through,
625 * but eat the escape character.
632 case '_': /* space */
638 /* Hmm. Better leave the escape escaped. */
644 case 'U': /* Unicode - FIX-ME this is wrong. */
647 scnt = strspn(inspec, "0123456789ABCDEFabcdef");
650 scnt = sscanf(inspec, "%2x%2x", &c1, &c2);
651 outspec[0] = c1 & 0xff;
652 outspec[1] = c2 & 0xff;
659 /* Error - do best we can to continue */
669 scnt = strspn(inspec, "0123456789ABCDEFabcdef");
673 scnt = sscanf(inspec, "%2x", &c1);
674 outspec[0] = c1 & 0xff;
695 /* vms_split_path - Verify that the input file specification is a
696 * VMS format file specification, and provide pointers to the components of
697 * it. With EFS format filenames, this is virtually the only way to
698 * parse a VMS path specification into components.
700 * If the sum of the components do not add up to the length of the
701 * string, then the passed file specification is probably a UNIX style
704 static int vms_split_path
719 struct dsc$descriptor path_desc;
723 struct filescan_itmlst_2 item_list[9];
724 const int filespec = 0;
725 const int nodespec = 1;
726 const int devspec = 2;
727 const int rootspec = 3;
728 const int dirspec = 4;
729 const int namespec = 5;
730 const int typespec = 6;
731 const int verspec = 7;
733 /* Assume the worst for an easy exit */
747 path_desc.dsc$a_pointer = (char *)path; /* cast ok */
748 path_desc.dsc$w_length = strlen(path);
749 path_desc.dsc$b_dtype = DSC$K_DTYPE_T;
750 path_desc.dsc$b_class = DSC$K_CLASS_S;
752 /* Get the total length, if it is shorter than the string passed
753 * then this was probably not a VMS formatted file specification
755 item_list[filespec].itmcode = FSCN$_FILESPEC;
756 item_list[filespec].length = 0;
757 item_list[filespec].component = NULL;
759 /* If the node is present, then it gets considered as part of the
760 * volume name to hopefully make things simple.
762 item_list[nodespec].itmcode = FSCN$_NODE;
763 item_list[nodespec].length = 0;
764 item_list[nodespec].component = NULL;
766 item_list[devspec].itmcode = FSCN$_DEVICE;
767 item_list[devspec].length = 0;
768 item_list[devspec].component = NULL;
770 /* root is a special case, adding it to either the directory or
771 * the device components will probably complicate things for the
772 * callers of this routine, so leave it separate.
774 item_list[rootspec].itmcode = FSCN$_ROOT;
775 item_list[rootspec].length = 0;
776 item_list[rootspec].component = NULL;
778 item_list[dirspec].itmcode = FSCN$_DIRECTORY;
779 item_list[dirspec].length = 0;
780 item_list[dirspec].component = NULL;
782 item_list[namespec].itmcode = FSCN$_NAME;
783 item_list[namespec].length = 0;
784 item_list[namespec].component = NULL;
786 item_list[typespec].itmcode = FSCN$_TYPE;
787 item_list[typespec].length = 0;
788 item_list[typespec].component = NULL;
790 item_list[verspec].itmcode = FSCN$_VERSION;
791 item_list[verspec].length = 0;
792 item_list[verspec].component = NULL;
794 item_list[8].itmcode = 0;
795 item_list[8].length = 0;
796 item_list[8].component = NULL;
798 status = sys$filescan
799 ((const struct dsc$descriptor_s *)&path_desc, item_list,
801 _ckvmssts_noperl(status); /* All failure status values indicate a coding error */
803 /* If we parsed it successfully these two lengths should be the same */
804 if (path_desc.dsc$w_length != item_list[filespec].length)
807 /* If we got here, then it is a VMS file specification */
810 /* set the volume name */
811 if (item_list[nodespec].length > 0) {
812 *volume = item_list[nodespec].component;
813 *vol_len = item_list[nodespec].length + item_list[devspec].length;
816 *volume = item_list[devspec].component;
817 *vol_len = item_list[devspec].length;
820 *root = item_list[rootspec].component;
821 *root_len = item_list[rootspec].length;
823 *dir = item_list[dirspec].component;
824 *dir_len = item_list[dirspec].length;
826 /* Now fun with versions and EFS file specifications
827 * The parser can not tell the difference when a "." is a version
828 * delimiter or a part of the file specification.
830 if ((decc_efs_charset) &&
831 (item_list[verspec].length > 0) &&
832 (item_list[verspec].component[0] == '.')) {
833 *name = item_list[namespec].component;
834 *name_len = item_list[namespec].length + item_list[typespec].length;
835 *ext = item_list[verspec].component;
836 *ext_len = item_list[verspec].length;
841 *name = item_list[namespec].component;
842 *name_len = item_list[namespec].length;
843 *ext = item_list[typespec].component;
844 *ext_len = item_list[typespec].length;
845 *version = item_list[verspec].component;
846 *ver_len = item_list[verspec].length;
851 /* Routine to determine if the file specification ends with .dir */
852 static int is_dir_ext(char * e_spec, int e_len, char * vs_spec, int vs_len) {
854 /* e_len must be 4, and version must be <= 2 characters */
855 if (e_len != 4 || vs_len > 2)
858 /* If a version number is present, it needs to be one */
859 if ((vs_len == 2) && (vs_spec[1] != '1'))
862 /* Look for the DIR on the extension */
863 if (vms_process_case_tolerant) {
864 if ((toupper(e_spec[1]) == 'D') &&
865 (toupper(e_spec[2]) == 'I') &&
866 (toupper(e_spec[3]) == 'R')) {
870 /* Directory extensions are supposed to be in upper case only */
871 /* I would not be surprised if this rule can not be enforced */
872 /* if and when someone fully debugs the case sensitive mode */
873 if ((e_spec[1] == 'D') &&
874 (e_spec[2] == 'I') &&
875 (e_spec[3] == 'R')) {
884 * Routine to retrieve the maximum equivalence index for an input
885 * logical name. Some calls to this routine have no knowledge if
886 * the variable is a logical or not. So on error we return a max
889 /*{{{int my_maxidx(const char *lnm) */
891 my_maxidx(const char *lnm)
895 int attr = LNM$M_CASE_BLIND;
896 struct dsc$descriptor lnmdsc;
897 struct itmlst_3 itlst[2] = {{sizeof(midx), LNM$_MAX_INDEX, &midx, 0},
900 lnmdsc.dsc$w_length = strlen(lnm);
901 lnmdsc.dsc$b_dtype = DSC$K_DTYPE_T;
902 lnmdsc.dsc$b_class = DSC$K_CLASS_S;
903 lnmdsc.dsc$a_pointer = (char *) lnm; /* Cast ok for read only parameter */
905 status = sys$trnlnm(&attr, &fildevdsc, &lnmdsc, 0, itlst);
906 if ((status & 1) == 0)
913 /*{{{int vmstrnenv(const char *lnm, char *eqv, unsigned long int idx, struct dsc$descriptor_s **tabvec, unsigned long int flags) */
915 Perl_vmstrnenv(const char *lnm, char *eqv, unsigned long int idx,
916 struct dsc$descriptor_s **tabvec, unsigned long int flags)
919 char uplnm[LNM$C_NAMLENGTH+1], *cp2;
920 unsigned short int eqvlen, curtab, ivlnm = 0, ivsym = 0, ivenv = 0, secure;
921 unsigned long int retsts, attr = LNM$M_CASE_BLIND;
923 unsigned char acmode;
924 struct dsc$descriptor_s lnmdsc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0},
925 tmpdsc = {6,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
926 struct itmlst_3 lnmlst[3] = {{sizeof idx, LNM$_INDEX, &idx, 0},
927 {LNM$C_NAMLENGTH, LNM$_STRING, eqv, &eqvlen},
929 $DESCRIPTOR(crtlenv,"CRTL_ENV"); $DESCRIPTOR(clisym,"CLISYM");
930 #if defined(PERL_IMPLICIT_CONTEXT)
933 aTHX = PERL_GET_INTERP;
939 if (!lnm || !eqv || ((idx != 0) && ((idx-1) > PERL_LNM_MAX_ALLOWED_INDEX))) {
940 set_errno(EINVAL); set_vaxc_errno(SS$_BADPARAM); return 0;
942 for (cp1 = lnm, cp2 = uplnm; *cp1; cp1++, cp2++) {
943 *cp2 = _toupper(*cp1);
944 if (cp1 - lnm > LNM$C_NAMLENGTH) {
945 set_errno(EINVAL); set_vaxc_errno(SS$_IVLOGNAM);
949 lnmdsc.dsc$w_length = cp1 - lnm;
950 lnmdsc.dsc$a_pointer = uplnm;
951 uplnm[lnmdsc.dsc$w_length] = '\0';
952 secure = flags & PERL__TRNENV_SECURE;
953 acmode = secure ? PSL$C_EXEC : PSL$C_USER;
954 if (!tabvec || !*tabvec) tabvec = env_tables;
956 for (curtab = 0; tabvec[curtab]; curtab++) {
957 if (!str$case_blind_compare(tabvec[curtab],&crtlenv)) {
958 if (!ivenv && !secure) {
963 #if defined(PERL_IMPLICIT_CONTEXT)
966 "Can't read CRTL environ\n");
969 Perl_warn(aTHX_ "Can't read CRTL environ\n");
972 retsts = SS$_NOLOGNAM;
973 for (i = 0; environ[i]; i++) {
974 if ((eq = strchr(environ[i],'=')) &&
975 lnmdsc.dsc$w_length == (eq - environ[i]) &&
976 !strncmp(environ[i],uplnm,eq - environ[i])) {
978 for (eqvlen = 0; eq[eqvlen]; eqvlen++) eqv[eqvlen] = eq[eqvlen];
979 if (!eqvlen) continue;
984 if (retsts != SS$_NOLOGNAM) break;
987 else if ((tmpdsc.dsc$a_pointer = tabvec[curtab]->dsc$a_pointer) &&
988 !str$case_blind_compare(&tmpdsc,&clisym)) {
989 if (!ivsym && !secure) {
990 unsigned short int deflen = LNM$C_NAMLENGTH;
991 struct dsc$descriptor_d eqvdsc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_D,0};
992 /* dynamic dsc to accommodate possible long value */
993 _ckvmssts_noperl(lib$sget1_dd(&deflen,&eqvdsc));
994 retsts = lib$get_symbol(&lnmdsc,&eqvdsc,&eqvlen,0);
996 if (eqvlen > MAX_DCL_SYMBOL) {
997 set_errno(EVMSERR); set_vaxc_errno(LIB$_STRTRU);
998 eqvlen = MAX_DCL_SYMBOL;
999 /* Special hack--we might be called before the interpreter's */
1000 /* fully initialized, in which case either thr or PL_curcop */
1001 /* might be bogus. We have to check, since ckWARN needs them */
1002 /* both to be valid if running threaded */
1003 #if defined(PERL_IMPLICIT_CONTEXT)
1006 "Value of CLI symbol \"%s\" too long",lnm);
1009 if (ckWARN(WARN_MISC)) {
1010 Perl_warner(aTHX_ packWARN(WARN_MISC),"Value of CLI symbol \"%s\" too long",lnm);
1013 strncpy(eqv,eqvdsc.dsc$a_pointer,eqvlen);
1015 _ckvmssts_noperl(lib$sfree1_dd(&eqvdsc));
1016 if (retsts == LIB$_INVSYMNAM) { ivsym = 1; continue; }
1017 if (retsts == LIB$_NOSUCHSYM) continue;
1022 if ( (idx == 0) && (flags & PERL__TRNENV_JOIN_SEARCHLIST) ) {
1023 midx = my_maxidx(lnm);
1024 for (idx = 0, cp2 = eqv; idx <= midx; idx++) {
1025 lnmlst[1].bufadr = cp2;
1027 retsts = sys$trnlnm(&attr,tabvec[curtab],&lnmdsc,&acmode,lnmlst);
1028 if (retsts == SS$_IVLOGNAM) { ivlnm = 1; break; }
1029 if (retsts == SS$_NOLOGNAM) break;
1030 /* PPFs have a prefix */
1033 *((int *)uplnm) == *((int *)"SYS$") &&
1035 eqvlen >= 4 && eqv[0] == 0x1b && eqv[1] == 0x00 &&
1036 ( (uplnm[4] == 'O' && !strcmp(uplnm,"SYS$OUTPUT")) ||
1037 (uplnm[4] == 'I' && !strcmp(uplnm,"SYS$INPUT")) ||
1038 (uplnm[4] == 'E' && !strcmp(uplnm,"SYS$ERROR")) ||
1039 (uplnm[4] == 'C' && !strcmp(uplnm,"SYS$COMMAND")) ) ) {
1040 memmove(eqv,eqv+4,eqvlen-4);
1046 if ((retsts == SS$_IVLOGNAM) ||
1047 (retsts == SS$_NOLOGNAM)) { continue; }
1050 retsts = sys$trnlnm(&attr,tabvec[curtab],&lnmdsc,&acmode,lnmlst);
1051 if (retsts == SS$_IVLOGNAM) { ivlnm = 1; continue; }
1052 if (retsts == SS$_NOLOGNAM) continue;
1055 eqvlen = strlen(eqv);
1059 if (retsts & 1) { eqv[eqvlen] = '\0'; return eqvlen; }
1060 else if (retsts == LIB$_NOSUCHSYM || retsts == LIB$_INVSYMNAM ||
1061 retsts == SS$_IVLOGNAM || retsts == SS$_IVLOGTAB ||
1062 retsts == SS$_NOLOGNAM) {
1063 set_errno(EINVAL); set_vaxc_errno(retsts);
1065 else _ckvmssts_noperl(retsts);
1067 } /* end of vmstrnenv */
1070 /*{{{ int my_trnlnm(const char *lnm, char *eqv, unsigned long int idx)*/
1071 /* Define as a function so we can access statics. */
1072 int Perl_my_trnlnm(pTHX_ const char *lnm, char *eqv, unsigned long int idx)
1076 #if defined(PERL_IMPLICIT_CONTEXT)
1079 #ifdef SECURE_INTERNAL_GETENV
1080 flags = (PL_curinterp ? TAINTING_get : will_taint) ?
1081 PERL__TRNENV_SECURE : 0;
1084 return vmstrnenv(lnm, eqv, idx, fildev, flags);
1089 * Note: Uses Perl temp to store result so char * can be returned to
1090 * caller; this pointer will be invalidated at next Perl statement
1092 * We define this as a function rather than a macro in terms of my_getenv_len()
1093 * so that it'll work when PL_curinterp is undefined (and we therefore can't
1096 /*{{{ char *my_getenv(const char *lnm, bool sys)*/
1098 Perl_my_getenv(pTHX_ const char *lnm, bool sys)
1101 static char *__my_getenv_eqv = NULL;
1102 char uplnm[LNM$C_NAMLENGTH+1], *cp2, *eqv;
1103 unsigned long int idx = 0;
1104 int success, secure, saverr, savvmserr;
1108 midx = my_maxidx(lnm) + 1;
1110 if (PL_curinterp) { /* Perl interpreter running -- may be threaded */
1111 /* Set up a temporary buffer for the return value; Perl will
1112 * clean it up at the next statement transition */
1113 tmpsv = sv_2mortal(newSVpv("",(LNM$C_NAMLENGTH*midx)+1));
1114 if (!tmpsv) return NULL;
1118 /* Assume no interpreter ==> single thread */
1119 if (__my_getenv_eqv != NULL) {
1120 Renew(__my_getenv_eqv,LNM$C_NAMLENGTH*midx+1,char);
1123 Newx(__my_getenv_eqv,LNM$C_NAMLENGTH*midx+1,char);
1125 eqv = __my_getenv_eqv;
1128 for (cp1 = lnm, cp2 = eqv; *cp1; cp1++,cp2++) *cp2 = _toupper(*cp1);
1129 if (cp1 - lnm == 7 && !strncmp(eqv,"DEFAULT",7)) {
1131 getcwd(eqv,LNM$C_NAMLENGTH);
1135 /* Get rid of "000000/ in rooted filespecs */
1138 zeros = strstr(eqv, "/000000/");
1139 if (zeros != NULL) {
1141 mlen = len - (zeros - eqv) - 7;
1142 memmove(zeros, &zeros[7], mlen);
1150 /* Impose security constraints only if tainting */
1152 /* Impose security constraints only if tainting */
1153 secure = PL_curinterp ? TAINTING_get : will_taint;
1154 saverr = errno; savvmserr = vaxc$errno;
1161 #ifdef SECURE_INTERNAL_GETENV
1162 secure ? PERL__TRNENV_SECURE : 0
1168 /* For the getenv interface we combine all the equivalence names
1169 * of a search list logical into one value to acquire a maximum
1170 * value length of 255*128 (assuming %ENV is using logicals).
1172 flags |= PERL__TRNENV_JOIN_SEARCHLIST;
1174 /* If the name contains a semicolon-delimited index, parse it
1175 * off and make sure we only retrieve the equivalence name for
1177 if ((cp2 = strchr(lnm,';')) != NULL) {
1178 my_strlcpy(uplnm, lnm, cp2 - lnm + 1);
1179 idx = strtoul(cp2+1,NULL,0);
1181 flags &= ~PERL__TRNENV_JOIN_SEARCHLIST;
1184 success = vmstrnenv(lnm,eqv,idx,secure ? fildev : NULL,flags);
1186 /* Discard NOLOGNAM on internal calls since we're often looking
1187 * for an optional name, and this "error" often shows up as the
1188 * (bogus) exit status for a die() call later on. */
1189 if (sys && vaxc$errno == SS$_NOLOGNAM) SETERRNO(saverr,savvmserr);
1190 return success ? eqv : NULL;
1193 } /* end of my_getenv() */
1197 /*{{{ SV *my_getenv_len(const char *lnm, bool sys)*/
1199 Perl_my_getenv_len(pTHX_ const char *lnm, unsigned long *len, bool sys)
1203 unsigned long idx = 0;
1205 static char *__my_getenv_len_eqv = NULL;
1206 int secure, saverr, savvmserr;
1209 midx = my_maxidx(lnm) + 1;
1211 if (PL_curinterp) { /* Perl interpreter running -- may be threaded */
1212 /* Set up a temporary buffer for the return value; Perl will
1213 * clean it up at the next statement transition */
1214 tmpsv = sv_2mortal(newSVpv("",(LNM$C_NAMLENGTH*midx)+1));
1215 if (!tmpsv) return NULL;
1219 /* Assume no interpreter ==> single thread */
1220 if (__my_getenv_len_eqv != NULL) {
1221 Renew(__my_getenv_len_eqv,LNM$C_NAMLENGTH*midx+1,char);
1224 Newx(__my_getenv_len_eqv,LNM$C_NAMLENGTH*midx+1,char);
1226 buf = __my_getenv_len_eqv;
1229 for (cp1 = lnm, cp2 = buf; *cp1; cp1++,cp2++) *cp2 = _toupper(*cp1);
1230 if (cp1 - lnm == 7 && !strncmp(buf,"DEFAULT",7)) {
1233 getcwd(buf,LNM$C_NAMLENGTH);
1236 /* Get rid of "000000/ in rooted filespecs */
1238 zeros = strstr(buf, "/000000/");
1239 if (zeros != NULL) {
1241 mlen = *len - (zeros - buf) - 7;
1242 memmove(zeros, &zeros[7], mlen);
1251 /* Impose security constraints only if tainting */
1252 secure = PL_curinterp ? TAINTING_get : will_taint;
1253 saverr = errno; savvmserr = vaxc$errno;
1260 #ifdef SECURE_INTERNAL_GETENV
1261 secure ? PERL__TRNENV_SECURE : 0
1267 flags |= PERL__TRNENV_JOIN_SEARCHLIST;
1269 if ((cp2 = strchr(lnm,';')) != NULL) {
1270 my_strlcpy(buf, lnm, cp2 - lnm + 1);
1271 idx = strtoul(cp2+1,NULL,0);
1273 flags &= ~PERL__TRNENV_JOIN_SEARCHLIST;
1276 *len = vmstrnenv(lnm,buf,idx,secure ? fildev : NULL,flags);
1278 /* Get rid of "000000/ in rooted filespecs */
1281 zeros = strstr(buf, "/000000/");
1282 if (zeros != NULL) {
1284 mlen = *len - (zeros - buf) - 7;
1285 memmove(zeros, &zeros[7], mlen);
1291 /* Discard NOLOGNAM on internal calls since we're often looking
1292 * for an optional name, and this "error" often shows up as the
1293 * (bogus) exit status for a die() call later on. */
1294 if (sys && vaxc$errno == SS$_NOLOGNAM) SETERRNO(saverr,savvmserr);
1295 return *len ? buf : NULL;
1298 } /* end of my_getenv_len() */
1301 static void create_mbx(unsigned short int *, struct dsc$descriptor_s *);
1303 static void riseandshine(unsigned long int dummy) { sys$wake(0,0); }
1305 /*{{{ void prime_env_iter() */
1307 prime_env_iter(void)
1308 /* Fill the %ENV associative array with all logical names we can
1309 * find, in preparation for iterating over it.
1312 static int primed = 0;
1313 HV *seenhv = NULL, *envhv;
1315 char cmd[LNM$C_NAMLENGTH+24], mbxnam[LNM$C_NAMLENGTH], *buf = NULL;
1316 unsigned short int chan;
1317 #ifndef CLI$M_TRUSTED
1318 # define CLI$M_TRUSTED 0x40 /* Missing from VAXC headers */
1320 unsigned long int defflags = CLI$M_NOWAIT | CLI$M_NOKEYPAD | CLI$M_TRUSTED;
1321 unsigned long int mbxbufsiz, flags, retsts, subpid = 0, substs = 0;
1323 bool have_sym = FALSE, have_lnm = FALSE;
1324 struct dsc$descriptor_s tmpdsc = {6,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
1325 $DESCRIPTOR(cmddsc,cmd); $DESCRIPTOR(nldsc,"_NLA0:");
1326 $DESCRIPTOR(clidsc,"DCL"); $DESCRIPTOR(clitabdsc,"DCLTABLES");
1327 $DESCRIPTOR(crtlenv,"CRTL_ENV"); $DESCRIPTOR(clisym,"CLISYM");
1328 $DESCRIPTOR(local,"_LOCAL"); $DESCRIPTOR(mbxdsc,mbxnam);
1329 #if defined(PERL_IMPLICIT_CONTEXT)
1332 #if defined(USE_ITHREADS)
1333 static perl_mutex primenv_mutex;
1334 MUTEX_INIT(&primenv_mutex);
1337 #if defined(PERL_IMPLICIT_CONTEXT)
1338 /* We jump through these hoops because we can be called at */
1339 /* platform-specific initialization time, which is before anything is */
1340 /* set up--we can't even do a plain dTHX since that relies on the */
1341 /* interpreter structure to be initialized */
1343 aTHX = PERL_GET_INTERP;
1345 /* we never get here because the NULL pointer will cause the */
1346 /* several of the routines called by this routine to access violate */
1348 /* This routine is only called by hv.c/hv_iterinit which has a */
1349 /* context, so the real fix may be to pass it through instead of */
1350 /* the hoops above */
1355 if (primed || !PL_envgv) return;
1356 MUTEX_LOCK(&primenv_mutex);
1357 if (primed) { MUTEX_UNLOCK(&primenv_mutex); return; }
1358 envhv = GvHVn(PL_envgv);
1359 /* Perform a dummy fetch as an lval to insure that the hash table is
1360 * set up. Otherwise, the hv_store() will turn into a nullop. */
1361 (void) hv_fetch(envhv,"DEFAULT",7,TRUE);
1363 for (i = 0; env_tables[i]; i++) {
1364 if (!have_sym && (tmpdsc.dsc$a_pointer = env_tables[i]->dsc$a_pointer) &&
1365 !str$case_blind_compare(&tmpdsc,&clisym)) have_sym = 1;
1366 if (!have_lnm && str$case_blind_compare(env_tables[i],&crtlenv)) have_lnm = 1;
1368 if (have_sym || have_lnm) {
1369 long int syiitm = SYI$_MAXBUF, dviitm = DVI$_DEVNAM;
1370 _ckvmssts(lib$getsyi(&syiitm, &mbxbufsiz, 0, 0, 0, 0));
1371 _ckvmssts(sys$crembx(0,&chan,mbxbufsiz,mbxbufsiz,0xff0f,0,0));
1372 _ckvmssts(lib$getdvi(&dviitm, &chan, NULL, NULL, &mbxdsc, &mbxdsc.dsc$w_length));
1375 for (i--; i >= 0; i--) {
1376 if (!str$case_blind_compare(env_tables[i],&crtlenv)) {
1379 for (j = 0; environ[j]; j++) {
1380 if (!(start = strchr(environ[j],'='))) {
1381 if (ckWARN(WARN_INTERNAL))
1382 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"Ill-formed CRTL environ value \"%s\"\n",environ[j]);
1386 sv = newSVpv(start,0);
1388 (void) hv_store(envhv,environ[j],start - environ[j] - 1,sv,0);
1393 else if ((tmpdsc.dsc$a_pointer = env_tables[i]->dsc$a_pointer) &&
1394 !str$case_blind_compare(&tmpdsc,&clisym)) {
1395 my_strlcpy(cmd, "Show Symbol/Global *", sizeof(cmd));
1396 cmddsc.dsc$w_length = 20;
1397 if (env_tables[i]->dsc$w_length == 12 &&
1398 (tmpdsc.dsc$a_pointer = env_tables[i]->dsc$a_pointer + 6) &&
1399 !str$case_blind_compare(&tmpdsc,&local)) my_strlcpy(cmd+12, "Local *", sizeof(cmd)-12);
1400 flags = defflags | CLI$M_NOLOGNAM;
1403 my_strlcpy(cmd, "Show Logical *", sizeof(cmd));
1404 if (str$case_blind_compare(env_tables[i],&fildevdsc)) {
1405 my_strlcat(cmd," /Table=", sizeof(cmd));
1406 cmddsc.dsc$w_length = my_strlcat(cmd, env_tables[i]->dsc$a_pointer, env_tables[i]->dsc$w_length + 1);
1408 else cmddsc.dsc$w_length = 14; /* N.B. We test this below */
1409 flags = defflags | CLI$M_NOCLISYM;
1412 /* Create a new subprocess to execute each command, to exclude the
1413 * remote possibility that someone could subvert a mbx or file used
1414 * to write multiple commands to a single subprocess.
1417 retsts = lib$spawn(&cmddsc,&nldsc,&mbxdsc,&flags,0,&subpid,&substs,
1418 0,&riseandshine,0,0,&clidsc,&clitabdsc);
1419 flags &= ~CLI$M_TRUSTED; /* Just in case we hit a really old version */
1420 defflags &= ~CLI$M_TRUSTED;
1421 } while (retsts == LIB$_INVARG && (flags | CLI$M_TRUSTED));
1423 if (!buf) Newx(buf,mbxbufsiz + 1,char);
1424 if (seenhv) SvREFCNT_dec(seenhv);
1427 char *cp1, *cp2, *key;
1428 unsigned long int sts, iosb[2], retlen, keylen;
1431 sts = sys$qiow(0,chan,IO$_READVBLK,iosb,0,0,buf,mbxbufsiz,0,0,0,0);
1432 if (sts & 1) sts = iosb[0] & 0xffff;
1433 if (sts == SS$_ENDOFFILE) {
1435 while (substs == 0) { sys$hiber(); wakect++;}
1436 if (wakect > 1) sys$wake(0,0); /* Stole someone else's wake */
1441 retlen = iosb[0] >> 16;
1442 if (!retlen) continue; /* blank line */
1444 if (iosb[1] != subpid) {
1446 Perl_croak(aTHX_ "Unknown process %x sent message to prime_env_iter: %s",buf);
1450 if (sts == SS$_BUFFEROVF && ckWARN(WARN_INTERNAL))
1451 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"Buffer overflow in prime_env_iter: %s",buf);
1453 for (cp1 = buf; *cp1 && isspace(*cp1); cp1++) ;
1454 if (*cp1 == '(' || /* Logical name table name */
1455 *cp1 == '=' /* Next eqv of searchlist */) continue;
1456 if (*cp1 == '"') cp1++;
1457 for (cp2 = cp1; *cp2 && *cp2 != '"' && *cp2 != ' '; cp2++) ;
1458 key = cp1; keylen = cp2 - cp1;
1459 if (keylen && hv_exists(seenhv,key,keylen)) continue;
1460 while (*cp2 && *cp2 != '=') cp2++;
1461 while (*cp2 && *cp2 == '=') cp2++;
1462 while (*cp2 && *cp2 == ' ') cp2++;
1463 if (*cp2 == '"') { /* String translation; may embed "" */
1464 for (cp1 = buf + retlen; *cp1 != '"'; cp1--) ;
1465 cp2++; cp1--; /* Skip "" surrounding translation */
1467 else { /* Numeric translation */
1468 for (cp1 = cp2; *cp1 && *cp1 != ' '; cp1++) ;
1469 cp1--; /* stop on last non-space char */
1471 if ((!keylen || (cp1 - cp2 < -1)) && ckWARN(WARN_INTERNAL)) {
1472 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"Ill-formed message in prime_env_iter: |%s|",buf);
1475 PERL_HASH(hash,key,keylen);
1477 if (cp1 == cp2 && *cp2 == '.') {
1478 /* A single dot usually means an unprintable character, such as a null
1479 * to indicate a zero-length value. Get the actual value to make sure.
1481 char lnm[LNM$C_NAMLENGTH+1];
1482 char eqv[MAX_DCL_SYMBOL+1];
1484 strncpy(lnm, key, keylen);
1485 trnlen = vmstrnenv(lnm, eqv, 0, fildev, 0);
1486 sv = newSVpvn(eqv, strlen(eqv));
1489 sv = newSVpvn(cp2,cp1 - cp2 + 1);
1493 hv_store(envhv,key,keylen,sv,hash);
1494 hv_store(seenhv,key,keylen,&PL_sv_yes,hash);
1496 if (cmddsc.dsc$w_length == 14) { /* We just read LNM$FILE_DEV */
1497 /* get the PPFs for this process, not the subprocess */
1498 const char *ppfs[] = {"SYS$COMMAND", "SYS$INPUT", "SYS$OUTPUT", "SYS$ERROR", NULL};
1499 char eqv[LNM$C_NAMLENGTH+1];
1501 for (i = 0; ppfs[i]; i++) {
1502 trnlen = vmstrnenv(ppfs[i],eqv,0,fildev,0);
1503 sv = newSVpv(eqv,trnlen);
1505 hv_store(envhv,ppfs[i],strlen(ppfs[i]),sv,0);
1510 if (have_sym || have_lnm) _ckvmssts(sys$dassgn(chan));
1511 if (buf) Safefree(buf);
1512 if (seenhv) SvREFCNT_dec(seenhv);
1513 MUTEX_UNLOCK(&primenv_mutex);
1516 } /* end of prime_env_iter */
1520 /*{{{ int vmssetenv(const char *lnm, const char *eqv)*/
1521 /* Define or delete an element in the same "environment" as
1522 * vmstrnenv(). If an element is to be deleted, it's removed from
1523 * the first place it's found. If it's to be set, it's set in the
1524 * place designated by the first element of the table vector.
1525 * Like setenv() returns 0 for success, non-zero on error.
1528 Perl_vmssetenv(pTHX_ const char *lnm, const char *eqv, struct dsc$descriptor_s **tabvec)
1531 char uplnm[LNM$C_NAMLENGTH], *cp2, *c;
1532 unsigned short int curtab, ivlnm = 0, ivsym = 0, ivenv = 0;
1534 unsigned long int retsts, usermode = PSL$C_USER;
1535 struct itmlst_3 *ile, *ilist;
1536 struct dsc$descriptor_s lnmdsc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,uplnm},
1537 eqvdsc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0},
1538 tmpdsc = {6,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
1539 $DESCRIPTOR(crtlenv,"CRTL_ENV"); $DESCRIPTOR(clisym,"CLISYM");
1540 $DESCRIPTOR(local,"_LOCAL");
1543 set_errno(EINVAL); set_vaxc_errno(SS$_IVLOGNAM);
1544 return SS$_IVLOGNAM;
1547 for (cp1 = lnm, cp2 = uplnm; *cp1; cp1++, cp2++) {
1548 *cp2 = _toupper(*cp1);
1549 if (cp1 - lnm > LNM$C_NAMLENGTH) {
1550 set_errno(EINVAL); set_vaxc_errno(SS$_IVLOGNAM);
1551 return SS$_IVLOGNAM;
1554 lnmdsc.dsc$w_length = cp1 - lnm;
1555 if (!tabvec || !*tabvec) tabvec = env_tables;
1557 if (!eqv) { /* we're deleting n element */
1558 for (curtab = 0; tabvec[curtab]; curtab++) {
1559 if (!ivenv && !str$case_blind_compare(tabvec[curtab],&crtlenv)) {
1561 for (i = 0; environ[i]; i++) { /* If it's an environ elt, reset */
1562 if ((cp1 = strchr(environ[i],'=')) &&
1563 lnmdsc.dsc$w_length == (cp1 - environ[i]) &&
1564 !strncmp(environ[i],lnm,cp1 - environ[i])) {
1566 return setenv(lnm,"",1) ? vaxc$errno : 0;
1569 ivenv = 1; retsts = SS$_NOLOGNAM;
1571 if (ckWARN(WARN_INTERNAL))
1572 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"This Perl can't reset CRTL environ elements (%s)",lnm);
1573 ivenv = 1; retsts = SS$_NOSUCHPGM;
1579 else if ((tmpdsc.dsc$a_pointer = tabvec[curtab]->dsc$a_pointer) &&
1580 !str$case_blind_compare(&tmpdsc,&clisym)) {
1581 unsigned int symtype;
1582 if (tabvec[curtab]->dsc$w_length == 12 &&
1583 (tmpdsc.dsc$a_pointer = tabvec[curtab]->dsc$a_pointer + 6) &&
1584 !str$case_blind_compare(&tmpdsc,&local))
1585 symtype = LIB$K_CLI_LOCAL_SYM;
1586 else symtype = LIB$K_CLI_GLOBAL_SYM;
1587 retsts = lib$delete_symbol(&lnmdsc,&symtype);
1588 if (retsts == LIB$_INVSYMNAM) { ivsym = 1; continue; }
1589 if (retsts == LIB$_NOSUCHSYM) continue;
1593 retsts = sys$dellnm(tabvec[curtab],&lnmdsc,&usermode); /* try user mode first */
1594 if (retsts == SS$_IVLOGNAM) { ivlnm = 1; continue; }
1595 if (retsts != SS$_NOLOGNAM && retsts != SS$_NOLOGTAB) break;
1596 retsts = lib$delete_logical(&lnmdsc,tabvec[curtab]); /* then supervisor mode */
1597 if (retsts != SS$_NOLOGNAM && retsts != SS$_NOLOGTAB) break;
1601 else { /* we're defining a value */
1602 if (!ivenv && !str$case_blind_compare(tabvec[0],&crtlenv)) {
1604 return setenv(lnm,eqv,1) ? vaxc$errno : 0;
1606 if (ckWARN(WARN_INTERNAL))
1607 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"This Perl can't set CRTL environ elements (%s=%s)",lnm,eqv);
1608 retsts = SS$_NOSUCHPGM;
1612 eqvdsc.dsc$a_pointer = (char *) eqv; /* cast ok to readonly parameter */
1613 eqvdsc.dsc$w_length = strlen(eqv);
1614 if ((tmpdsc.dsc$a_pointer = tabvec[0]->dsc$a_pointer) &&
1615 !str$case_blind_compare(&tmpdsc,&clisym)) {
1616 unsigned int symtype;
1617 if (tabvec[0]->dsc$w_length == 12 &&
1618 (tmpdsc.dsc$a_pointer = tabvec[0]->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$set_symbol(&lnmdsc,&eqvdsc,&symtype);
1625 if (!*eqv) eqvdsc.dsc$w_length = 1;
1626 if (eqvdsc.dsc$w_length > LNM$C_NAMLENGTH) {
1628 nseg = (eqvdsc.dsc$w_length + LNM$C_NAMLENGTH - 1) / LNM$C_NAMLENGTH;
1629 if (nseg > PERL_LNM_MAX_ALLOWED_INDEX + 1) {
1630 Perl_warner(aTHX_ packWARN(WARN_MISC),"Value of logical \"%s\" too long. Truncating to %i bytes",
1631 lnm, LNM$C_NAMLENGTH * (PERL_LNM_MAX_ALLOWED_INDEX+1));
1632 eqvdsc.dsc$w_length = LNM$C_NAMLENGTH * (PERL_LNM_MAX_ALLOWED_INDEX+1);
1633 nseg = PERL_LNM_MAX_ALLOWED_INDEX + 1;
1636 Newx(ilist,nseg+1,struct itmlst_3);
1639 set_errno(ENOMEM); set_vaxc_errno(SS$_INSFMEM);
1642 memset(ilist, 0, (sizeof(struct itmlst_3) * (nseg+1)));
1644 for (j = 0, c = eqvdsc.dsc$a_pointer; j < nseg; j++, ile++, c += LNM$C_NAMLENGTH) {
1645 ile->itmcode = LNM$_STRING;
1647 if ((j+1) == nseg) {
1648 ile->buflen = strlen(c);
1649 /* in case we are truncating one that's too long */
1650 if (ile->buflen > LNM$C_NAMLENGTH) ile->buflen = LNM$C_NAMLENGTH;
1653 ile->buflen = LNM$C_NAMLENGTH;
1657 retsts = lib$set_logical(&lnmdsc,0,tabvec[0],0,ilist);
1661 retsts = lib$set_logical(&lnmdsc,&eqvdsc,tabvec[0],0,0);
1666 if (!(retsts & 1)) {
1668 case LIB$_AMBSYMDEF: case LIB$_INSCLIMEM:
1669 case SS$_NOLOGTAB: case SS$_TOOMANYLNAM: case SS$_IVLOGTAB:
1670 set_errno(EVMSERR); break;
1671 case LIB$_INVARG: case LIB$_INVSYMNAM: case SS$_IVLOGNAM:
1672 case LIB$_NOSUCHSYM: case SS$_NOLOGNAM:
1673 set_errno(EINVAL); break;
1675 set_errno(EACCES); break;
1680 set_vaxc_errno(retsts);
1681 return (int) retsts || 44; /* retsts should never be 0, but just in case */
1684 /* We reset error values on success because Perl does an hv_fetch()
1685 * before each hv_store(), and if the thing we're setting didn't
1686 * previously exist, we've got a leftover error message. (Of course,
1687 * this fails in the face of
1688 * $foo = $ENV{nonexistent}; $ENV{existent} = 'foo';
1689 * in that the error reported in $! isn't spurious,
1690 * but it's right more often than not.)
1692 set_errno(0); set_vaxc_errno(retsts);
1696 } /* end of vmssetenv() */
1699 /*{{{ void my_setenv(const char *lnm, const char *eqv)*/
1700 /* This has to be a function since there's a prototype for it in proto.h */
1702 Perl_my_setenv(pTHX_ const char *lnm, const char *eqv)
1705 int len = strlen(lnm);
1709 for (i = 0; lnm[i]; i++) uplnm[i] = _toupper(lnm[i]);
1710 if (!strcmp(uplnm,"DEFAULT")) {
1711 if (eqv && *eqv) my_chdir(eqv);
1716 (void) vmssetenv(lnm,eqv,NULL);
1720 /*{{{static void vmssetuserlnm(char *name, char *eqv); */
1722 * sets a user-mode logical in the process logical name table
1723 * used for redirection of sys$error
1726 Perl_vmssetuserlnm(const char *name, const char *eqv)
1728 $DESCRIPTOR(d_tab, "LNM$PROCESS");
1729 struct dsc$descriptor_d d_name = {0,DSC$K_DTYPE_T,DSC$K_CLASS_D,0};
1730 unsigned long int iss, attr = LNM$M_CONFINE;
1731 unsigned char acmode = PSL$C_USER;
1732 struct itmlst_3 lnmlst[2] = {{0, LNM$_STRING, 0, 0},
1734 d_name.dsc$a_pointer = (char *)name; /* Cast OK for read only parameter */
1735 d_name.dsc$w_length = strlen(name);
1737 lnmlst[0].buflen = strlen(eqv);
1738 lnmlst[0].bufadr = (char *)eqv; /* Cast OK for read only parameter */
1740 iss = sys$crelnm(&attr,&d_tab,&d_name,&acmode,lnmlst);
1741 if (!(iss&1)) lib$signal(iss);
1746 /*{{{ char *my_crypt(const char *textpasswd, const char *usrname)*/
1747 /* my_crypt - VMS password hashing
1748 * my_crypt() provides an interface compatible with the Unix crypt()
1749 * C library function, and uses sys$hash_password() to perform VMS
1750 * password hashing. The quadword hashed password value is returned
1751 * as a NUL-terminated 8 character string. my_crypt() does not change
1752 * the case of its string arguments; in order to match the behavior
1753 * of LOGINOUT et al., alphabetic characters in both arguments must
1754 * be upcased by the caller.
1756 * - fix me to call ACM services when available
1759 Perl_my_crypt(pTHX_ const char *textpasswd, const char *usrname)
1761 # ifndef UAI$C_PREFERRED_ALGORITHM
1762 # define UAI$C_PREFERRED_ALGORITHM 127
1764 unsigned char alg = UAI$C_PREFERRED_ALGORITHM;
1765 unsigned short int salt = 0;
1766 unsigned long int sts;
1768 unsigned short int dsc$w_length;
1769 unsigned char dsc$b_type;
1770 unsigned char dsc$b_class;
1771 const char * dsc$a_pointer;
1772 } usrdsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0},
1773 txtdsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
1774 struct itmlst_3 uailst[3] = {
1775 { sizeof alg, UAI$_ENCRYPT, &alg, 0},
1776 { sizeof salt, UAI$_SALT, &salt, 0},
1777 { 0, 0, NULL, NULL}};
1778 static char hash[9];
1780 usrdsc.dsc$w_length = strlen(usrname);
1781 usrdsc.dsc$a_pointer = usrname;
1782 if (!((sts = sys$getuai(0, 0, &usrdsc, uailst, 0, 0, 0)) & 1)) {
1784 case SS$_NOGRPPRV: case SS$_NOSYSPRV:
1788 set_errno(ESRCH); /* There isn't a Unix no-such-user error */
1793 set_vaxc_errno(sts);
1794 if (sts != RMS$_RNF) return NULL;
1797 txtdsc.dsc$w_length = strlen(textpasswd);
1798 txtdsc.dsc$a_pointer = textpasswd;
1799 if (!((sts = sys$hash_password(&txtdsc, alg, salt, &usrdsc, &hash)) & 1)) {
1800 set_errno(EVMSERR); set_vaxc_errno(sts); return NULL;
1803 return (char *) hash;
1805 } /* end of my_crypt() */
1809 static char *mp_do_rmsexpand(pTHX_ const char *, char *, int, const char *, unsigned, int *, int *);
1810 static char *mp_do_fileify_dirspec(pTHX_ const char *, char *, int, int *);
1811 static char *mp_do_tovmsspec(pTHX_ const char *, char *, int, int, int *);
1813 /* fixup barenames that are directories for internal use.
1814 * There have been problems with the consistent handling of UNIX
1815 * style directory names when routines are presented with a name that
1816 * has no directory delimiters at all. So this routine will eventually
1819 static char * fixup_bare_dirnames(const char * name)
1821 if (decc_disable_to_vms_logname_translation) {
1827 /* 8.3, remove() is now broken on symbolic links */
1828 static int rms_erase(const char * vmsname);
1832 * A little hack to get around a bug in some implementation of remove()
1833 * that do not know how to delete a directory
1835 * Delete any file to which user has control access, regardless of whether
1836 * delete access is explicitly allowed.
1837 * Limitations: User must have write access to parent directory.
1838 * Does not block signals or ASTs; if interrupted in midstream
1839 * may leave file with an altered ACL.
1842 /*{{{int mp_do_kill_file(const char *name, int dirflag)*/
1844 mp_do_kill_file(pTHX_ const char *name, int dirflag)
1848 unsigned long int jpicode = JPI$_UIC, type = ACL$C_FILE;
1849 unsigned long int cxt = 0, aclsts, fndsts, rmsts = -1;
1850 struct dsc$descriptor_s fildsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
1852 unsigned char myace$b_length;
1853 unsigned char myace$b_type;
1854 unsigned short int myace$w_flags;
1855 unsigned long int myace$l_access;
1856 unsigned long int myace$l_ident;
1857 } newace = { sizeof(struct myacedef), ACE$C_KEYID, 0,
1858 ACE$M_READ | ACE$M_WRITE | ACE$M_DELETE | ACE$M_CONTROL, 0},
1859 oldace = { sizeof(struct myacedef), ACE$C_KEYID, 0, 0, 0};
1861 findlst[3] = {{sizeof oldace, ACL$C_FNDACLENT, &oldace, 0},
1862 {sizeof oldace, ACL$C_READACE, &oldace, 0},{0,0,0,0}},
1863 addlst[2] = {{sizeof newace, ACL$C_ADDACLENT, &newace, 0},{0,0,0,0}},
1864 dellst[2] = {{sizeof newace, ACL$C_DELACLENT, &newace, 0},{0,0,0,0}},
1865 lcklst[2] = {{sizeof newace, ACL$C_WLOCK_ACL, &newace, 0},{0,0,0,0}},
1866 ulklst[2] = {{sizeof newace, ACL$C_UNLOCK_ACL, &newace, 0},{0,0,0,0}};
1868 /* Expand the input spec using RMS, since the CRTL remove() and
1869 * system services won't do this by themselves, so we may miss
1870 * a file "hiding" behind a logical name or search list. */
1871 vmsname = (char *)PerlMem_malloc(NAM$C_MAXRSS+1);
1872 if (vmsname == NULL) _ckvmssts_noperl(SS$_INSFMEM);
1874 rslt = int_rmsexpand_tovms(name, vmsname, PERL_RMSEXPAND_M_SYMLINK);
1876 PerlMem_free(vmsname);
1880 /* Erase the file */
1881 rmsts = rms_erase(vmsname);
1883 /* Did it succeed */
1884 if ($VMS_STATUS_SUCCESS(rmsts)) {
1885 PerlMem_free(vmsname);
1889 /* If not, can changing protections help? */
1890 if (rmsts != RMS$_PRV) {
1891 set_vaxc_errno(rmsts);
1892 PerlMem_free(vmsname);
1896 /* No, so we get our own UIC to use as a rights identifier,
1897 * and the insert an ACE at the head of the ACL which allows us
1898 * to delete the file.
1900 _ckvmssts_noperl(lib$getjpi(&jpicode,0,0,&(oldace.myace$l_ident),0,0));
1901 fildsc.dsc$w_length = strlen(vmsname);
1902 fildsc.dsc$a_pointer = vmsname;
1904 newace.myace$l_ident = oldace.myace$l_ident;
1906 if (!((aclsts = sys$change_acl(0,&type,&fildsc,lcklst,0,0,0)) & 1)) {
1908 case RMS$_FNF: case RMS$_DNF: case SS$_NOSUCHOBJECT:
1909 set_errno(ENOENT); break;
1911 set_errno(ENOTDIR); break;
1913 set_errno(ENODEV); break;
1914 case RMS$_SYN: case SS$_INVFILFOROP:
1915 set_errno(EINVAL); break;
1917 set_errno(EACCES); break;
1919 _ckvmssts_noperl(aclsts);
1921 set_vaxc_errno(aclsts);
1922 PerlMem_free(vmsname);
1925 /* Grab any existing ACEs with this identifier in case we fail */
1926 aclsts = fndsts = sys$change_acl(0,&type,&fildsc,findlst,0,0,&cxt);
1927 if ( fndsts & 1 || fndsts == SS$_ACLEMPTY || fndsts == SS$_NOENTRY
1928 || fndsts == SS$_NOMOREACE ) {
1929 /* Add the new ACE . . . */
1930 if (!((aclsts = sys$change_acl(0,&type,&fildsc,addlst,0,0,0)) & 1))
1933 rmsts = rms_erase(vmsname);
1934 if ($VMS_STATUS_SUCCESS(rmsts)) {
1939 /* We blew it - dir with files in it, no write priv for
1940 * parent directory, etc. Put things back the way they were. */
1941 if (!((aclsts = sys$change_acl(0,&type,&fildsc,dellst,0,0,0)) & 1))
1944 addlst[0].bufadr = &oldace;
1945 if (!((aclsts = sys$change_acl(0,&type,&fildsc,addlst,0,0,&cxt)) & 1))
1952 fndsts = sys$change_acl(0,&type,&fildsc,ulklst,0,0,0);
1953 /* We just deleted it, so of course it's not there. Some versions of
1954 * VMS seem to return success on the unlock operation anyhow (after all
1955 * the unlock is successful), but others don't.
1957 if (fndsts == RMS$_FNF || fndsts == SS$_NOSUCHOBJECT) fndsts = SS$_NORMAL;
1958 if (aclsts & 1) aclsts = fndsts;
1959 if (!(aclsts & 1)) {
1961 set_vaxc_errno(aclsts);
1964 PerlMem_free(vmsname);
1967 } /* end of kill_file() */
1971 /*{{{int do_rmdir(char *name)*/
1973 Perl_do_rmdir(pTHX_ const char *name)
1979 /* lstat returns a VMS fileified specification of the name */
1980 /* that is looked up, and also lets verifies that this is a directory */
1982 retval = flex_lstat(name, &st);
1986 /* Due to a historical feature, flex_stat/lstat can not see some */
1987 /* Unix format file names that the rest of the CRTL can see */
1988 /* Fixing that feature will cause some perl tests to fail */
1989 /* So try this one more time. */
1991 retval = lstat(name, &st.crtl_stat);
1995 /* force it to a file spec for the kill file to work. */
1996 ret_spec = do_fileify_dirspec(name, st.st_devnam, 0, NULL);
1997 if (ret_spec == NULL) {
2003 if (!S_ISDIR(st.st_mode)) {
2008 dirfile = st.st_devnam;
2010 /* It may be possible for flex_stat to find a file and vmsify() to */
2011 /* fail with ODS-2 specifications. mp_do_kill_file can not deal */
2012 /* with that case, so fail it */
2013 if (dirfile[0] == 0) {
2018 retval = mp_do_kill_file(aTHX_ dirfile, 1);
2023 } /* end of do_rmdir */
2027 * Delete any file to which user has control access, regardless of whether
2028 * delete access is explicitly allowed.
2029 * Limitations: User must have write access to parent directory.
2030 * Does not block signals or ASTs; if interrupted in midstream
2031 * may leave file with an altered ACL.
2034 /*{{{int kill_file(char *name)*/
2036 Perl_kill_file(pTHX_ const char *name)
2042 /* Convert the filename to VMS format and see if it is a directory */
2043 /* flex_lstat returns a vmsified file specification */
2044 rmsts = flex_lstat(name, &st);
2047 /* Due to a historical feature, flex_stat/lstat can not see some */
2048 /* Unix format file names that the rest of the CRTL can see when */
2049 /* ODS-2 file specifications are in use. */
2050 /* Fixing that feature will cause some perl tests to fail */
2051 /* [.lib.ExtUtils.t]Manifest.t is one of them */
2053 vmsfile = (char *) name; /* cast ok */
2056 vmsfile = st.st_devnam;
2057 if (vmsfile[0] == 0) {
2058 /* It may be possible for flex_stat to find a file and vmsify() */
2059 /* to fail with ODS-2 specifications. mp_do_kill_file can not */
2060 /* deal with that case, so fail it */
2066 /* Remove() is allowed to delete directories, according to the X/Open
2068 * This may need special handling to work with the ACL hacks.
2070 if (S_ISDIR(st.st_mode)) {
2071 rmsts = mp_do_kill_file(aTHX_ vmsfile, 1);
2075 rmsts = mp_do_kill_file(aTHX_ vmsfile, 0);
2077 /* Need to delete all versions ? */
2078 if ((rmsts == 0) && (vms_unlink_all_versions == 1)) {
2081 /* Just use lstat() here as do not need st_dev */
2082 /* and we know that the file is in VMS format or that */
2083 /* because of a historical bug, flex_stat can not see the file */
2084 while (lstat(vmsfile, (stat_t *)&st) == 0) {
2085 rmsts = mp_do_kill_file(aTHX_ vmsfile, 0);
2090 /* Make sure that we do not loop forever */
2101 } /* end of kill_file() */
2105 /*{{{int my_mkdir(char *,Mode_t)*/
2107 Perl_my_mkdir(pTHX_ const char *dir, Mode_t mode)
2109 STRLEN dirlen = strlen(dir);
2111 /* zero length string sometimes gives ACCVIO */
2112 if (dirlen == 0) return -1;
2114 /* CRTL mkdir() doesn't tolerate trailing /, since that implies
2115 * null file name/type. However, it's commonplace under Unix,
2116 * so we'll allow it for a gain in portability.
2118 if (dir[dirlen-1] == '/') {
2119 char *newdir = savepvn(dir,dirlen-1);
2120 int ret = mkdir(newdir,mode);
2124 else return mkdir(dir,mode);
2125 } /* end of my_mkdir */
2128 /*{{{int my_chdir(char *)*/
2130 Perl_my_chdir(pTHX_ const char *dir)
2132 STRLEN dirlen = strlen(dir);
2134 /* zero length string sometimes gives ACCVIO */
2135 if (dirlen == 0) return -1;
2138 /* Perl is passing the output of the DCL SHOW DEFAULT with leading spaces.
2139 * This does not work if DECC$EFS_CHARSET is active. Hack it here
2140 * so that existing scripts do not need to be changed.
2143 while ((dirlen > 0) && (*dir1 == ' ')) {
2148 /* some versions of CRTL chdir() doesn't tolerate trailing /, since
2150 * null file name/type. However, it's commonplace under Unix,
2151 * so we'll allow it for a gain in portability.
2153 * '/' is valid when SYS$POSIX_ROOT or POSIX compliant pathnames are active.
2155 if ((dirlen > 1) && (dir1[dirlen-1] == '/')) {
2158 newdir = (char *)PerlMem_malloc(dirlen);
2160 _ckvmssts_noperl(SS$_INSFMEM);
2161 memcpy(newdir, dir1, dirlen-1);
2162 newdir[dirlen-1] = '\0';
2163 ret = chdir(newdir);
2164 PerlMem_free(newdir);
2167 else return chdir(dir1);
2168 } /* end of my_chdir */
2172 /*{{{int my_chmod(char *, mode_t)*/
2174 Perl_my_chmod(pTHX_ const char *file_spec, mode_t mode)
2179 STRLEN speclen = strlen(file_spec);
2181 /* zero length string sometimes gives ACCVIO */
2182 if (speclen == 0) return -1;
2184 /* some versions of CRTL chmod() doesn't tolerate trailing /, since
2185 * that implies null file name/type. However, it's commonplace under Unix,
2186 * so we'll allow it for a gain in portability.
2188 * Tests are showing that chmod() on VMS 8.3 is only accepting directories
2189 * in VMS file.dir notation.
2191 changefile = (char *) file_spec; /* cast ok */
2192 ret = flex_lstat(file_spec, &st);
2195 /* Due to a historical feature, flex_stat/lstat can not see some */
2196 /* Unix format file names that the rest of the CRTL can see when */
2197 /* ODS-2 file specifications are in use. */
2198 /* Fixing that feature will cause some perl tests to fail */
2199 /* [.lib.ExtUtils.t]Manifest.t is one of them */
2203 /* It may be possible to get here with nothing in st_devname */
2204 /* chmod still may work though */
2205 if (st.st_devnam[0] != 0) {
2206 changefile = st.st_devnam;
2209 ret = chmod(changefile, mode);
2211 } /* end of my_chmod */
2215 /*{{{FILE *my_tmpfile()*/
2222 if ((fp = tmpfile())) return fp;
2224 cp = (char *)PerlMem_malloc(L_tmpnam+24);
2225 if (cp == NULL) _ckvmssts_noperl(SS$_INSFMEM);
2227 if (decc_filename_unix_only == 0)
2228 strcpy(cp,"Sys$Scratch:");
2231 tmpnam(cp+strlen(cp));
2232 strcat(cp,".Perltmp");
2233 fp = fopen(cp,"w+","fop=dlt");
2241 * The C RTL's sigaction fails to check for invalid signal numbers so we
2242 * help it out a bit. The docs are correct, but the actual routine doesn't
2243 * do what the docs say it will.
2245 /*{{{int Perl_my_sigaction (pTHX_ int, const struct sigaction*, struct sigaction*);*/
2247 Perl_my_sigaction (pTHX_ int sig, const struct sigaction* act,
2248 struct sigaction* oact)
2250 if (sig == SIGKILL || sig == SIGSTOP || sig == SIGCONT) {
2251 SETERRNO(EINVAL, SS$_INVARG);
2254 return sigaction(sig, act, oact);
2258 #ifdef KILL_BY_SIGPRC
2259 #include <errnodef.h>
2261 /* We implement our own kill() using the undocumented system service
2262 sys$sigprc for one of two reasons:
2264 1.) If the kill() in an older CRTL uses sys$forcex, causing the
2265 target process to do a sys$exit, which usually can't be handled
2266 gracefully...certainly not by Perl and the %SIG{} mechanism.
2268 2.) If the kill() in the CRTL can't be called from a signal
2269 handler without disappearing into the ether, i.e., the signal
2270 it purportedly sends is never trapped. Still true as of VMS 7.3.
2272 sys$sigprc has the same parameters as sys$forcex, but throws an exception
2273 in the target process rather than calling sys$exit.
2275 Note that distinguishing SIGSEGV from SIGBUS requires an extra arg
2276 on the ACCVIO condition, which sys$sigprc (and sys$forcex) don't
2277 provide. On VMS 7.0+ this is taken care of by doing sys$sigprc
2278 with condition codes C$_SIG0+nsig*8, catching the exception on the
2279 target process and resignaling with appropriate arguments.
2281 But we don't have that VMS 7.0+ exception handler, so if you
2282 Perl_my_kill(.., SIGSEGV) it will show up as a SIGBUS. Oh well.
2284 Also note that SIGTERM is listed in the docs as being "unimplemented",
2285 yet always seems to be signaled with a VMS condition code of 4 (and
2286 correctly handled for that code). So we hardwire it in.
2288 Unlike the VMS 7.0+ CRTL kill() function, we actually check the signal
2289 number to see if it's valid. So Perl_my_kill(pid,0) returns -1 rather
2290 than signalling with an unrecognized (and unhandled by CRTL) code.
2293 #define _MY_SIG_MAX 28
2296 Perl_sig_to_vmscondition_int(int sig)
2298 static unsigned int sig_code[_MY_SIG_MAX+1] =
2301 SS$_HANGUP, /* 1 SIGHUP */
2302 SS$_CONTROLC, /* 2 SIGINT */
2303 SS$_CONTROLY, /* 3 SIGQUIT */
2304 SS$_RADRMOD, /* 4 SIGILL */
2305 SS$_BREAK, /* 5 SIGTRAP */
2306 SS$_OPCCUS, /* 6 SIGABRT */
2307 SS$_COMPAT, /* 7 SIGEMT */
2309 SS$_FLTOVF, /* 8 SIGFPE VAX */
2311 SS$_HPARITH, /* 8 SIGFPE AXP */
2313 SS$_ABORT, /* 9 SIGKILL */
2314 SS$_ACCVIO, /* 10 SIGBUS */
2315 SS$_ACCVIO, /* 11 SIGSEGV */
2316 SS$_BADPARAM, /* 12 SIGSYS */
2317 SS$_NOMBX, /* 13 SIGPIPE */
2318 SS$_ASTFLT, /* 14 SIGALRM */
2335 static int initted = 0;
2338 sig_code[16] = C$_SIGUSR1;
2339 sig_code[17] = C$_SIGUSR2;
2340 sig_code[20] = C$_SIGCHLD;
2341 #if __CRTL_VER >= 70300000
2342 sig_code[28] = C$_SIGWINCH;
2346 if (sig < _SIG_MIN) return 0;
2347 if (sig > _MY_SIG_MAX) return 0;
2348 return sig_code[sig];
2352 Perl_sig_to_vmscondition(int sig)
2355 if (vms_debug_on_exception != 0)
2356 lib$signal(SS$_DEBUG);
2358 return Perl_sig_to_vmscondition_int(sig);
2362 #define sys$sigprc SYS$SIGPRC
2366 int sys$sigprc(unsigned int *pidadr,
2367 struct dsc$descriptor_s *prcname,
2374 Perl_my_kill(int pid, int sig)
2379 /* sig 0 means validate the PID */
2380 /*------------------------------*/
2382 const unsigned long int jpicode = JPI$_PID;
2385 status = lib$getjpi(&jpicode, &pid, NULL, &ret_pid, NULL, NULL);
2386 if ($VMS_STATUS_SUCCESS(status))
2389 case SS$_NOSUCHNODE:
2390 case SS$_UNREACHABLE:
2404 code = Perl_sig_to_vmscondition_int(sig);
2407 SETERRNO(EINVAL, SS$_BADPARAM);
2411 /* Fixme: Per official UNIX specification: If pid = 0, or negative then
2412 * signals are to be sent to multiple processes.
2413 * pid = 0 - all processes in group except ones that the system exempts
2414 * pid = -1 - all processes except ones that the system exempts
2415 * pid = -n - all processes in group (abs(n)) except ...
2416 * For now, just report as not supported.
2420 SETERRNO(ENOTSUP, SS$_UNSUPPORTED);
2424 iss = sys$sigprc((unsigned int *)&pid,0,code);
2425 if (iss&1) return 0;
2429 set_errno(EPERM); break;
2431 case SS$_NOSUCHNODE:
2432 case SS$_UNREACHABLE:
2433 set_errno(ESRCH); break;
2435 set_errno(ENOMEM); break;
2437 _ckvmssts_noperl(iss);
2440 set_vaxc_errno(iss);
2446 /* Routine to convert a VMS status code to a UNIX status code.
2447 ** More tricky than it appears because of conflicting conventions with
2450 ** VMS status codes are a bit mask, with the least significant bit set for
2453 ** Special UNIX status of EVMSERR indicates that no translation is currently
2454 ** available, and programs should check the VMS status code.
2456 ** Programs compiled with _POSIX_EXIT have a special encoding that requires
2460 #ifndef C_FACILITY_NO
2461 #define C_FACILITY_NO 0x350000
2464 #define DCL_IVVERB 0x38090
2467 int Perl_vms_status_to_unix(int vms_status, int child_flag)
2475 /* Assume the best or the worst */
2476 if (vms_status & STS$M_SUCCESS)
2479 unix_status = EVMSERR;
2481 msg_status = vms_status & ~STS$M_CONTROL;
2483 facility = vms_status & STS$M_FAC_NO;
2484 fac_sp = vms_status & STS$M_FAC_SP;
2485 msg_no = vms_status & (STS$M_MSG_NO | STS$M_SEVERITY);
2487 if (((facility == 0) || (fac_sp == 0)) && (child_flag == 0)) {
2493 unix_status = EFAULT;
2495 case SS$_DEVOFFLINE:
2496 unix_status = EBUSY;
2499 unix_status = ENOTCONN;
2507 case SS$_INVFILFOROP:
2511 unix_status = EINVAL;
2513 case SS$_UNSUPPORTED:
2514 unix_status = ENOTSUP;
2519 unix_status = EACCES;
2521 case SS$_DEVICEFULL:
2522 unix_status = ENOSPC;
2525 unix_status = ENODEV;
2527 case SS$_NOSUCHFILE:
2528 case SS$_NOSUCHOBJECT:
2529 unix_status = ENOENT;
2531 case SS$_ABORT: /* Fatal case */
2532 case ((SS$_ABORT & STS$M_COND_ID) | STS$K_ERROR): /* Error case */
2533 case ((SS$_ABORT & STS$M_COND_ID) | STS$K_WARNING): /* Warning case */
2534 unix_status = EINTR;
2537 unix_status = E2BIG;
2540 unix_status = ENOMEM;
2543 unix_status = EPERM;
2545 case SS$_NOSUCHNODE:
2546 case SS$_UNREACHABLE:
2547 unix_status = ESRCH;
2550 unix_status = ECHILD;
2553 if ((facility == 0) && (msg_no < 8)) {
2554 /* These are not real VMS status codes so assume that they are
2555 ** already UNIX status codes
2557 unix_status = msg_no;
2563 /* Translate a POSIX exit code to a UNIX exit code */
2564 if ((facility == C_FACILITY_NO) && ((msg_no & 0xA000) == 0xA000)) {
2565 unix_status = (msg_no & 0x07F8) >> 3;
2569 /* Documented traditional behavior for handling VMS child exits */
2570 /*--------------------------------------------------------------*/
2571 if (child_flag != 0) {
2573 /* Success / Informational return 0 */
2574 /*----------------------------------*/
2575 if (msg_no & STS$K_SUCCESS)
2578 /* Warning returns 1 */
2579 /*-------------------*/
2580 if ((msg_no & (STS$K_ERROR | STS$K_SEVERE)) == 0)
2583 /* Everything else pass through the severity bits */
2584 /*------------------------------------------------*/
2585 return (msg_no & STS$M_SEVERITY);
2588 /* Normal VMS status to ERRNO mapping attempt */
2589 /*--------------------------------------------*/
2590 switch(msg_status) {
2591 /* case RMS$_EOF: */ /* End of File */
2592 case RMS$_FNF: /* File Not Found */
2593 case RMS$_DNF: /* Dir Not Found */
2594 unix_status = ENOENT;
2596 case RMS$_RNF: /* Record Not Found */
2597 unix_status = ESRCH;
2600 unix_status = ENOTDIR;
2603 unix_status = ENODEV;
2608 unix_status = EBADF;
2611 unix_status = EEXIST;
2615 case LIB$_INVSTRDES:
2617 case LIB$_NOSUCHSYM:
2618 case LIB$_INVSYMNAM:
2620 unix_status = EINVAL;
2626 unix_status = E2BIG;
2628 case RMS$_PRV: /* No privilege */
2629 case RMS$_ACC: /* ACP file access failed */
2630 case RMS$_WLK: /* Device write locked */
2631 unix_status = EACCES;
2633 case RMS$_MKD: /* Failed to mark for delete */
2634 unix_status = EPERM;
2636 /* case RMS$_NMF: */ /* No more files */
2644 /* Try to guess at what VMS error status should go with a UNIX errno
2645 * value. This is hard to do as there could be many possible VMS
2646 * error statuses that caused the errno value to be set.
2649 int Perl_unix_status_to_vms(int unix_status)
2651 int test_unix_status;
2653 /* Trivial cases first */
2654 /*---------------------*/
2655 if (unix_status == EVMSERR)
2658 /* Is vaxc$errno sane? */
2659 /*---------------------*/
2660 test_unix_status = Perl_vms_status_to_unix(vaxc$errno, 0);
2661 if (test_unix_status == unix_status)
2664 /* If way out of range, must be VMS code already */
2665 /*-----------------------------------------------*/
2666 if (unix_status > EVMSERR)
2669 /* If out of range, punt */
2670 /*-----------------------*/
2671 if (unix_status > __ERRNO_MAX)
2675 /* Ok, now we have to do it the hard way. */
2676 /*----------------------------------------*/
2677 switch(unix_status) {
2678 case 0: return SS$_NORMAL;
2679 case EPERM: return SS$_NOPRIV;
2680 case ENOENT: return SS$_NOSUCHOBJECT;
2681 case ESRCH: return SS$_UNREACHABLE;
2682 case EINTR: return SS$_ABORT;
2685 case E2BIG: return SS$_BUFFEROVF;
2687 case EBADF: return RMS$_IFI;
2688 case ECHILD: return SS$_NONEXPR;
2690 case ENOMEM: return SS$_INSFMEM;
2691 case EACCES: return SS$_FILACCERR;
2692 case EFAULT: return SS$_ACCVIO;
2694 case EBUSY: return SS$_DEVOFFLINE;
2695 case EEXIST: return RMS$_FEX;
2697 case ENODEV: return SS$_NOSUCHDEV;
2698 case ENOTDIR: return RMS$_DIR;
2700 case EINVAL: return SS$_INVARG;
2706 case ENOSPC: return SS$_DEVICEFULL;
2707 case ESPIPE: return LIB$_INVARG;
2712 case ERANGE: return LIB$_INVARG;
2713 /* case EWOULDBLOCK */
2714 /* case EINPROGRESS */
2717 /* case EDESTADDRREQ */
2719 /* case EPROTOTYPE */
2720 /* case ENOPROTOOPT */
2721 /* case EPROTONOSUPPORT */
2722 /* case ESOCKTNOSUPPORT */
2723 /* case EOPNOTSUPP */
2724 /* case EPFNOSUPPORT */
2725 /* case EAFNOSUPPORT */
2726 /* case EADDRINUSE */
2727 /* case EADDRNOTAVAIL */
2729 /* case ENETUNREACH */
2730 /* case ENETRESET */
2731 /* case ECONNABORTED */
2732 /* case ECONNRESET */
2735 case ENOTCONN: return SS$_CLEARED;
2736 /* case ESHUTDOWN */
2737 /* case ETOOMANYREFS */
2738 /* case ETIMEDOUT */
2739 /* case ECONNREFUSED */
2741 /* case ENAMETOOLONG */
2742 /* case EHOSTDOWN */
2743 /* case EHOSTUNREACH */
2744 /* case ENOTEMPTY */
2756 /* case ECANCELED */
2760 return SS$_UNSUPPORTED;
2766 /* case EABANDONED */
2768 return SS$_ABORT; /* punt */
2773 /* default piping mailbox size */
2775 # define PERL_BUFSIZ 512
2777 # define PERL_BUFSIZ 8192
2782 create_mbx(unsigned short int *chan, struct dsc$descriptor_s *namdsc)
2784 unsigned long int mbxbufsiz;
2785 static unsigned long int syssize = 0;
2786 unsigned long int dviitm = DVI$_DEVNAM;
2787 char csize[LNM$C_NAMLENGTH+1];
2791 unsigned long syiitm = SYI$_MAXBUF;
2793 * Get the SYSGEN parameter MAXBUF
2795 * If the logical 'PERL_MBX_SIZE' is defined
2796 * use the value of the logical instead of PERL_BUFSIZ, but
2797 * keep the size between 128 and MAXBUF.
2800 _ckvmssts_noperl(lib$getsyi(&syiitm, &syssize, 0, 0, 0, 0));
2803 if (vmstrnenv("PERL_MBX_SIZE", csize, 0, fildev, 0)) {
2804 mbxbufsiz = atoi(csize);
2806 mbxbufsiz = PERL_BUFSIZ;
2808 if (mbxbufsiz < 128) mbxbufsiz = 128;
2809 if (mbxbufsiz > syssize) mbxbufsiz = syssize;
2811 _ckvmssts_noperl(sts = sys$crembx(0,chan,mbxbufsiz,mbxbufsiz,0,0,0));
2813 sts = lib$getdvi(&dviitm, chan, NULL, NULL, namdsc, &namdsc->dsc$w_length);
2814 _ckvmssts_noperl(sts);
2815 namdsc->dsc$a_pointer[namdsc->dsc$w_length] = '\0';
2817 } /* end of create_mbx() */
2820 /*{{{ my_popen and my_pclose*/
2822 typedef struct _iosb IOSB;
2823 typedef struct _iosb* pIOSB;
2824 typedef struct _pipe Pipe;
2825 typedef struct _pipe* pPipe;
2826 typedef struct pipe_details Info;
2827 typedef struct pipe_details* pInfo;
2828 typedef struct _srqp RQE;
2829 typedef struct _srqp* pRQE;
2830 typedef struct _tochildbuf CBuf;
2831 typedef struct _tochildbuf* pCBuf;
2834 unsigned short status;
2835 unsigned short count;
2836 unsigned long dvispec;
2839 #pragma member_alignment save
2840 #pragma nomember_alignment quadword
2841 struct _srqp { /* VMS self-relative queue entry */
2842 unsigned long qptr[2];
2844 #pragma member_alignment restore
2845 static RQE RQE_ZERO = {0,0};
2847 struct _tochildbuf {
2850 unsigned short size;
2858 unsigned short chan_in;
2859 unsigned short chan_out;
2861 unsigned int bufsize;
2873 #if defined(PERL_IMPLICIT_CONTEXT)
2874 void *thx; /* Either a thread or an interpreter */
2875 /* pointer, depending on how we're built */
2883 PerlIO *fp; /* file pointer to pipe mailbox */
2884 int useFILE; /* using stdio, not perlio */
2885 int pid; /* PID of subprocess */
2886 int mode; /* == 'r' if pipe open for reading */
2887 int done; /* subprocess has completed */
2888 int waiting; /* waiting for completion/closure */
2889 int closing; /* my_pclose is closing this pipe */
2890 unsigned long completion; /* termination status of subprocess */
2891 pPipe in; /* pipe in to sub */
2892 pPipe out; /* pipe out of sub */
2893 pPipe err; /* pipe of sub's sys$error */
2894 int in_done; /* true when in pipe finished */
2897 unsigned short xchan; /* channel to debug xterm */
2898 unsigned short xchan_valid; /* channel is assigned */
2901 struct exit_control_block
2903 struct exit_control_block *flink;
2904 unsigned long int (*exit_routine)(void);
2905 unsigned long int arg_count;
2906 unsigned long int *status_address;
2907 unsigned long int exit_status;
2910 typedef struct _closed_pipes Xpipe;
2911 typedef struct _closed_pipes* pXpipe;
2913 struct _closed_pipes {
2914 int pid; /* PID of subprocess */
2915 unsigned long completion; /* termination status of subprocess */
2917 #define NKEEPCLOSED 50
2918 static Xpipe closed_list[NKEEPCLOSED];
2919 static int closed_index = 0;
2920 static int closed_num = 0;
2922 #define RETRY_DELAY "0 ::0.20"
2923 #define MAX_RETRY 50
2925 static int pipe_ef = 0; /* first call to safe_popen inits these*/
2926 static unsigned long mypid;
2927 static unsigned long delaytime[2];
2929 static pInfo open_pipes = NULL;
2930 static $DESCRIPTOR(nl_desc, "NL:");
2932 #define PIPE_COMPLETION_WAIT 30 /* seconds, for EOF/FORCEX wait */
2936 static unsigned long int
2937 pipe_exit_routine(void)
2940 unsigned long int retsts = SS$_NORMAL, abort = SS$_TIMEOUT;
2941 int sts, did_stuff, j;
2944 * Flush any pending i/o, but since we are in process run-down, be
2945 * careful about referencing PerlIO structures that may already have
2946 * been deallocated. We may not even have an interpreter anymore.
2951 #if defined(PERL_IMPLICIT_CONTEXT)
2952 /* We need to use the Perl context of the thread that created */
2956 aTHX = info->err->thx;
2958 aTHX = info->out->thx;
2960 aTHX = info->in->thx;
2963 #if defined(USE_ITHREADS)
2967 && PL_perlio_fd_refcnt
2970 PerlIO_flush(info->fp);
2972 fflush((FILE *)info->fp);
2978 next we try sending an EOF...ignore if doesn't work, make sure we
2985 _ckvmssts_noperl(sys$setast(0));
2986 if (info->in && !info->in->shut_on_empty) {
2987 _ckvmssts_noperl(sys$qio(0,info->in->chan_in,IO$_WRITEOF,0,0,0,
2992 _ckvmssts_noperl(sys$setast(1));
2996 /* wait for EOF to have effect, up to ~ 30 sec [default] */
2998 for (j = 0; did_stuff && j < PIPE_COMPLETION_WAIT; j++) {
3003 _ckvmssts_noperl(sys$setast(0));
3004 if (info->waiting && info->done)
3006 nwait += info->waiting;
3007 _ckvmssts_noperl(sys$setast(1));
3017 _ckvmssts_noperl(sys$setast(0));
3018 if (!info->done) { /* Tap them gently on the shoulder . . .*/
3019 sts = sys$forcex(&info->pid,0,&abort);
3020 if (!(sts&1) && sts != SS$_NONEXPR) _ckvmssts_noperl(sts);
3023 _ckvmssts_noperl(sys$setast(1));
3027 /* again, wait for effect */
3029 for (j = 0; did_stuff && j < PIPE_COMPLETION_WAIT; j++) {
3034 _ckvmssts_noperl(sys$setast(0));
3035 if (info->waiting && info->done)
3037 nwait += info->waiting;
3038 _ckvmssts_noperl(sys$setast(1));
3047 _ckvmssts_noperl(sys$setast(0));
3048 if (!info->done) { /* We tried to be nice . . . */
3049 sts = sys$delprc(&info->pid,0);
3050 if (!(sts&1) && sts != SS$_NONEXPR) _ckvmssts_noperl(sts);
3051 info->done = 1; /* sys$delprc is as done as we're going to get. */
3053 _ckvmssts_noperl(sys$setast(1));
3059 #if defined(PERL_IMPLICIT_CONTEXT)
3060 /* We need to use the Perl context of the thread that created */
3063 if (open_pipes->err)
3064 aTHX = open_pipes->err->thx;
3065 else if (open_pipes->out)
3066 aTHX = open_pipes->out->thx;
3067 else if (open_pipes->in)
3068 aTHX = open_pipes->in->thx;
3070 if ((sts = my_pclose(open_pipes->fp)) == -1) retsts = vaxc$errno;
3071 else if (!(sts & 1)) retsts = sts;
3076 static struct exit_control_block pipe_exitblock =
3077 {(struct exit_control_block *) 0,
3078 pipe_exit_routine, 0, &pipe_exitblock.exit_status, 0};
3080 static void pipe_mbxtofd_ast(pPipe p);
3081 static void pipe_tochild1_ast(pPipe p);
3082 static void pipe_tochild2_ast(pPipe p);
3085 popen_completion_ast(pInfo info)
3087 pInfo i = open_pipes;
3090 info->completion &= 0x0FFFFFFF; /* strip off "control" field */
3091 closed_list[closed_index].pid = info->pid;
3092 closed_list[closed_index].completion = info->completion;
3094 if (closed_index == NKEEPCLOSED)
3099 if (i == info) break;
3102 if (!i) return; /* unlinked, probably freed too */
3107 Writing to subprocess ...
3108 if my_pclose'd: EOF already sent, should shutdown chan_in part of pipe
3110 chan_out may be waiting for "done" flag, or hung waiting
3111 for i/o completion to child...cancel the i/o. This will
3112 put it into "snarf mode" (done but no EOF yet) that discards
3115 Output from subprocess (stdout, stderr) needs to be flushed and
3116 shut down. We try sending an EOF, but if the mbx is full the pipe
3117 routine should still catch the "shut_on_empty" flag, telling it to
3118 use immediate-style reads so that "mbx empty" -> EOF.
3122 if (info->in && !info->in_done) { /* only for mode=w */
3123 if (info->in->shut_on_empty && info->in->need_wake) {
3124 info->in->need_wake = FALSE;
3125 _ckvmssts_noperl(sys$dclast(pipe_tochild2_ast,info->in,0));
3127 _ckvmssts_noperl(sys$cancel(info->in->chan_out));
3131 if (info->out && !info->out_done) { /* were we also piping output? */
3132 info->out->shut_on_empty = TRUE;
3133 iss = sys$qio(0,info->out->chan_in,IO$_WRITEOF|IO$M_NORSWAIT, 0, 0, 0, 0, 0, 0, 0, 0, 0);
3134 if (iss == SS$_MBFULL) iss = SS$_NORMAL;
3135 _ckvmssts_noperl(iss);
3138 if (info->err && !info->err_done) { /* we were piping stderr */
3139 info->err->shut_on_empty = TRUE;
3140 iss = sys$qio(0,info->err->chan_in,IO$_WRITEOF|IO$M_NORSWAIT, 0, 0, 0, 0, 0, 0, 0, 0, 0);
3141 if (iss == SS$_MBFULL) iss = SS$_NORMAL;
3142 _ckvmssts_noperl(iss);
3144 _ckvmssts_noperl(sys$setef(pipe_ef));
3148 static unsigned long int setup_cmddsc(pTHX_ const char *cmd, int check_img, int *suggest_quote, struct dsc$descriptor_s **pvmscmd);
3149 static void vms_execfree(struct dsc$descriptor_s *vmscmd);
3150 static void pipe_infromchild_ast(pPipe p);
3153 I'm using LIB$(GET|FREE)_VM here so that we can allocate and deallocate
3154 inside an AST routine without worrying about reentrancy and which Perl
3155 memory allocator is being used.
3157 We read data and queue up the buffers, then spit them out one at a
3158 time to the output mailbox when the output mailbox is ready for one.
3161 #define INITIAL_TOCHILDQUEUE 2
3164 pipe_tochild_setup(pTHX_ char *rmbx, char *wmbx)
3168 char mbx1[64], mbx2[64];
3169 struct dsc$descriptor_s d_mbx1 = {sizeof mbx1, DSC$K_DTYPE_T,
3170 DSC$K_CLASS_S, mbx1},
3171 d_mbx2 = {sizeof mbx2, DSC$K_DTYPE_T,
3172 DSC$K_CLASS_S, mbx2};
3173 unsigned int dviitm = DVI$_DEVBUFSIZ;
3177 _ckvmssts_noperl(lib$get_vm(&n, &p));
3179 create_mbx(&p->chan_in , &d_mbx1);
3180 create_mbx(&p->chan_out, &d_mbx2);
3181 _ckvmssts_noperl(lib$getdvi(&dviitm, &p->chan_in, 0, &p->bufsize));
3184 p->shut_on_empty = FALSE;
3185 p->need_wake = FALSE;
3188 p->iosb.status = SS$_NORMAL;
3189 p->iosb2.status = SS$_NORMAL;
3195 #ifdef PERL_IMPLICIT_CONTEXT
3199 n = sizeof(CBuf) + p->bufsize;
3201 for (j = 0; j < INITIAL_TOCHILDQUEUE; j++) {
3202 _ckvmssts_noperl(lib$get_vm(&n, &b));
3203 b->buf = (char *) b + sizeof(CBuf);
3204 _ckvmssts_noperl(lib$insqhi(b, &p->free));
3207 pipe_tochild2_ast(p);
3208 pipe_tochild1_ast(p);
3214 /* reads the MBX Perl is writing, and queues */
3217 pipe_tochild1_ast(pPipe p)
3220 int iss = p->iosb.status;
3221 int eof = (iss == SS$_ENDOFFILE);
3223 #ifdef PERL_IMPLICIT_CONTEXT
3229 p->shut_on_empty = TRUE;
3231 _ckvmssts_noperl(sys$dassgn(p->chan_in));
3233 _ckvmssts_noperl(iss);
3237 b->size = p->iosb.count;
3238 _ckvmssts_noperl(sts = lib$insqhi(b, &p->wait));
3240 p->need_wake = FALSE;
3241 _ckvmssts_noperl(sys$dclast(pipe_tochild2_ast,p,0));
3244 p->retry = 1; /* initial call */
3247 if (eof) { /* flush the free queue, return when done */
3248 int n = sizeof(CBuf) + p->bufsize;
3250 iss = lib$remqti(&p->free, &b);
3251 if (iss == LIB$_QUEWASEMP) return;
3252 _ckvmssts_noperl(iss);
3253 _ckvmssts_noperl(lib$free_vm(&n, &b));
3257 iss = lib$remqti(&p->free, &b);
3258 if (iss == LIB$_QUEWASEMP) {
3259 int n = sizeof(CBuf) + p->bufsize;
3260 _ckvmssts_noperl(lib$get_vm(&n, &b));
3261 b->buf = (char *) b + sizeof(CBuf);
3263 _ckvmssts_noperl(iss);
3267 iss = sys$qio(0,p->chan_in,
3268 IO$_READVBLK|(p->shut_on_empty ? IO$M_NOWAIT : 0),
3270 pipe_tochild1_ast, p, b->buf, p->bufsize, 0, 0, 0, 0);
3271 if (iss == SS$_ENDOFFILE && p->shut_on_empty) iss = SS$_NORMAL;
3272 _ckvmssts_noperl(iss);
3276 /* writes queued buffers to output, waits for each to complete before
3280 pipe_tochild2_ast(pPipe p)
3283 int iss = p->iosb2.status;
3284 int n = sizeof(CBuf) + p->bufsize;
3285 int done = (p->info && p->info->done) ||
3286 iss == SS$_CANCEL || iss == SS$_ABORT;
3287 #if defined(PERL_IMPLICIT_CONTEXT)
3292 if (p->type) { /* type=1 has old buffer, dispose */
3293 if (p->shut_on_empty) {
3294 _ckvmssts_noperl(lib$free_vm(&n, &b));
3296 _ckvmssts_noperl(lib$insqhi(b, &p->free));
3301 iss = lib$remqti(&p->wait, &b);
3302 if (iss == LIB$_QUEWASEMP) {
3303 if (p->shut_on_empty) {
3305 _ckvmssts_noperl(sys$dassgn(p->chan_out));
3306 *p->pipe_done = TRUE;
3307 _ckvmssts_noperl(sys$setef(pipe_ef));
3309 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEOF,
3310 &p->iosb2, pipe_tochild2_ast, p, 0, 0, 0, 0, 0, 0));
3314 p->need_wake = TRUE;
3317 _ckvmssts_noperl(iss);
3324 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEOF,
3325 &p->iosb2, pipe_tochild2_ast, p, 0, 0, 0, 0, 0, 0));
3327 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEVBLK,
3328 &p->iosb2, pipe_tochild2_ast, p, b->buf, b->size, 0, 0, 0, 0));
3337 pipe_infromchild_setup(pTHX_ char *rmbx, char *wmbx)
3340 char mbx1[64], mbx2[64];
3341 struct dsc$descriptor_s d_mbx1 = {sizeof mbx1, DSC$K_DTYPE_T,
3342 DSC$K_CLASS_S, mbx1},
3343 d_mbx2 = {sizeof mbx2, DSC$K_DTYPE_T,
3344 DSC$K_CLASS_S, mbx2};
3345 unsigned int dviitm = DVI$_DEVBUFSIZ;
3347 int n = sizeof(Pipe);
3348 _ckvmssts_noperl(lib$get_vm(&n, &p));
3349 create_mbx(&p->chan_in , &d_mbx1);
3350 create_mbx(&p->chan_out, &d_mbx2);
3352 _ckvmssts_noperl(lib$getdvi(&dviitm, &p->chan_in, 0, &p->bufsize));
3353 n = p->bufsize * sizeof(char);
3354 _ckvmssts_noperl(lib$get_vm(&n, &p->buf));
3355 p->shut_on_empty = FALSE;
3358 p->iosb.status = SS$_NORMAL;
3359 #if defined(PERL_IMPLICIT_CONTEXT)
3362 pipe_infromchild_ast(p);
3370 pipe_infromchild_ast(pPipe p)
3372 int iss = p->iosb.status;
3373 int eof = (iss == SS$_ENDOFFILE);
3374 int myeof = (eof && (p->iosb.dvispec == mypid || p->iosb.dvispec == 0));
3375 int kideof = (eof && (p->iosb.dvispec == p->info->pid));
3376 #if defined(PERL_IMPLICIT_CONTEXT)
3380 if (p->info && p->info->closing && p->chan_out) { /* output shutdown */
3381 _ckvmssts_noperl(sys$dassgn(p->chan_out));
3386 input shutdown if EOF from self (done or shut_on_empty)
3387 output shutdown if closing flag set (my_pclose)
3388 send data/eof from child or eof from self
3389 otherwise, re-read (snarf of data from child)
3394 if (myeof && p->chan_in) { /* input shutdown */
3395 _ckvmssts_noperl(sys$dassgn(p->chan_in));
3400 if (myeof || kideof) { /* pass EOF to parent */
3401 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEOF, &p->iosb,
3402 pipe_infromchild_ast, p,
3405 } else if (eof) { /* eat EOF --- fall through to read*/
3407 } else { /* transmit data */
3408 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEVBLK,&p->iosb,
3409 pipe_infromchild_ast,p,
3410 p->buf, p->iosb.count, 0, 0, 0, 0));
3416 /* everything shut? flag as done */
3418 if (!p->chan_in && !p->chan_out) {
3419 *p->pipe_done = TRUE;
3420 _ckvmssts_noperl(sys$setef(pipe_ef));
3424 /* write completed (or read, if snarfing from child)
3425 if still have input active,
3426 queue read...immediate mode if shut_on_empty so we get EOF if empty
3428 check if Perl reading, generate EOFs as needed
3434 iss = sys$qio(0,p->chan_in,IO$_READVBLK|(p->shut_on_empty ? IO$M_NOW : 0),&p->iosb,
3435 pipe_infromchild_ast,p,
3436 p->buf, p->bufsize, 0, 0, 0, 0);
3437 if (p->shut_on_empty && iss == SS$_ENDOFFILE) iss = SS$_NORMAL;
3438 _ckvmssts_noperl(iss);
3439 } else { /* send EOFs for extra reads */
3440 p->iosb.status = SS$_ENDOFFILE;
3441 p->iosb.dvispec = 0;
3442 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_SETMODE|IO$M_READATTN,
3444 pipe_infromchild_ast, p, 0, 0, 0, 0));
3450 pipe_mbxtofd_setup(pTHX_ int fd, char *out)
3454 unsigned long dviitm = DVI$_DEVBUFSIZ;
3456 struct dsc$descriptor_s d_mbx = {sizeof mbx, DSC$K_DTYPE_T,
3457 DSC$K_CLASS_S, mbx};
3458 int n = sizeof(Pipe);
3460 /* things like terminals and mbx's don't need this filter */
3461 if (fd && fstat(fd,&s) == 0) {
3462 unsigned long devchar;
3464 unsigned short dev_len;
3465 struct dsc$descriptor_s d_dev;
3467 struct item_list_3 items[3];
3469 unsigned short dvi_iosb[4];
3471 cptr = getname(fd, out, 1);
3472 if (cptr == NULL) _ckvmssts_noperl(SS$_NOSUCHDEV);
3473 d_dev.dsc$a_pointer = out;
3474 d_dev.dsc$w_length = strlen(out);
3475 d_dev.dsc$b_dtype = DSC$K_DTYPE_T;
3476 d_dev.dsc$b_class = DSC$K_CLASS_S;
3479 items[0].code = DVI$_DEVCHAR;
3480 items[0].bufadr = &devchar;
3481 items[0].retadr = NULL;
3483 items[1].code = DVI$_FULLDEVNAM;
3484 items[1].bufadr = device;
3485 items[1].retadr = &dev_len;
3489 status = sys$getdviw
3490 (NO_EFN, 0, &d_dev, items, dvi_iosb, NULL, NULL, NULL);
3491 _ckvmssts_noperl(status);
3492 if ($VMS_STATUS_SUCCESS(dvi_iosb[0])) {
3493 device[dev_len] = 0;
3495 if (!(devchar & DEV$M_DIR)) {
3496 strcpy(out, device);
3502 _ckvmssts_noperl(lib$get_vm(&n, &p));
3503 p->fd_out = dup(fd);
3504 create_mbx(&p->chan_in, &d_mbx);
3505 _ckvmssts_noperl(lib$getdvi(&dviitm, &p->chan_in, 0, &p->bufsize));
3506 n = (p->bufsize+1) * sizeof(char);
3507 _ckvmssts_noperl(lib$get_vm(&n, &p->buf));
3508 p->shut_on_empty = FALSE;
3513 _ckvmssts_noperl(sys$qio(0, p->chan_in, IO$_READVBLK, &p->iosb,
3514 pipe_mbxtofd_ast, p,
3515 p->buf, p->bufsize, 0, 0, 0, 0));
3521 pipe_mbxtofd_ast(pPipe p)
3523 int iss = p->iosb.status;
3524 int done = p->info->done;
3526 int eof = (iss == SS$_ENDOFFILE);
3527 int myeof = eof && ((p->iosb.dvispec == mypid)||(p->iosb.dvispec == 0));
3528 int err = !(iss&1) && !eof;
3529 #if defined(PERL_IMPLICIT_CONTEXT)
3533 if (done && myeof) { /* end piping */
3535 sys$dassgn(p->chan_in);
3536 *p->pipe_done = TRUE;
3537 _ckvmssts_noperl(sys$setef(pipe_ef));
3541 if (!err && !eof) { /* good data to send to file */
3542 p->buf[p->iosb.count] = '\n';
3543 iss2 = write(p->fd_out, p->buf, p->iosb.count+1);
3546 if (p->retry < MAX_RETRY) {
3547 _ckvmssts_noperl(sys$setimr(0,delaytime,pipe_mbxtofd_ast,p));
3553 _ckvmssts_noperl(iss);
3557 iss = sys$qio(0, p->chan_in, IO$_READVBLK|(p->shut_on_empty ? IO$M_NOW : 0), &p->iosb,
3558 pipe_mbxtofd_ast, p,
3559 p->buf, p->bufsize, 0, 0, 0, 0);
3560 if (p->shut_on_empty && (iss == SS$_ENDOFFILE)) iss = SS$_NORMAL;
3561 _ckvmssts_noperl(iss);
3565 typedef struct _pipeloc PLOC;
3566 typedef struct _pipeloc* pPLOC;
3570 char dir[NAM$C_MAXRSS+1];
3572 static pPLOC head_PLOC = 0;
3575 free_pipelocs(pTHX_ void *head)
3578 pPLOC *pHead = (pPLOC *)head;
3590 store_pipelocs(pTHX)
3598 char temp[NAM$C_MAXRSS+1];
3602 free_pipelocs(aTHX_ &head_PLOC);
3604 /* the . directory from @INC comes last */
3606 p = (pPLOC) PerlMem_malloc(sizeof(PLOC));
3607 if (p == NULL) _ckvmssts_noperl(SS$_INSFMEM);
3608 p->next = head_PLOC;
3610 strcpy(p->dir,"./");
3612 /* get the directory from $^X */
3614 unixdir = (char *)PerlMem_malloc(VMS_MAXRSS);
3615 if (unixdir == NULL) _ckvmssts_noperl(SS$_INSFMEM);
3617 #ifdef PERL_IMPLICIT_CONTEXT
3618 if (aTHX && PL_origargv && PL_origargv[0]) { /* maybe nul if embedded Perl */
3620 if (PL_origargv && PL_origargv[0]) { /* maybe nul if embedded Perl */
3622 my_strlcpy(temp, PL_origargv[0], sizeof(temp));
3623 x = strrchr(temp,']');
3625 x = strrchr(temp,'>');
3627 /* It could be a UNIX path */
3628 x = strrchr(temp,'/');
3634 /* Got a bare name, so use default directory */
3639 if ((tounixpath_utf8(temp, unixdir, NULL)) != NULL) {
3640 p = (pPLOC) PerlMem_malloc(sizeof(PLOC));
3641 if (p == NULL) _ckvmssts_noperl(SS$_INSFMEM);
3642 p->next = head_PLOC;
3644 my_strlcpy(p->dir, unixdir, sizeof(p->dir));
3648 /* reverse order of @INC entries, skip "." since entered above */
3650 #ifdef PERL_IMPLICIT_CONTEXT
3653 if (PL_incgv) av = GvAVn(PL_incgv);
3655 for (i = 0; av && i <= AvFILL(av); i++) {
3656 dirsv = *av_fetch(av,i,TRUE);
3658 if (SvROK(dirsv)) continue;
3659 dir = SvPVx(dirsv,n_a);
3660 if (strcmp(dir,".") == 0) continue;
3661 if ((tounixpath_utf8(dir, unixdir, NULL)) == NULL)
3664 p = (pPLOC) PerlMem_malloc(sizeof(PLOC));
3665 p->next = head_PLOC;
3667 my_strlcpy(p->dir, unixdir, sizeof(p->dir));
3670 /* most likely spot (ARCHLIB) put first in the list */
3673 if ((tounixpath_utf8(ARCHLIB_EXP, unixdir, NULL)) != NULL) {
3674 p = (pPLOC) PerlMem_malloc(sizeof(PLOC));
3675 if (p == NULL) _ckvmssts_noperl(SS$_INSFMEM);
3676 p->next = head_PLOC;
3678 my_strlcpy(p->dir, unixdir, sizeof(p->dir));
3681 PerlMem_free(unixdir);
3685 Perl_cando_by_name_int
3686 (pTHX_ I32 bit, bool effective, const char *fname, int opts);
3687 #if !defined(PERL_IMPLICIT_CONTEXT)
3688 #define cando_by_name_int Perl_cando_by_name_int
3690 #define cando_by_name_int(a,b,c,d) Perl_cando_by_name_int(aTHX_ a,b,c,d)
3696 static int vmspipe_file_status = 0;
3697 static char vmspipe_file[NAM$C_MAXRSS+1];
3699 /* already found? Check and use ... need read+execute permission */
3701 if (vmspipe_file_status == 1) {
3702 if (cando_by_name_int(S_IRUSR, 0, vmspipe_file, PERL_RMSEXPAND_M_VMS_IN)
3703 && cando_by_name_int
3704 (S_IXUSR, 0, vmspipe_file, PERL_RMSEXPAND_M_VMS_IN)) {
3705 return vmspipe_file;
3707 vmspipe_file_status = 0;
3710 /* scan through stored @INC, $^X */
3712 if (vmspipe_file_status == 0) {
3713 char file[NAM$C_MAXRSS+1];
3714 pPLOC p = head_PLOC;
3719 dirlen = my_strlcpy(file, p->dir, sizeof(file));
3720 my_strlcat(file, "vmspipe.com", sizeof(file));
3723 exp_res = int_rmsexpand_tovms(file, vmspipe_file, 0);
3724 if (!exp_res) continue;
3726 if (cando_by_name_int
3727 (S_IRUSR, 0, vmspipe_file, PERL_RMSEXPAND_M_VMS_IN)
3728 && cando_by_name_int
3729 (S_IXUSR, 0, vmspipe_file, PERL_RMSEXPAND_M_VMS_IN)) {
3730 vmspipe_file_status = 1;
3731 return vmspipe_file;
3734 vmspipe_file_status = -1; /* failed, use tempfiles */
3741 vmspipe_tempfile(pTHX)
3743 char file[NAM$C_MAXRSS+1];
3745 static int index = 0;
3749 /* create a tempfile */
3751 /* we can't go from W, shr=get to R, shr=get without
3752 an intermediate vulnerable state, so don't bother trying...
3754 and lib$spawn doesn't shr=put, so have to close the write
3756 So... match up the creation date/time and the FID to
3757 make sure we're dealing with the same file
3762 if (!decc_filename_unix_only) {
3763 sprintf(file,"sys$scratch:perlpipe_%08.8x_%d.com",mypid,index);
3764 fp = fopen(file,"w");
3766 sprintf(file,"sys$login:perlpipe_%08.8x_%d.com",mypid,index);
3767 fp = fopen(file,"w");
3769 sprintf(file,"sys$disk:[]perlpipe_%08.8x_%d.com",mypid,index);
3770 fp = fopen(file,"w");
3775 sprintf(file,"/tmp/perlpipe_%08.8x_%d.com",mypid,index);
3776 fp = fopen(file,"w");
3778 sprintf(file,"/sys$login/perlpipe_%08.8x_%d.com",mypid,index);
3779 fp = fopen(file,"w");
3781 sprintf(file,"./perlpipe_%08.8x_%d.com",mypid,index);
3782 fp = fopen(file,"w");
3786 if (!fp) return 0; /* we're hosed */
3788 fprintf(fp,"$! 'f$verify(0)'\n");
3789 fprintf(fp,"$! --- protect against nonstandard definitions ---\n");
3790 fprintf(fp,"$ perl_cfile = f$environment(\"procedure\")\n");
3791 fprintf(fp,"$ perl_define = \"define/nolog\"\n");
3792 fprintf(fp,"$ perl_on = \"set noon\"\n");
3793 fprintf(fp,"$ perl_exit = \"exit\"\n");
3794 fprintf(fp,"$ perl_del = \"delete\"\n");
3795 fprintf(fp,"$ pif = \"if\"\n");
3796 fprintf(fp,"$! --- define i/o redirection (sys$output set by lib$spawn)\n");
3797 fprintf(fp,"$ pif perl_popen_in .nes. \"\" then perl_define/user/name_attributes=confine sys$input 'perl_popen_in'\n");
3798 fprintf(fp,"$ pif perl_popen_err .nes. \"\" then perl_define/user/name_attributes=confine sys$error 'perl_popen_err'\n");
3799 fprintf(fp,"$ pif perl_popen_out .nes. \"\" then perl_define sys$output 'perl_popen_out'\n");
3800 fprintf(fp,"$! --- build command line to get max possible length\n");
3801 fprintf(fp,"$c=perl_popen_cmd0\n");
3802 fprintf(fp,"$c=c+perl_popen_cmd1\n");
3803 fprintf(fp,"$c=c+perl_popen_cmd2\n");
3804 fprintf(fp,"$x=perl_popen_cmd3\n");
3805 fprintf(fp,"$c=c+x\n");
3806 fprintf(fp,"$ perl_on\n");
3807 fprintf(fp,"$ 'c'\n");
3808 fprintf(fp,"$ perl_status = $STATUS\n");
3809 fprintf(fp,"$ perl_del 'perl_cfile'\n");
3810 fprintf(fp,"$ perl_exit 'perl_status'\n");
3813 fgetname(fp, file, 1);
3814 fstat(fileno(fp), &s0.crtl_stat);
3817 if (decc_filename_unix_only)
3818 int_tounixspec(file, file, NULL);
3819 fp = fopen(file,"r","shr=get");
3821 fstat(fileno(fp), &s1.crtl_stat);
3823 cmp_result = VMS_INO_T_COMPARE(s0.crtl_stat.st_ino, s1.crtl_stat.st_ino);
3824 if ((cmp_result != 0) && (s0.st_ctime != s1.st_ctime)) {
3833 static int vms_is_syscommand_xterm(void)
3835 const static struct dsc$descriptor_s syscommand_dsc =
3836 { 11, DSC$K_DTYPE_T, DSC$K_CLASS_S, "SYS$COMMAND" };
3838 const static struct dsc$descriptor_s decwdisplay_dsc =
3839 { 12, DSC$K_DTYPE_T, DSC$K_CLASS_S, "DECW$DISPLAY" };
3841 struct item_list_3 items[2];
3842 unsigned short dvi_iosb[4];
3843 unsigned long devchar;
3844 unsigned long devclass;
3847 /* Very simple check to guess if sys$command is a decterm? */
3848 /* First see if the DECW$DISPLAY: device exists */
3850 items[0].code = DVI$_DEVCHAR;
3851 items[0].bufadr = &devchar;
3852 items[0].retadr = NULL;
3856 status = sys$getdviw
3857 (NO_EFN, 0, &decwdisplay_dsc, items, dvi_iosb, NULL, NULL, NULL);
3859 if ($VMS_STATUS_SUCCESS(status)) {
3860 status = dvi_iosb[0];
3863 if (!$VMS_STATUS_SUCCESS(status)) {
3864 SETERRNO(EVMSERR, status);
3868 /* If it does, then for now assume that we are on a workstation */
3869 /* Now verify that SYS$COMMAND is a terminal */
3870 /* for creating the debugger DECTerm */
3873 items[0].code = DVI$_DEVCLASS;
3874 items[0].bufadr = &devclass;
3875 items[0].retadr = NULL;
3879 status = sys$getdviw
3880 (NO_EFN, 0, &syscommand_dsc, items, dvi_iosb, NULL, NULL, NULL);
3882 if ($VMS_STATUS_SUCCESS(status)) {
3883 status = dvi_iosb[0];
3886 if (!$VMS_STATUS_SUCCESS(status)) {
3887 SETERRNO(EVMSERR, status);
3891 if (devclass == DC$_TERM) {
3898 /* If we are on a DECTerm, we can pretend to fork xterms when requested */
3899 static PerlIO * create_forked_xterm(pTHX_ const char *cmd, const char *mode)
3904 char device_name[65];
3905 unsigned short device_name_len;
3906 struct dsc$descriptor_s customization_dsc;
3907 struct dsc$descriptor_s device_name_dsc;
3909 char customization[200];
3913 unsigned short p_chan;
3915 unsigned short iosb[4];
3916 const char * cust_str =
3917 "DECW$TERMINAL.iconName:\tPerl Dbg\nDECW$TERMINAL.title:\t%40s\n";
3918 struct dsc$descriptor_s d_mbx1 = {sizeof mbx1, DSC$K_DTYPE_T,
3919 DSC$K_CLASS_S, mbx1};
3921 /* LIB$FIND_IMAGE_SIGNAL needs a handler */
3922 /*---------------------------------------*/
3923 VAXC$ESTABLISH((__vms_handler)lib$sig_to_ret);
3926 /* Make sure that this is from the Perl debugger */
3927 ret_char = strstr(cmd," xterm ");
3928 if (ret_char == NULL)
3930 cptr = ret_char + 7;
3931 ret_char = strstr(cmd,"tty");
3932 if (ret_char == NULL)
3934 ret_char = strstr(cmd,"sleep");
3935 if (ret_char == NULL)
3938 if (decw_term_port == 0) {
3939 $DESCRIPTOR(filename1_dsc, "DECW$TERMINALSHR12");
3940 $DESCRIPTOR(filename2_dsc, "DECW$TERMINALSHR");
3941 $DESCRIPTOR(decw_term_port_dsc, "DECW$TERM_PORT");
3943 status = lib$find_image_symbol
3945 &decw_term_port_dsc,
3946 (void *)&decw_term_port,
3950 /* Try again with the other image name */
3951 if (!$VMS_STATUS_SUCCESS(status)) {
3953 status = lib$find_image_symbol
3955 &decw_term_port_dsc,
3956 (void *)&decw_term_port,
3965 /* No decw$term_port, give it up */
3966 if (!$VMS_STATUS_SUCCESS(status))
3969 /* Are we on a workstation? */
3970 /* to do: capture the rows / columns and pass their properties */
3971 ret_stat = vms_is_syscommand_xterm();
3975 /* Make the title: */
3976 ret_char = strstr(cptr,"-title");
3977 if (ret_char != NULL) {
3978 while ((*cptr != 0) && (*cptr != '\"')) {
3984 while ((*cptr != 0) && (*cptr != '\"')) {
3997 strcpy(title,"Perl Debug DECTerm");
3999 sprintf(customization, cust_str, title);
4001 customization_dsc.dsc$a_pointer = customization;
4002 customization_dsc.dsc$w_length = strlen(customization);
4003 customization_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
4004 customization_dsc.dsc$b_class = DSC$K_CLASS_S;
4006 device_name_dsc.dsc$a_pointer = device_name;
4007 device_name_dsc.dsc$w_length = sizeof device_name -1;
4008 device_name_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
4009 device_name_dsc.dsc$b_class = DSC$K_CLASS_S;
4011 device_name_len = 0;
4013 /* Try to create the window */
4014 status = (*decw_term_port)
4023 if (!$VMS_STATUS_SUCCESS(status)) {
4024 SETERRNO(EVMSERR, status);
4028 device_name[device_name_len] = '\0';
4030 /* Need to set this up to look like a pipe for cleanup */
4032 status = lib$get_vm(&n, &info);
4033 if (!$VMS_STATUS_SUCCESS(status)) {
4034 SETERRNO(ENOMEM, status);
4040 info->completion = 0;
4041 info->closing = FALSE;
4048 info->in_done = TRUE;
4049 info->out_done = TRUE;
4050 info->err_done = TRUE;
4052 /* Assign a channel on this so that it will persist, and not login */
4053 /* We stash this channel in the info structure for reference. */
4054 /* The created xterm self destructs when the last channel is removed */
4055 /* and it appears that perl5db.pl (perl debugger) does this routinely */
4056 /* So leave this assigned. */
4057 device_name_dsc.dsc$w_length = device_name_len;
4058 status = sys$assign(&device_name_dsc,&info->xchan,0,0);
4059 if (!$VMS_STATUS_SUCCESS(status)) {
4060 SETERRNO(EVMSERR, status);
4063 info->xchan_valid = 1;
4065 /* Now create a mailbox to be read by the application */
4067 create_mbx(&p_chan, &d_mbx1);
4069 /* write the name of the created terminal to the mailbox */
4070 status = sys$qiow(NO_EFN, p_chan, IO$_WRITEVBLK|IO$M_NOW,
4071 iosb, NULL, NULL, device_name, device_name_len, 0, 0, 0, 0);
4073 if (!$VMS_STATUS_SUCCESS(status)) {
4074 SETERRNO(EVMSERR, status);
4078 info->fp = PerlIO_open(mbx1, mode);
4080 /* Done with this channel */
4083 /* If any errors, then clean up */
4086 _ckvmssts_noperl(lib$free_vm(&n, &info));
4094 static I32 my_pclose_pinfo(pTHX_ pInfo info);
4097 safe_popen(pTHX_ const char *cmd, const char *in_mode, int *psts)
4099 static int handler_set_up = FALSE;
4101 unsigned long int sts, flags = CLI$M_NOWAIT;
4102 /* The use of a GLOBAL table (as was done previously) rendered
4103 * Perl's qx() or `` unusable from a C<$ SET SYMBOL/SCOPE=NOGLOBAL> DCL
4104 * environment. Hence we've switched to LOCAL symbol table.
4106 unsigned int table = LIB$K_CLI_LOCAL_SYM;
4108 char *p, mode[10], symbol[MAX_DCL_SYMBOL+1], *vmspipe;
4109 char *in, *out, *err, mbx[512];
4111 char tfilebuf[NAM$C_MAXRSS+1];
4113 char cmd_sym_name[20];
4114 struct dsc$descriptor_s d_symbol= {0, DSC$K_DTYPE_T,
4115 DSC$K_CLASS_S, symbol};
4116 struct dsc$descriptor_s vmspipedsc = {0, DSC$K_DTYPE_T,
4118 struct dsc$descriptor_s d_sym_cmd = {0, DSC$K_DTYPE_T,
4119 DSC$K_CLASS_S, cmd_sym_name};
4120 struct dsc$descriptor_s *vmscmd;
4121 $DESCRIPTOR(d_sym_in ,"PERL_POPEN_IN");
4122 $DESCRIPTOR(d_sym_out,"PERL_POPEN_OUT");
4123 $DESCRIPTOR(d_sym_err,"PERL_POPEN_ERR");
4125 /* Check here for Xterm create request. This means looking for
4126 * "3>&1 xterm\b" and "\btty 1>&3\b$" in the command, and that it
4127 * is possible to create an xterm.
4129 if (*in_mode == 'r') {
4132 #if defined(PERL_IMPLICIT_CONTEXT)
4133 /* Can not fork an xterm with a NULL context */
4134 /* This probably could never happen */
4138 xterm_fd = create_forked_xterm(aTHX_ cmd, in_mode);
4139 if (xterm_fd != NULL)
4143 if (!head_PLOC) store_pipelocs(aTHX); /* at least TRY to use a static vmspipe file */
4145 /* once-per-program initialization...
4146 note that the SETAST calls and the dual test of pipe_ef
4147 makes sure that only the FIRST thread through here does
4148 the initialization...all other threads wait until it's
4151 Yeah, uglier than a pthread call, it's got all the stuff inline
4152 rather than in a separate routine.
4156 _ckvmssts_noperl(sys$setast(0));
4158 unsigned long int pidcode = JPI$_PID;
4159 $DESCRIPTOR(d_delay, RETRY_DELAY);
4160 _ckvmssts_noperl(lib$get_ef(&pipe_ef));
4161 _ckvmssts_noperl(lib$getjpi(&pidcode,0,0,&mypid,0,0));
4162 _ckvmssts_noperl(sys$bintim(&d_delay, delaytime));
4164 if (!handler_set_up) {
4165 _ckvmssts_noperl(sys$dclexh(&pipe_exitblock));
4166 handler_set_up = TRUE;
4168 _ckvmssts_noperl(sys$setast(1));
4171 /* see if we can find a VMSPIPE.COM */
4174 vmspipe = find_vmspipe(aTHX);
4176 vmspipedsc.dsc$w_length = my_strlcpy(tfilebuf+1, vmspipe, sizeof(tfilebuf)-1) + 1;
4177 } else { /* uh, oh...we're in tempfile hell */
4178 tpipe = vmspipe_tempfile(aTHX);
4179 if (!tpipe) { /* a fish popular in Boston */
4180 if (ckWARN(WARN_PIPE)) {
4181 Perl_warner(aTHX_ packWARN(WARN_PIPE),"unable to find VMSPIPE.COM for i/o piping");
4185 fgetname(tpipe,tfilebuf+1,1);
4186 vmspipedsc.dsc$w_length = strlen(tfilebuf);
4188 vmspipedsc.dsc$a_pointer = tfilebuf;
4190 sts = setup_cmddsc(aTHX_ cmd,0,0,&vmscmd);
4193 case RMS$_FNF: case RMS$_DNF:
4194 set_errno(ENOENT); break;
4196 set_errno(ENOTDIR); break;
4198 set_errno(ENODEV); break;
4200 set_errno(EACCES); break;
4202 set_errno(EINVAL); break;
4203 case CLI$_BUFOVF: case RMS$_RTB: case CLI$_TKNOVF: case CLI$_RSLOVF:
4204 set_errno(E2BIG); break;
4205 case LIB$_INVARG: case LIB$_INVSTRDES: case SS$_ACCVIO: /* shouldn't happen */
4206 _ckvmssts_noperl(sts); /* fall through */
4207 default: /* SS$_DUPLNAM, SS$_CLI, resource exhaustion, etc. */
4210 set_vaxc_errno(sts);
4211 if (*in_mode != 'n' && ckWARN(WARN_PIPE)) {
4212 Perl_warner(aTHX_ packWARN(WARN_PIPE),"Can't pipe \"%*s\": %s", strlen(cmd), cmd, Strerror(errno));
4218 _ckvmssts_noperl(lib$get_vm(&n, &info));
4220 my_strlcpy(mode, in_mode, sizeof(mode));
4223 info->completion = 0;
4224 info->closing = FALSE;
4231 info->in_done = TRUE;
4232 info->out_done = TRUE;
4233 info->err_done = TRUE;
4235 info->xchan_valid = 0;
4237 in = (char *)PerlMem_malloc(VMS_MAXRSS);
4238 if (in == NULL) _ckvmssts_noperl(SS$_INSFMEM);
4239 out = (char *)PerlMem_malloc(VMS_MAXRSS);
4240 if (out == NULL) _ckvmssts_noperl(SS$_INSFMEM);
4241 err = (char *)PerlMem_malloc(VMS_MAXRSS);
4242 if (err == NULL) _ckvmssts_noperl(SS$_INSFMEM);
4244 in[0] = out[0] = err[0] = '\0';
4246 if ((p = strchr(mode,'F')) != NULL) { /* F -> use FILE* */
4250 if ((p = strchr(mode,'W')) != NULL) { /* W -> wait for completion */
4255 if (*mode == 'r') { /* piping from subroutine */
4257 info->out = pipe_infromchild_setup(aTHX_ mbx,out);
4259 info->out->pipe_done = &info->out_done;
4260 info->out_done = FALSE;
4261 info->out->info = info;
4263 if (!info->useFILE) {
4264 info->fp = PerlIO_open(mbx, mode);
4266 info->fp = (PerlIO *) freopen(mbx, mode, stdin);
4267 vmssetuserlnm("SYS$INPUT", mbx);
4270 if (!info->fp && info->out) {
4271 sys$cancel(info->out->chan_out);
4273 while (!info->out_done) {
4275 _ckvmssts_noperl(sys$setast(0));
4276 done = info->out_done;
4277 if (!done) _ckvmssts_noperl(sys$clref(pipe_ef));
4278 _ckvmssts_noperl(sys$setast(1));
4279 if (!done) _ckvmssts_noperl(sys$waitfr(pipe_ef));
4282 if (info->out->buf) {
4283 n = info->out->bufsize * sizeof(char);
4284 _ckvmssts_noperl(lib$free_vm(&n, &info->out->buf));
4287 _ckvmssts_noperl(lib$free_vm(&n, &info->out));
4289 _ckvmssts_noperl(lib$free_vm(&n, &info));
4294 info->err = pipe_mbxtofd_setup(aTHX_ fileno(stderr), err);
4296 info->err->pipe_done = &info->err_done;
4297 info->err_done = FALSE;
4298 info->err->info = info;
4301 } else if (*mode == 'w') { /* piping to subroutine */
4303 info->out = pipe_mbxtofd_setup(aTHX_ fileno(stdout), out);
4305 info->out->pipe_done = &info->out_done;
4306 info->out_done = FALSE;
4307 info->out->info = info;
4310 info->err = pipe_mbxtofd_setup(aTHX_ fileno(stderr), err);
4312 info->err->pipe_done = &info->err_done;
4313 info->err_done = FALSE;
4314 info->err->info = info;
4317 info->in = pipe_tochild_setup(aTHX_ in,mbx);
4318 if (!info->useFILE) {
4319 info->fp = PerlIO_open(mbx, mode);
4321 info->fp = (PerlIO *) freopen(mbx, mode, stdout);
4322 vmssetuserlnm("SYS$OUTPUT", mbx);
4326 info->in->pipe_done = &info->in_done;
4327 info->in_done = FALSE;
4328 info->in->info = info;
4332 if (!info->fp && info->in) {
4334 _ckvmssts_noperl(sys$qiow(0,info->in->chan_in, IO$_WRITEOF, 0,
4335 0, 0, 0, 0, 0, 0, 0, 0));
4337 while (!info->in_done) {
4339 _ckvmssts_noperl(sys$setast(0));
4340 done = info->in_done;
4341 if (!done) _ckvmssts_noperl(sys$clref(pipe_ef));
4342 _ckvmssts_noperl(sys$setast(1));
4343 if (!done) _ckvmssts_noperl(sys$waitfr(pipe_ef));
4346 if (info->in->buf) {
4347 n = info->in->bufsize * sizeof(char);
4348 _ckvmssts_noperl(lib$free_vm(&n, &info->in->buf));
4351 _ckvmssts_noperl(lib$free_vm(&n, &info->in));
4353 _ckvmssts_noperl(lib$free_vm(&n, &info));
4359 } else if (*mode == 'n') { /* separate subprocess, no Perl i/o */
4360 info->out = pipe_mbxtofd_setup(aTHX_ fileno(stdout), out);
4362 info->out->pipe_done = &info->out_done;
4363 info->out_done = FALSE;
4364 info->out->info = info;
4367 info->err = pipe_mbxtofd_setup(aTHX_ fileno(stderr), err);
4369 info->err->pipe_done = &info->err_done;
4370 info->err_done = FALSE;
4371 info->err->info = info;
4375 d_symbol.dsc$w_length = my_strlcpy(symbol, in, sizeof(symbol));
4376 _ckvmssts_noperl(lib$set_symbol(&d_sym_in, &d_symbol, &table));
4378 d_symbol.dsc$w_length = my_strlcpy(symbol, err, sizeof(symbol));
4379 _ckvmssts_noperl(lib$set_symbol(&d_sym_err, &d_symbol, &table));
4381 d_symbol.dsc$w_length = my_strlcpy(symbol, out, sizeof(symbol));
4382 _ckvmssts_noperl(lib$set_symbol(&d_sym_out, &d_symbol, &table));
4384 /* Done with the names for the pipes */
4389 p = vmscmd->dsc$a_pointer;
4390 while (*p == ' ' || *p == '\t') p++; /* remove leading whitespace */
4391 if (*p == '$') p++; /* remove leading $ */
4392 while (*p == ' ' || *p == '\t') p++;
4394 for (j = 0; j < 4; j++) {
4395 sprintf(cmd_sym_name,"PERL_POPEN_CMD%d",j);
4396 d_sym_cmd.dsc$w_length = strlen(cmd_sym_name);
4398 d_symbol.dsc$w_length = my_strlcpy(symbol, p, sizeof(symbol));
4399 _ckvmssts_noperl(lib$set_symbol(&d_sym_cmd, &d_symbol, &table));
4401 if (strlen(p) > MAX_DCL_SYMBOL) {
4402 p += MAX_DCL_SYMBOL;
4407 _ckvmssts_noperl(sys$setast(0));
4408 info->next=open_pipes; /* prepend to list */
4410 _ckvmssts_noperl(sys$setast(1));
4411 /* Omit arg 2 (input file) so the child will get the parent's SYS$INPUT
4412 * and SYS$COMMAND. vmspipe.com will redefine SYS$INPUT, but we'll still
4413 * have SYS$COMMAND if we need it.
4415 _ckvmssts_noperl(lib$spawn(&vmspipedsc, 0, &nl_desc, &flags,
4416 0, &info->pid, &info->completion,
4417 0, popen_completion_ast,info,0,0,0));
4419 /* if we were using a tempfile, close it now */
4421 if (tpipe) fclose(tpipe);
4423 /* once the subprocess is spawned, it has copied the symbols and
4424 we can get rid of ours */
4426 for (j = 0; j < 4; j++) {
4427 sprintf(cmd_sym_name,"PERL_POPEN_CMD%d",j);
4428 d_sym_cmd.dsc$w_length = strlen(cmd_sym_name);
4429 _ckvmssts_noperl(lib$delete_symbol(&d_sym_cmd, &table));
4431 _ckvmssts_noperl(lib$delete_symbol(&d_sym_in, &table));
4432 _ckvmssts_noperl(lib$delete_symbol(&d_sym_err, &table));
4433 _ckvmssts_noperl(lib$delete_symbol(&d_sym_out, &table));
4434 vms_execfree(vmscmd);
4436 #ifdef PERL_IMPLICIT_CONTEXT
4439 PL_forkprocess = info->pid;
4446 _ckvmssts_noperl(sys$setast(0));
4448 if (!done) _ckvmssts_noperl(sys$clref(pipe_ef));
4449 _ckvmssts_noperl(sys$setast(1));
4450 if (!done) _ckvmssts_noperl(sys$waitfr(pipe_ef));
4452 *psts = info->completion;
4453 /* Caller thinks it is open and tries to close it. */
4454 /* This causes some problems, as it changes the error status */
4455 /* my_pclose(info->fp); */
4457 /* If we did not have a file pointer open, then we have to */
4458 /* clean up here or eventually we will run out of something */
4460 if (info->fp == NULL) {
4461 my_pclose_pinfo(aTHX_ info);
4469 } /* end of safe_popen */
4472 /*{{{ PerlIO *my_popen(char *cmd, char *mode)*/
4474 Perl_my_popen(pTHX_ const char *cmd, const char *mode)
4478 TAINT_PROPER("popen");
4479 PERL_FLUSHALL_FOR_CHILD;
4480 return safe_popen(aTHX_ cmd,mode,&sts);
4486 /* Routine to close and cleanup a pipe info structure */
4488 static I32 my_pclose_pinfo(pTHX_ pInfo info) {
4490 unsigned long int retsts;
4494 /* If we were writing to a subprocess, insure that someone reading from
4495 * the mailbox gets an EOF. It looks like a simple fclose() doesn't
4496 * produce an EOF record in the mailbox.
4498 * well, at least sometimes it *does*, so we have to watch out for
4499 * the first EOF closing the pipe (and DASSGN'ing the channel)...
4503 #if defined(USE_ITHREADS)
4507 && PL_perlio_fd_refcnt
4510 PerlIO_flush(info->fp);
4512 fflush((FILE *)info->fp);
4515 _ckvmssts(sys$setast(0));
4516 info->closing = TRUE;
4517 done = info->done && info->in_done && info->out_done && info->err_done;
4518 /* hanging on write to Perl's input? cancel it */
4519 if (info->mode == 'r' && info->out && !info->out_done) {
4520 if (info->out->chan_out) {
4521 _ckvmssts(sys$cancel(info->out->chan_out));
4522 if (!info->out->chan_in) { /* EOF generation, need AST */
4523 _ckvmssts(sys$dclast(pipe_infromchild_ast,info->out,0));
4527 if (info->in && !info->in_done && !info->in->shut_on_empty) /* EOF if hasn't had one yet */
4528 _ckvmssts(sys$qio(0,info->in->chan_in,IO$_WRITEOF,0,0,0,
4530 _ckvmssts(sys$setast(1));
4533 #if defined(USE_ITHREADS)
4537 && PL_perlio_fd_refcnt
4540 PerlIO_close(info->fp);
4542 fclose((FILE *)info->fp);
4545 we have to wait until subprocess completes, but ALSO wait until all
4546 the i/o completes...otherwise we'll be freeing the "info" structure
4547 that the i/o ASTs could still be using...
4551 _ckvmssts(sys$setast(0));
4552 done = info->done && info->in_done && info->out_done && info->err_done;
4553 if (!done) _ckvmssts(sys$clref(pipe_ef));
4554 _ckvmssts(sys$setast(1));
4555 if (!done) _ckvmssts(sys$waitfr(pipe_ef));
4557 retsts = info->completion;
4559 /* remove from list of open pipes */
4560 _ckvmssts(sys$setast(0));
4562 for (next = open_pipes; next != NULL; last = next, next = next->next) {
4568 last->next = info->next;
4570 open_pipes = info->next;
4571 _ckvmssts(sys$setast(1));
4573 /* free buffers and structures */
4576 if (info->in->buf) {
4577 n = info->in->bufsize * sizeof(char);
4578 _ckvmssts(lib$free_vm(&n, &info->in->buf));
4581 _ckvmssts(lib$free_vm(&n, &info->in));
4584 if (info->out->buf) {
4585 n = info->out->bufsize * sizeof(char);
4586 _ckvmssts(lib$free_vm(&n, &info->out->buf));
4589 _ckvmssts(lib$free_vm(&n, &info->out));
4592 if (info->err->buf) {
4593 n = info->err->bufsize * sizeof(char);
4594 _ckvmssts(lib$free_vm(&n, &info->err->buf));
4597 _ckvmssts(lib$free_vm(&n, &info->err));
4600 _ckvmssts(lib$free_vm(&n, &info));
4606 /*{{{ I32 my_pclose(PerlIO *fp)*/
4607 I32 Perl_my_pclose(pTHX_ PerlIO *fp)
4609 pInfo info, last = NULL;
4612 /* Fixme - need ast and mutex protection here */
4613 for (info = open_pipes; info != NULL; last = info, info = info->next)
4614 if (info->fp == fp) break;
4616 if (info == NULL) { /* no such pipe open */
4617 set_errno(ECHILD); /* quoth POSIX */
4618 set_vaxc_errno(SS$_NONEXPR);
4622 ret_status = my_pclose_pinfo(aTHX_ info);
4626 } /* end of my_pclose() */
4628 #if defined(__CRTL_VER) && __CRTL_VER >= 70200000
4629 /* Roll our own prototype because we want this regardless of whether
4630 * _VMS_WAIT is defined.
4636 __pid_t __vms_waitpid( __pid_t __pid, int *__stat_loc, int __options );
4642 /* sort-of waitpid; special handling of pipe clean-up for subprocesses
4643 created with popen(); otherwise partially emulate waitpid() unless
4644 we have a suitable one from the CRTL that came with VMS 7.2 and later.
4645 Also check processes not considered by the CRTL waitpid().
4647 /*{{{Pid_t my_waitpid(Pid_t pid, int *statusp, int flags)*/
4649 Perl_my_waitpid(pTHX_ Pid_t pid, int *statusp, int flags)
4656 if (statusp) *statusp = 0;
4658 for (info = open_pipes; info != NULL; info = info->next)
4659 if (info->pid == pid) break;
4661 if (info != NULL) { /* we know about this child */
4662 while (!info->done) {
4663 _ckvmssts(sys$setast(0));
4665 if (!done) _ckvmssts(sys$clref(pipe_ef));
4666 _ckvmssts(sys$setast(1));
4667 if (!done) _ckvmssts(sys$waitfr(pipe_ef));
4670 if (statusp) *statusp = info->completion;
4674 /* child that already terminated? */
4676 for (j = 0; j < NKEEPCLOSED && j < closed_num; j++) {
4677 if (closed_list[j].pid == pid) {
4678 if (statusp) *statusp = closed_list[j].completion;
4683 /* fall through if this child is not one of our own pipe children */
4685 #if defined(__CRTL_VER) && __CRTL_VER >= 70200000
4687 /* waitpid() became available in the CRTL as of VMS 7.0, but only
4688 * in 7.2 did we get a version that fills in the VMS completion
4689 * status as Perl has always tried to do.
4692 sts = __vms_waitpid( pid, statusp, flags );
4694 if ( sts == 0 || !(sts == -1 && errno == ECHILD) )
4697 /* If the real waitpid tells us the child does not exist, we
4698 * fall through here to implement waiting for a child that
4699 * was created by some means other than exec() (say, spawned
4700 * from DCL) or to wait for a process that is not a subprocess
4701 * of the current process.
4704 #endif /* defined(__CRTL_VER) && __CRTL_VER >= 70200000 */
4707 $DESCRIPTOR(intdsc,"0 00:00:01");
4708 unsigned long int ownercode = JPI$_OWNER, ownerpid;
4709 unsigned long int pidcode = JPI$_PID, mypid;
4710 unsigned long int interval[2];
4711 unsigned int jpi_iosb[2];
4712 struct itmlst_3 jpilist[2] = {
4713 {sizeof(ownerpid), JPI$_OWNER, &ownerpid, 0},
4718 /* Sorry folks, we don't presently implement rooting around for
4719 the first child we can find, and we definitely don't want to
4720 pass a pid of -1 to $getjpi, where it is a wildcard operation.
4726 /* Get the owner of the child so I can warn if it's not mine. If the
4727 * process doesn't exist or I don't have the privs to look at it,
4728 * I can go home early.
4730 sts = sys$getjpiw(0,&pid,NULL,&jpilist,&jpi_iosb,NULL,NULL);
4731 if (sts & 1) sts = jpi_iosb[0];
4743 set_vaxc_errno(sts);
4747 if (ckWARN(WARN_EXEC)) {
4748 /* remind folks they are asking for non-standard waitpid behavior */
4749 _ckvmssts(lib$getjpi(&pidcode,0,0,&mypid,0,0));
4750 if (ownerpid != mypid)
4751 Perl_warner(aTHX_ packWARN(WARN_EXEC),
4752 "waitpid: process %x is not a child of process %x",
4756 /* simply check on it once a second until it's not there anymore. */
4758 _ckvmssts(sys$bintim(&intdsc,interval));
4759 while ((sts=lib$getjpi(&ownercode,&pid,0,&ownerpid,0,0)) & 1) {
4760 _ckvmssts(sys$schdwk(0,0,interval,0));
4761 _ckvmssts(sys$hiber());
4763 if (sts == SS$_NONEXPR) sts = SS$_NORMAL;
4768 } /* end of waitpid() */
4773 /*{{{ char *my_gconvert(double val, int ndig, int trail, char *buf) */
4775 my_gconvert(double val, int ndig, int trail, char *buf)
4777 static char __gcvtbuf[DBL_DIG+1];
4780 loc = buf ? buf : __gcvtbuf;
4783 if (!buf && ndig > DBL_DIG) ndig = DBL_DIG;
4784 return gcvt(val,ndig,loc);
4787 loc[0] = '0'; loc[1] = '\0';
4794 #if defined(__VAX) || !defined(NAML$C_MAXRSS)
4795 static int rms_free_search_context(struct FAB * fab)
4799 nam = fab->fab$l_nam;
4800 nam->nam$b_nop |= NAM$M_SYNCHK;
4801 nam->nam$l_rlf = NULL;
4803 return sys$parse(fab, NULL, NULL);
4806 #define rms_setup_nam(nam) struct NAM nam = cc$rms_nam
4807 #define rms_clear_nam_nop(nam) nam.nam$b_nop = 0;
4808 #define rms_set_nam_nop(nam, opt) nam.nam$b_nop |= (opt)
4809 #define rms_set_nam_fnb(nam, opt) nam.nam$l_fnb |= (opt)
4810 #define rms_is_nam_fnb(nam, opt) (nam.nam$l_fnb & (opt))
4811 #define rms_nam_esll(nam) nam.nam$b_esl
4812 #define rms_nam_esl(nam) nam.nam$b_esl
4813 #define rms_nam_name(nam) nam.nam$l_name
4814 #define rms_nam_namel(nam) nam.nam$l_name
4815 #define rms_nam_type(nam) nam.nam$l_type
4816 #define rms_nam_typel(nam) nam.nam$l_type
4817 #define rms_nam_ver(nam) nam.nam$l_ver
4818 #define rms_nam_verl(nam) nam.nam$l_ver
4819 #define rms_nam_rsll(nam) nam.nam$b_rsl
4820 #define rms_nam_rsl(nam) nam.nam$b_rsl
4821 #define rms_bind_fab_nam(fab, nam) fab.fab$l_nam = &nam
4822 #define rms_set_fna(fab, nam, name, size) \
4823 { fab.fab$b_fns = size; fab.fab$l_fna = name; }
4824 #define rms_get_fna(fab, nam) fab.fab$l_fna
4825 #define rms_set_dna(fab, nam, name, size) \
4826 { fab.fab$b_dns = size; fab.fab$l_dna = name; }
4827 #define rms_nam_dns(fab, nam) fab.fab$b_dns
4828 #define rms_set_esa(nam, name, size) \
4829 { nam.nam$b_ess = size; nam.nam$l_esa = nam