1 /* vms.c 2 * 3 * VMS-specific routines for perl5 4 * 5 * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 6 * 2002, 2003, 2004, 2005, 2006, 2007 by Charles Bailey and others. 7 * 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. 10 * 11 * Please see Changes*.* or the Perl Repository Browser for revision history. 12 */ 13 14 /* 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 22 * 23 * [p.162 of _The Lays of Beleriand_] 24 */ 25 26 #include <acedef.h> 27 #include <acldef.h> 28 #include <armdef.h> 29 #include <atrdef.h> 30 #include <chpdef.h> 31 #include <clidef.h> 32 #include <climsgdef.h> 33 #include <dcdef.h> 34 #include <descrip.h> 35 #include <devdef.h> 36 #include <dvidef.h> 37 #include <fibdef.h> 38 #include <float.h> 39 #include <fscndef.h> 40 #include <iodef.h> 41 #include <jpidef.h> 42 #include <kgbdef.h> 43 #include <libclidef.h> 44 #include <libdef.h> 45 #include <lib$routines.h> 46 #include <lnmdef.h> 47 #include <msgdef.h> 48 #include <ossdef.h> 49 #if __CRTL_VER >= 70301000 && !defined(__VAX) 50 #include <ppropdef.h> 51 #endif 52 #include <prvdef.h> 53 #include <psldef.h> 54 #include <rms.h> 55 #include <shrdef.h> 56 #include <ssdef.h> 57 #include <starlet.h> 58 #include <strdef.h> 59 #include <str$routines.h> 60 #include <syidef.h> 61 #include <uaidef.h> 62 #include <uicdef.h> 63 #include <stsdef.h> 64 #include <rmsdef.h> 65 #include <smgdef.h> 66 #if __CRTL_VER >= 70000000 /* FIXME to earliest version */ 67 #include <efndef.h> 68 #define NO_EFN EFN$C_ENF 69 #else 70 #define NO_EFN 0; 71 #endif 72 73 #if __CRTL_VER < 70301000 && __CRTL_VER >= 70300000 74 int decc$feature_get_index(const char *name); 75 char* decc$feature_get_name(int index); 76 int decc$feature_get_value(int index, int mode); 77 int decc$feature_set_value(int index, int mode, int value); 78 #else 79 #include <unixlib.h> 80 #endif 81 82 #pragma member_alignment save 83 #pragma nomember_alignment longword 84 struct item_list_3 { 85 unsigned short len; 86 unsigned short code; 87 void * bufadr; 88 unsigned short * retadr; 89 }; 90 #pragma member_alignment restore 91 92 /* More specific prototype than in starlet_c.h makes programming errors 93 more visible. 94 */ 95 #ifdef sys$getdviw 96 #undef sys$getdviw 97 int sys$getdviw 98 (unsigned long efn, 99 unsigned short chan, 100 const struct dsc$descriptor_s * devnam, 101 const struct item_list_3 * itmlst, 102 void * iosb, 103 void * (astadr)(unsigned long), 104 void * astprm, 105 void * nullarg); 106 #endif 107 108 #ifdef sys$get_security 109 #undef sys$get_security 110 int sys$get_security 111 (const struct dsc$descriptor_s * clsnam, 112 const struct dsc$descriptor_s * objnam, 113 const unsigned int *objhan, 114 unsigned int flags, 115 const struct item_list_3 * itmlst, 116 unsigned int * contxt, 117 const unsigned int * acmode); 118 #endif 119 120 #ifdef sys$set_security 121 #undef sys$set_security 122 int sys$set_security 123 (const struct dsc$descriptor_s * clsnam, 124 const struct dsc$descriptor_s * objnam, 125 const unsigned int *objhan, 126 unsigned int flags, 127 const struct item_list_3 * itmlst, 128 unsigned int * contxt, 129 const unsigned int * acmode); 130 #endif 131 132 #ifdef lib$find_image_symbol 133 #undef lib$find_image_symbol 134 int lib$find_image_symbol 135 (const struct dsc$descriptor_s * imgname, 136 const struct dsc$descriptor_s * symname, 137 void * symval, 138 const struct dsc$descriptor_s * defspec, 139 unsigned long flag); 140 #endif 141 142 #ifdef lib$rename_file 143 #undef lib$rename_file 144 int lib$rename_file 145 (const struct dsc$descriptor_s * old_file_dsc, 146 const struct dsc$descriptor_s * new_file_dsc, 147 const struct dsc$descriptor_s * default_file_dsc, 148 const struct dsc$descriptor_s * related_file_dsc, 149 const unsigned long * flags, 150 void * (success)(const struct dsc$descriptor_s * old_dsc, 151 const struct dsc$descriptor_s * new_dsc, 152 const void *), 153 void * (error)(const struct dsc$descriptor_s * old_dsc, 154 const struct dsc$descriptor_s * new_dsc, 155 const int * rms_sts, 156 const int * rms_stv, 157 const int * error_src, 158 const void * usr_arg), 159 int (confirm)(const struct dsc$descriptor_s * old_dsc, 160 const struct dsc$descriptor_s * new_dsc, 161 const void * old_fab, 162 const void * usr_arg), 163 void * user_arg, 164 struct dsc$descriptor_s * old_result_name_dsc, 165 struct dsc$descriptor_s * new_result_name_dsc, 166 unsigned long * file_scan_context); 167 #endif 168 169 #if __CRTL_VER >= 70300000 && !defined(__VAX) 170 171 static int set_feature_default(const char *name, int value) 172 { 173 int status; 174 int index; 175 176 index = decc$feature_get_index(name); 177 178 status = decc$feature_set_value(index, 1, value); 179 if (index == -1 || (status == -1)) { 180 return -1; 181 } 182 183 status = decc$feature_get_value(index, 1); 184 if (status != value) { 185 return -1; 186 } 187 188 return 0; 189 } 190 #endif 191 192 /* Older versions of ssdef.h don't have these */ 193 #ifndef SS$_INVFILFOROP 194 # define SS$_INVFILFOROP 3930 195 #endif 196 #ifndef SS$_NOSUCHOBJECT 197 # define SS$_NOSUCHOBJECT 2696 198 #endif 199 200 /* We implement I/O here, so we will be mixing PerlIO and stdio calls. */ 201 #define PERLIO_NOT_STDIO 0 202 203 /* Don't replace system definitions of vfork, getenv, lstat, and stat, 204 * code below needs to get to the underlying CRTL routines. */ 205 #define DONT_MASK_RTL_CALLS 206 #include "EXTERN.h" 207 #include "perl.h" 208 #include "XSUB.h" 209 /* Anticipating future expansion in lexical warnings . . . */ 210 #ifndef WARN_INTERNAL 211 # define WARN_INTERNAL WARN_MISC 212 #endif 213 214 #ifdef VMS_LONGNAME_SUPPORT 215 #include <libfildef.h> 216 #endif 217 218 #if defined(__VMS_VER) && __VMS_VER >= 70000000 && __DECC_VER >= 50200000 219 # define RTL_USES_UTC 1 220 #endif 221 222 #if !defined(__VAX) && __CRTL_VER >= 80200000 223 #ifdef lstat 224 #undef lstat 225 #endif 226 #else 227 #ifdef lstat 228 #undef lstat 229 #endif 230 #define lstat(_x, _y) stat(_x, _y) 231 #endif 232 233 /* Routine to create a decterm for use with the Perl debugger */ 234 /* No headers, this information was found in the Programming Concepts Manual */ 235 236 static int (*decw_term_port) 237 (const struct dsc$descriptor_s * display, 238 const struct dsc$descriptor_s * setup_file, 239 const struct dsc$descriptor_s * customization, 240 struct dsc$descriptor_s * result_device_name, 241 unsigned short * result_device_name_length, 242 void * controller, 243 void * char_buffer, 244 void * char_change_buffer) = 0; 245 246 /* gcc's header files don't #define direct access macros 247 * corresponding to VAXC's variant structs */ 248 #ifdef __GNUC__ 249 # define uic$v_format uic$r_uic_form.uic$v_format 250 # define uic$v_group uic$r_uic_form.uic$v_group 251 # define uic$v_member uic$r_uic_form.uic$v_member 252 # define prv$v_bypass prv$r_prvdef_bits0.prv$v_bypass 253 # define prv$v_grpprv prv$r_prvdef_bits0.prv$v_grpprv 254 # define prv$v_readall prv$r_prvdef_bits0.prv$v_readall 255 # define prv$v_sysprv prv$r_prvdef_bits0.prv$v_sysprv 256 #endif 257 258 #if defined(NEED_AN_H_ERRNO) 259 dEXT int h_errno; 260 #endif 261 262 #ifdef __DECC 263 #pragma message disable pragma 264 #pragma member_alignment save 265 #pragma nomember_alignment longword 266 #pragma message save 267 #pragma message disable misalgndmem 268 #endif 269 struct itmlst_3 { 270 unsigned short int buflen; 271 unsigned short int itmcode; 272 void *bufadr; 273 unsigned short int *retlen; 274 }; 275 276 struct filescan_itmlst_2 { 277 unsigned short length; 278 unsigned short itmcode; 279 char * component; 280 }; 281 282 struct vs_str_st { 283 unsigned short length; 284 char str[65536]; 285 }; 286 287 #ifdef __DECC 288 #pragma message restore 289 #pragma member_alignment restore 290 #endif 291 292 #define do_fileify_dirspec(a,b,c,d) mp_do_fileify_dirspec(aTHX_ a,b,c,d) 293 #define do_pathify_dirspec(a,b,c,d) mp_do_pathify_dirspec(aTHX_ a,b,c,d) 294 #define do_tovmsspec(a,b,c,d) mp_do_tovmsspec(aTHX_ a,b,c,0,d) 295 #define do_tovmspath(a,b,c,d) mp_do_tovmspath(aTHX_ a,b,c,d) 296 #define do_rmsexpand(a,b,c,d,e,f,g) mp_do_rmsexpand(aTHX_ a,b,c,d,e,f,g) 297 #define do_vms_realpath(a,b,c) mp_do_vms_realpath(aTHX_ a,b,c) 298 #define do_vms_realname(a,b,c) mp_do_vms_realname(aTHX_ a,b,c) 299 #define do_tounixspec(a,b,c,d) mp_do_tounixspec(aTHX_ a,b,c,d) 300 #define do_tounixpath(a,b,c,d) mp_do_tounixpath(aTHX_ a,b,c,d) 301 #define do_vms_case_tolerant(a) mp_do_vms_case_tolerant(a) 302 #define expand_wild_cards(a,b,c,d) mp_expand_wild_cards(aTHX_ a,b,c,d) 303 #define getredirection(a,b) mp_getredirection(aTHX_ a,b) 304 305 static char *mp_do_tovmspath(pTHX_ const char *path, char *buf, int ts, int *); 306 static char *mp_do_tounixpath(pTHX_ const char *path, char *buf, int ts, int *); 307 static char *mp_do_tounixspec(pTHX_ const char *, char *, int, int *); 308 static char *mp_do_pathify_dirspec(pTHX_ const char *dir,char *buf, int ts, int *); 309 310 static char * int_rmsexpand_vms( 311 const char * filespec, char * outbuf, unsigned opts); 312 static char * int_rmsexpand_tovms( 313 const char * filespec, char * outbuf, unsigned opts); 314 static char *int_tovmsspec 315 (const char *path, char *buf, int dir_flag, int * utf8_flag); 316 static char * int_fileify_dirspec(const char *dir, char *buf, int *utf8_fl); 317 static char * int_tounixspec(const char *spec, char *buf, int * utf8_fl); 318 static char * int_tovmspath(const char *path, char *buf, int * utf8_fl); 319 320 /* see system service docs for $TRNLNM -- NOT the same as LNM$_MAX_INDEX */ 321 #define PERL_LNM_MAX_ALLOWED_INDEX 127 322 323 /* OpenVMS User's Guide says at least 9 iterative translations will be performed, 324 * depending on the facility. SHOW LOGICAL does 10, so we'll imitate that for 325 * the Perl facility. 326 */ 327 #define PERL_LNM_MAX_ITER 10 328 329 /* New values with 7.3-2*/ /* why does max DCL have 4 byte subtracted from it? */ 330 #if __CRTL_VER >= 70302000 && !defined(__VAX) 331 #define MAX_DCL_SYMBOL (8192) 332 #define MAX_DCL_LINE_LENGTH (4096 - 4) 333 #else 334 #define MAX_DCL_SYMBOL (1024) 335 #define MAX_DCL_LINE_LENGTH (1024 - 4) 336 #endif 337 338 static char *__mystrtolower(char *str) 339 { 340 if (str) for (; *str; ++str) *str= tolower(*str); 341 return str; 342 } 343 344 static struct dsc$descriptor_s fildevdsc = 345 { 12, DSC$K_DTYPE_T, DSC$K_CLASS_S, "LNM$FILE_DEV" }; 346 static struct dsc$descriptor_s crtlenvdsc = 347 { 8, DSC$K_DTYPE_T, DSC$K_CLASS_S, "CRTL_ENV" }; 348 static struct dsc$descriptor_s *fildev[] = { &fildevdsc, NULL }; 349 static struct dsc$descriptor_s *defenv[] = { &fildevdsc, &crtlenvdsc, NULL }; 350 static struct dsc$descriptor_s **env_tables = defenv; 351 static bool will_taint = FALSE; /* tainting active, but no PL_curinterp yet */ 352 353 /* True if we shouldn't treat barewords as logicals during directory */ 354 /* munching */ 355 static int no_translate_barewords; 356 357 #ifndef RTL_USES_UTC 358 static int tz_updated = 1; 359 #endif 360 361 /* DECC Features that may need to affect how Perl interprets 362 * displays filename information 363 */ 364 static int decc_disable_to_vms_logname_translation = 1; 365 static int decc_disable_posix_root = 1; 366 int decc_efs_case_preserve = 0; 367 static int decc_efs_charset = 0; 368 static int decc_efs_charset_index = -1; 369 static int decc_filename_unix_no_version = 0; 370 static int decc_filename_unix_only = 0; 371 int decc_filename_unix_report = 0; 372 int decc_posix_compliant_pathnames = 0; 373 int decc_readdir_dropdotnotype = 0; 374 static int vms_process_case_tolerant = 1; 375 int vms_vtf7_filenames = 0; 376 int gnv_unix_shell = 0; 377 static int vms_unlink_all_versions = 0; 378 static int vms_posix_exit = 0; 379 380 /* bug workarounds if needed */ 381 int decc_bug_devnull = 1; 382 int decc_dir_barename = 0; 383 int vms_bug_stat_filename = 0; 384 385 static int vms_debug_on_exception = 0; 386 static int vms_debug_fileify = 0; 387 388 /* Simple logical name translation */ 389 static int simple_trnlnm 390 (const char * logname, 391 char * value, 392 int value_len) 393 { 394 const $DESCRIPTOR(table_dsc, "LNM$FILE_DEV"); 395 const unsigned long attr = LNM$M_CASE_BLIND; 396 struct dsc$descriptor_s name_dsc; 397 int status; 398 unsigned short result; 399 struct itmlst_3 itlst[2] = {{value_len, LNM$_STRING, value, &result}, 400 {0, 0, 0, 0}}; 401 402 name_dsc.dsc$w_length = strlen(logname); 403 name_dsc.dsc$a_pointer = (char *)logname; 404 name_dsc.dsc$b_dtype = DSC$K_DTYPE_T; 405 name_dsc.dsc$b_class = DSC$K_CLASS_S; 406 407 status = sys$trnlnm(&attr, &table_dsc, &name_dsc, 0, itlst); 408 409 if ($VMS_STATUS_SUCCESS(status)) { 410 411 /* Null terminate and return the string */ 412 /*--------------------------------------*/ 413 value[result] = 0; 414 return result; 415 } 416 417 return 0; 418 } 419 420 421 /* Is this a UNIX file specification? 422 * No longer a simple check with EFS file specs 423 * For now, not a full check, but need to 424 * handle POSIX ^UP^ specifications 425 * Fixing to handle ^/ cases would require 426 * changes to many other conversion routines. 427 */ 428 429 static int is_unix_filespec(const char *path) 430 { 431 int ret_val; 432 const char * pch1; 433 434 ret_val = 0; 435 if (strncmp(path,"\"^UP^",5) != 0) { 436 pch1 = strchr(path, '/'); 437 if (pch1 != NULL) 438 ret_val = 1; 439 else { 440 441 /* If the user wants UNIX files, "." needs to be treated as in UNIX */ 442 if (decc_filename_unix_report || decc_filename_unix_only) { 443 if (strcmp(path,".") == 0) 444 ret_val = 1; 445 } 446 } 447 } 448 return ret_val; 449 } 450 451 /* This routine converts a UCS-2 character to be VTF-7 encoded. 452 */ 453 454 static void ucs2_to_vtf7 455 (char *outspec, 456 unsigned long ucs2_char, 457 int * output_cnt) 458 { 459 unsigned char * ucs_ptr; 460 int hex; 461 462 ucs_ptr = (unsigned char *)&ucs2_char; 463 464 outspec[0] = '^'; 465 outspec[1] = 'U'; 466 hex = (ucs_ptr[1] >> 4) & 0xf; 467 if (hex < 0xA) 468 outspec[2] = hex + '0'; 469 else 470 outspec[2] = (hex - 9) + 'A'; 471 hex = ucs_ptr[1] & 0xF; 472 if (hex < 0xA) 473 outspec[3] = hex + '0'; 474 else { 475 outspec[3] = (hex - 9) + 'A'; 476 } 477 hex = (ucs_ptr[0] >> 4) & 0xf; 478 if (hex < 0xA) 479 outspec[4] = hex + '0'; 480 else 481 outspec[4] = (hex - 9) + 'A'; 482 hex = ucs_ptr[1] & 0xF; 483 if (hex < 0xA) 484 outspec[5] = hex + '0'; 485 else { 486 outspec[5] = (hex - 9) + 'A'; 487 } 488 *output_cnt = 6; 489 } 490 491 492 /* This handles the conversion of a UNIX extended character set to a ^ 493 * escaped VMS character. 494 * in a UNIX file specification. 495 * 496 * The output count variable contains the number of characters added 497 * to the output string. 498 * 499 * The return value is the number of characters read from the input string 500 */ 501 static int copy_expand_unix_filename_escape 502 (char *outspec, const char *inspec, int *output_cnt, const int * utf8_fl) 503 { 504 int count; 505 int scnt; 506 int utf8_flag; 507 508 utf8_flag = 0; 509 if (utf8_fl) 510 utf8_flag = *utf8_fl; 511 512 count = 0; 513 *output_cnt = 0; 514 if (*inspec >= 0x80) { 515 if (utf8_fl && vms_vtf7_filenames) { 516 unsigned long ucs_char; 517 518 ucs_char = 0; 519 520 if ((*inspec & 0xE0) == 0xC0) { 521 /* 2 byte Unicode */ 522 ucs_char = ((inspec[0] & 0x1F) << 6) + (inspec[1] & 0x3f); 523 if (ucs_char >= 0x80) { 524 ucs2_to_vtf7(outspec, ucs_char, output_cnt); 525 return 2; 526 } 527 } else if ((*inspec & 0xF0) == 0xE0) { 528 /* 3 byte Unicode */ 529 ucs_char = ((inspec[0] & 0xF) << 12) + 530 ((inspec[1] & 0x3f) << 6) + 531 (inspec[2] & 0x3f); 532 if (ucs_char >= 0x800) { 533 ucs2_to_vtf7(outspec, ucs_char, output_cnt); 534 return 3; 535 } 536 537 #if 0 /* I do not see longer sequences supported by OpenVMS */ 538 /* Maybe some one can fix this later */ 539 } else if ((*inspec & 0xF8) == 0xF0) { 540 /* 4 byte Unicode */ 541 /* UCS-4 to UCS-2 */ 542 } else if ((*inspec & 0xFC) == 0xF8) { 543 /* 5 byte Unicode */ 544 /* UCS-4 to UCS-2 */ 545 } else if ((*inspec & 0xFE) == 0xFC) { 546 /* 6 byte Unicode */ 547 /* UCS-4 to UCS-2 */ 548 #endif 549 } 550 } 551 552 /* High bit set, but not a Unicode character! */ 553 554 /* Non printing DECMCS or ISO Latin-1 character? */ 555 if (*inspec <= 0x9F) { 556 int hex; 557 outspec[0] = '^'; 558 outspec++; 559 hex = (*inspec >> 4) & 0xF; 560 if (hex < 0xA) 561 outspec[1] = hex + '0'; 562 else { 563 outspec[1] = (hex - 9) + 'A'; 564 } 565 hex = *inspec & 0xF; 566 if (hex < 0xA) 567 outspec[2] = hex + '0'; 568 else { 569 outspec[2] = (hex - 9) + 'A'; 570 } 571 *output_cnt = 3; 572 return 1; 573 } else if (*inspec == 0xA0) { 574 outspec[0] = '^'; 575 outspec[1] = 'A'; 576 outspec[2] = '0'; 577 *output_cnt = 3; 578 return 1; 579 } else if (*inspec == 0xFF) { 580 outspec[0] = '^'; 581 outspec[1] = 'F'; 582 outspec[2] = 'F'; 583 *output_cnt = 3; 584 return 1; 585 } 586 *outspec = *inspec; 587 *output_cnt = 1; 588 return 1; 589 } 590 591 /* Is this a macro that needs to be passed through? 592 * Macros start with $( and an alpha character, followed 593 * by a string of alpha numeric characters ending with a ) 594 * If this does not match, then encode it as ODS-5. 595 */ 596 if ((inspec[0] == '$') && (inspec[1] == '(')) { 597 int tcnt; 598 599 if (isalnum(inspec[2]) || (inspec[2] == '.') || (inspec[2] == '_')) { 600 tcnt = 3; 601 outspec[0] = inspec[0]; 602 outspec[1] = inspec[1]; 603 outspec[2] = inspec[2]; 604 605 while(isalnum(inspec[tcnt]) || 606 (inspec[2] == '.') || (inspec[2] == '_')) { 607 outspec[tcnt] = inspec[tcnt]; 608 tcnt++; 609 } 610 if (inspec[tcnt] == ')') { 611 outspec[tcnt] = inspec[tcnt]; 612 tcnt++; 613 *output_cnt = tcnt; 614 return tcnt; 615 } 616 } 617 } 618 619 switch (*inspec) { 620 case 0x7f: 621 outspec[0] = '^'; 622 outspec[1] = '7'; 623 outspec[2] = 'F'; 624 *output_cnt = 3; 625 return 1; 626 break; 627 case '?': 628 if (decc_efs_charset == 0) 629 outspec[0] = '%'; 630 else 631 outspec[0] = '?'; 632 *output_cnt = 1; 633 return 1; 634 break; 635 case '.': 636 case '~': 637 case '!': 638 case '#': 639 case '&': 640 case '\'': 641 case '`': 642 case '(': 643 case ')': 644 case '+': 645 case '@': 646 case '{': 647 case '}': 648 case ',': 649 case ';': 650 case '[': 651 case ']': 652 case '%': 653 case '^': 654 case '\\': 655 /* Don't escape again if following character is 656 * already something we escape. 657 */ 658 if (strchr(".~!#&\'`()+@{},;[]%^=_\\", *(inspec+1))) { 659 *outspec = *inspec; 660 *output_cnt = 1; 661 return 1; 662 break; 663 } 664 /* But otherwise fall through and escape it. */ 665 case '=': 666 /* Assume that this is to be escaped */ 667 outspec[0] = '^'; 668 outspec[1] = *inspec; 669 *output_cnt = 2; 670 return 1; 671 break; 672 case ' ': /* space */ 673 /* Assume that this is to be escaped */ 674 outspec[0] = '^'; 675 outspec[1] = '_'; 676 *output_cnt = 2; 677 return 1; 678 break; 679 default: 680 *outspec = *inspec; 681 *output_cnt = 1; 682 return 1; 683 break; 684 } 685 } 686 687 688 /* This handles the expansion of a '^' prefix to the proper character 689 * in a UNIX file specification. 690 * 691 * The output count variable contains the number of characters added 692 * to the output string. 693 * 694 * The return value is the number of characters read from the input 695 * string 696 */ 697 static int copy_expand_vms_filename_escape 698 (char *outspec, const char *inspec, int *output_cnt) 699 { 700 int count; 701 int scnt; 702 703 count = 0; 704 *output_cnt = 0; 705 if (*inspec == '^') { 706 inspec++; 707 switch (*inspec) { 708 /* Spaces and non-trailing dots should just be passed through, 709 * but eat the escape character. 710 */ 711 case '.': 712 *outspec = *inspec; 713 count += 2; 714 (*output_cnt)++; 715 break; 716 case '_': /* space */ 717 *outspec = ' '; 718 count += 2; 719 (*output_cnt)++; 720 break; 721 case '^': 722 /* Hmm. Better leave the escape escaped. */ 723 outspec[0] = '^'; 724 outspec[1] = '^'; 725 count += 2; 726 (*output_cnt) += 2; 727 break; 728 case 'U': /* Unicode - FIX-ME this is wrong. */ 729 inspec++; 730 count++; 731 scnt = strspn(inspec, "0123456789ABCDEFabcdef"); 732 if (scnt == 4) { 733 unsigned int c1, c2; 734 scnt = sscanf(inspec, "%2x%2x", &c1, &c2); 735 outspec[0] == c1 & 0xff; 736 outspec[1] == c2 & 0xff; 737 if (scnt > 1) { 738 (*output_cnt) += 2; 739 count += 4; 740 } 741 } 742 else { 743 /* Error - do best we can to continue */ 744 *outspec = 'U'; 745 outspec++; 746 (*output_cnt++); 747 *outspec = *inspec; 748 count++; 749 (*output_cnt++); 750 } 751 break; 752 default: 753 scnt = strspn(inspec, "0123456789ABCDEFabcdef"); 754 if (scnt == 2) { 755 /* Hex encoded */ 756 unsigned int c1; 757 scnt = sscanf(inspec, "%2x", &c1); 758 outspec[0] = c1 & 0xff; 759 if (scnt > 0) { 760 (*output_cnt++); 761 count += 2; 762 } 763 } 764 else { 765 *outspec = *inspec; 766 count++; 767 (*output_cnt++); 768 } 769 } 770 } 771 else { 772 *outspec = *inspec; 773 count++; 774 (*output_cnt)++; 775 } 776 return count; 777 } 778 779 #ifdef sys$filescan 780 #undef sys$filescan 781 int sys$filescan 782 (const struct dsc$descriptor_s * srcstr, 783 struct filescan_itmlst_2 * valuelist, 784 unsigned long * fldflags, 785 struct dsc$descriptor_s *auxout, 786 unsigned short * retlen); 787 #endif 788 789 /* vms_split_path - Verify that the input file specification is a 790 * VMS format file specification, and provide pointers to the components of 791 * it. With EFS format filenames, this is virtually the only way to 792 * parse a VMS path specification into components. 793 * 794 * If the sum of the components do not add up to the length of the 795 * string, then the passed file specification is probably a UNIX style 796 * path. 797 */ 798 static int vms_split_path 799 (const char * path, 800 char * * volume, 801 int * vol_len, 802 char * * root, 803 int * root_len, 804 char * * dir, 805 int * dir_len, 806 char * * name, 807 int * name_len, 808 char * * ext, 809 int * ext_len, 810 char * * version, 811 int * ver_len) 812 { 813 struct dsc$descriptor path_desc; 814 int status; 815 unsigned long flags; 816 int ret_stat; 817 struct filescan_itmlst_2 item_list[9]; 818 const int filespec = 0; 819 const int nodespec = 1; 820 const int devspec = 2; 821 const int rootspec = 3; 822 const int dirspec = 4; 823 const int namespec = 5; 824 const int typespec = 6; 825 const int verspec = 7; 826 827 /* Assume the worst for an easy exit */ 828 ret_stat = -1; 829 *volume = NULL; 830 *vol_len = 0; 831 *root = NULL; 832 *root_len = 0; 833 *dir = NULL; 834 *dir_len; 835 *name = NULL; 836 *name_len = 0; 837 *ext = NULL; 838 *ext_len = 0; 839 *version = NULL; 840 *ver_len = 0; 841 842 path_desc.dsc$a_pointer = (char *)path; /* cast ok */ 843 path_desc.dsc$w_length = strlen(path); 844 path_desc.dsc$b_dtype = DSC$K_DTYPE_T; 845 path_desc.dsc$b_class = DSC$K_CLASS_S; 846 847 /* Get the total length, if it is shorter than the string passed 848 * then this was probably not a VMS formatted file specification 849 */ 850 item_list[filespec].itmcode = FSCN$_FILESPEC; 851 item_list[filespec].length = 0; 852 item_list[filespec].component = NULL; 853 854 /* If the node is present, then it gets considered as part of the 855 * volume name to hopefully make things simple. 856 */ 857 item_list[nodespec].itmcode = FSCN$_NODE; 858 item_list[nodespec].length = 0; 859 item_list[nodespec].component = NULL; 860 861 item_list[devspec].itmcode = FSCN$_DEVICE; 862 item_list[devspec].length = 0; 863 item_list[devspec].component = NULL; 864 865 /* root is a special case, adding it to either the directory or 866 * the device components will probalby complicate things for the 867 * callers of this routine, so leave it separate. 868 */ 869 item_list[rootspec].itmcode = FSCN$_ROOT; 870 item_list[rootspec].length = 0; 871 item_list[rootspec].component = NULL; 872 873 item_list[dirspec].itmcode = FSCN$_DIRECTORY; 874 item_list[dirspec].length = 0; 875 item_list[dirspec].component = NULL; 876 877 item_list[namespec].itmcode = FSCN$_NAME; 878 item_list[namespec].length = 0; 879 item_list[namespec].component = NULL; 880 881 item_list[typespec].itmcode = FSCN$_TYPE; 882 item_list[typespec].length = 0; 883 item_list[typespec].component = NULL; 884 885 item_list[verspec].itmcode = FSCN$_VERSION; 886 item_list[verspec].length = 0; 887 item_list[verspec].component = NULL; 888 889 item_list[8].itmcode = 0; 890 item_list[8].length = 0; 891 item_list[8].component = NULL; 892 893 status = sys$filescan 894 ((const struct dsc$descriptor_s *)&path_desc, item_list, 895 &flags, NULL, NULL); 896 _ckvmssts_noperl(status); /* All failure status values indicate a coding error */ 897 898 /* If we parsed it successfully these two lengths should be the same */ 899 if (path_desc.dsc$w_length != item_list[filespec].length) 900 return ret_stat; 901 902 /* If we got here, then it is a VMS file specification */ 903 ret_stat = 0; 904 905 /* set the volume name */ 906 if (item_list[nodespec].length > 0) { 907 *volume = item_list[nodespec].component; 908 *vol_len = item_list[nodespec].length + item_list[devspec].length; 909 } 910 else { 911 *volume = item_list[devspec].component; 912 *vol_len = item_list[devspec].length; 913 } 914 915 *root = item_list[rootspec].component; 916 *root_len = item_list[rootspec].length; 917 918 *dir = item_list[dirspec].component; 919 *dir_len = item_list[dirspec].length; 920 921 /* Now fun with versions and EFS file specifications 922 * The parser can not tell the difference when a "." is a version 923 * delimiter or a part of the file specification. 924 */ 925 if ((decc_efs_charset) && 926 (item_list[verspec].length > 0) && 927 (item_list[verspec].component[0] == '.')) { 928 *name = item_list[namespec].component; 929 *name_len = item_list[namespec].length + item_list[typespec].length; 930 *ext = item_list[verspec].component; 931 *ext_len = item_list[verspec].length; 932 *version = NULL; 933 *ver_len = 0; 934 } 935 else { 936 *name = item_list[namespec].component; 937 *name_len = item_list[namespec].length; 938 *ext = item_list[typespec].component; 939 *ext_len = item_list[typespec].length; 940 *version = item_list[verspec].component; 941 *ver_len = item_list[verspec].length; 942 } 943 return ret_stat; 944 } 945 946 /* Routine to determine if the file specification ends with .dir */ 947 static int is_dir_ext(char * e_spec, int e_len, char * vs_spec, int vs_len) { 948 949 /* e_len must be 4, and version must be <= 2 characters */ 950 if (e_len != 4 || vs_len > 2) 951 return 0; 952 953 /* If a version number is present, it needs to be one */ 954 if ((vs_len == 2) && (vs_spec[1] != '1')) 955 return 0; 956 957 /* Look for the DIR on the extension */ 958 if (vms_process_case_tolerant) { 959 if ((toupper(e_spec[1]) == 'D') && 960 (toupper(e_spec[2]) == 'I') && 961 (toupper(e_spec[3]) == 'R')) { 962 return 1; 963 } 964 } else { 965 /* Directory extensions are supposed to be in upper case only */ 966 /* I would not be surprised if this rule can not be enforced */ 967 /* if and when someone fully debugs the case sensitive mode */ 968 if ((e_spec[1] == 'D') && 969 (e_spec[2] == 'I') && 970 (e_spec[3] == 'R')) { 971 return 1; 972 } 973 } 974 return 0; 975 } 976 977 978 /* my_maxidx 979 * Routine to retrieve the maximum equivalence index for an input 980 * logical name. Some calls to this routine have no knowledge if 981 * the variable is a logical or not. So on error we return a max 982 * index of zero. 983 */ 984 /*{{{int my_maxidx(const char *lnm) */ 985 static int 986 my_maxidx(const char *lnm) 987 { 988 int status; 989 int midx; 990 int attr = LNM$M_CASE_BLIND; 991 struct dsc$descriptor lnmdsc; 992 struct itmlst_3 itlst[2] = {{sizeof(midx), LNM$_MAX_INDEX, &midx, 0}, 993 {0, 0, 0, 0}}; 994 995 lnmdsc.dsc$w_length = strlen(lnm); 996 lnmdsc.dsc$b_dtype = DSC$K_DTYPE_T; 997 lnmdsc.dsc$b_class = DSC$K_CLASS_S; 998 lnmdsc.dsc$a_pointer = (char *) lnm; /* Cast ok for read only parameter */ 999 1000 status = sys$trnlnm(&attr, &fildevdsc, &lnmdsc, 0, itlst); 1001 if ((status & 1) == 0) 1002 midx = 0; 1003 1004 return (midx); 1005 } 1006 /*}}}*/ 1007 1008 /*{{{int vmstrnenv(const char *lnm, char *eqv, unsigned long int idx, struct dsc$descriptor_s **tabvec, unsigned long int flags) */ 1009 int 1010 Perl_vmstrnenv(const char *lnm, char *eqv, unsigned long int idx, 1011 struct dsc$descriptor_s **tabvec, unsigned long int flags) 1012 { 1013 const char *cp1; 1014 char uplnm[LNM$C_NAMLENGTH+1], *cp2; 1015 unsigned short int eqvlen, curtab, ivlnm = 0, ivsym = 0, ivenv = 0, secure; 1016 unsigned long int retsts, attr = LNM$M_CASE_BLIND; 1017 int midx; 1018 unsigned char acmode; 1019 struct dsc$descriptor_s lnmdsc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0}, 1020 tmpdsc = {6,DSC$K_DTYPE_T,DSC$K_CLASS_S,0}; 1021 struct itmlst_3 lnmlst[3] = {{sizeof idx, LNM$_INDEX, &idx, 0}, 1022 {LNM$C_NAMLENGTH, LNM$_STRING, eqv, &eqvlen}, 1023 {0, 0, 0, 0}}; 1024 $DESCRIPTOR(crtlenv,"CRTL_ENV"); $DESCRIPTOR(clisym,"CLISYM"); 1025 #if defined(PERL_IMPLICIT_CONTEXT) 1026 pTHX = NULL; 1027 if (PL_curinterp) { 1028 aTHX = PERL_GET_INTERP; 1029 } else { 1030 aTHX = NULL; 1031 } 1032 #endif 1033 1034 if (!lnm || !eqv || ((idx != 0) && ((idx-1) > PERL_LNM_MAX_ALLOWED_INDEX))) { 1035 set_errno(EINVAL); set_vaxc_errno(SS$_BADPARAM); return 0; 1036 } 1037 for (cp1 = lnm, cp2 = uplnm; *cp1; cp1++, cp2++) { 1038 *cp2 = _toupper(*cp1); 1039 if (cp1 - lnm > LNM$C_NAMLENGTH) { 1040 set_errno(EINVAL); set_vaxc_errno(SS$_IVLOGNAM); 1041 return 0; 1042 } 1043 } 1044 lnmdsc.dsc$w_length = cp1 - lnm; 1045 lnmdsc.dsc$a_pointer = uplnm; 1046 uplnm[lnmdsc.dsc$w_length] = '\0'; 1047 secure = flags & PERL__TRNENV_SECURE; 1048 acmode = secure ? PSL$C_EXEC : PSL$C_USER; 1049 if (!tabvec || !*tabvec) tabvec = env_tables; 1050 1051 for (curtab = 0; tabvec[curtab]; curtab++) { 1052 if (!str$case_blind_compare(tabvec[curtab],&crtlenv)) { 1053 if (!ivenv && !secure) { 1054 char *eq, *end; 1055 int i; 1056 if (!environ) { 1057 ivenv = 1; 1058 #if defined(PERL_IMPLICIT_CONTEXT) 1059 if (aTHX == NULL) { 1060 fprintf(stderr, 1061 "Can't read CRTL environ\n"); 1062 } else 1063 #endif 1064 Perl_warn(aTHX_ "Can't read CRTL environ\n"); 1065 continue; 1066 } 1067 retsts = SS$_NOLOGNAM; 1068 for (i = 0; environ[i]; i++) { 1069 if ((eq = strchr(environ[i],'=')) && 1070 lnmdsc.dsc$w_length == (eq - environ[i]) && 1071 !strncmp(environ[i],uplnm,eq - environ[i])) { 1072 eq++; 1073 for (eqvlen = 0; eq[eqvlen]; eqvlen++) eqv[eqvlen] = eq[eqvlen]; 1074 if (!eqvlen) continue; 1075 retsts = SS$_NORMAL; 1076 break; 1077 } 1078 } 1079 if (retsts != SS$_NOLOGNAM) break; 1080 } 1081 } 1082 else if ((tmpdsc.dsc$a_pointer = tabvec[curtab]->dsc$a_pointer) && 1083 !str$case_blind_compare(&tmpdsc,&clisym)) { 1084 if (!ivsym && !secure) { 1085 unsigned short int deflen = LNM$C_NAMLENGTH; 1086 struct dsc$descriptor_d eqvdsc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_D,0}; 1087 /* dynamic dsc to accomodate possible long value */ 1088 _ckvmssts_noperl(lib$sget1_dd(&deflen,&eqvdsc)); 1089 retsts = lib$get_symbol(&lnmdsc,&eqvdsc,&eqvlen,0); 1090 if (retsts & 1) { 1091 if (eqvlen > MAX_DCL_SYMBOL) { 1092 set_errno(EVMSERR); set_vaxc_errno(LIB$_STRTRU); 1093 eqvlen = MAX_DCL_SYMBOL; 1094 /* Special hack--we might be called before the interpreter's */ 1095 /* fully initialized, in which case either thr or PL_curcop */ 1096 /* might be bogus. We have to check, since ckWARN needs them */ 1097 /* both to be valid if running threaded */ 1098 #if defined(PERL_IMPLICIT_CONTEXT) 1099 if (aTHX == NULL) { 1100 fprintf(stderr, 1101 "Value of CLI symbol \"%s\" too long",lnm); 1102 } else 1103 #endif 1104 if (ckWARN(WARN_MISC)) { 1105 Perl_warner(aTHX_ packWARN(WARN_MISC),"Value of CLI symbol \"%s\" too long",lnm); 1106 } 1107 } 1108 strncpy(eqv,eqvdsc.dsc$a_pointer,eqvlen); 1109 } 1110 _ckvmssts_noperl(lib$sfree1_dd(&eqvdsc)); 1111 if (retsts == LIB$_INVSYMNAM) { ivsym = 1; continue; } 1112 if (retsts == LIB$_NOSUCHSYM) continue; 1113 break; 1114 } 1115 } 1116 else if (!ivlnm) { 1117 if ( (idx == 0) && (flags & PERL__TRNENV_JOIN_SEARCHLIST) ) { 1118 midx = my_maxidx(lnm); 1119 for (idx = 0, cp2 = eqv; idx <= midx; idx++) { 1120 lnmlst[1].bufadr = cp2; 1121 eqvlen = 0; 1122 retsts = sys$trnlnm(&attr,tabvec[curtab],&lnmdsc,&acmode,lnmlst); 1123 if (retsts == SS$_IVLOGNAM) { ivlnm = 1; break; } 1124 if (retsts == SS$_NOLOGNAM) break; 1125 /* PPFs have a prefix */ 1126 if ( 1127 #if INTSIZE == 4 1128 *((int *)uplnm) == *((int *)"SYS$") && 1129 #endif 1130 eqvlen >= 4 && eqv[0] == 0x1b && eqv[1] == 0x00 && 1131 ( (uplnm[4] == 'O' && !strcmp(uplnm,"SYS$OUTPUT")) || 1132 (uplnm[4] == 'I' && !strcmp(uplnm,"SYS$INPUT")) || 1133 (uplnm[4] == 'E' && !strcmp(uplnm,"SYS$ERROR")) || 1134 (uplnm[4] == 'C' && !strcmp(uplnm,"SYS$COMMAND")) ) ) { 1135 memmove(eqv,eqv+4,eqvlen-4); 1136 eqvlen -= 4; 1137 } 1138 cp2 += eqvlen; 1139 *cp2 = '\0'; 1140 } 1141 if ((retsts == SS$_IVLOGNAM) || 1142 (retsts == SS$_NOLOGNAM)) { continue; } 1143 } 1144 else { 1145 retsts = sys$trnlnm(&attr,tabvec[curtab],&lnmdsc,&acmode,lnmlst); 1146 if (retsts == SS$_IVLOGNAM) { ivlnm = 1; continue; } 1147 if (retsts == SS$_NOLOGNAM) continue; 1148 eqv[eqvlen] = '\0'; 1149 } 1150 eqvlen = strlen(eqv); 1151 break; 1152 } 1153 } 1154 if (retsts & 1) { eqv[eqvlen] = '\0'; return eqvlen; } 1155 else if (retsts == LIB$_NOSUCHSYM || retsts == LIB$_INVSYMNAM || 1156 retsts == SS$_IVLOGNAM || retsts == SS$_IVLOGTAB || 1157 retsts == SS$_NOLOGNAM) { 1158 set_errno(EINVAL); set_vaxc_errno(retsts); 1159 } 1160 else _ckvmssts_noperl(retsts); 1161 return 0; 1162 } /* end of vmstrnenv */ 1163 /*}}}*/ 1164 1165 /*{{{ int my_trnlnm(const char *lnm, char *eqv, unsigned long int idx)*/ 1166 /* Define as a function so we can access statics. */ 1167 int Perl_my_trnlnm(pTHX_ const char *lnm, char *eqv, unsigned long int idx) 1168 { 1169 int flags = 0; 1170 1171 #if defined(PERL_IMPLICIT_CONTEXT) 1172 if (aTHX != NULL) 1173 #endif 1174 #ifdef SECURE_INTERNAL_GETENV 1175 flags = (PL_curinterp ? PL_tainting : will_taint) ? 1176 PERL__TRNENV_SECURE : 0; 1177 #endif 1178 1179 return vmstrnenv(lnm, eqv, idx, fildev, flags); 1180 } 1181 /*}}}*/ 1182 1183 /* my_getenv 1184 * Note: Uses Perl temp to store result so char * can be returned to 1185 * caller; this pointer will be invalidated at next Perl statement 1186 * transition. 1187 * We define this as a function rather than a macro in terms of my_getenv_len() 1188 * so that it'll work when PL_curinterp is undefined (and we therefore can't 1189 * allocate SVs). 1190 */ 1191 /*{{{ char *my_getenv(const char *lnm, bool sys)*/ 1192 char * 1193 Perl_my_getenv(pTHX_ const char *lnm, bool sys) 1194 { 1195 const char *cp1; 1196 static char *__my_getenv_eqv = NULL; 1197 char uplnm[LNM$C_NAMLENGTH+1], *cp2, *eqv; 1198 unsigned long int idx = 0; 1199 int trnsuccess, success, secure, saverr, savvmserr; 1200 int midx, flags; 1201 SV *tmpsv; 1202 1203 midx = my_maxidx(lnm) + 1; 1204 1205 if (PL_curinterp) { /* Perl interpreter running -- may be threaded */ 1206 /* Set up a temporary buffer for the return value; Perl will 1207 * clean it up at the next statement transition */ 1208 tmpsv = sv_2mortal(newSVpv("",(LNM$C_NAMLENGTH*midx)+1)); 1209 if (!tmpsv) return NULL; 1210 eqv = SvPVX(tmpsv); 1211 } 1212 else { 1213 /* Assume no interpreter ==> single thread */ 1214 if (__my_getenv_eqv != NULL) { 1215 Renew(__my_getenv_eqv,LNM$C_NAMLENGTH*midx+1,char); 1216 } 1217 else { 1218 Newx(__my_getenv_eqv,LNM$C_NAMLENGTH*midx+1,char); 1219 } 1220 eqv = __my_getenv_eqv; 1221 } 1222 1223 for (cp1 = lnm, cp2 = eqv; *cp1; cp1++,cp2++) *cp2 = _toupper(*cp1); 1224 if (cp1 - lnm == 7 && !strncmp(eqv,"DEFAULT",7)) { 1225 int len; 1226 getcwd(eqv,LNM$C_NAMLENGTH); 1227 1228 len = strlen(eqv); 1229 1230 /* Get rid of "000000/ in rooted filespecs */ 1231 if (len > 7) { 1232 char * zeros; 1233 zeros = strstr(eqv, "/000000/"); 1234 if (zeros != NULL) { 1235 int mlen; 1236 mlen = len - (zeros - eqv) - 7; 1237 memmove(zeros, &zeros[7], mlen); 1238 len = len - 7; 1239 eqv[len] = '\0'; 1240 } 1241 } 1242 return eqv; 1243 } 1244 else { 1245 /* Impose security constraints only if tainting */ 1246 if (sys) { 1247 /* Impose security constraints only if tainting */ 1248 secure = PL_curinterp ? PL_tainting : will_taint; 1249 saverr = errno; savvmserr = vaxc$errno; 1250 } 1251 else { 1252 secure = 0; 1253 } 1254 1255 flags = 1256 #ifdef SECURE_INTERNAL_GETENV 1257 secure ? PERL__TRNENV_SECURE : 0 1258 #else 1259 0 1260 #endif 1261 ; 1262 1263 /* For the getenv interface we combine all the equivalence names 1264 * of a search list logical into one value to acquire a maximum 1265 * value length of 255*128 (assuming %ENV is using logicals). 1266 */ 1267 flags |= PERL__TRNENV_JOIN_SEARCHLIST; 1268 1269 /* If the name contains a semicolon-delimited index, parse it 1270 * off and make sure we only retrieve the equivalence name for 1271 * that index. */ 1272 if ((cp2 = strchr(lnm,';')) != NULL) { 1273 strcpy(uplnm,lnm); 1274 uplnm[cp2-lnm] = '\0'; 1275 idx = strtoul(cp2+1,NULL,0); 1276 lnm = uplnm; 1277 flags &= ~PERL__TRNENV_JOIN_SEARCHLIST; 1278 } 1279 1280 success = vmstrnenv(lnm,eqv,idx,secure ? fildev : NULL,flags); 1281 1282 /* Discard NOLOGNAM on internal calls since we're often looking 1283 * for an optional name, and this "error" often shows up as the 1284 * (bogus) exit status for a die() call later on. */ 1285 if (sys && vaxc$errno == SS$_NOLOGNAM) SETERRNO(saverr,savvmserr); 1286 return success ? eqv : NULL; 1287 } 1288 1289 } /* end of my_getenv() */ 1290 /*}}}*/ 1291 1292 1293 /*{{{ SV *my_getenv_len(const char *lnm, bool sys)*/ 1294 char * 1295 Perl_my_getenv_len(pTHX_ const char *lnm, unsigned long *len, bool sys) 1296 { 1297 const char *cp1; 1298 char *buf, *cp2; 1299 unsigned long idx = 0; 1300 int midx, flags; 1301 static char *__my_getenv_len_eqv = NULL; 1302 int secure, saverr, savvmserr; 1303 SV *tmpsv; 1304 1305 midx = my_maxidx(lnm) + 1; 1306 1307 if (PL_curinterp) { /* Perl interpreter running -- may be threaded */ 1308 /* Set up a temporary buffer for the return value; Perl will 1309 * clean it up at the next statement transition */ 1310 tmpsv = sv_2mortal(newSVpv("",(LNM$C_NAMLENGTH*midx)+1)); 1311 if (!tmpsv) return NULL; 1312 buf = SvPVX(tmpsv); 1313 } 1314 else { 1315 /* Assume no interpreter ==> single thread */ 1316 if (__my_getenv_len_eqv != NULL) { 1317 Renew(__my_getenv_len_eqv,LNM$C_NAMLENGTH*midx+1,char); 1318 } 1319 else { 1320 Newx(__my_getenv_len_eqv,LNM$C_NAMLENGTH*midx+1,char); 1321 } 1322 buf = __my_getenv_len_eqv; 1323 } 1324 1325 for (cp1 = lnm, cp2 = buf; *cp1; cp1++,cp2++) *cp2 = _toupper(*cp1); 1326 if (cp1 - lnm == 7 && !strncmp(buf,"DEFAULT",7)) { 1327 char * zeros; 1328 1329 getcwd(buf,LNM$C_NAMLENGTH); 1330 *len = strlen(buf); 1331 1332 /* Get rid of "000000/ in rooted filespecs */ 1333 if (*len > 7) { 1334 zeros = strstr(buf, "/000000/"); 1335 if (zeros != NULL) { 1336 int mlen; 1337 mlen = *len - (zeros - buf) - 7; 1338 memmove(zeros, &zeros[7], mlen); 1339 *len = *len - 7; 1340 buf[*len] = '\0'; 1341 } 1342 } 1343 return buf; 1344 } 1345 else { 1346 if (sys) { 1347 /* Impose security constraints only if tainting */ 1348 secure = PL_curinterp ? PL_tainting : will_taint; 1349 saverr = errno; savvmserr = vaxc$errno; 1350 } 1351 else { 1352 secure = 0; 1353 } 1354 1355 flags = 1356 #ifdef SECURE_INTERNAL_GETENV 1357 secure ? PERL__TRNENV_SECURE : 0 1358 #else 1359 0 1360 #endif 1361 ; 1362 1363 flags |= PERL__TRNENV_JOIN_SEARCHLIST; 1364 1365 if ((cp2 = strchr(lnm,';')) != NULL) { 1366 strcpy(buf,lnm); 1367 buf[cp2-lnm] = '\0'; 1368 idx = strtoul(cp2+1,NULL,0); 1369 lnm = buf; 1370 flags &= ~PERL__TRNENV_JOIN_SEARCHLIST; 1371 } 1372 1373 *len = vmstrnenv(lnm,buf,idx,secure ? fildev : NULL,flags); 1374 1375 /* Get rid of "000000/ in rooted filespecs */ 1376 if (*len > 7) { 1377 char * zeros; 1378 zeros = strstr(buf, "/000000/"); 1379 if (zeros != NULL) { 1380 int mlen; 1381 mlen = *len - (zeros - buf) - 7; 1382 memmove(zeros, &zeros[7], mlen); 1383 *len = *len - 7; 1384 buf[*len] = '\0'; 1385 } 1386 } 1387 1388 /* Discard NOLOGNAM on internal calls since we're often looking 1389 * for an optional name, and this "error" often shows up as the 1390 * (bogus) exit status for a die() call later on. */ 1391 if (sys && vaxc$errno == SS$_NOLOGNAM) SETERRNO(saverr,savvmserr); 1392 return *len ? buf : NULL; 1393 } 1394 1395 } /* end of my_getenv_len() */ 1396 /*}}}*/ 1397 1398 static void create_mbx(unsigned short int *, struct dsc$descriptor_s *); 1399 1400 static void riseandshine(unsigned long int dummy) { sys$wake(0,0); } 1401 1402 /*{{{ void prime_env_iter() */ 1403 void 1404 prime_env_iter(void) 1405 /* Fill the %ENV associative array with all logical names we can 1406 * find, in preparation for iterating over it. 1407 */ 1408 { 1409 static int primed = 0; 1410 HV *seenhv = NULL, *envhv; 1411 SV *sv = NULL; 1412 char cmd[LNM$C_NAMLENGTH+24], mbxnam[LNM$C_NAMLENGTH], *buf = NULL; 1413 unsigned short int chan; 1414 #ifndef CLI$M_TRUSTED 1415 # define CLI$M_TRUSTED 0x40 /* Missing from VAXC headers */ 1416 #endif 1417 unsigned long int defflags = CLI$M_NOWAIT | CLI$M_NOKEYPAD | CLI$M_TRUSTED; 1418 unsigned long int mbxbufsiz, flags, retsts, subpid = 0, substs = 0, wakect = 0; 1419 long int i; 1420 bool have_sym = FALSE, have_lnm = FALSE; 1421 struct dsc$descriptor_s tmpdsc = {6,DSC$K_DTYPE_T,DSC$K_CLASS_S,0}; 1422 $DESCRIPTOR(cmddsc,cmd); $DESCRIPTOR(nldsc,"_NLA0:"); 1423 $DESCRIPTOR(clidsc,"DCL"); $DESCRIPTOR(clitabdsc,"DCLTABLES"); 1424 $DESCRIPTOR(crtlenv,"CRTL_ENV"); $DESCRIPTOR(clisym,"CLISYM"); 1425 $DESCRIPTOR(local,"_LOCAL"); $DESCRIPTOR(mbxdsc,mbxnam); 1426 #if defined(PERL_IMPLICIT_CONTEXT) 1427 pTHX; 1428 #endif 1429 #if defined(USE_ITHREADS) 1430 static perl_mutex primenv_mutex; 1431 MUTEX_INIT(&primenv_mutex); 1432 #endif 1433 1434 #if defined(PERL_IMPLICIT_CONTEXT) 1435 /* We jump through these hoops because we can be called at */ 1436 /* platform-specific initialization time, which is before anything is */ 1437 /* set up--we can't even do a plain dTHX since that relies on the */ 1438 /* interpreter structure to be initialized */ 1439 if (PL_curinterp) { 1440 aTHX = PERL_GET_INTERP; 1441 } else { 1442 /* we never get here because the NULL pointer will cause the */ 1443 /* several of the routines called by this routine to access violate */ 1444 1445 /* This routine is only called by hv.c/hv_iterinit which has a */ 1446 /* context, so the real fix may be to pass it through instead of */ 1447 /* the hoops above */ 1448 aTHX = NULL; 1449 } 1450 #endif 1451 1452 if (primed || !PL_envgv) return; 1453 MUTEX_LOCK(&primenv_mutex); 1454 if (primed) { MUTEX_UNLOCK(&primenv_mutex); return; } 1455 envhv = GvHVn(PL_envgv); 1456 /* Perform a dummy fetch as an lval to insure that the hash table is 1457 * set up. Otherwise, the hv_store() will turn into a nullop. */ 1458 (void) hv_fetch(envhv,"DEFAULT",7,TRUE); 1459 1460 for (i = 0; env_tables[i]; i++) { 1461 if (!have_sym && (tmpdsc.dsc$a_pointer = env_tables[i]->dsc$a_pointer) && 1462 !str$case_blind_compare(&tmpdsc,&clisym)) have_sym = 1; 1463 if (!have_lnm && str$case_blind_compare(env_tables[i],&crtlenv)) have_lnm = 1; 1464 } 1465 if (have_sym || have_lnm) { 1466 long int syiitm = SYI$_MAXBUF, dviitm = DVI$_DEVNAM; 1467 _ckvmssts(lib$getsyi(&syiitm, &mbxbufsiz, 0, 0, 0, 0)); 1468 _ckvmssts(sys$crembx(0,&chan,mbxbufsiz,mbxbufsiz,0xff0f,0,0)); 1469 _ckvmssts(lib$getdvi(&dviitm, &chan, NULL, NULL, &mbxdsc, &mbxdsc.dsc$w_length)); 1470 } 1471 1472 for (i--; i >= 0; i--) { 1473 if (!str$case_blind_compare(env_tables[i],&crtlenv)) { 1474 char *start; 1475 int j; 1476 for (j = 0; environ[j]; j++) { 1477 if (!(start = strchr(environ[j],'='))) { 1478 if (ckWARN(WARN_INTERNAL)) 1479 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"Ill-formed CRTL environ value \"%s\"\n",environ[j]); 1480 } 1481 else { 1482 start++; 1483 sv = newSVpv(start,0); 1484 SvTAINTED_on(sv); 1485 (void) hv_store(envhv,environ[j],start - environ[j] - 1,sv,0); 1486 } 1487 } 1488 continue; 1489 } 1490 else if ((tmpdsc.dsc$a_pointer = env_tables[i]->dsc$a_pointer) && 1491 !str$case_blind_compare(&tmpdsc,&clisym)) { 1492 strcpy(cmd,"Show Symbol/Global *"); 1493 cmddsc.dsc$w_length = 20; 1494 if (env_tables[i]->dsc$w_length == 12 && 1495 (tmpdsc.dsc$a_pointer = env_tables[i]->dsc$a_pointer + 6) && 1496 !str$case_blind_compare(&tmpdsc,&local)) strcpy(cmd+12,"Local *"); 1497 flags = defflags | CLI$M_NOLOGNAM; 1498 } 1499 else { 1500 strcpy(cmd,"Show Logical *"); 1501 if (str$case_blind_compare(env_tables[i],&fildevdsc)) { 1502 strcat(cmd," /Table="); 1503 strncat(cmd,env_tables[i]->dsc$a_pointer,env_tables[i]->dsc$w_length); 1504 cmddsc.dsc$w_length = strlen(cmd); 1505 } 1506 else cmddsc.dsc$w_length = 14; /* N.B. We test this below */ 1507 flags = defflags | CLI$M_NOCLISYM; 1508 } 1509 1510 /* Create a new subprocess to execute each command, to exclude the 1511 * remote possibility that someone could subvert a mbx or file used 1512 * to write multiple commands to a single subprocess. 1513 */ 1514 do { 1515 retsts = lib$spawn(&cmddsc,&nldsc,&mbxdsc,&flags,0,&subpid,&substs, 1516 0,&riseandshine,0,0,&clidsc,&clitabdsc); 1517 flags &= ~CLI$M_TRUSTED; /* Just in case we hit a really old version */ 1518 defflags &= ~CLI$M_TRUSTED; 1519 } while (retsts == LIB$_INVARG && (flags | CLI$M_TRUSTED)); 1520 _ckvmssts(retsts); 1521 if (!buf) Newx(buf,mbxbufsiz + 1,char); 1522 if (seenhv) SvREFCNT_dec(seenhv); 1523 seenhv = newHV(); 1524 while (1) { 1525 char *cp1, *cp2, *key; 1526 unsigned long int sts, iosb[2], retlen, keylen; 1527 register U32 hash; 1528 1529 sts = sys$qiow(0,chan,IO$_READVBLK,iosb,0,0,buf,mbxbufsiz,0,0,0,0); 1530 if (sts & 1) sts = iosb[0] & 0xffff; 1531 if (sts == SS$_ENDOFFILE) { 1532 int wakect = 0; 1533 while (substs == 0) { sys$hiber(); wakect++;} 1534 if (wakect > 1) sys$wake(0,0); /* Stole someone else's wake */ 1535 _ckvmssts(substs); 1536 break; 1537 } 1538 _ckvmssts(sts); 1539 retlen = iosb[0] >> 16; 1540 if (!retlen) continue; /* blank line */ 1541 buf[retlen] = '\0'; 1542 if (iosb[1] != subpid) { 1543 if (iosb[1]) { 1544 Perl_croak(aTHX_ "Unknown process %x sent message to prime_env_iter: %s",buf); 1545 } 1546 continue; 1547 } 1548 if (sts == SS$_BUFFEROVF && ckWARN(WARN_INTERNAL)) 1549 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"Buffer overflow in prime_env_iter: %s",buf); 1550 1551 for (cp1 = buf; *cp1 && isspace(*cp1); cp1++) ; 1552 if (*cp1 == '(' || /* Logical name table name */ 1553 *cp1 == '=' /* Next eqv of searchlist */) continue; 1554 if (*cp1 == '"') cp1++; 1555 for (cp2 = cp1; *cp2 && *cp2 != '"' && *cp2 != ' '; cp2++) ; 1556 key = cp1; keylen = cp2 - cp1; 1557 if (keylen && hv_exists(seenhv,key,keylen)) continue; 1558 while (*cp2 && *cp2 != '=') cp2++; 1559 while (*cp2 && *cp2 == '=') cp2++; 1560 while (*cp2 && *cp2 == ' ') cp2++; 1561 if (*cp2 == '"') { /* String translation; may embed "" */ 1562 for (cp1 = buf + retlen; *cp1 != '"'; cp1--) ; 1563 cp2++; cp1--; /* Skip "" surrounding translation */ 1564 } 1565 else { /* Numeric translation */ 1566 for (cp1 = cp2; *cp1 && *cp1 != ' '; cp1++) ; 1567 cp1--; /* stop on last non-space char */ 1568 } 1569 if ((!keylen || (cp1 - cp2 < -1)) && ckWARN(WARN_INTERNAL)) { 1570 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"Ill-formed message in prime_env_iter: |%s|",buf); 1571 continue; 1572 } 1573 PERL_HASH(hash,key,keylen); 1574 1575 if (cp1 == cp2 && *cp2 == '.') { 1576 /* A single dot usually means an unprintable character, such as a null 1577 * to indicate a zero-length value. Get the actual value to make sure. 1578 */ 1579 char lnm[LNM$C_NAMLENGTH+1]; 1580 char eqv[MAX_DCL_SYMBOL+1]; 1581 int trnlen; 1582 strncpy(lnm, key, keylen); 1583 trnlen = vmstrnenv(lnm, eqv, 0, fildev, 0); 1584 sv = newSVpvn(eqv, strlen(eqv)); 1585 } 1586 else { 1587 sv = newSVpvn(cp2,cp1 - cp2 + 1); 1588 } 1589 1590 SvTAINTED_on(sv); 1591 hv_store(envhv,key,keylen,sv,hash); 1592 hv_store(seenhv,key,keylen,&PL_sv_yes,hash); 1593 } 1594 if (cmddsc.dsc$w_length == 14) { /* We just read LNM$FILE_DEV */ 1595 /* get the PPFs for this process, not the subprocess */ 1596 const char *ppfs[] = {"SYS$COMMAND", "SYS$INPUT", "SYS$OUTPUT", "SYS$ERROR", NULL}; 1597 char eqv[LNM$C_NAMLENGTH+1]; 1598 int trnlen, i; 1599 for (i = 0; ppfs[i]; i++) { 1600 trnlen = vmstrnenv(ppfs[i],eqv,0,fildev,0); 1601 sv = newSVpv(eqv,trnlen); 1602 SvTAINTED_on(sv); 1603 hv_store(envhv,ppfs[i],strlen(ppfs[i]),sv,0); 1604 } 1605 } 1606 } 1607 primed = 1; 1608 if (have_sym || have_lnm) _ckvmssts(sys$dassgn(chan)); 1609 if (buf) Safefree(buf); 1610 if (seenhv) SvREFCNT_dec(seenhv); 1611 MUTEX_UNLOCK(&primenv_mutex); 1612 return; 1613 1614 } /* end of prime_env_iter */ 1615 /*}}}*/ 1616 1617 1618 /*{{{ int vmssetenv(const char *lnm, const char *eqv)*/ 1619 /* Define or delete an element in the same "environment" as 1620 * vmstrnenv(). If an element is to be deleted, it's removed from 1621 * the first place it's found. If it's to be set, it's set in the 1622 * place designated by the first element of the table vector. 1623 * Like setenv() returns 0 for success, non-zero on error. 1624 */ 1625 int 1626 Perl_vmssetenv(pTHX_ const char *lnm, const char *eqv, struct dsc$descriptor_s **tabvec) 1627 { 1628 const char *cp1; 1629 char uplnm[LNM$C_NAMLENGTH], *cp2, *c; 1630 unsigned short int curtab, ivlnm = 0, ivsym = 0, ivenv = 0; 1631 int nseg = 0, j; 1632 unsigned long int retsts, usermode = PSL$C_USER; 1633 struct itmlst_3 *ile, *ilist; 1634 struct dsc$descriptor_s lnmdsc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,uplnm}, 1635 eqvdsc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0}, 1636 tmpdsc = {6,DSC$K_DTYPE_T,DSC$K_CLASS_S,0}; 1637 $DESCRIPTOR(crtlenv,"CRTL_ENV"); $DESCRIPTOR(clisym,"CLISYM"); 1638 $DESCRIPTOR(local,"_LOCAL"); 1639 1640 if (!lnm) { 1641 set_errno(EINVAL); set_vaxc_errno(SS$_IVLOGNAM); 1642 return SS$_IVLOGNAM; 1643 } 1644 1645 for (cp1 = lnm, cp2 = uplnm; *cp1; cp1++, cp2++) { 1646 *cp2 = _toupper(*cp1); 1647 if (cp1 - lnm > LNM$C_NAMLENGTH) { 1648 set_errno(EINVAL); set_vaxc_errno(SS$_IVLOGNAM); 1649 return SS$_IVLOGNAM; 1650 } 1651 } 1652 lnmdsc.dsc$w_length = cp1 - lnm; 1653 if (!tabvec || !*tabvec) tabvec = env_tables; 1654 1655 if (!eqv) { /* we're deleting n element */ 1656 for (curtab = 0; tabvec[curtab]; curtab++) { 1657 if (!ivenv && !str$case_blind_compare(tabvec[curtab],&crtlenv)) { 1658 int i; 1659 for (i = 0; environ[i]; i++) { /* If it's an environ elt, reset */ 1660 if ((cp1 = strchr(environ[i],'=')) && 1661 lnmdsc.dsc$w_length == (cp1 - environ[i]) && 1662 !strncmp(environ[i],lnm,cp1 - environ[i])) { 1663 #ifdef HAS_SETENV 1664 return setenv(lnm,"",1) ? vaxc$errno : 0; 1665 } 1666 } 1667 ivenv = 1; retsts = SS$_NOLOGNAM; 1668 #else 1669 if (ckWARN(WARN_INTERNAL)) 1670 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"This Perl can't reset CRTL environ elements (%s)",lnm); 1671 ivenv = 1; retsts = SS$_NOSUCHPGM; 1672 break; 1673 } 1674 } 1675 #endif 1676 } 1677 else if ((tmpdsc.dsc$a_pointer = tabvec[curtab]->dsc$a_pointer) && 1678 !str$case_blind_compare(&tmpdsc,&clisym)) { 1679 unsigned int symtype; 1680 if (tabvec[curtab]->dsc$w_length == 12 && 1681 (tmpdsc.dsc$a_pointer = tabvec[curtab]->dsc$a_pointer + 6) && 1682 !str$case_blind_compare(&tmpdsc,&local)) 1683 symtype = LIB$K_CLI_LOCAL_SYM; 1684 else symtype = LIB$K_CLI_GLOBAL_SYM; 1685 retsts = lib$delete_symbol(&lnmdsc,&symtype); 1686 if (retsts == LIB$_INVSYMNAM) { ivsym = 1; continue; } 1687 if (retsts == LIB$_NOSUCHSYM) continue; 1688 break; 1689 } 1690 else if (!ivlnm) { 1691 retsts = sys$dellnm(tabvec[curtab],&lnmdsc,&usermode); /* try user mode first */ 1692 if (retsts == SS$_IVLOGNAM) { ivlnm = 1; continue; } 1693 if (retsts != SS$_NOLOGNAM && retsts != SS$_NOLOGTAB) break; 1694 retsts = lib$delete_logical(&lnmdsc,tabvec[curtab]); /* then supervisor mode */ 1695 if (retsts != SS$_NOLOGNAM && retsts != SS$_NOLOGTAB) break; 1696 } 1697 } 1698 } 1699 else { /* we're defining a value */ 1700 if (!ivenv && !str$case_blind_compare(tabvec[0],&crtlenv)) { 1701 #ifdef HAS_SETENV 1702 return setenv(lnm,eqv,1) ? vaxc$errno : 0; 1703 #else 1704 if (ckWARN(WARN_INTERNAL)) 1705 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"This Perl can't set CRTL environ elements (%s=%s)",lnm,eqv); 1706 retsts = SS$_NOSUCHPGM; 1707 #endif 1708 } 1709 else { 1710 eqvdsc.dsc$a_pointer = (char *) eqv; /* cast ok to readonly parameter */ 1711 eqvdsc.dsc$w_length = strlen(eqv); 1712 if ((tmpdsc.dsc$a_pointer = tabvec[0]->dsc$a_pointer) && 1713 !str$case_blind_compare(&tmpdsc,&clisym)) { 1714 unsigned int symtype; 1715 if (tabvec[0]->dsc$w_length == 12 && 1716 (tmpdsc.dsc$a_pointer = tabvec[0]->dsc$a_pointer + 6) && 1717 !str$case_blind_compare(&tmpdsc,&local)) 1718 symtype = LIB$K_CLI_LOCAL_SYM; 1719 else symtype = LIB$K_CLI_GLOBAL_SYM; 1720 retsts = lib$set_symbol(&lnmdsc,&eqvdsc,&symtype); 1721 } 1722 else { 1723 if (!*eqv) eqvdsc.dsc$w_length = 1; 1724 if (eqvdsc.dsc$w_length > LNM$C_NAMLENGTH) { 1725 1726 nseg = (eqvdsc.dsc$w_length + LNM$C_NAMLENGTH - 1) / LNM$C_NAMLENGTH; 1727 if (nseg > PERL_LNM_MAX_ALLOWED_INDEX + 1) { 1728 Perl_warner(aTHX_ packWARN(WARN_MISC),"Value of logical \"%s\" too long. Truncating to %i bytes", 1729 lnm, LNM$C_NAMLENGTH * (PERL_LNM_MAX_ALLOWED_INDEX+1)); 1730 eqvdsc.dsc$w_length = LNM$C_NAMLENGTH * (PERL_LNM_MAX_ALLOWED_INDEX+1); 1731 nseg = PERL_LNM_MAX_ALLOWED_INDEX + 1; 1732 } 1733 1734 Newx(ilist,nseg+1,struct itmlst_3); 1735 ile = ilist; 1736 if (!ile) { 1737 set_errno(ENOMEM); set_vaxc_errno(SS$_INSFMEM); 1738 return SS$_INSFMEM; 1739 } 1740 memset(ilist, 0, (sizeof(struct itmlst_3) * (nseg+1))); 1741 1742 for (j = 0, c = eqvdsc.dsc$a_pointer; j < nseg; j++, ile++, c += LNM$C_NAMLENGTH) { 1743 ile->itmcode = LNM$_STRING; 1744 ile->bufadr = c; 1745 if ((j+1) == nseg) { 1746 ile->buflen = strlen(c); 1747 /* in case we are truncating one that's too long */ 1748 if (ile->buflen > LNM$C_NAMLENGTH) ile->buflen = LNM$C_NAMLENGTH; 1749 } 1750 else { 1751 ile->buflen = LNM$C_NAMLENGTH; 1752 } 1753 } 1754 1755 retsts = lib$set_logical(&lnmdsc,0,tabvec[0],0,ilist); 1756 Safefree (ilist); 1757 } 1758 else { 1759 retsts = lib$set_logical(&lnmdsc,&eqvdsc,tabvec[0],0,0); 1760 } 1761 } 1762 } 1763 } 1764 if (!(retsts & 1)) { 1765 switch (retsts) { 1766 case LIB$_AMBSYMDEF: case LIB$_INSCLIMEM: 1767 case SS$_NOLOGTAB: case SS$_TOOMANYLNAM: case SS$_IVLOGTAB: 1768 set_errno(EVMSERR); break; 1769 case LIB$_INVARG: case LIB$_INVSYMNAM: case SS$_IVLOGNAM: 1770 case LIB$_NOSUCHSYM: case SS$_NOLOGNAM: 1771 set_errno(EINVAL); break; 1772 case SS$_NOPRIV: 1773 set_errno(EACCES); break; 1774 default: 1775 _ckvmssts(retsts); 1776 set_errno(EVMSERR); 1777 } 1778 set_vaxc_errno(retsts); 1779 return (int) retsts || 44; /* retsts should never be 0, but just in case */ 1780 } 1781 else { 1782 /* We reset error values on success because Perl does an hv_fetch() 1783 * before each hv_store(), and if the thing we're setting didn't 1784 * previously exist, we've got a leftover error message. (Of course, 1785 * this fails in the face of 1786 * $foo = $ENV{nonexistent}; $ENV{existent} = 'foo'; 1787 * in that the error reported in $! isn't spurious, 1788 * but it's right more often than not.) 1789 */ 1790 set_errno(0); set_vaxc_errno(retsts); 1791 return 0; 1792 } 1793 1794 } /* end of vmssetenv() */ 1795 /*}}}*/ 1796 1797 /*{{{ void my_setenv(const char *lnm, const char *eqv)*/ 1798 /* This has to be a function since there's a prototype for it in proto.h */ 1799 void 1800 Perl_my_setenv(pTHX_ const char *lnm, const char *eqv) 1801 { 1802 if (lnm && *lnm) { 1803 int len = strlen(lnm); 1804 if (len == 7) { 1805 char uplnm[8]; 1806 int i; 1807 for (i = 0; lnm[i]; i++) uplnm[i] = _toupper(lnm[i]); 1808 if (!strcmp(uplnm,"DEFAULT")) { 1809 if (eqv && *eqv) my_chdir(eqv); 1810 return; 1811 } 1812 } 1813 #ifndef RTL_USES_UTC 1814 if (len == 6 || len == 2) { 1815 char uplnm[7]; 1816 int i; 1817 for (i = 0; lnm[i]; i++) uplnm[i] = _toupper(lnm[i]); 1818 uplnm[len] = '\0'; 1819 if (!strcmp(uplnm,"UCX$TZ")) tz_updated = 1; 1820 if (!strcmp(uplnm,"TZ")) tz_updated = 1; 1821 } 1822 #endif 1823 } 1824 (void) vmssetenv(lnm,eqv,NULL); 1825 } 1826 /*}}}*/ 1827 1828 /*{{{static void vmssetuserlnm(char *name, char *eqv); */ 1829 /* vmssetuserlnm 1830 * sets a user-mode logical in the process logical name table 1831 * used for redirection of sys$error 1832 * 1833 * Fix-me: The pTHX is not needed for this routine, however doio.c 1834 * is calling it with one instead of using a macro. 1835 * A macro needs to be added to vmsish.h and doio.c updated to use it. 1836 * 1837 */ 1838 void 1839 Perl_vmssetuserlnm(pTHX_ const char *name, const char *eqv) 1840 { 1841 $DESCRIPTOR(d_tab, "LNM$PROCESS"); 1842 struct dsc$descriptor_d d_name = {0,DSC$K_DTYPE_T,DSC$K_CLASS_D,0}; 1843 unsigned long int iss, attr = LNM$M_CONFINE; 1844 unsigned char acmode = PSL$C_USER; 1845 struct itmlst_3 lnmlst[2] = {{0, LNM$_STRING, 0, 0}, 1846 {0, 0, 0, 0}}; 1847 d_name.dsc$a_pointer = (char *)name; /* Cast OK for read only parameter */ 1848 d_name.dsc$w_length = strlen(name); 1849 1850 lnmlst[0].buflen = strlen(eqv); 1851 lnmlst[0].bufadr = (char *)eqv; /* Cast OK for read only parameter */ 1852 1853 iss = sys$crelnm(&attr,&d_tab,&d_name,&acmode,lnmlst); 1854 if (!(iss&1)) lib$signal(iss); 1855 } 1856 /*}}}*/ 1857 1858 1859 /*{{{ char *my_crypt(const char *textpasswd, const char *usrname)*/ 1860 /* my_crypt - VMS password hashing 1861 * my_crypt() provides an interface compatible with the Unix crypt() 1862 * C library function, and uses sys$hash_password() to perform VMS 1863 * password hashing. The quadword hashed password value is returned 1864 * as a NUL-terminated 8 character string. my_crypt() does not change 1865 * the case of its string arguments; in order to match the behavior 1866 * of LOGINOUT et al., alphabetic characters in both arguments must 1867 * be upcased by the caller. 1868 * 1869 * - fix me to call ACM services when available 1870 */ 1871 char * 1872 Perl_my_crypt(pTHX_ const char *textpasswd, const char *usrname) 1873 { 1874 # ifndef UAI$C_PREFERRED_ALGORITHM 1875 # define UAI$C_PREFERRED_ALGORITHM 127 1876 # endif 1877 unsigned char alg = UAI$C_PREFERRED_ALGORITHM; 1878 unsigned short int salt = 0; 1879 unsigned long int sts; 1880 struct const_dsc { 1881 unsigned short int dsc$w_length; 1882 unsigned char dsc$b_type; 1883 unsigned char dsc$b_class; 1884 const char * dsc$a_pointer; 1885 } usrdsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0}, 1886 txtdsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0}; 1887 struct itmlst_3 uailst[3] = { 1888 { sizeof alg, UAI$_ENCRYPT, &alg, 0}, 1889 { sizeof salt, UAI$_SALT, &salt, 0}, 1890 { 0, 0, NULL, NULL}}; 1891 static char hash[9]; 1892 1893 usrdsc.dsc$w_length = strlen(usrname); 1894 usrdsc.dsc$a_pointer = usrname; 1895 if (!((sts = sys$getuai(0, 0, &usrdsc, uailst, 0, 0, 0)) & 1)) { 1896 switch (sts) { 1897 case SS$_NOGRPPRV: case SS$_NOSYSPRV: 1898 set_errno(EACCES); 1899 break; 1900 case RMS$_RNF: 1901 set_errno(ESRCH); /* There isn't a Unix no-such-user error */ 1902 break; 1903 default: 1904 set_errno(EVMSERR); 1905 } 1906 set_vaxc_errno(sts); 1907 if (sts != RMS$_RNF) return NULL; 1908 } 1909 1910 txtdsc.dsc$w_length = strlen(textpasswd); 1911 txtdsc.dsc$a_pointer = textpasswd; 1912 if (!((sts = sys$hash_password(&txtdsc, alg, salt, &usrdsc, &hash)) & 1)) { 1913 set_errno(EVMSERR); set_vaxc_errno(sts); return NULL; 1914 } 1915 1916 return (char *) hash; 1917 1918 } /* end of my_crypt() */ 1919 /*}}}*/ 1920 1921 1922 static char *mp_do_rmsexpand(pTHX_ const char *, char *, int, const char *, unsigned, int *, int *); 1923 static char *mp_do_fileify_dirspec(pTHX_ const char *, char *, int, int *); 1924 static char *mp_do_tovmsspec(pTHX_ const char *, char *, int, int, int *); 1925 1926 /* fixup barenames that are directories for internal use. 1927 * There have been problems with the consistent handling of UNIX 1928 * style directory names when routines are presented with a name that 1929 * has no directory delimitors at all. So this routine will eventually 1930 * fix the issue. 1931 */ 1932 static char * fixup_bare_dirnames(const char * name) 1933 { 1934 if (decc_disable_to_vms_logname_translation) { 1935 /* fix me */ 1936 } 1937 return NULL; 1938 } 1939 1940 /* 8.3, remove() is now broken on symbolic links */ 1941 static int rms_erase(const char * vmsname); 1942 1943 1944 /* mp_do_kill_file 1945 * A little hack to get around a bug in some implemenation of remove() 1946 * that do not know how to delete a directory 1947 * 1948 * Delete any file to which user has control access, regardless of whether 1949 * delete access is explicitly allowed. 1950 * Limitations: User must have write access to parent directory. 1951 * Does not block signals or ASTs; if interrupted in midstream 1952 * may leave file with an altered ACL. 1953 * HANDLE WITH CARE! 1954 */ 1955 /*{{{int mp_do_kill_file(const char *name, int dirflag)*/ 1956 static int 1957 mp_do_kill_file(pTHX_ const char *name, int dirflag) 1958 { 1959 char *vmsname; 1960 char *rslt; 1961 unsigned long int jpicode = JPI$_UIC, type = ACL$C_FILE; 1962 unsigned long int cxt = 0, aclsts, fndsts, rmsts = -1; 1963 struct dsc$descriptor_s fildsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0}; 1964 struct myacedef { 1965 unsigned char myace$b_length; 1966 unsigned char myace$b_type; 1967 unsigned short int myace$w_flags; 1968 unsigned long int myace$l_access; 1969 unsigned long int myace$l_ident; 1970 } newace = { sizeof(struct myacedef), ACE$C_KEYID, 0, 1971 ACE$M_READ | ACE$M_WRITE | ACE$M_DELETE | ACE$M_CONTROL, 0}, 1972 oldace = { sizeof(struct myacedef), ACE$C_KEYID, 0, 0, 0}; 1973 struct itmlst_3 1974 findlst[3] = {{sizeof oldace, ACL$C_FNDACLENT, &oldace, 0}, 1975 {sizeof oldace, ACL$C_READACE, &oldace, 0},{0,0,0,0}}, 1976 addlst[2] = {{sizeof newace, ACL$C_ADDACLENT, &newace, 0},{0,0,0,0}}, 1977 dellst[2] = {{sizeof newace, ACL$C_DELACLENT, &newace, 0},{0,0,0,0}}, 1978 lcklst[2] = {{sizeof newace, ACL$C_WLOCK_ACL, &newace, 0},{0,0,0,0}}, 1979 ulklst[2] = {{sizeof newace, ACL$C_UNLOCK_ACL, &newace, 0},{0,0,0,0}}; 1980 1981 /* Expand the input spec using RMS, since the CRTL remove() and 1982 * system services won't do this by themselves, so we may miss 1983 * a file "hiding" behind a logical name or search list. */ 1984 vmsname = PerlMem_malloc(NAM$C_MAXRSS+1); 1985 if (vmsname == NULL) _ckvmssts_noperl(SS$_INSFMEM); 1986 1987 rslt = int_rmsexpand_tovms(name, vmsname, PERL_RMSEXPAND_M_SYMLINK); 1988 if (rslt == NULL) { 1989 PerlMem_free(vmsname); 1990 return -1; 1991 } 1992 1993 /* Erase the file */ 1994 rmsts = rms_erase(vmsname); 1995 1996 /* Did it succeed */ 1997 if ($VMS_STATUS_SUCCESS(rmsts)) { 1998 PerlMem_free(vmsname); 1999 return 0; 2000 } 2001 2002 /* If not, can changing protections help? */ 2003 if (rmsts != RMS$_PRV) { 2004 set_vaxc_errno(rmsts); 2005 PerlMem_free(vmsname); 2006 return -1; 2007 } 2008 2009 /* No, so we get our own UIC to use as a rights identifier, 2010 * and the insert an ACE at the head of the ACL which allows us 2011 * to delete the file. 2012 */ 2013 _ckvmssts_noperl(lib$getjpi(&jpicode,0,0,&(oldace.myace$l_ident),0,0)); 2014 fildsc.dsc$w_length = strlen(vmsname); 2015 fildsc.dsc$a_pointer = vmsname; 2016 cxt = 0; 2017 newace.myace$l_ident = oldace.myace$l_ident; 2018 rmsts = -1; 2019 if (!((aclsts = sys$change_acl(0,&type,&fildsc,lcklst,0,0,0)) & 1)) { 2020 switch (aclsts) { 2021 case RMS$_FNF: case RMS$_DNF: case SS$_NOSUCHOBJECT: 2022 set_errno(ENOENT); break; 2023 case RMS$_DIR: 2024 set_errno(ENOTDIR); break; 2025 case RMS$_DEV: 2026 set_errno(ENODEV); break; 2027 case RMS$_SYN: case SS$_INVFILFOROP: 2028 set_errno(EINVAL); break; 2029 case RMS$_PRV: 2030 set_errno(EACCES); break; 2031 default: 2032 _ckvmssts_noperl(aclsts); 2033 } 2034 set_vaxc_errno(aclsts); 2035 PerlMem_free(vmsname); 2036 return -1; 2037 } 2038 /* Grab any existing ACEs with this identifier in case we fail */ 2039 aclsts = fndsts = sys$change_acl(0,&type,&fildsc,findlst,0,0,&cxt); 2040 if ( fndsts & 1 || fndsts == SS$_ACLEMPTY || fndsts == SS$_NOENTRY 2041 || fndsts == SS$_NOMOREACE ) { 2042 /* Add the new ACE . . . */ 2043 if (!((aclsts = sys$change_acl(0,&type,&fildsc,addlst,0,0,0)) & 1)) 2044 goto yourroom; 2045 2046 rmsts = rms_erase(vmsname); 2047 if ($VMS_STATUS_SUCCESS(rmsts)) { 2048 rmsts = 0; 2049 } 2050 else { 2051 rmsts = -1; 2052 /* We blew it - dir with files in it, no write priv for 2053 * parent directory, etc. Put things back the way they were. */ 2054 if (!((aclsts = sys$change_acl(0,&type,&fildsc,dellst,0,0,0)) & 1)) 2055 goto yourroom; 2056 if (fndsts & 1) { 2057 addlst[0].bufadr = &oldace; 2058 if (!((aclsts = sys$change_acl(0,&type,&fildsc,addlst,0,0,&cxt)) & 1)) 2059 goto yourroom; 2060 } 2061 } 2062 } 2063 2064 yourroom: 2065 fndsts = sys$change_acl(0,&type,&fildsc,ulklst,0,0,0); 2066 /* We just deleted it, so of course it's not there. Some versions of 2067 * VMS seem to return success on the unlock operation anyhow (after all 2068 * the unlock is successful), but others don't. 2069 */ 2070 if (fndsts == RMS$_FNF || fndsts == SS$_NOSUCHOBJECT) fndsts = SS$_NORMAL; 2071 if (aclsts & 1) aclsts = fndsts; 2072 if (!(aclsts & 1)) { 2073 set_errno(EVMSERR); 2074 set_vaxc_errno(aclsts); 2075 } 2076 2077 PerlMem_free(vmsname); 2078 return rmsts; 2079 2080 } /* end of kill_file() */ 2081 /*}}}*/ 2082 2083 2084 /*{{{int do_rmdir(char *name)*/ 2085 int 2086 Perl_do_rmdir(pTHX_ const char *name) 2087 { 2088 char * dirfile; 2089 int retval; 2090 Stat_t st; 2091 2092 /* lstat returns a VMS fileified specification of the name */ 2093 /* that is looked up, and also lets verifies that this is a directory */ 2094 2095 retval = flex_lstat(name, &st); 2096 if (retval != 0) { 2097 char * ret_spec; 2098 2099 /* Due to a historical feature, flex_stat/lstat can not see some */ 2100 /* Unix format file names that the rest of the CRTL can see */ 2101 /* Fixing that feature will cause some perl tests to fail */ 2102 /* So try this one more time. */ 2103 2104 retval = lstat(name, &st.crtl_stat); 2105 if (retval != 0) 2106 return -1; 2107 2108 /* force it to a file spec for the kill file to work. */ 2109 ret_spec = do_fileify_dirspec(name, st.st_devnam, 0, NULL); 2110 if (ret_spec == NULL) { 2111 errno = EIO; 2112 return -1; 2113 } 2114 } 2115 2116 if (!S_ISDIR(st.st_mode)) { 2117 errno = ENOTDIR; 2118 retval = -1; 2119 } 2120 else { 2121 dirfile = st.st_devnam; 2122 2123 /* It may be possible for flex_stat to find a file and vmsify() to */ 2124 /* fail with ODS-2 specifications. mp_do_kill_file can not deal */ 2125 /* with that case, so fail it */ 2126 if (dirfile[0] == 0) { 2127 errno = EIO; 2128 return -1; 2129 } 2130 2131 retval = mp_do_kill_file(aTHX_ dirfile, 1); 2132 } 2133 2134 return retval; 2135 2136 } /* end of do_rmdir */ 2137 /*}}}*/ 2138 2139 /* kill_file 2140 * Delete any file to which user has control access, regardless of whether 2141 * delete access is explicitly allowed. 2142 * Limitations: User must have write access to parent directory. 2143 * Does not block signals or ASTs; if interrupted in midstream 2144 * may leave file with an altered ACL. 2145 * HANDLE WITH CARE! 2146 */ 2147 /*{{{int kill_file(char *name)*/ 2148 int 2149 Perl_kill_file(pTHX_ const char *name) 2150 { 2151 char * vmsfile; 2152 Stat_t st; 2153 int rmsts; 2154 2155 /* Convert the filename to VMS format and see if it is a directory */ 2156 /* flex_lstat returns a vmsified file specification */ 2157 rmsts = flex_lstat(name, &st); 2158 if (rmsts != 0) { 2159 2160 /* Due to a historical feature, flex_stat/lstat can not see some */ 2161 /* Unix format file names that the rest of the CRTL can see when */ 2162 /* ODS-2 file specifications are in use. */ 2163 /* Fixing that feature will cause some perl tests to fail */ 2164 /* [.lib.ExtUtils.t]Manifest.t is one of them */ 2165 st.st_mode = 0; 2166 vmsfile = (char *) name; /* cast ok */ 2167 2168 } else { 2169 vmsfile = st.st_devnam; 2170 if (vmsfile[0] == 0) { 2171 /* It may be possible for flex_stat to find a file and vmsify() */ 2172 /* to fail with ODS-2 specifications. mp_do_kill_file can not */ 2173 /* deal with that case, so fail it */ 2174 errno = EIO; 2175 return -1; 2176 } 2177 } 2178 2179 /* Remove() is allowed to delete directories, according to the X/Open 2180 * specifications. 2181 * This may need special handling to work with the ACL hacks. 2182 */ 2183 if (S_ISDIR(st.st_mode)) { 2184 rmsts = mp_do_kill_file(aTHX_ vmsfile, 1); 2185 return rmsts; 2186 } 2187 2188 rmsts = mp_do_kill_file(aTHX_ vmsfile, 0); 2189 2190 /* Need to delete all versions ? */ 2191 if ((rmsts == 0) && (vms_unlink_all_versions == 1)) { 2192 int i = 0; 2193 2194 /* Just use lstat() here as do not need st_dev */ 2195 /* and we know that the file is in VMS format or that */ 2196 /* because of a historical bug, flex_stat can not see the file */ 2197 while (lstat(vmsfile, (stat_t *)&st) == 0) { 2198 rmsts = mp_do_kill_file(aTHX_ vmsfile, 0); 2199 if (rmsts != 0) 2200 break; 2201 i++; 2202 2203 /* Make sure that we do not loop forever */ 2204 if (i > 32767) { 2205 errno = EIO; 2206 rmsts = -1; 2207 break; 2208 } 2209 } 2210 } 2211 2212 return rmsts; 2213 2214 } /* end of kill_file() */ 2215 /*}}}*/ 2216 2217 2218 /*{{{int my_mkdir(char *,Mode_t)*/ 2219 int 2220 Perl_my_mkdir(pTHX_ const char *dir, Mode_t mode) 2221 { 2222 STRLEN dirlen = strlen(dir); 2223 2224 /* zero length string sometimes gives ACCVIO */ 2225 if (dirlen == 0) return -1; 2226 2227 /* CRTL mkdir() doesn't tolerate trailing /, since that implies 2228 * null file name/type. However, it's commonplace under Unix, 2229 * so we'll allow it for a gain in portability. 2230 */ 2231 if (dir[dirlen-1] == '/') { 2232 char *newdir = savepvn(dir,dirlen-1); 2233 int ret = mkdir(newdir,mode); 2234 Safefree(newdir); 2235 return ret; 2236 } 2237 else return mkdir(dir,mode); 2238 } /* end of my_mkdir */ 2239 /*}}}*/ 2240 2241 /*{{{int my_chdir(char *)*/ 2242 int 2243 Perl_my_chdir(pTHX_ const char *dir) 2244 { 2245 STRLEN dirlen = strlen(dir); 2246 2247 /* zero length string sometimes gives ACCVIO */ 2248 if (dirlen == 0) return -1; 2249 const char *dir1; 2250 2251 /* Perl is passing the output of the DCL SHOW DEFAULT with leading spaces. 2252 * This does not work if DECC$EFS_CHARSET is active. Hack it here 2253 * so that existing scripts do not need to be changed. 2254 */ 2255 dir1 = dir; 2256 while ((dirlen > 0) && (*dir1 == ' ')) { 2257 dir1++; 2258 dirlen--; 2259 } 2260 2261 /* some versions of CRTL chdir() doesn't tolerate trailing /, since 2262 * that implies 2263 * null file name/type. However, it's commonplace under Unix, 2264 * so we'll allow it for a gain in portability. 2265 * 2266 * '/' is valid when SYS$POSIX_ROOT or POSIX compliant pathnames are active. 2267 */ 2268 if ((dirlen > 1) && (dir1[dirlen-1] == '/')) { 2269 char *newdir; 2270 int ret; 2271 newdir = PerlMem_malloc(dirlen); 2272 if (newdir ==NULL) 2273 _ckvmssts_noperl(SS$_INSFMEM); 2274 strncpy(newdir, dir1, dirlen-1); 2275 newdir[dirlen-1] = '\0'; 2276 ret = chdir(newdir); 2277 PerlMem_free(newdir); 2278 return ret; 2279 } 2280 else return chdir(dir1); 2281 } /* end of my_chdir */ 2282 /*}}}*/ 2283 2284 2285 /*{{{int my_chmod(char *, mode_t)*/ 2286 int 2287 Perl_my_chmod(pTHX_ const char *file_spec, mode_t mode) 2288 { 2289 Stat_t st; 2290 int ret = -1; 2291 char * changefile; 2292 STRLEN speclen = strlen(file_spec); 2293 2294 /* zero length string sometimes gives ACCVIO */ 2295 if (speclen == 0) return -1; 2296 2297 /* some versions of CRTL chmod() doesn't tolerate trailing /, since 2298 * that implies null file name/type. However, it's commonplace under Unix, 2299 * so we'll allow it for a gain in portability. 2300 * 2301 * Tests are showing that chmod() on VMS 8.3 is only accepting directories 2302 * in VMS file.dir notation. 2303 */ 2304 changefile = (char *) file_spec; /* cast ok */ 2305 ret = flex_lstat(file_spec, &st); 2306 if (ret != 0) { 2307 2308 /* Due to a historical feature, flex_stat/lstat can not see some */ 2309 /* Unix format file names that the rest of the CRTL can see when */ 2310 /* ODS-2 file specifications are in use. */ 2311 /* Fixing that feature will cause some perl tests to fail */ 2312 /* [.lib.ExtUtils.t]Manifest.t is one of them */ 2313 st.st_mode = 0; 2314 2315 } else { 2316 /* It may be possible to get here with nothing in st_devname */ 2317 /* chmod still may work though */ 2318 if (st.st_devnam[0] != 0) { 2319 changefile = st.st_devnam; 2320 } 2321 } 2322 ret = chmod(changefile, mode); 2323 return ret; 2324 } /* end of my_chmod */ 2325 /*}}}*/ 2326 2327 2328 /*{{{FILE *my_tmpfile()*/ 2329 FILE * 2330 my_tmpfile(void) 2331 { 2332 FILE *fp; 2333 char *cp; 2334 2335 if ((fp = tmpfile())) return fp; 2336 2337 cp = PerlMem_malloc(L_tmpnam+24); 2338 if (cp == NULL) _ckvmssts_noperl(SS$_INSFMEM); 2339 2340 if (decc_filename_unix_only == 0) 2341 strcpy(cp,"Sys$Scratch:"); 2342 else 2343 strcpy(cp,"/tmp/"); 2344 tmpnam(cp+strlen(cp)); 2345 strcat(cp,".Perltmp"); 2346 fp = fopen(cp,"w+","fop=dlt"); 2347 PerlMem_free(cp); 2348 return fp; 2349 } 2350 /*}}}*/ 2351 2352 2353 #ifndef HOMEGROWN_POSIX_SIGNALS 2354 /* 2355 * The C RTL's sigaction fails to check for invalid signal numbers so we 2356 * help it out a bit. The docs are correct, but the actual routine doesn't 2357 * do what the docs say it will. 2358 */ 2359 /*{{{int Perl_my_sigaction (pTHX_ int, const struct sigaction*, struct sigaction*);*/ 2360 int 2361 Perl_my_sigaction (pTHX_ int sig, const struct sigaction* act, 2362 struct sigaction* oact) 2363 { 2364 if (sig == SIGKILL || sig == SIGSTOP || sig == SIGCONT) { 2365 SETERRNO(EINVAL, SS$_INVARG); 2366 return -1; 2367 } 2368 return sigaction(sig, act, oact); 2369 } 2370 /*}}}*/ 2371 #endif 2372 2373 #ifdef KILL_BY_SIGPRC 2374 #include <errnodef.h> 2375 2376 /* We implement our own kill() using the undocumented system service 2377 sys$sigprc for one of two reasons: 2378 2379 1.) If the kill() in an older CRTL uses sys$forcex, causing the 2380 target process to do a sys$exit, which usually can't be handled 2381 gracefully...certainly not by Perl and the %SIG{} mechanism. 2382 2383 2.) If the kill() in the CRTL can't be called from a signal 2384 handler without disappearing into the ether, i.e., the signal 2385 it purportedly sends is never trapped. Still true as of VMS 7.3. 2386 2387 sys$sigprc has the same parameters as sys$forcex, but throws an exception 2388 in the target process rather than calling sys$exit. 2389 2390 Note that distinguishing SIGSEGV from SIGBUS requires an extra arg 2391 on the ACCVIO condition, which sys$sigprc (and sys$forcex) don't 2392 provide. On VMS 7.0+ this is taken care of by doing sys$sigprc 2393 with condition codes C$_SIG0+nsig*8, catching the exception on the 2394 target process and resignaling with appropriate arguments. 2395 2396 But we don't have that VMS 7.0+ exception handler, so if you 2397 Perl_my_kill(.., SIGSEGV) it will show up as a SIGBUS. Oh well. 2398 2399 Also note that SIGTERM is listed in the docs as being "unimplemented", 2400 yet always seems to be signaled with a VMS condition code of 4 (and 2401 correctly handled for that code). So we hardwire it in. 2402 2403 Unlike the VMS 7.0+ CRTL kill() function, we actually check the signal 2404 number to see if it's valid. So Perl_my_kill(pid,0) returns -1 rather 2405 than signalling with an unrecognized (and unhandled by CRTL) code. 2406 */ 2407 2408 #define _MY_SIG_MAX 28 2409 2410 static unsigned int 2411 Perl_sig_to_vmscondition_int(int sig) 2412 { 2413 static unsigned int sig_code[_MY_SIG_MAX+1] = 2414 { 2415 0, /* 0 ZERO */ 2416 SS$_HANGUP, /* 1 SIGHUP */ 2417 SS$_CONTROLC, /* 2 SIGINT */ 2418 SS$_CONTROLY, /* 3 SIGQUIT */ 2419 SS$_RADRMOD, /* 4 SIGILL */ 2420 SS$_BREAK, /* 5 SIGTRAP */ 2421 SS$_OPCCUS, /* 6 SIGABRT */ 2422 SS$_COMPAT, /* 7 SIGEMT */ 2423 #ifdef __VAX 2424 SS$_FLTOVF, /* 8 SIGFPE VAX */ 2425 #else 2426 SS$_HPARITH, /* 8 SIGFPE AXP */ 2427 #endif 2428 SS$_ABORT, /* 9 SIGKILL */ 2429 SS$_ACCVIO, /* 10 SIGBUS */ 2430 SS$_ACCVIO, /* 11 SIGSEGV */ 2431 SS$_BADPARAM, /* 12 SIGSYS */ 2432 SS$_NOMBX, /* 13 SIGPIPE */ 2433 SS$_ASTFLT, /* 14 SIGALRM */ 2434 4, /* 15 SIGTERM */ 2435 0, /* 16 SIGUSR1 */ 2436 0, /* 17 SIGUSR2 */ 2437 0, /* 18 */ 2438 0, /* 19 */ 2439 0, /* 20 SIGCHLD */ 2440 0, /* 21 SIGCONT */ 2441 0, /* 22 SIGSTOP */ 2442 0, /* 23 SIGTSTP */ 2443 0, /* 24 SIGTTIN */ 2444 0, /* 25 SIGTTOU */ 2445 0, /* 26 */ 2446 0, /* 27 */ 2447 0 /* 28 SIGWINCH */ 2448 }; 2449 2450 #if __VMS_VER >= 60200000 2451 static int initted = 0; 2452 if (!initted) { 2453 initted = 1; 2454 sig_code[16] = C$_SIGUSR1; 2455 sig_code[17] = C$_SIGUSR2; 2456 #if __CRTL_VER >= 70000000 2457 sig_code[20] = C$_SIGCHLD; 2458 #endif 2459 #if __CRTL_VER >= 70300000 2460 sig_code[28] = C$_SIGWINCH; 2461 #endif 2462 } 2463 #endif 2464 2465 if (sig < _SIG_MIN) return 0; 2466 if (sig > _MY_SIG_MAX) return 0; 2467 return sig_code[sig]; 2468 } 2469 2470 unsigned int 2471 Perl_sig_to_vmscondition(int sig) 2472 { 2473 #ifdef SS$_DEBUG 2474 if (vms_debug_on_exception != 0) 2475 lib$signal(SS$_DEBUG); 2476 #endif 2477 return Perl_sig_to_vmscondition_int(sig); 2478 } 2479 2480 2481 int 2482 Perl_my_kill(int pid, int sig) 2483 { 2484 dTHX; 2485 int iss; 2486 unsigned int code; 2487 int sys$sigprc(unsigned int *pidadr, 2488 struct dsc$descriptor_s *prcname, 2489 unsigned int code); 2490 2491 /* sig 0 means validate the PID */ 2492 /*------------------------------*/ 2493 if (sig == 0) { 2494 const unsigned long int jpicode = JPI$_PID; 2495 pid_t ret_pid; 2496 int status; 2497 status = lib$getjpi(&jpicode, &pid, NULL, &ret_pid, NULL, NULL); 2498 if ($VMS_STATUS_SUCCESS(status)) 2499 return 0; 2500 switch (status) { 2501 case SS$_NOSUCHNODE: 2502 case SS$_UNREACHABLE: 2503 case SS$_NONEXPR: 2504 errno = ESRCH; 2505 break; 2506 case SS$_NOPRIV: 2507 errno = EPERM; 2508 break; 2509 default: 2510 errno = EVMSERR; 2511 } 2512 vaxc$errno=status; 2513 return -1; 2514 } 2515 2516 code = Perl_sig_to_vmscondition_int(sig); 2517 2518 if (!code) { 2519 SETERRNO(EINVAL, SS$_BADPARAM); 2520 return -1; 2521 } 2522 2523 /* Fixme: Per official UNIX specification: If pid = 0, or negative then 2524 * signals are to be sent to multiple processes. 2525 * pid = 0 - all processes in group except ones that the system exempts 2526 * pid = -1 - all processes except ones that the system exempts 2527 * pid = -n - all processes in group (abs(n)) except ... 2528 * For now, just report as not supported. 2529 */ 2530 2531 if (pid <= 0) { 2532 SETERRNO(ENOTSUP, SS$_UNSUPPORTED); 2533 return -1; 2534 } 2535 2536 iss = sys$sigprc((unsigned int *)&pid,0,code); 2537 if (iss&1) return 0; 2538 2539 switch (iss) { 2540 case SS$_NOPRIV: 2541 set_errno(EPERM); break; 2542 case SS$_NONEXPR: 2543 case SS$_NOSUCHNODE: 2544 case SS$_UNREACHABLE: 2545 set_errno(ESRCH); break; 2546 case SS$_INSFMEM: 2547 set_errno(ENOMEM); break; 2548 default: 2549 _ckvmssts_noperl(iss); 2550 set_errno(EVMSERR); 2551 } 2552 set_vaxc_errno(iss); 2553 2554 return -1; 2555 } 2556 #endif 2557 2558 /* Routine to convert a VMS status code to a UNIX status code. 2559 ** More tricky than it appears because of conflicting conventions with 2560 ** existing code. 2561 ** 2562 ** VMS status codes are a bit mask, with the least significant bit set for 2563 ** success. 2564 ** 2565 ** Special UNIX status of EVMSERR indicates that no translation is currently 2566 ** available, and programs should check the VMS status code. 2567 ** 2568 ** Programs compiled with _POSIX_EXIT have a special encoding that requires 2569 ** decoding. 2570 */ 2571 2572 #ifndef C_FACILITY_NO 2573 #define C_FACILITY_NO 0x350000 2574 #endif 2575 #ifndef DCL_IVVERB 2576 #define DCL_IVVERB 0x38090 2577 #endif 2578 2579 int Perl_vms_status_to_unix(int vms_status, int child_flag) 2580 { 2581 int facility; 2582 int fac_sp; 2583 int msg_no; 2584 int msg_status; 2585 int unix_status; 2586 2587 /* Assume the best or the worst */ 2588 if (vms_status & STS$M_SUCCESS) 2589 unix_status = 0; 2590 else 2591 unix_status = EVMSERR; 2592 2593 msg_status = vms_status & ~STS$M_CONTROL; 2594 2595 facility = vms_status & STS$M_FAC_NO; 2596 fac_sp = vms_status & STS$M_FAC_SP; 2597 msg_no = vms_status & (STS$M_MSG_NO | STS$M_SEVERITY); 2598 2599 if (((facility == 0) || (fac_sp == 0)) && (child_flag == 0)) { 2600 switch(msg_no) { 2601 case SS$_NORMAL: 2602 unix_status = 0; 2603 break; 2604 case SS$_ACCVIO: 2605 unix_status = EFAULT; 2606 break; 2607 case SS$_DEVOFFLINE: 2608 unix_status = EBUSY; 2609 break; 2610 case SS$_CLEARED: 2611 unix_status = ENOTCONN; 2612 break; 2613 case SS$_IVCHAN: 2614 case SS$_IVLOGNAM: 2615 case SS$_BADPARAM: 2616 case SS$_IVLOGTAB: 2617 case SS$_NOLOGNAM: 2618 case SS$_NOLOGTAB: 2619 case SS$_INVFILFOROP: 2620 case SS$_INVARG: 2621 case SS$_NOSUCHID: 2622 case SS$_IVIDENT: 2623 unix_status = EINVAL; 2624 break; 2625 case SS$_UNSUPPORTED: 2626 unix_status = ENOTSUP; 2627 break; 2628 case SS$_FILACCERR: 2629 case SS$_NOGRPPRV: 2630 case SS$_NOSYSPRV: 2631 unix_status = EACCES; 2632 break; 2633 case SS$_DEVICEFULL: 2634 unix_status = ENOSPC; 2635 break; 2636 case SS$_NOSUCHDEV: 2637 unix_status = ENODEV; 2638 break; 2639 case SS$_NOSUCHFILE: 2640 case SS$_NOSUCHOBJECT: 2641 unix_status = ENOENT; 2642 break; 2643 case SS$_ABORT: /* Fatal case */ 2644 case ((SS$_ABORT & STS$M_COND_ID) | STS$K_ERROR): /* Error case */ 2645 case ((SS$_ABORT & STS$M_COND_ID) | STS$K_WARNING): /* Warning case */ 2646 unix_status = EINTR; 2647 break; 2648 case SS$_BUFFEROVF: 2649 unix_status = E2BIG; 2650 break; 2651 case SS$_INSFMEM: 2652 unix_status = ENOMEM; 2653 break; 2654 case SS$_NOPRIV: 2655 unix_status = EPERM; 2656 break; 2657 case SS$_NOSUCHNODE: 2658 case SS$_UNREACHABLE: 2659 unix_status = ESRCH; 2660 break; 2661 case SS$_NONEXPR: 2662 unix_status = ECHILD; 2663 break; 2664 default: 2665 if ((facility == 0) && (msg_no < 8)) { 2666 /* These are not real VMS status codes so assume that they are 2667 ** already UNIX status codes 2668 */ 2669 unix_status = msg_no; 2670 break; 2671 } 2672 } 2673 } 2674 else { 2675 /* Translate a POSIX exit code to a UNIX exit code */ 2676 if ((facility == C_FACILITY_NO) && ((msg_no & 0xA000) == 0xA000)) { 2677 unix_status = (msg_no & 0x07F8) >> 3; 2678 } 2679 else { 2680 2681 /* Documented traditional behavior for handling VMS child exits */ 2682 /*--------------------------------------------------------------*/ 2683 if (child_flag != 0) { 2684 2685 /* Success / Informational return 0 */ 2686 /*----------------------------------*/ 2687 if (msg_no & STS$K_SUCCESS) 2688 return 0; 2689 2690 /* Warning returns 1 */ 2691 /*-------------------*/ 2692 if ((msg_no & (STS$K_ERROR | STS$K_SEVERE)) == 0) 2693 return 1; 2694 2695 /* Everything else pass through the severity bits */ 2696 /*------------------------------------------------*/ 2697 return (msg_no & STS$M_SEVERITY); 2698 } 2699 2700 /* Normal VMS status to ERRNO mapping attempt */ 2701 /*--------------------------------------------*/ 2702 switch(msg_status) { 2703 /* case RMS$_EOF: */ /* End of File */ 2704 case RMS$_FNF: /* File Not Found */ 2705 case RMS$_DNF: /* Dir Not Found */ 2706 unix_status = ENOENT; 2707 break; 2708 case RMS$_RNF: /* Record Not Found */ 2709 unix_status = ESRCH; 2710 break; 2711 case RMS$_DIR: 2712 unix_status = ENOTDIR; 2713 break; 2714 case RMS$_DEV: 2715 unix_status = ENODEV; 2716 break; 2717 case RMS$_IFI: 2718 case RMS$_FAC: 2719 case RMS$_ISI: 2720 unix_status = EBADF; 2721 break; 2722 case RMS$_FEX: 2723 unix_status = EEXIST; 2724 break; 2725 case RMS$_SYN: 2726 case RMS$_FNM: 2727 case LIB$_INVSTRDES: 2728 case LIB$_INVARG: 2729 case LIB$_NOSUCHSYM: 2730 case LIB$_INVSYMNAM: 2731 case DCL_IVVERB: 2732 unix_status = EINVAL; 2733 break; 2734 case CLI$_BUFOVF: 2735 case RMS$_RTB: 2736 case CLI$_TKNOVF: 2737 case CLI$_RSLOVF: 2738 unix_status = E2BIG; 2739 break; 2740 case RMS$_PRV: /* No privilege */ 2741 case RMS$_ACC: /* ACP file access failed */ 2742 case RMS$_WLK: /* Device write locked */ 2743 unix_status = EACCES; 2744 break; 2745 case RMS$_MKD: /* Failed to mark for delete */ 2746 unix_status = EPERM; 2747 break; 2748 /* case RMS$_NMF: */ /* No more files */ 2749 } 2750 } 2751 } 2752 2753 return unix_status; 2754 } 2755 2756 /* Try to guess at what VMS error status should go with a UNIX errno 2757 * value. This is hard to do as there could be many possible VMS 2758 * error statuses that caused the errno value to be set. 2759 */ 2760 2761 int Perl_unix_status_to_vms(int unix_status) 2762 { 2763 int test_unix_status; 2764 2765 /* Trivial cases first */ 2766 /*---------------------*/ 2767 if (unix_status == EVMSERR) 2768 return vaxc$errno; 2769 2770 /* Is vaxc$errno sane? */ 2771 /*---------------------*/ 2772 test_unix_status = Perl_vms_status_to_unix(vaxc$errno, 0); 2773 if (test_unix_status == unix_status) 2774 return vaxc$errno; 2775 2776 /* If way out of range, must be VMS code already */ 2777 /*-----------------------------------------------*/ 2778 if (unix_status > EVMSERR) 2779 return unix_status; 2780 2781 /* If out of range, punt */ 2782 /*-----------------------*/ 2783 if (unix_status > __ERRNO_MAX) 2784 return SS$_ABORT; 2785 2786 2787 /* Ok, now we have to do it the hard way. */ 2788 /*----------------------------------------*/ 2789 switch(unix_status) { 2790 case 0: return SS$_NORMAL; 2791 case EPERM: return SS$_NOPRIV; 2792 case ENOENT: return SS$_NOSUCHOBJECT; 2793 case ESRCH: return SS$_UNREACHABLE; 2794 case EINTR: return SS$_ABORT; 2795 /* case EIO: */ 2796 /* case ENXIO: */ 2797 case E2BIG: return SS$_BUFFEROVF; 2798 /* case ENOEXEC */ 2799 case EBADF: return RMS$_IFI; 2800 case ECHILD: return SS$_NONEXPR; 2801 /* case EAGAIN */ 2802 case ENOMEM: return SS$_INSFMEM; 2803 case EACCES: return SS$_FILACCERR; 2804 case EFAULT: return SS$_ACCVIO; 2805 /* case ENOTBLK */ 2806 case EBUSY: return SS$_DEVOFFLINE; 2807 case EEXIST: return RMS$_FEX; 2808 /* case EXDEV */ 2809 case ENODEV: return SS$_NOSUCHDEV; 2810 case ENOTDIR: return RMS$_DIR; 2811 /* case EISDIR */ 2812 case EINVAL: return SS$_INVARG; 2813 /* case ENFILE */ 2814 /* case EMFILE */ 2815 /* case ENOTTY */ 2816 /* case ETXTBSY */ 2817 /* case EFBIG */ 2818 case ENOSPC: return SS$_DEVICEFULL; 2819 case ESPIPE: return LIB$_INVARG; 2820 /* case EROFS: */ 2821 /* case EMLINK: */ 2822 /* case EPIPE: */ 2823 /* case EDOM */ 2824 case ERANGE: return LIB$_INVARG; 2825 /* case EWOULDBLOCK */ 2826 /* case EINPROGRESS */ 2827 /* case EALREADY */ 2828 /* case ENOTSOCK */ 2829 /* case EDESTADDRREQ */ 2830 /* case EMSGSIZE */ 2831 /* case EPROTOTYPE */ 2832 /* case ENOPROTOOPT */ 2833 /* case EPROTONOSUPPORT */ 2834 /* case ESOCKTNOSUPPORT */ 2835 /* case EOPNOTSUPP */ 2836 /* case EPFNOSUPPORT */ 2837 /* case EAFNOSUPPORT */ 2838 /* case EADDRINUSE */ 2839 /* case EADDRNOTAVAIL */ 2840 /* case ENETDOWN */ 2841 /* case ENETUNREACH */ 2842 /* case ENETRESET */ 2843 /* case ECONNABORTED */ 2844 /* case ECONNRESET */ 2845 /* case ENOBUFS */ 2846 /* case EISCONN */ 2847 case ENOTCONN: return SS$_CLEARED; 2848 /* case ESHUTDOWN */ 2849 /* case ETOOMANYREFS */ 2850 /* case ETIMEDOUT */ 2851 /* case ECONNREFUSED */ 2852 /* case ELOOP */ 2853 /* case ENAMETOOLONG */ 2854 /* case EHOSTDOWN */ 2855 /* case EHOSTUNREACH */ 2856 /* case ENOTEMPTY */ 2857 /* case EPROCLIM */ 2858 /* case EUSERS */ 2859 /* case EDQUOT */ 2860 /* case ENOMSG */ 2861 /* case EIDRM */ 2862 /* case EALIGN */ 2863 /* case ESTALE */ 2864 /* case EREMOTE */ 2865 /* case ENOLCK */ 2866 /* case ENOSYS */ 2867 /* case EFTYPE */ 2868 /* case ECANCELED */ 2869 /* case EFAIL */ 2870 /* case EINPROG */ 2871 case ENOTSUP: 2872 return SS$_UNSUPPORTED; 2873 /* case EDEADLK */ 2874 /* case ENWAIT */ 2875 /* case EILSEQ */ 2876 /* case EBADCAT */ 2877 /* case EBADMSG */ 2878 /* case EABANDONED */ 2879 default: 2880 return SS$_ABORT; /* punt */ 2881 } 2882 2883 return SS$_ABORT; /* Should not get here */ 2884 } 2885 2886 2887 /* default piping mailbox size */ 2888 #ifdef __VAX 2889 # define PERL_BUFSIZ 512 2890 #else 2891 # define PERL_BUFSIZ 8192 2892 #endif 2893 2894 2895 static void 2896 create_mbx(unsigned short int *chan, struct dsc$descriptor_s *namdsc) 2897 { 2898 unsigned long int mbxbufsiz; 2899 static unsigned long int syssize = 0; 2900 unsigned long int dviitm = DVI$_DEVNAM; 2901 char csize[LNM$C_NAMLENGTH+1]; 2902 int sts; 2903 2904 if (!syssize) { 2905 unsigned long syiitm = SYI$_MAXBUF; 2906 /* 2907 * Get the SYSGEN parameter MAXBUF 2908 * 2909 * If the logical 'PERL_MBX_SIZE' is defined 2910 * use the value of the logical instead of PERL_BUFSIZ, but 2911 * keep the size between 128 and MAXBUF. 2912 * 2913 */ 2914 _ckvmssts_noperl(lib$getsyi(&syiitm, &syssize, 0, 0, 0, 0)); 2915 } 2916 2917 if (vmstrnenv("PERL_MBX_SIZE", csize, 0, fildev, 0)) { 2918 mbxbufsiz = atoi(csize); 2919 } else { 2920 mbxbufsiz = PERL_BUFSIZ; 2921 } 2922 if (mbxbufsiz < 128) mbxbufsiz = 128; 2923 if (mbxbufsiz > syssize) mbxbufsiz = syssize; 2924 2925 _ckvmssts_noperl(sts = sys$crembx(0,chan,mbxbufsiz,mbxbufsiz,0,0,0)); 2926 2927 sts = lib$getdvi(&dviitm, chan, NULL, NULL, namdsc, &namdsc->dsc$w_length); 2928 _ckvmssts_noperl(sts); 2929 namdsc->dsc$a_pointer[namdsc->dsc$w_length] = '\0'; 2930 2931 } /* end of create_mbx() */ 2932 2933 2934 /*{{{ my_popen and my_pclose*/ 2935 2936 typedef struct _iosb IOSB; 2937 typedef struct _iosb* pIOSB; 2938 typedef struct _pipe Pipe; 2939 typedef struct _pipe* pPipe; 2940 typedef struct pipe_details Info; 2941 typedef struct pipe_details* pInfo; 2942 typedef struct _srqp RQE; 2943 typedef struct _srqp* pRQE; 2944 typedef struct _tochildbuf CBuf; 2945 typedef struct _tochildbuf* pCBuf; 2946 2947 struct _iosb { 2948 unsigned short status; 2949 unsigned short count; 2950 unsigned long dvispec; 2951 }; 2952 2953 #pragma member_alignment save 2954 #pragma nomember_alignment quadword 2955 struct _srqp { /* VMS self-relative queue entry */ 2956 unsigned long qptr[2]; 2957 }; 2958 #pragma member_alignment restore 2959 static RQE RQE_ZERO = {0,0}; 2960 2961 struct _tochildbuf { 2962 RQE q; 2963 int eof; 2964 unsigned short size; 2965 char *buf; 2966 }; 2967 2968 struct _pipe { 2969 RQE free; 2970 RQE wait; 2971 int fd_out; 2972 unsigned short chan_in; 2973 unsigned short chan_out; 2974 char *buf; 2975 unsigned int bufsize; 2976 IOSB iosb; 2977 IOSB iosb2; 2978 int *pipe_done; 2979 int retry; 2980 int type; 2981 int shut_on_empty; 2982 int need_wake; 2983 pPipe *home; 2984 pInfo info; 2985 pCBuf curr; 2986 pCBuf curr2; 2987 #if defined(PERL_IMPLICIT_CONTEXT) 2988 void *thx; /* Either a thread or an interpreter */ 2989 /* pointer, depending on how we're built */ 2990 #endif 2991 }; 2992 2993 2994 struct pipe_details 2995 { 2996 pInfo next; 2997 PerlIO *fp; /* file pointer to pipe mailbox */ 2998 int useFILE; /* using stdio, not perlio */ 2999 int pid; /* PID of subprocess */ 3000 int mode; /* == 'r' if pipe open for reading */ 3001 int done; /* subprocess has completed */ 3002 int waiting; /* waiting for completion/closure */ 3003 int closing; /* my_pclose is closing this pipe */ 3004 unsigned long completion; /* termination status of subprocess */ 3005 pPipe in; /* pipe in to sub */ 3006 pPipe out; /* pipe out of sub */ 3007 pPipe err; /* pipe of sub's sys$error */ 3008 int in_done; /* true when in pipe finished */ 3009 int out_done; 3010 int err_done; 3011 unsigned short xchan; /* channel to debug xterm */ 3012 unsigned short xchan_valid; /* channel is assigned */ 3013 }; 3014 3015 struct exit_control_block 3016 { 3017 struct exit_control_block *flink; 3018 unsigned long int (*exit_routine)(); 3019 unsigned long int arg_count; 3020 unsigned long int *status_address; 3021 unsigned long int exit_status; 3022 }; 3023 3024 typedef struct _closed_pipes Xpipe; 3025 typedef struct _closed_pipes* pXpipe; 3026 3027 struct _closed_pipes { 3028 int pid; /* PID of subprocess */ 3029 unsigned long completion; /* termination status of subprocess */ 3030 }; 3031 #define NKEEPCLOSED 50 3032 static Xpipe closed_list[NKEEPCLOSED]; 3033 static int closed_index = 0; 3034 static int closed_num = 0; 3035 3036 #define RETRY_DELAY "0 ::0.20" 3037 #define MAX_RETRY 50 3038 3039 static int pipe_ef = 0; /* first call to safe_popen inits these*/ 3040 static unsigned long mypid; 3041 static unsigned long delaytime[2]; 3042 3043 static pInfo open_pipes = NULL; 3044 static $DESCRIPTOR(nl_desc, "NL:"); 3045 3046 #define PIPE_COMPLETION_WAIT 30 /* seconds, for EOF/FORCEX wait */ 3047 3048 3049 3050 static unsigned long int 3051 pipe_exit_routine() 3052 { 3053 pInfo info; 3054 unsigned long int retsts = SS$_NORMAL, abort = SS$_TIMEOUT; 3055 int sts, did_stuff, need_eof, j; 3056 3057 /* 3058 * Flush any pending i/o, but since we are in process run-down, be 3059 * careful about referencing PerlIO structures that may already have 3060 * been deallocated. We may not even have an interpreter anymore. 3061 */ 3062 info = open_pipes; 3063 while (info) { 3064 if (info->fp) { 3065 #if defined(PERL_IMPLICIT_CONTEXT) 3066 /* We need to use the Perl context of the thread that created */ 3067 /* the pipe. */ 3068 pTHX; 3069 if (info->err) 3070 aTHX = info->err->thx; 3071 else if (info->out) 3072 aTHX = info->out->thx; 3073 else if (info->in) 3074 aTHX = info->in->thx; 3075 #endif 3076 if (!info->useFILE 3077 #if defined(USE_ITHREADS) 3078 && my_perl 3079 #endif 3080 #ifdef USE_PERLIO 3081 && PL_perlio_fd_refcnt 3082 #endif 3083 ) 3084 PerlIO_flush(info->fp); 3085 else 3086 fflush((FILE *)info->fp); 3087 } 3088 info = info->next; 3089 } 3090 3091 /* 3092 next we try sending an EOF...ignore if doesn't work, make sure we 3093 don't hang 3094 */ 3095 did_stuff = 0; 3096 info = open_pipes; 3097 3098 while (info) { 3099 int need_eof; 3100 _ckvmssts_noperl(sys$setast(0)); 3101 if (info->in && !info->in->shut_on_empty) { 3102 _ckvmssts_noperl(sys$qio(0,info->in->chan_in,IO$_WRITEOF,0,0,0, 3103 0, 0, 0, 0, 0, 0)); 3104 info->waiting = 1; 3105 did_stuff = 1; 3106 } 3107 _ckvmssts_noperl(sys$setast(1)); 3108 info = info->next; 3109 } 3110 3111 /* wait for EOF to have effect, up to ~ 30 sec [default] */ 3112 3113 for (j = 0; did_stuff && j < PIPE_COMPLETION_WAIT; j++) { 3114 int nwait = 0; 3115 3116 info = open_pipes; 3117 while (info) { 3118 _ckvmssts_noperl(sys$setast(0)); 3119 if (info->waiting && info->done) 3120 info->waiting = 0; 3121 nwait += info->waiting; 3122 _ckvmssts_noperl(sys$setast(1)); 3123 info = info->next; 3124 } 3125 if (!nwait) break; 3126 sleep(1); 3127 } 3128 3129 did_stuff = 0; 3130 info = open_pipes; 3131 while (info) { 3132 _ckvmssts_noperl(sys$setast(0)); 3133 if (!info->done) { /* Tap them gently on the shoulder . . .*/ 3134 sts = sys$forcex(&info->pid,0,&abort); 3135 if (!(sts&1) && sts != SS$_NONEXPR) _ckvmssts_noperl(sts); 3136 did_stuff = 1; 3137 } 3138 _ckvmssts_noperl(sys$setast(1)); 3139 info = info->next; 3140 } 3141 3142 /* again, wait for effect */ 3143 3144 for (j = 0; did_stuff && j < PIPE_COMPLETION_WAIT; j++) { 3145 int nwait = 0; 3146 3147 info = open_pipes; 3148 while (info) { 3149 _ckvmssts_noperl(sys$setast(0)); 3150 if (info->waiting && info->done) 3151 info->waiting = 0; 3152 nwait += info->waiting; 3153 _ckvmssts_noperl(sys$setast(1)); 3154 info = info->next; 3155 } 3156 if (!nwait) break; 3157 sleep(1); 3158 } 3159 3160 info = open_pipes; 3161 while (info) { 3162 _ckvmssts_noperl(sys$setast(0)); 3163 if (!info->done) { /* We tried to be nice . . . */ 3164 sts = sys$delprc(&info->pid,0); 3165 if (!(sts&1) && sts != SS$_NONEXPR) _ckvmssts_noperl(sts); 3166 info->done = 1; /* sys$delprc is as done as we're going to get. */ 3167 } 3168 _ckvmssts_noperl(sys$setast(1)); 3169 info = info->next; 3170 } 3171 3172 while(open_pipes) { 3173 3174 #if defined(PERL_IMPLICIT_CONTEXT) 3175 /* We need to use the Perl context of the thread that created */ 3176 /* the pipe. */ 3177 pTHX; 3178 if (open_pipes->err) 3179 aTHX = open_pipes->err->thx; 3180 else if (open_pipes->out) 3181 aTHX = open_pipes->out->thx; 3182 else if (open_pipes->in) 3183 aTHX = open_pipes->in->thx; 3184 #endif 3185 if ((sts = my_pclose(open_pipes->fp)) == -1) retsts = vaxc$errno; 3186 else if (!(sts & 1)) retsts = sts; 3187 } 3188 return retsts; 3189 } 3190 3191 static struct exit_control_block pipe_exitblock = 3192 {(struct exit_control_block *) 0, 3193 pipe_exit_routine, 0, &pipe_exitblock.exit_status, 0}; 3194 3195 static void pipe_mbxtofd_ast(pPipe p); 3196 static void pipe_tochild1_ast(pPipe p); 3197 static void pipe_tochild2_ast(pPipe p); 3198 3199 static void 3200 popen_completion_ast(pInfo info) 3201 { 3202 pInfo i = open_pipes; 3203 int iss; 3204 int sts; 3205 pXpipe x; 3206 3207 info->completion &= 0x0FFFFFFF; /* strip off "control" field */ 3208 closed_list[closed_index].pid = info->pid; 3209 closed_list[closed_index].completion = info->completion; 3210 closed_index++; 3211 if (closed_index == NKEEPCLOSED) 3212 closed_index = 0; 3213 closed_num++; 3214 3215 while (i) { 3216 if (i == info) break; 3217 i = i->next; 3218 } 3219 if (!i) return; /* unlinked, probably freed too */ 3220 3221 info->done = TRUE; 3222 3223 /* 3224 Writing to subprocess ... 3225 if my_pclose'd: EOF already sent, should shutdown chan_in part of pipe 3226 3227 chan_out may be waiting for "done" flag, or hung waiting 3228 for i/o completion to child...cancel the i/o. This will 3229 put it into "snarf mode" (done but no EOF yet) that discards 3230 input. 3231 3232 Output from subprocess (stdout, stderr) needs to be flushed and 3233 shut down. We try sending an EOF, but if the mbx is full the pipe 3234 routine should still catch the "shut_on_empty" flag, telling it to 3235 use immediate-style reads so that "mbx empty" -> EOF. 3236 3237 3238 */ 3239 if (info->in && !info->in_done) { /* only for mode=w */ 3240 if (info->in->shut_on_empty && info->in->need_wake) { 3241 info->in->need_wake = FALSE; 3242 _ckvmssts_noperl(sys$dclast(pipe_tochild2_ast,info->in,0)); 3243 } else { 3244 _ckvmssts_noperl(sys$cancel(info->in->chan_out)); 3245 } 3246 } 3247 3248 if (info->out && !info->out_done) { /* were we also piping output? */ 3249 info->out->shut_on_empty = TRUE; 3250 iss = sys$qio(0,info->out->chan_in,IO$_WRITEOF|IO$M_NORSWAIT, 0, 0, 0, 0, 0, 0, 0, 0, 0); 3251 if (iss == SS$_MBFULL) iss = SS$_NORMAL; 3252 _ckvmssts_noperl(iss); 3253 } 3254 3255 if (info->err && !info->err_done) { /* we were piping stderr */ 3256 info->err->shut_on_empty = TRUE; 3257 iss = sys$qio(0,info->err->chan_in,IO$_WRITEOF|IO$M_NORSWAIT, 0, 0, 0, 0, 0, 0, 0, 0, 0); 3258 if (iss == SS$_MBFULL) iss = SS$_NORMAL; 3259 _ckvmssts_noperl(iss); 3260 } 3261 _ckvmssts_noperl(sys$setef(pipe_ef)); 3262 3263 } 3264 3265 static unsigned long int setup_cmddsc(pTHX_ const char *cmd, int check_img, int *suggest_quote, struct dsc$descriptor_s **pvmscmd); 3266 static void vms_execfree(struct dsc$descriptor_s *vmscmd); 3267 3268 /* 3269 we actually differ from vmstrnenv since we use this to 3270 get the RMS IFI to check if SYS$OUTPUT and SYS$ERROR *really* 3271 are pointing to the same thing 3272 */ 3273 3274 static unsigned short 3275 popen_translate(pTHX_ char *logical, char *result) 3276 { 3277 int iss; 3278 $DESCRIPTOR(d_table,"LNM$PROCESS_TABLE"); 3279 $DESCRIPTOR(d_log,""); 3280 struct _il3 { 3281 unsigned short length; 3282 unsigned short code; 3283 char * buffer_addr; 3284 unsigned short *retlenaddr; 3285 } itmlst[2]; 3286 unsigned short l, ifi; 3287 3288 d_log.dsc$a_pointer = logical; 3289 d_log.dsc$w_length = strlen(logical); 3290 3291 itmlst[0].code = LNM$_STRING; 3292 itmlst[0].length = 255; 3293 itmlst[0].buffer_addr = result; 3294 itmlst[0].retlenaddr = &l; 3295 3296 itmlst[1].code = 0; 3297 itmlst[1].length = 0; 3298 itmlst[1].buffer_addr = 0; 3299 itmlst[1].retlenaddr = 0; 3300 3301 iss = sys$trnlnm(0, &d_table, &d_log, 0, itmlst); 3302 if (iss == SS$_NOLOGNAM) { 3303 iss = SS$_NORMAL; 3304 l = 0; 3305 } 3306 if (!(iss&1)) lib$signal(iss); 3307 result[l] = '\0'; 3308 /* 3309 logicals for PPFs have a 4 byte prefix ESC+NUL+(RMS IFI) 3310 strip it off and return the ifi, if any 3311 */ 3312 ifi = 0; 3313 if (result[0] == 0x1b && result[1] == 0x00) { 3314 memmove(&ifi,result+2,2); 3315 strcpy(result,result+4); 3316 } 3317 return ifi; /* this is the RMS internal file id */ 3318 } 3319 3320 static void pipe_infromchild_ast(pPipe p); 3321 3322 /* 3323 I'm using LIB$(GET|FREE)_VM here so that we can allocate and deallocate 3324 inside an AST routine without worrying about reentrancy and which Perl 3325 memory allocator is being used. 3326 3327 We read data and queue up the buffers, then spit them out one at a 3328 time to the output mailbox when the output mailbox is ready for one. 3329 3330 */ 3331 #define INITIAL_TOCHILDQUEUE 2 3332 3333 static pPipe 3334 pipe_tochild_setup(pTHX_ char *rmbx, char *wmbx) 3335 { 3336 pPipe p; 3337 pCBuf b; 3338 char mbx1[64], mbx2[64]; 3339 struct dsc$descriptor_s d_mbx1 = {sizeof mbx1, DSC$K_DTYPE_T, 3340 DSC$K_CLASS_S, mbx1}, 3341 d_mbx2 = {sizeof mbx2, DSC$K_DTYPE_T, 3342 DSC$K_CLASS_S, mbx2}; 3343 unsigned int dviitm = DVI$_DEVBUFSIZ; 3344 int j, n; 3345 3346 n = sizeof(Pipe); 3347 _ckvmssts_noperl(lib$get_vm(&n, &p)); 3348 3349 create_mbx(&p->chan_in , &d_mbx1); 3350 create_mbx(&p->chan_out, &d_mbx2); 3351 _ckvmssts_noperl(lib$getdvi(&dviitm, &p->chan_in, 0, &p->bufsize)); 3352 3353 p->buf = 0; 3354 p->shut_on_empty = FALSE; 3355 p->need_wake = FALSE; 3356 p->type = 0; 3357 p->retry = 0; 3358 p->iosb.status = SS$_NORMAL; 3359 p->iosb2.status = SS$_NORMAL; 3360 p->free = RQE_ZERO; 3361 p->wait = RQE_ZERO; 3362 p->curr = 0; 3363 p->curr2 = 0; 3364 p->info = 0; 3365 #ifdef PERL_IMPLICIT_CONTEXT 3366 p->thx = aTHX; 3367 #endif 3368 3369 n = sizeof(CBuf) + p->bufsize; 3370 3371 for (j = 0; j < INITIAL_TOCHILDQUEUE; j++) { 3372 _ckvmssts_noperl(lib$get_vm(&n, &b)); 3373 b->buf = (char *) b + sizeof(CBuf); 3374 _ckvmssts_noperl(lib$insqhi(b, &p->free)); 3375 } 3376 3377 pipe_tochild2_ast(p); 3378 pipe_tochild1_ast(p); 3379 strcpy(wmbx, mbx1); 3380 strcpy(rmbx, mbx2); 3381 return p; 3382 } 3383 3384 /* reads the MBX Perl is writing, and queues */ 3385 3386 static void 3387 pipe_tochild1_ast(pPipe p) 3388 { 3389 pCBuf b = p->curr; 3390 int iss = p->iosb.status; 3391 int eof = (iss == SS$_ENDOFFILE); 3392 int sts; 3393 #ifdef PERL_IMPLICIT_CONTEXT 3394 pTHX = p->thx; 3395 #endif 3396 3397 if (p->retry) { 3398 if (eof) { 3399 p->shut_on_empty = TRUE; 3400 b->eof = TRUE; 3401 _ckvmssts_noperl(sys$dassgn(p->chan_in)); 3402 } else { 3403 _ckvmssts_noperl(iss); 3404 } 3405 3406 b->eof = eof; 3407 b->size = p->iosb.count; 3408 _ckvmssts_noperl(sts = lib$insqhi(b, &p->wait)); 3409 if (p->need_wake) { 3410 p->need_wake = FALSE; 3411 _ckvmssts_noperl(sys$dclast(pipe_tochild2_ast,p,0)); 3412 } 3413 } else { 3414 p->retry = 1; /* initial call */ 3415 } 3416 3417 if (eof) { /* flush the free queue, return when done */ 3418 int n = sizeof(CBuf) + p->bufsize; 3419 while (1) { 3420 iss = lib$remqti(&p->free, &b); 3421 if (iss == LIB$_QUEWASEMP) return; 3422 _ckvmssts_noperl(iss); 3423 _ckvmssts_noperl(lib$free_vm(&n, &b)); 3424 } 3425 } 3426 3427 iss = lib$remqti(&p->free, &b); 3428 if (iss == LIB$_QUEWASEMP) { 3429 int n = sizeof(CBuf) + p->bufsize; 3430 _ckvmssts_noperl(lib$get_vm(&n, &b)); 3431 b->buf = (char *) b + sizeof(CBuf); 3432 } else { 3433 _ckvmssts_noperl(iss); 3434 } 3435 3436 p->curr = b; 3437 iss = sys$qio(0,p->chan_in, 3438 IO$_READVBLK|(p->shut_on_empty ? IO$M_NOWAIT : 0), 3439 &p->iosb, 3440 pipe_tochild1_ast, p, b->buf, p->bufsize, 0, 0, 0, 0); 3441 if (iss == SS$_ENDOFFILE && p->shut_on_empty) iss = SS$_NORMAL; 3442 _ckvmssts_noperl(iss); 3443 } 3444 3445 3446 /* writes queued buffers to output, waits for each to complete before 3447 doing the next */ 3448 3449 static void 3450 pipe_tochild2_ast(pPipe p) 3451 { 3452 pCBuf b = p->curr2; 3453 int iss = p->iosb2.status; 3454 int n = sizeof(CBuf) + p->bufsize; 3455 int done = (p->info && p->info->done) || 3456 iss == SS$_CANCEL || iss == SS$_ABORT; 3457 #if defined(PERL_IMPLICIT_CONTEXT) 3458 pTHX = p->thx; 3459 #endif 3460 3461 do { 3462 if (p->type) { /* type=1 has old buffer, dispose */ 3463 if (p->shut_on_empty) { 3464 _ckvmssts_noperl(lib$free_vm(&n, &b)); 3465 } else { 3466 _ckvmssts_noperl(lib$insqhi(b, &p->free)); 3467 } 3468 p->type = 0; 3469 } 3470 3471 iss = lib$remqti(&p->wait, &b); 3472 if (iss == LIB$_QUEWASEMP) { 3473 if (p->shut_on_empty) { 3474 if (done) { 3475 _ckvmssts_noperl(sys$dassgn(p->chan_out)); 3476 *p->pipe_done = TRUE; 3477 _ckvmssts_noperl(sys$setef(pipe_ef)); 3478 } else { 3479 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEOF, 3480 &p->iosb2, pipe_tochild2_ast, p, 0, 0, 0, 0, 0, 0)); 3481 } 3482 return; 3483 } 3484 p->need_wake = TRUE; 3485 return; 3486 } 3487 _ckvmssts_noperl(iss); 3488 p->type = 1; 3489 } while (done); 3490 3491 3492 p->curr2 = b; 3493 if (b->eof) { 3494 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEOF, 3495 &p->iosb2, pipe_tochild2_ast, p, 0, 0, 0, 0, 0, 0)); 3496 } else { 3497 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEVBLK, 3498 &p->iosb2, pipe_tochild2_ast, p, b->buf, b->size, 0, 0, 0, 0)); 3499 } 3500 3501 return; 3502 3503 } 3504 3505 3506 static pPipe 3507 pipe_infromchild_setup(pTHX_ char *rmbx, char *wmbx) 3508 { 3509 pPipe p; 3510 char mbx1[64], mbx2[64]; 3511 struct dsc$descriptor_s d_mbx1 = {sizeof mbx1, DSC$K_DTYPE_T, 3512 DSC$K_CLASS_S, mbx1}, 3513 d_mbx2 = {sizeof mbx2, DSC$K_DTYPE_T, 3514 DSC$K_CLASS_S, mbx2}; 3515 unsigned int dviitm = DVI$_DEVBUFSIZ; 3516 3517 int n = sizeof(Pipe); 3518 _ckvmssts_noperl(lib$get_vm(&n, &p)); 3519 create_mbx(&p->chan_in , &d_mbx1); 3520 create_mbx(&p->chan_out, &d_mbx2); 3521 3522 _ckvmssts_noperl(lib$getdvi(&dviitm, &p->chan_in, 0, &p->bufsize)); 3523 n = p->bufsize * sizeof(char); 3524 _ckvmssts_noperl(lib$get_vm(&n, &p->buf)); 3525 p->shut_on_empty = FALSE; 3526 p->info = 0; 3527 p->type = 0; 3528 p->iosb.status = SS$_NORMAL; 3529 #if defined(PERL_IMPLICIT_CONTEXT) 3530 p->thx = aTHX; 3531 #endif 3532 pipe_infromchild_ast(p); 3533 3534 strcpy(wmbx, mbx1); 3535 strcpy(rmbx, mbx2); 3536 return p; 3537 } 3538 3539 static void 3540 pipe_infromchild_ast(pPipe p) 3541 { 3542 int iss = p->iosb.status; 3543 int eof = (iss == SS$_ENDOFFILE); 3544 int myeof = (eof && (p->iosb.dvispec == mypid || p->iosb.dvispec == 0)); 3545 int kideof = (eof && (p->iosb.dvispec == p->info->pid)); 3546 #if defined(PERL_IMPLICIT_CONTEXT) 3547 pTHX = p->thx; 3548 #endif 3549 3550 if (p->info && p->info->closing && p->chan_out) { /* output shutdown */ 3551 _ckvmssts_noperl(sys$dassgn(p->chan_out)); 3552 p->chan_out = 0; 3553 } 3554 3555 /* read completed: 3556 input shutdown if EOF from self (done or shut_on_empty) 3557 output shutdown if closing flag set (my_pclose) 3558 send data/eof from child or eof from self 3559 otherwise, re-read (snarf of data from child) 3560 */ 3561 3562 if (p->type == 1) { 3563 p->type = 0; 3564 if (myeof && p->chan_in) { /* input shutdown */ 3565 _ckvmssts_noperl(sys$dassgn(p->chan_in)); 3566 p->chan_in = 0; 3567 } 3568 3569 if (p->chan_out) { 3570 if (myeof || kideof) { /* pass EOF to parent */ 3571 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEOF, &p->iosb, 3572 pipe_infromchild_ast, p, 3573 0, 0, 0, 0, 0, 0)); 3574 return; 3575 } else if (eof) { /* eat EOF --- fall through to read*/ 3576 3577 } else { /* transmit data */ 3578 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEVBLK,&p->iosb, 3579 pipe_infromchild_ast,p, 3580 p->buf, p->iosb.count, 0, 0, 0, 0)); 3581 return; 3582 } 3583 } 3584 } 3585 3586 /* everything shut? flag as done */ 3587 3588 if (!p->chan_in && !p->chan_out) { 3589 *p->pipe_done = TRUE; 3590 _ckvmssts_noperl(sys$setef(pipe_ef)); 3591 return; 3592 } 3593 3594 /* write completed (or read, if snarfing from child) 3595 if still have input active, 3596 queue read...immediate mode if shut_on_empty so we get EOF if empty 3597 otherwise, 3598 check if Perl reading, generate EOFs as needed 3599 */ 3600 3601 if (p->type == 0) { 3602 p->type = 1; 3603 if (p->chan_in) { 3604 iss = sys$qio(0,p->chan_in,IO$_READVBLK|(p->shut_on_empty ? IO$M_NOW : 0),&p->iosb, 3605 pipe_infromchild_ast,p, 3606 p->buf, p->bufsize, 0, 0, 0, 0); 3607 if (p->shut_on_empty && iss == SS$_ENDOFFILE) iss = SS$_NORMAL; 3608 _ckvmssts_noperl(iss); 3609 } else { /* send EOFs for extra reads */ 3610 p->iosb.status = SS$_ENDOFFILE; 3611 p->iosb.dvispec = 0; 3612 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_SETMODE|IO$M_READATTN, 3613 0, 0, 0, 3614 pipe_infromchild_ast, p, 0, 0, 0, 0)); 3615 } 3616 } 3617 } 3618 3619 static pPipe 3620 pipe_mbxtofd_setup(pTHX_ int fd, char *out) 3621 { 3622 pPipe p; 3623 char mbx[64]; 3624 unsigned long dviitm = DVI$_DEVBUFSIZ; 3625 struct stat s; 3626 struct dsc$descriptor_s d_mbx = {sizeof mbx, DSC$K_DTYPE_T, 3627 DSC$K_CLASS_S, mbx}; 3628 int n = sizeof(Pipe); 3629 3630 /* things like terminals and mbx's don't need this filter */ 3631 if (fd && fstat(fd,&s) == 0) { 3632 unsigned long dviitm = DVI$_DEVCHAR, devchar; 3633 char device[65]; 3634 unsigned short dev_len; 3635 struct dsc$descriptor_s d_dev; 3636 char * cptr; 3637 struct item_list_3 items[3]; 3638 int status; 3639 unsigned short dvi_iosb[4]; 3640 3641 cptr = getname(fd, out, 1); 3642 if (cptr == NULL) _ckvmssts_noperl(SS$_NOSUCHDEV); 3643 d_dev.dsc$a_pointer = out; 3644 d_dev.dsc$w_length = strlen(out); 3645 d_dev.dsc$b_dtype = DSC$K_DTYPE_T; 3646 d_dev.dsc$b_class = DSC$K_CLASS_S; 3647 3648 items[0].len = 4; 3649 items[0].code = DVI$_DEVCHAR; 3650 items[0].bufadr = &devchar; 3651 items[0].retadr = NULL; 3652 items[1].len = 64; 3653 items[1].code = DVI$_FULLDEVNAM; 3654 items[1].bufadr = device; 3655 items[1].retadr = &dev_len; 3656 items[2].len = 0; 3657 items[2].code = 0; 3658 3659 status = sys$getdviw 3660 (NO_EFN, 0, &d_dev, items, dvi_iosb, NULL, NULL, NULL); 3661 _ckvmssts_noperl(status); 3662 if ($VMS_STATUS_SUCCESS(dvi_iosb[0])) { 3663 device[dev_len] = 0; 3664 3665 if (!(devchar & DEV$M_DIR)) { 3666 strcpy(out, device); 3667 return 0; 3668 } 3669 } 3670 } 3671 3672 _ckvmssts_noperl(lib$get_vm(&n, &p)); 3673 p->fd_out = dup(fd); 3674 create_mbx(&p->chan_in, &d_mbx); 3675 _ckvmssts_noperl(lib$getdvi(&dviitm, &p->chan_in, 0, &p->bufsize)); 3676 n = (p->bufsize+1) * sizeof(char); 3677 _ckvmssts_noperl(lib$get_vm(&n, &p->buf)); 3678 p->shut_on_empty = FALSE; 3679 p->retry = 0; 3680 p->info = 0; 3681 strcpy(out, mbx); 3682 3683 _ckvmssts_noperl(sys$qio(0, p->chan_in, IO$_READVBLK, &p->iosb, 3684 pipe_mbxtofd_ast, p, 3685 p->buf, p->bufsize, 0, 0, 0, 0)); 3686 3687 return p; 3688 } 3689 3690 static void 3691 pipe_mbxtofd_ast(pPipe p) 3692 { 3693 int iss = p->iosb.status; 3694 int done = p->info->done; 3695 int iss2; 3696 int eof = (iss == SS$_ENDOFFILE); 3697 int myeof = eof && ((p->iosb.dvispec == mypid)||(p->iosb.dvispec == 0)); 3698 int err = !(iss&1) && !eof; 3699 #if defined(PERL_IMPLICIT_CONTEXT) 3700 pTHX = p->thx; 3701 #endif 3702 3703 if (done && myeof) { /* end piping */ 3704 close(p->fd_out); 3705 sys$dassgn(p->chan_in); 3706 *p->pipe_done = TRUE; 3707 _ckvmssts_noperl(sys$setef(pipe_ef)); 3708 return; 3709 } 3710 3711 if (!err && !eof) { /* good data to send to file */ 3712 p->buf[p->iosb.count] = '\n'; 3713 iss2 = write(p->fd_out, p->buf, p->iosb.count+1); 3714 if (iss2 < 0) { 3715 p->retry++; 3716 if (p->retry < MAX_RETRY) { 3717 _ckvmssts_noperl(sys$setimr(0,delaytime,pipe_mbxtofd_ast,p)); 3718 return; 3719 } 3720 } 3721 p->retry = 0; 3722 } else if (err) { 3723 _ckvmssts_noperl(iss); 3724 } 3725 3726 3727 iss = sys$qio(0, p->chan_in, IO$_READVBLK|(p->shut_on_empty ? IO$M_NOW : 0), &p->iosb, 3728 pipe_mbxtofd_ast, p, 3729 p->buf, p->bufsize, 0, 0, 0, 0); 3730 if (p->shut_on_empty && (iss == SS$_ENDOFFILE)) iss = SS$_NORMAL; 3731 _ckvmssts_noperl(iss); 3732 } 3733 3734 3735 typedef struct _pipeloc PLOC; 3736 typedef struct _pipeloc* pPLOC; 3737 3738 struct _pipeloc { 3739 pPLOC next; 3740 char dir[NAM$C_MAXRSS+1]; 3741 }; 3742 static pPLOC head_PLOC = 0; 3743 3744 void 3745 free_pipelocs(pTHX_ void *head) 3746 { 3747 pPLOC p, pnext; 3748 pPLOC *pHead = (pPLOC *)head; 3749 3750 p = *pHead; 3751 while (p) { 3752 pnext = p->next; 3753 PerlMem_free(p); 3754 p = pnext; 3755 } 3756 *pHead = 0; 3757 } 3758 3759 static void 3760 store_pipelocs(pTHX) 3761 { 3762 int i; 3763 pPLOC p; 3764 AV *av = 0; 3765 SV *dirsv; 3766 GV *gv; 3767 char *dir, *x; 3768 char *unixdir; 3769 char temp[NAM$C_MAXRSS+1]; 3770 STRLEN n_a; 3771 3772 if (head_PLOC) 3773 free_pipelocs(aTHX_ &head_PLOC); 3774 3775 /* the . directory from @INC comes last */ 3776 3777 p = (pPLOC) PerlMem_malloc(sizeof(PLOC)); 3778 if (p == NULL) _ckvmssts_noperl(SS$_INSFMEM); 3779 p->next = head_PLOC; 3780 head_PLOC = p; 3781 strcpy(p->dir,"./"); 3782 3783 /* get the directory from $^X */ 3784 3785 unixdir = PerlMem_malloc(VMS_MAXRSS); 3786 if (unixdir == NULL) _ckvmssts_noperl(SS$_INSFMEM); 3787 3788 #ifdef PERL_IMPLICIT_CONTEXT 3789 if (aTHX && PL_origargv && PL_origargv[0]) { /* maybe nul if embedded Perl */ 3790 #else 3791 if (PL_origargv && PL_origargv[0]) { /* maybe nul if embedded Perl */ 3792 #endif 3793 strcpy(temp, PL_origargv[0]); 3794 x = strrchr(temp,']'); 3795 if (x == NULL) { 3796 x = strrchr(temp,'>'); 3797 if (x == NULL) { 3798 /* It could be a UNIX path */ 3799 x = strrchr(temp,'/'); 3800 } 3801 } 3802 if (x) 3803 x[1] = '\0'; 3804 else { 3805 /* Got a bare name, so use default directory */ 3806 temp[0] = '.'; 3807 temp[1] = '\0'; 3808 } 3809 3810 if ((tounixpath_utf8(temp, unixdir, NULL)) != NULL) { 3811 p = (pPLOC) PerlMem_malloc(sizeof(PLOC)); 3812 if (p == NULL) _ckvmssts_noperl(SS$_INSFMEM); 3813 p->next = head_PLOC; 3814 head_PLOC = p; 3815 strncpy(p->dir,unixdir,sizeof(p->dir)-1); 3816 p->dir[NAM$C_MAXRSS] = '\0'; 3817 } 3818 } 3819 3820 /* reverse order of @INC entries, skip "." since entered above */ 3821 3822 #ifdef PERL_IMPLICIT_CONTEXT 3823 if (aTHX) 3824 #endif 3825 if (PL_incgv) av = GvAVn(PL_incgv); 3826 3827 for (i = 0; av && i <= AvFILL(av); i++) { 3828 dirsv = *av_fetch(av,i,TRUE); 3829 3830 if (SvROK(dirsv)) continue; 3831 dir = SvPVx(dirsv,n_a); 3832 if (strcmp(dir,".") == 0) continue; 3833 if ((tounixpath_utf8(dir, unixdir, NULL)) == NULL) 3834 continue; 3835 3836 p = (pPLOC) PerlMem_malloc(sizeof(PLOC)); 3837 p->next = head_PLOC; 3838 head_PLOC = p; 3839 strncpy(p->dir,unixdir,sizeof(p->dir)-1); 3840 p->dir[NAM$C_MAXRSS] = '\0'; 3841 } 3842 3843 /* most likely spot (ARCHLIB) put first in the list */ 3844 3845 #ifdef ARCHLIB_EXP 3846 if ((tounixpath_utf8(ARCHLIB_EXP, unixdir, NULL)) != NULL) { 3847 p = (pPLOC) PerlMem_malloc(sizeof(PLOC)); 3848 if (p == NULL) _ckvmssts_noperl(SS$_INSFMEM); 3849 p->next = head_PLOC; 3850 head_PLOC = p; 3851 strncpy(p->dir,unixdir,sizeof(p->dir)-1); 3852 p->dir[NAM$C_MAXRSS] = '\0'; 3853 } 3854 #endif 3855 PerlMem_free(unixdir); 3856 } 3857 3858 static I32 3859 Perl_cando_by_name_int 3860 (pTHX_ I32 bit, bool effective, const char *fname, int opts); 3861 #if !defined(PERL_IMPLICIT_CONTEXT) 3862 #define cando_by_name_int Perl_cando_by_name_int 3863 #else 3864 #define cando_by_name_int(a,b,c,d) Perl_cando_by_name_int(aTHX_ a,b,c,d) 3865 #endif 3866 3867 static char * 3868 find_vmspipe(pTHX) 3869 { 3870 static int vmspipe_file_status = 0; 3871 static char vmspipe_file[NAM$C_MAXRSS+1]; 3872 3873 /* already found? Check and use ... need read+execute permission */ 3874 3875 if (vmspipe_file_status == 1) { 3876 if (cando_by_name_int(S_IRUSR, 0, vmspipe_file, PERL_RMSEXPAND_M_VMS_IN) 3877 && cando_by_name_int 3878 (S_IXUSR, 0, vmspipe_file, PERL_RMSEXPAND_M_VMS_IN)) { 3879 return vmspipe_file; 3880 } 3881 vmspipe_file_status = 0; 3882 } 3883 3884 /* scan through stored @INC, $^X */ 3885 3886 if (vmspipe_file_status == 0) { 3887 char file[NAM$C_MAXRSS+1]; 3888 pPLOC p = head_PLOC; 3889 3890 while (p) { 3891 char * exp_res; 3892 int dirlen; 3893 strcpy(file, p->dir); 3894 dirlen = strlen(file); 3895 strncat(file, "vmspipe.com",NAM$C_MAXRSS - dirlen); 3896 file[NAM$C_MAXRSS] = '\0'; 3897 p = p->next; 3898 3899 exp_res = int_rmsexpand_tovms(file, vmspipe_file, 0); 3900 if (!exp_res) continue; 3901 3902 if (cando_by_name_int 3903 (S_IRUSR, 0, vmspipe_file, PERL_RMSEXPAND_M_VMS_IN) 3904 && cando_by_name_int 3905 (S_IXUSR, 0, vmspipe_file, PERL_RMSEXPAND_M_VMS_IN)) { 3906 vmspipe_file_status = 1; 3907 return vmspipe_file; 3908 } 3909 } 3910 vmspipe_file_status = -1; /* failed, use tempfiles */ 3911 } 3912 3913 return 0; 3914 } 3915 3916 static FILE * 3917 vmspipe_tempfile(pTHX) 3918 { 3919 char file[NAM$C_MAXRSS+1]; 3920 FILE *fp; 3921 static int index = 0; 3922 Stat_t s0, s1; 3923 int cmp_result; 3924 3925 /* create a tempfile */ 3926 3927 /* we can't go from W, shr=get to R, shr=get without 3928 an intermediate vulnerable state, so don't bother trying... 3929 3930 and lib$spawn doesn't shr=put, so have to close the write 3931 3932 So... match up the creation date/time and the FID to 3933 make sure we're dealing with the same file 3934 3935 */ 3936 3937 index++; 3938 if (!decc_filename_unix_only) { 3939 sprintf(file,"sys$scratch:perlpipe_%08.8x_%d.com",mypid,index); 3940 fp = fopen(file,"w"); 3941 if (!fp) { 3942 sprintf(file,"sys$login:perlpipe_%08.8x_%d.com",mypid,index); 3943 fp = fopen(file,"w"); 3944 if (!fp) { 3945 sprintf(file,"sys$disk:[]perlpipe_%08.8x_%d.com",mypid,index); 3946 fp = fopen(file,"w"); 3947 } 3948 } 3949 } 3950 else { 3951 sprintf(file,"/tmp/perlpipe_%08.8x_%d.com",mypid,index); 3952 fp = fopen(file,"w"); 3953 if (!fp) { 3954 sprintf(file,"/sys$login/perlpipe_%08.8x_%d.com",mypid,index); 3955 fp = fopen(file,"w"); 3956 if (!fp) { 3957 sprintf(file,"./perlpipe_%08.8x_%d.com",mypid,index); 3958 fp = fopen(file,"w"); 3959 } 3960 } 3961 } 3962 if (!fp) return 0; /* we're hosed */ 3963 3964 fprintf(fp,"$! 'f$verify(0)'\n"); 3965 fprintf(fp,"$! --- protect against nonstandard definitions ---\n"); 3966 fprintf(fp,"$ perl_cfile = f$environment(\"procedure\")\n"); 3967 fprintf(fp,"$ perl_define = \"define/nolog\"\n"); 3968 fprintf(fp,"$ perl_on = \"set noon\"\n"); 3969 fprintf(fp,"$ perl_exit = \"exit\"\n"); 3970 fprintf(fp,"$ perl_del = \"delete\"\n"); 3971 fprintf(fp,"$ pif = \"if\"\n"); 3972 fprintf(fp,"$! --- define i/o redirection (sys$output set by lib$spawn)\n"); 3973 fprintf(fp,"$ pif perl_popen_in .nes. \"\" then perl_define/user/name_attributes=confine sys$input 'perl_popen_in'\n"); 3974 fprintf(fp,"$ pif perl_popen_err .nes. \"\" then perl_define/user/name_attributes=confine sys$error 'perl_popen_err'\n"); 3975 fprintf(fp,"$ pif perl_popen_out .nes. \"\" then perl_define sys$output 'perl_popen_out'\n"); 3976 fprintf(fp,"$! --- build command line to get max possible length\n"); 3977 fprintf(fp,"$c=perl_popen_cmd0\n"); 3978 fprintf(fp,"$c=c+perl_popen_cmd1\n"); 3979 fprintf(fp,"$c=c+perl_popen_cmd2\n"); 3980 fprintf(fp,"$x=perl_popen_cmd3\n"); 3981 fprintf(fp,"$c=c+x\n"); 3982 fprintf(fp,"$ perl_on\n"); 3983 fprintf(fp,"$ 'c'\n"); 3984 fprintf(fp,"$ perl_status = $STATUS\n"); 3985 fprintf(fp,"$ perl_del 'perl_cfile'\n"); 3986 fprintf(fp,"$ perl_exit 'perl_status'\n"); 3987 fsync(fileno(fp)); 3988 3989 fgetname(fp, file, 1); 3990 fstat(fileno(fp), &s0.crtl_stat); 3991 fclose(fp); 3992 3993 if (decc_filename_unix_only) 3994 int_tounixspec(file, file, NULL); 3995 fp = fopen(file,"r","shr=get"); 3996 if (!fp) return 0; 3997 fstat(fileno(fp), &s1.crtl_stat); 3998 3999 cmp_result = VMS_INO_T_COMPARE(s0.crtl_stat.st_ino, s1.crtl_stat.st_ino); 4000 if ((cmp_result != 0) && (s0.st_ctime != s1.st_ctime)) { 4001 fclose(fp); 4002 return 0; 4003 } 4004 4005 return fp; 4006 } 4007 4008 4009 static int vms_is_syscommand_xterm(void) 4010 { 4011 const static struct dsc$descriptor_s syscommand_dsc = 4012 { 11, DSC$K_DTYPE_T, DSC$K_CLASS_S, "SYS$COMMAND" }; 4013 4014 const static struct dsc$descriptor_s decwdisplay_dsc = 4015 { 12, DSC$K_DTYPE_T, DSC$K_CLASS_S, "DECW$DISPLAY" }; 4016 4017 struct item_list_3 items[2]; 4018 unsigned short dvi_iosb[4]; 4019 unsigned long devchar; 4020 unsigned long devclass; 4021 int status; 4022 4023 /* Very simple check to guess if sys$command is a decterm? */ 4024 /* First see if the DECW$DISPLAY: device exists */ 4025 items[0].len = 4; 4026 items[0].code = DVI$_DEVCHAR; 4027 items[0].bufadr = &devchar; 4028 items[0].retadr = NULL; 4029 items[1].len = 0; 4030 items[1].code = 0; 4031 4032 status = sys$getdviw 4033 (NO_EFN, 0, &decwdisplay_dsc, items, dvi_iosb, NULL, NULL, NULL); 4034 4035 if ($VMS_STATUS_SUCCESS(status)) { 4036 status = dvi_iosb[0]; 4037 } 4038 4039 if (!$VMS_STATUS_SUCCESS(status)) { 4040 SETERRNO(EVMSERR, status); 4041 return -1; 4042 } 4043 4044 /* If it does, then for now assume that we are on a workstation */ 4045 /* Now verify that SYS$COMMAND is a terminal */ 4046 /* for creating the debugger DECTerm */ 4047 4048 items[0].len = 4; 4049 items[0].code = DVI$_DEVCLASS; 4050 items[0].bufadr = &devclass; 4051 items[0].retadr = NULL; 4052 items[1].len = 0; 4053 items[1].code = 0; 4054 4055 status = sys$getdviw 4056 (NO_EFN, 0, &syscommand_dsc, items, dvi_iosb, NULL, NULL, NULL); 4057 4058 if ($VMS_STATUS_SUCCESS(status)) { 4059 status = dvi_iosb[0]; 4060 } 4061 4062 if (!$VMS_STATUS_SUCCESS(status)) { 4063 SETERRNO(EVMSERR, status); 4064 return -1; 4065 } 4066 else { 4067 if (devclass == DC$_TERM) { 4068 return 0; 4069 } 4070 } 4071 return -1; 4072 } 4073 4074 /* If we are on a DECTerm, we can pretend to fork xterms when requested */ 4075 static PerlIO * create_forked_xterm(pTHX_ const char *cmd, const char *mode) 4076 { 4077 int status; 4078 int ret_stat; 4079 char * ret_char; 4080 char device_name[65]; 4081 unsigned short device_name_len; 4082 struct dsc$descriptor_s customization_dsc; 4083 struct dsc$descriptor_s device_name_dsc; 4084 const char * cptr; 4085 char * tptr; 4086 char customization[200]; 4087 char title[40]; 4088 pInfo info = NULL; 4089 char mbx1[64]; 4090 unsigned short p_chan; 4091 int n; 4092 unsigned short iosb[4]; 4093 struct item_list_3 items[2]; 4094 const char * cust_str = 4095 "DECW$TERMINAL.iconName:\tPerl Dbg\nDECW$TERMINAL.title:\t%40s\n"; 4096 struct dsc$descriptor_s d_mbx1 = {sizeof mbx1, DSC$K_DTYPE_T, 4097 DSC$K_CLASS_S, mbx1}; 4098 4099 /* LIB$FIND_IMAGE_SIGNAL needs a handler */ 4100 /*---------------------------------------*/ 4101 VAXC$ESTABLISH((__vms_handler)lib$sig_to_ret); 4102 4103 4104 /* Make sure that this is from the Perl debugger */ 4105 ret_char = strstr(cmd," xterm "); 4106 if (ret_char == NULL) 4107 return NULL; 4108 cptr = ret_char + 7; 4109 ret_char = strstr(cmd,"tty"); 4110 if (ret_char == NULL) 4111 return NULL; 4112 ret_char = strstr(cmd,"sleep"); 4113 if (ret_char == NULL) 4114 return NULL; 4115 4116 if (decw_term_port == 0) { 4117 $DESCRIPTOR(filename1_dsc, "DECW$TERMINALSHR12"); 4118 $DESCRIPTOR(filename2_dsc, "DECW$TERMINALSHR"); 4119 $DESCRIPTOR(decw_term_port_dsc, "DECW$TERM_PORT"); 4120 4121 status = lib$find_image_symbol 4122 (&filename1_dsc, 4123 &decw_term_port_dsc, 4124 (void *)&decw_term_port, 4125 NULL, 4126 0); 4127 4128 /* Try again with the other image name */ 4129 if (!$VMS_STATUS_SUCCESS(status)) { 4130 4131 status = lib$find_image_symbol 4132 (&filename2_dsc, 4133 &decw_term_port_dsc, 4134 (void *)&decw_term_port, 4135 NULL, 4136 0); 4137 4138 } 4139 4140 } 4141 4142 4143 /* No decw$term_port, give it up */ 4144 if (!$VMS_STATUS_SUCCESS(status)) 4145 return NULL; 4146 4147 /* Are we on a workstation? */ 4148 /* to do: capture the rows / columns and pass their properties */ 4149 ret_stat = vms_is_syscommand_xterm(); 4150 if (ret_stat < 0) 4151 return NULL; 4152 4153 /* Make the title: */ 4154 ret_char = strstr(cptr,"-title"); 4155 if (ret_char != NULL) { 4156 while ((*cptr != 0) && (*cptr != '\"')) { 4157 cptr++; 4158 } 4159 if (*cptr == '\"') 4160 cptr++; 4161 n = 0; 4162 while ((*cptr != 0) && (*cptr != '\"')) { 4163 title[n] = *cptr; 4164 n++; 4165 if (n == 39) { 4166 title[39] == 0; 4167 break; 4168 } 4169 cptr++; 4170 } 4171 title[n] = 0; 4172 } 4173 else { 4174 /* Default title */ 4175 strcpy(title,"Perl Debug DECTerm"); 4176 } 4177 sprintf(customization, cust_str, title); 4178 4179 customization_dsc.dsc$a_pointer = customization; 4180 customization_dsc.dsc$w_length = strlen(customization); 4181 customization_dsc.dsc$b_dtype = DSC$K_DTYPE_T; 4182 customization_dsc.dsc$b_class = DSC$K_CLASS_S; 4183 4184 device_name_dsc.dsc$a_pointer = device_name; 4185 device_name_dsc.dsc$w_length = sizeof device_name -1; 4186 device_name_dsc.dsc$b_dtype = DSC$K_DTYPE_T; 4187 device_name_dsc.dsc$b_class = DSC$K_CLASS_S; 4188 4189 device_name_len = 0; 4190 4191 /* Try to create the window */ 4192 status = (*decw_term_port) 4193 (NULL, 4194 NULL, 4195 &customization_dsc, 4196 &device_name_dsc, 4197 &device_name_len, 4198 NULL, 4199 NULL, 4200 NULL); 4201 if (!$VMS_STATUS_SUCCESS(status)) { 4202 SETERRNO(EVMSERR, status); 4203 return NULL; 4204 } 4205 4206 device_name[device_name_len] = '\0'; 4207 4208 /* Need to set this up to look like a pipe for cleanup */ 4209 n = sizeof(Info); 4210 status = lib$get_vm(&n, &info); 4211 if (!$VMS_STATUS_SUCCESS(status)) { 4212 SETERRNO(ENOMEM, status); 4213 return NULL; 4214 } 4215 4216 info->mode = *mode; 4217 info->done = FALSE; 4218 info->completion = 0; 4219 info->closing = FALSE; 4220 info->in = 0; 4221 info->out = 0; 4222 info->err = 0; 4223 info->fp = NULL; 4224 info->useFILE = 0; 4225 info->waiting = 0; 4226 info->in_done = TRUE; 4227 info->out_done = TRUE; 4228 info->err_done = TRUE; 4229 4230 /* Assign a channel on this so that it will persist, and not login */ 4231 /* We stash this channel in the info structure for reference. */ 4232 /* The created xterm self destructs when the last channel is removed */ 4233 /* and it appears that perl5db.pl (perl debugger) does this routinely */ 4234 /* So leave this assigned. */ 4235 device_name_dsc.dsc$w_length = device_name_len; 4236 status = sys$assign(&device_name_dsc,&info->xchan,0,0); 4237 if (!$VMS_STATUS_SUCCESS(status)) { 4238 SETERRNO(EVMSERR, status); 4239 return NULL; 4240 } 4241 info->xchan_valid = 1; 4242 4243 /* Now create a mailbox to be read by the application */ 4244 4245 create_mbx(&p_chan, &d_mbx1); 4246 4247 /* write the name of the created terminal to the mailbox */ 4248 status = sys$qiow(NO_EFN, p_chan, IO$_WRITEVBLK|IO$M_NOW, 4249 iosb, NULL, NULL, device_name, device_name_len, 0, 0, 0, 0); 4250 4251 if (!$VMS_STATUS_SUCCESS(status)) { 4252 SETERRNO(EVMSERR, status); 4253 return NULL; 4254 } 4255 4256 info->fp = PerlIO_open(mbx1, mode); 4257 4258 /* Done with this channel */ 4259 sys$dassgn(p_chan); 4260 4261 /* If any errors, then clean up */ 4262 if (!info->fp) { 4263 n = sizeof(Info); 4264 _ckvmssts_noperl(lib$free_vm(&n, &info)); 4265 return NULL; 4266 } 4267 4268 /* All done */ 4269 return info->fp; 4270 } 4271 4272 static I32 my_pclose_pinfo(pTHX_ pInfo info); 4273 4274 static PerlIO * 4275 safe_popen(pTHX_ const char *cmd, const char *in_mode, int *psts) 4276 { 4277 static int handler_set_up = FALSE; 4278 PerlIO * ret_fp; 4279 unsigned long int sts, flags = CLI$M_NOWAIT; 4280 /* The use of a GLOBAL table (as was done previously) rendered 4281 * Perl's qx() or `` unusable from a C<$ SET SYMBOL/SCOPE=NOGLOBAL> DCL 4282 * environment. Hence we've switched to LOCAL symbol table. 4283 */ 4284 unsigned int table = LIB$K_CLI_LOCAL_SYM; 4285 int j, wait = 0, n; 4286 char *p, mode[10], symbol[MAX_DCL_SYMBOL+1], *vmspipe; 4287 char *in, *out, *err, mbx[512]; 4288 FILE *tpipe = 0; 4289 char tfilebuf[NAM$C_MAXRSS+1]; 4290 pInfo info = NULL; 4291 char cmd_sym_name[20]; 4292 struct dsc$descriptor_s d_symbol= {0, DSC$K_DTYPE_T, 4293 DSC$K_CLASS_S, symbol}; 4294 struct dsc$descriptor_s vmspipedsc = {0, DSC$K_DTYPE_T, 4295 DSC$K_CLASS_S, 0}; 4296 struct dsc$descriptor_s d_sym_cmd = {0, DSC$K_DTYPE_T, 4297 DSC$K_CLASS_S, cmd_sym_name}; 4298 struct dsc$descriptor_s *vmscmd; 4299 $DESCRIPTOR(d_sym_in ,"PERL_POPEN_IN"); 4300 $DESCRIPTOR(d_sym_out,"PERL_POPEN_OUT"); 4301 $DESCRIPTOR(d_sym_err,"PERL_POPEN_ERR"); 4302 4303 /* Check here for Xterm create request. This means looking for 4304 * "3>&1 xterm\b" and "\btty 1>&3\b$" in the command, and that it 4305 * is possible to create an xterm. 4306 */ 4307 if (*in_mode == 'r') { 4308 PerlIO * xterm_fd; 4309 4310 #if defined(PERL_IMPLICIT_CONTEXT) 4311 /* Can not fork an xterm with a NULL context */ 4312 /* This probably could never happen */ 4313 xterm_fd = NULL; 4314 if (aTHX != NULL) 4315 #endif 4316 xterm_fd = create_forked_xterm(aTHX_ cmd, in_mode); 4317 if (xterm_fd != NULL) 4318 return xterm_fd; 4319 } 4320 4321 if (!head_PLOC) store_pipelocs(aTHX); /* at least TRY to use a static vmspipe file */ 4322 4323 /* once-per-program initialization... 4324 note that the SETAST calls and the dual test of pipe_ef 4325 makes sure that only the FIRST thread through here does 4326 the initialization...all other threads wait until it's 4327 done. 4328 4329 Yeah, uglier than a pthread call, it's got all the stuff inline 4330 rather than in a separate routine. 4331 */ 4332 4333 if (!pipe_ef) { 4334 _ckvmssts_noperl(sys$setast(0)); 4335 if (!pipe_ef) { 4336 unsigned long int pidcode = JPI$_PID; 4337 $DESCRIPTOR(d_delay, RETRY_DELAY); 4338 _ckvmssts_noperl(lib$get_ef(&pipe_ef)); 4339 _ckvmssts_noperl(lib$getjpi(&pidcode,0,0,&mypid,0,0)); 4340 _ckvmssts_noperl(sys$bintim(&d_delay, delaytime)); 4341 } 4342 if (!handler_set_up) { 4343 _ckvmssts_noperl(sys$dclexh(&pipe_exitblock)); 4344 handler_set_up = TRUE; 4345 } 4346 _ckvmssts_noperl(sys$setast(1)); 4347 } 4348 4349 /* see if we can find a VMSPIPE.COM */ 4350 4351 tfilebuf[0] = '@'; 4352 vmspipe = find_vmspipe(aTHX); 4353 if (vmspipe) { 4354 strcpy(tfilebuf+1,vmspipe); 4355 } else { /* uh, oh...we're in tempfile hell */ 4356 tpipe = vmspipe_tempfile(aTHX); 4357 if (!tpipe) { /* a fish popular in Boston */ 4358 if (ckWARN(WARN_PIPE)) { 4359 Perl_warner(aTHX_ packWARN(WARN_PIPE),"unable to find VMSPIPE.COM for i/o piping"); 4360 } 4361 return NULL; 4362 } 4363 fgetname(tpipe,tfilebuf+1,1); 4364 } 4365 vmspipedsc.dsc$a_pointer = tfilebuf; 4366 vmspipedsc.dsc$w_length = strlen(tfilebuf); 4367 4368 sts = setup_cmddsc(aTHX_ cmd,0,0,&vmscmd); 4369 if (!(sts & 1)) { 4370 switch (sts) { 4371 case RMS$_FNF: case RMS$_DNF: 4372 set_errno(ENOENT); break; 4373 case RMS$_DIR: 4374 set_errno(ENOTDIR); break; 4375 case RMS$_DEV: 4376 set_errno(ENODEV); break; 4377 case RMS$_PRV: 4378 set_errno(EACCES); break; 4379 case RMS$_SYN: 4380 set_errno(EINVAL); break; 4381 case CLI$_BUFOVF: case RMS$_RTB: case CLI$_TKNOVF: case CLI$_RSLOVF: 4382 set_errno(E2BIG); break; 4383 case LIB$_INVARG: case LIB$_INVSTRDES: case SS$_ACCVIO: /* shouldn't happen */ 4384 _ckvmssts_noperl(sts); /* fall through */ 4385 default: /* SS$_DUPLNAM, SS$_CLI, resource exhaustion, etc. */ 4386 set_errno(EVMSERR); 4387 } 4388 set_vaxc_errno(sts); 4389 if (*in_mode != 'n' && ckWARN(WARN_PIPE)) { 4390 Perl_warner(aTHX_ packWARN(WARN_PIPE),"Can't pipe \"%*s\": %s", strlen(cmd), cmd, Strerror(errno)); 4391 } 4392 *psts = sts; 4393 return NULL; 4394 } 4395 n = sizeof(Info); 4396 _ckvmssts_noperl(lib$get_vm(&n, &info)); 4397 4398 strcpy(mode,in_mode); 4399 info->mode = *mode; 4400 info->done = FALSE; 4401 info->completion = 0; 4402 info->closing = FALSE; 4403 info->in = 0; 4404 info->out = 0; 4405 info->err = 0; 4406 info->fp = NULL; 4407 info->useFILE = 0; 4408 info->waiting = 0; 4409 info->in_done = TRUE; 4410 info->out_done = TRUE; 4411 info->err_done = TRUE; 4412 info->xchan = 0; 4413 info->xchan_valid = 0; 4414 4415 in = PerlMem_malloc(VMS_MAXRSS); 4416 if (in == NULL) _ckvmssts_noperl(SS$_INSFMEM); 4417 out = PerlMem_malloc(VMS_MAXRSS); 4418 if (out == NULL) _ckvmssts_noperl(SS$_INSFMEM); 4419 err = PerlMem_malloc(VMS_MAXRSS); 4420 if (err == NULL) _ckvmssts_noperl(SS$_INSFMEM); 4421 4422 in[0] = out[0] = err[0] = '\0'; 4423 4424 if ((p = strchr(mode,'F')) != NULL) { /* F -> use FILE* */ 4425 info->useFILE = 1; 4426 strcpy(p,p+1); 4427 } 4428 if ((p = strchr(mode,'W')) != NULL) { /* W -> wait for completion */ 4429 wait = 1; 4430 strcpy(p,p+1); 4431 } 4432 4433 if (*mode == 'r') { /* piping from subroutine */ 4434 4435 info->out = pipe_infromchild_setup(aTHX_ mbx,out); 4436 if (info->out) { 4437 info->out->pipe_done = &info->out_done; 4438 info->out_done = FALSE; 4439 info->out->info = info; 4440 } 4441 if (!info->useFILE) { 4442 info->fp = PerlIO_open(mbx, mode); 4443 } else { 4444 info->fp = (PerlIO *) freopen(mbx, mode, stdin); 4445 Perl_vmssetuserlnm(aTHX_ "SYS$INPUT",mbx); 4446 } 4447 4448 if (!info->fp && info->out) { 4449 sys$cancel(info->out->chan_out); 4450 4451 while (!info->out_done) { 4452 int done; 4453 _ckvmssts_noperl(sys$setast(0)); 4454 done = info->out_done; 4455 if (!done) _ckvmssts_noperl(sys$clref(pipe_ef)); 4456 _ckvmssts_noperl(sys$setast(1)); 4457 if (!done) _ckvmssts_noperl(sys$waitfr(pipe_ef)); 4458 } 4459 4460 if (info->out->buf) { 4461 n = info->out->bufsize * sizeof(char); 4462 _ckvmssts_noperl(lib$free_vm(&n, &info->out->buf)); 4463 } 4464 n = sizeof(Pipe); 4465 _ckvmssts_noperl(lib$free_vm(&n, &info->out)); 4466 n = sizeof(Info); 4467 _ckvmssts_noperl(lib$free_vm(&n, &info)); 4468 *psts = RMS$_FNF; 4469 return NULL; 4470 } 4471 4472 info->err = pipe_mbxtofd_setup(aTHX_ fileno(stderr), err); 4473 if (info->err) { 4474 info->err->pipe_done = &info->err_done; 4475 info->err_done = FALSE; 4476 info->err->info = info; 4477 } 4478 4479 } else if (*mode == 'w') { /* piping to subroutine */ 4480 4481 info->out = pipe_mbxtofd_setup(aTHX_ fileno(stdout), out); 4482 if (info->out) { 4483 info->out->pipe_done = &info->out_done; 4484 info->out_done = FALSE; 4485 info->out->info = info; 4486 } 4487 4488 info->err = pipe_mbxtofd_setup(aTHX_ fileno(stderr), err); 4489 if (info->err) { 4490 info->err->pipe_done = &info->err_done; 4491 info->err_done = FALSE; 4492 info->err->info = info; 4493 } 4494 4495 info->in = pipe_tochild_setup(aTHX_ in,mbx); 4496 if (!info->useFILE) { 4497 info->fp = PerlIO_open(mbx, mode); 4498 } else { 4499 info->fp = (PerlIO *) freopen(mbx, mode, stdout); 4500 Perl_vmssetuserlnm(aTHX_ "SYS$OUTPUT",mbx); 4501 } 4502 4503 if (info->in) { 4504 info->in->pipe_done = &info->in_done; 4505 info->in_done = FALSE; 4506 info->in->info = info; 4507 } 4508 4509 /* error cleanup */ 4510 if (!info->fp && info->in) { 4511 info->done = TRUE; 4512 _ckvmssts_noperl(sys$qiow(0,info->in->chan_in, IO$_WRITEOF, 0, 4513 0, 0, 0, 0, 0, 0, 0, 0)); 4514 4515 while (!info->in_done) { 4516 int done; 4517 _ckvmssts_noperl(sys$setast(0)); 4518 done = info->in_done; 4519 if (!done) _ckvmssts_noperl(sys$clref(pipe_ef)); 4520 _ckvmssts_noperl(sys$setast(1)); 4521 if (!done) _ckvmssts_noperl(sys$waitfr(pipe_ef)); 4522 } 4523 4524 if (info->in->buf) { 4525 n = info->in->bufsize * sizeof(char); 4526 _ckvmssts_noperl(lib$free_vm(&n, &info->in->buf)); 4527 } 4528 n = sizeof(Pipe); 4529 _ckvmssts_noperl(lib$free_vm(&n, &info->in)); 4530 n = sizeof(Info); 4531 _ckvmssts_noperl(lib$free_vm(&n, &info)); 4532 *psts = RMS$_FNF; 4533 return NULL; 4534 } 4535 4536 4537 } else if (*mode == 'n') { /* separate subprocess, no Perl i/o */ 4538 info->out = pipe_mbxtofd_setup(aTHX_ fileno(stdout), out); 4539 if (info->out) { 4540 info->out->pipe_done = &info->out_done; 4541 info->out_done = FALSE; 4542 info->out->info = info; 4543 } 4544 4545 info->err = pipe_mbxtofd_setup(aTHX_ fileno(stderr), err); 4546 if (info->err) { 4547 info->err->pipe_done = &info->err_done; 4548 info->err_done = FALSE; 4549 info->err->info = info; 4550 } 4551 } 4552 4553 symbol[MAX_DCL_SYMBOL] = '\0'; 4554 4555 strncpy(symbol, in, MAX_DCL_SYMBOL); 4556 d_symbol.dsc$w_length = strlen(symbol); 4557 _ckvmssts_noperl(lib$set_symbol(&d_sym_in, &d_symbol, &table)); 4558 4559 strncpy(symbol, err, MAX_DCL_SYMBOL); 4560 d_symbol.dsc$w_length = strlen(symbol); 4561 _ckvmssts_noperl(lib$set_symbol(&d_sym_err, &d_symbol, &table)); 4562 4563 strncpy(symbol, out, MAX_DCL_SYMBOL); 4564 d_symbol.dsc$w_length = strlen(symbol); 4565 _ckvmssts_noperl(lib$set_symbol(&d_sym_out, &d_symbol, &table)); 4566 4567 /* Done with the names for the pipes */ 4568 PerlMem_free(err); 4569 PerlMem_free(out); 4570 PerlMem_free(in); 4571 4572 p = vmscmd->dsc$a_pointer; 4573 while (*p == ' ' || *p == '\t') p++; /* remove leading whitespace */ 4574 if (*p == '$') p++; /* remove leading $ */ 4575 while (*p == ' ' || *p == '\t') p++; 4576 4577 for (j = 0; j < 4; j++) { 4578 sprintf(cmd_sym_name,"PERL_POPEN_CMD%d",j); 4579 d_sym_cmd.dsc$w_length = strlen(cmd_sym_name); 4580 4581 strncpy(symbol, p, MAX_DCL_SYMBOL); 4582 d_symbol.dsc$w_length = strlen(symbol); 4583 _ckvmssts_noperl(lib$set_symbol(&d_sym_cmd, &d_symbol, &table)); 4584 4585 if (strlen(p) > MAX_DCL_SYMBOL) { 4586 p += MAX_DCL_SYMBOL; 4587 } else { 4588 p += strlen(p); 4589 } 4590 } 4591 _ckvmssts_noperl(sys$setast(0)); 4592 info->next=open_pipes; /* prepend to list */ 4593 open_pipes=info; 4594 _ckvmssts_noperl(sys$setast(1)); 4595 /* Omit arg 2 (input file) so the child will get the parent's SYS$INPUT 4596 * and SYS$COMMAND. vmspipe.com will redefine SYS$INPUT, but we'll still 4597 * have SYS$COMMAND if we need it. 4598 */ 4599 _ckvmssts_noperl(lib$spawn(&vmspipedsc, 0, &nl_desc, &flags, 4600 0, &info->pid, &info->completion, 4601 0, popen_completion_ast,info,0,0,0)); 4602 4603 /* if we were using a tempfile, close it now */ 4604 4605 if (tpipe) fclose(tpipe); 4606 4607 /* once the subprocess is spawned, it has copied the symbols and 4608 we can get rid of ours */ 4609 4610 for (j = 0; j < 4; j++) { 4611 sprintf(cmd_sym_name,"PERL_POPEN_CMD%d",j); 4612 d_sym_cmd.dsc$w_length = strlen(cmd_sym_name); 4613 _ckvmssts_noperl(lib$delete_symbol(&d_sym_cmd, &table)); 4614 } 4615 _ckvmssts_noperl(lib$delete_symbol(&d_sym_in, &table)); 4616 _ckvmssts_noperl(lib$delete_symbol(&d_sym_err, &table)); 4617 _ckvmssts_noperl(lib$delete_symbol(&d_sym_out, &table)); 4618 vms_execfree(vmscmd); 4619 4620 #ifdef PERL_IMPLICIT_CONTEXT 4621 if (aTHX) 4622 #endif 4623 PL_forkprocess = info->pid; 4624 4625 ret_fp = info->fp; 4626 if (wait) { 4627 dSAVEDERRNO; 4628 int done = 0; 4629 while (!done) { 4630 _ckvmssts_noperl(sys$setast(0)); 4631 done = info->done; 4632 if (!done) _ckvmssts_noperl(sys$clref(pipe_ef)); 4633 _ckvmssts_noperl(sys$setast(1)); 4634 if (!done) _ckvmssts_noperl(sys$waitfr(pipe_ef)); 4635 } 4636 *psts = info->completion; 4637 /* Caller thinks it is open and tries to close it. */ 4638 /* This causes some problems, as it changes the error status */ 4639 /* my_pclose(info->fp); */ 4640 4641 /* If we did not have a file pointer open, then we have to */ 4642 /* clean up here or eventually we will run out of something */ 4643 SAVE_ERRNO; 4644 if (info->fp == NULL) { 4645 my_pclose_pinfo(aTHX_ info); 4646 } 4647 RESTORE_ERRNO; 4648 4649 } else { 4650 *psts = info->pid; 4651 } 4652 return ret_fp; 4653 } /* end of safe_popen */ 4654 4655 4656 /*{{{ PerlIO *my_popen(char *cmd, char *mode)*/ 4657 PerlIO * 4658 Perl_my_popen(pTHX_ const char *cmd, const char *mode) 4659 { 4660 int sts; 4661 TAINT_ENV(); 4662 TAINT_PROPER("popen"); 4663 PERL_FLUSHALL_FOR_CHILD; 4664 return safe_popen(aTHX_ cmd,mode,&sts); 4665 } 4666 4667 /*}}}*/ 4668 4669 4670 /* Routine to close and cleanup a pipe info structure */ 4671 4672 static I32 my_pclose_pinfo(pTHX_ pInfo info) { 4673 4674 unsigned long int retsts; 4675 int done, iss, n; 4676 int status; 4677 pInfo next, last; 4678 4679 /* If we were writing to a subprocess, insure that someone reading from 4680 * the mailbox gets an EOF. It looks like a simple fclose() doesn't 4681 * produce an EOF record in the mailbox. 4682 * 4683 * well, at least sometimes it *does*, so we have to watch out for 4684 * the first EOF closing the pipe (and DASSGN'ing the channel)... 4685 */ 4686 if (info->fp) { 4687 if (!info->useFILE 4688 #if defined(USE_ITHREADS) 4689 && my_perl 4690 #endif 4691 #ifdef USE_PERLIO 4692 && PL_perlio_fd_refcnt 4693 #endif 4694 ) 4695 PerlIO_flush(info->fp); 4696 else 4697 fflush((FILE *)info->fp); 4698 } 4699 4700 _ckvmssts(sys$setast(0)); 4701 info->closing = TRUE; 4702 done = info->done && info->in_done && info->out_done && info->err_done; 4703 /* hanging on write to Perl's input? cancel it */ 4704 if (info->mode == 'r' && info->out && !info->out_done) { 4705 if (info->out->chan_out) { 4706 _ckvmssts(sys$cancel(info->out->chan_out)); 4707 if (!info->out->chan_in) { /* EOF generation, need AST */ 4708 _ckvmssts(sys$dclast(pipe_infromchild_ast,info->out,0)); 4709 } 4710 } 4711 } 4712 if (info->in && !info->in_done && !info->in->shut_on_empty) /* EOF if hasn't had one yet */ 4713 _ckvmssts(sys$qio(0,info->in->chan_in,IO$_WRITEOF,0,0,0, 4714 0, 0, 0, 0, 0, 0)); 4715 _ckvmssts(sys$setast(1)); 4716 if (info->fp) { 4717 if (!info->useFILE 4718 #if defined(USE_ITHREADS) 4719 && my_perl 4720 #endif 4721 #ifdef USE_PERLIO 4722 && PL_perlio_fd_refcnt 4723 #endif 4724 ) 4725 PerlIO_close(info->fp); 4726 else 4727 fclose((FILE *)info->fp); 4728 } 4729 /* 4730 we have to wait until subprocess completes, but ALSO wait until all 4731 the i/o completes...otherwise we'll be freeing the "info" structure 4732 that the i/o ASTs could still be using... 4733 */ 4734 4735 while (!done) { 4736 _ckvmssts(sys$setast(0)); 4737 done = info->done && info->in_done && info->out_done && info->err_done; 4738 if (!done) _ckvmssts(sys$clref(pipe_ef)); 4739 _ckvmssts(sys$setast(1)); 4740 if (!done) _ckvmssts(sys$waitfr(pipe_ef)); 4741 } 4742 retsts = info->completion; 4743 4744 /* remove from list of open pipes */ 4745 _ckvmssts(sys$setast(0)); 4746 last = NULL; 4747 for (next = open_pipes; next != NULL; last = next, next = next->next) { 4748 if (next == info) 4749 break; 4750 } 4751 4752 if (last) 4753 last->next = info->next; 4754 else 4755 open_pipes = info->next; 4756 _ckvmssts(sys$setast(1)); 4757 4758 /* free buffers and structures */ 4759 4760 if (info->in) { 4761 if (info->in->buf) { 4762 n = info->in->bufsize * sizeof(char); 4763 _ckvmssts(lib$free_vm(&n, &info->in->buf)); 4764 } 4765 n = sizeof(Pipe); 4766 _ckvmssts(lib$free_vm(&n, &info->in)); 4767 } 4768 if (info->out) { 4769 if (info->out->buf) { 4770 n = info->out->bufsize * sizeof(char); 4771 _ckvmssts(lib$free_vm(&n, &info->out->buf)); 4772 } 4773 n = sizeof(Pipe); 4774 _ckvmssts(lib$free_vm(&n, &info->out)); 4775 } 4776 if (info->err) { 4777 if (info->err->buf) { 4778 n = info->err->bufsize * sizeof(char); 4779 _ckvmssts(lib$free_vm(&n, &info->err->buf)); 4780 } 4781 n = sizeof(Pipe); 4782 _ckvmssts(lib$free_vm(&n, &info->err)); 4783 } 4784 n = sizeof(Info); 4785 _ckvmssts(lib$free_vm(&n, &info)); 4786 4787 return retsts; 4788 } 4789 4790 4791 /*{{{ I32 my_pclose(PerlIO *fp)*/ 4792 I32 Perl_my_pclose(pTHX_ PerlIO *fp) 4793 { 4794 pInfo info, last = NULL; 4795 I32 ret_status; 4796 4797 /* Fixme - need ast and mutex protection here */ 4798 for (info = open_pipes; info != NULL; last = info, info = info->next) 4799 if (info->fp == fp) break; 4800 4801 if (info == NULL) { /* no such pipe open */ 4802 set_errno(ECHILD); /* quoth POSIX */ 4803 set_vaxc_errno(SS$_NONEXPR); 4804 return -1; 4805 } 4806 4807 ret_status = my_pclose_pinfo(aTHX_ info); 4808 4809 return ret_status; 4810 4811 } /* end of my_pclose() */ 4812 4813 #if defined(__CRTL_VER) && __CRTL_VER >= 70200000 4814 /* Roll our own prototype because we want this regardless of whether 4815 * _VMS_WAIT is defined. 4816 */ 4817 __pid_t __vms_waitpid( __pid_t __pid, int *__stat_loc, int __options ); 4818 #endif 4819 /* sort-of waitpid; special handling of pipe clean-up for subprocesses 4820 created with popen(); otherwise partially emulate waitpid() unless 4821 we have a suitable one from the CRTL that came with VMS 7.2 and later. 4822 Also check processes not considered by the CRTL waitpid(). 4823 */ 4824 /*{{{Pid_t my_waitpid(Pid_t pid, int *statusp, int flags)*/ 4825 Pid_t 4826 Perl_my_waitpid(pTHX_ Pid_t pid, int *statusp, int flags) 4827 { 4828 pInfo info; 4829 int done; 4830 int sts; 4831 int j; 4832 4833 if (statusp) *statusp = 0; 4834 4835 for (info = open_pipes; info != NULL; info = info->next) 4836 if (info->pid == pid) break; 4837 4838 if (info != NULL) { /* we know about this child */ 4839 while (!info->done) { 4840 _ckvmssts(sys$setast(0)); 4841 done = info->done; 4842 if (!done) _ckvmssts(sys$clref(pipe_ef)); 4843 _ckvmssts(sys$setast(1)); 4844 if (!done) _ckvmssts(sys$waitfr(pipe_ef)); 4845 } 4846 4847 if (statusp) *statusp = info->completion; 4848 return pid; 4849 } 4850 4851 /* child that already terminated? */ 4852 4853 for (j = 0; j < NKEEPCLOSED && j < closed_num; j++) { 4854 if (closed_list[j].pid == pid) { 4855 if (statusp) *statusp = closed_list[j].completion; 4856 return pid; 4857 } 4858 } 4859 4860 /* fall through if this child is not one of our own pipe children */ 4861 4862 #if defined(__CRTL_VER) && __CRTL_VER >= 70200000 4863 4864 /* waitpid() became available in the CRTL as of VMS 7.0, but only 4865 * in 7.2 did we get a version that fills in the VMS completion 4866 * status as Perl has always tried to do. 4867 */ 4868 4869 sts = __vms_waitpid( pid, statusp, flags ); 4870 4871 if ( sts == 0 || !(sts == -1 && errno == ECHILD) ) 4872 return sts; 4873 4874 /* If the real waitpid tells us the child does not exist, we 4875 * fall through here to implement waiting for a child that 4876 * was created by some means other than exec() (say, spawned 4877 * from DCL) or to wait for a process that is not a subprocess 4878 * of the current process. 4879 */ 4880 4881 #endif /* defined(__CRTL_VER) && __CRTL_VER >= 70200000 */ 4882 4883 { 4884 $DESCRIPTOR(intdsc,"0 00:00:01"); 4885 unsigned long int ownercode = JPI$_OWNER, ownerpid; 4886 unsigned long int pidcode = JPI$_PID, mypid; 4887 unsigned long int interval[2]; 4888 unsigned int jpi_iosb[2]; 4889 struct itmlst_3 jpilist[2] = { 4890 {sizeof(ownerpid), JPI$_OWNER, &ownerpid, 0}, 4891 { 0, 0, 0, 0} 4892 }; 4893 4894 if (pid <= 0) { 4895 /* Sorry folks, we don't presently implement rooting around for 4896 the first child we can find, and we definitely don't want to 4897 pass a pid of -1 to $getjpi, where it is a wildcard operation. 4898 */ 4899 set_errno(ENOTSUP); 4900 return -1; 4901 } 4902 4903 /* Get the owner of the child so I can warn if it's not mine. If the 4904 * process doesn't exist or I don't have the privs to look at it, 4905 * I can go home early. 4906 */ 4907 sts = sys$getjpiw(0,&pid,NULL,&jpilist,&jpi_iosb,NULL,NULL); 4908 if (sts & 1) sts = jpi_iosb[0]; 4909 if (!(sts & 1)) { 4910 switch (sts) { 4911 case SS$_NONEXPR: 4912 set_errno(ECHILD); 4913 break; 4914 case SS$_NOPRIV: 4915 set_errno(EACCES); 4916 break; 4917 default: 4918 _ckvmssts(sts); 4919 } 4920 set_vaxc_errno(sts); 4921 return -1; 4922 } 4923 4924 if (ckWARN(WARN_EXEC)) { 4925 /* remind folks they are asking for non-standard waitpid behavior */ 4926 _ckvmssts(lib$getjpi(&pidcode,0,0,&mypid,0,0)); 4927 if (ownerpid != mypid) 4928 Perl_warner(aTHX_ packWARN(WARN_EXEC), 4929 "waitpid: process %x is not a child of process %x", 4930 pid,mypid); 4931 } 4932 4933 /* simply check on it once a second until it's not there anymore. */ 4934 4935 _ckvmssts(sys$bintim(&intdsc,interval)); 4936 while ((sts=lib$getjpi(&ownercode,&pid,0,&ownerpid,0,0)) & 1) { 4937 _ckvmssts(sys$schdwk(0,0,interval,0)); 4938 _ckvmssts(sys$hiber()); 4939 } 4940 if (sts == SS$_NONEXPR) sts = SS$_NORMAL; 4941 4942 _ckvmssts(sts); 4943 return pid; 4944 } 4945 } /* end of waitpid() */ 4946 /*}}}*/ 4947 /*}}}*/ 4948 /*}}}*/ 4949 4950 /*{{{ char *my_gconvert(double val, int ndig, int trail, char *buf) */ 4951 char * 4952 my_gconvert(double val, int ndig, int trail, char *buf) 4953 { 4954 static char __gcvtbuf[DBL_DIG+1]; 4955 char *loc; 4956 4957 loc = buf ? buf : __gcvtbuf; 4958 4959 #ifndef __DECC /* VAXCRTL gcvt uses E format for numbers < 1 */ 4960 if (val < 1) { 4961 sprintf(loc,"%.*g",ndig,val); 4962 return loc; 4963 } 4964 #endif 4965 4966 if (val) { 4967 if (!buf && ndig > DBL_DIG) ndig = DBL_DIG; 4968 return gcvt(val,ndig,loc); 4969 } 4970 else { 4971 loc[0] = '0'; loc[1] = '\0'; 4972 return loc; 4973 } 4974 4975 } 4976 /*}}}*/ 4977 4978 #if defined(__VAX) || !defined(NAML$C_MAXRSS) 4979 static int rms_free_search_context(struct FAB * fab) 4980 { 4981 struct NAM * nam; 4982 4983 nam = fab->fab$l_nam; 4984 nam->nam$b_nop |= NAM$M_SYNCHK; 4985 nam->nam$l_rlf = NULL; 4986 fab->fab$b_dns = 0; 4987 return sys$parse(fab, NULL, NULL); 4988 } 4989 4990 #define rms_setup_nam(nam) struct NAM nam = cc$rms_nam 4991 #define rms_clear_nam_nop(nam) nam.nam$b_nop = 0; 4992 #define rms_set_nam_nop(nam, opt) nam.nam$b_nop |= (opt) 4993 #define rms_set_nam_fnb(nam, opt) nam.nam$l_fnb |= (opt) 4994 #define rms_is_nam_fnb(nam, opt) (nam.nam$l_fnb & (opt)) 4995 #define rms_nam_esll(nam) nam.nam$b_esl 4996 #define rms_nam_esl(nam) nam.nam$b_esl 4997 #define rms_nam_name(nam) nam.nam$l_name 4998 #define rms_nam_namel(nam) nam.nam$l_name 4999 #define rms_nam_type(nam) nam.nam$l_type 5000 #define rms_nam_typel(nam) nam.nam$l_type 5001 #define rms_nam_ver(nam) nam.nam$l_ver 5002 #define rms_nam_verl(nam) nam.nam$l_ver 5003 #define rms_nam_rsll(nam) nam.nam$b_rsl 5004 #define rms_nam_rsl(nam) nam.nam$b_rsl 5005 #define rms_bind_fab_nam(fab, nam) fab.fab$l_nam = &nam 5006 #define rms_set_fna(fab, nam, name, size) \ 5007 { fab.fab$b_fns = size; fab.fab$l_fna = name; } 5008 #define rms_get_fna(fab, nam) fab.fab$l_fna 5009 #define rms_set_dna(fab, nam, name, size) \ 5010 { fab.fab$b_dns = size; fab.fab$l_dna = name; } 5011 #define rms_nam_dns(fab, nam) fab.fab$b_dns 5012 #define rms_set_esa(nam, name, size) \ 5013 { nam.nam$b_ess = size; nam.nam$l_esa = name; } 5014 #define rms_set_esal(nam, s_name, s_size, l_name, l_size) \ 5015 { nam.nam$l_esa = s_name; nam.nam$b_ess = s_size;} 5016 #define rms_set_rsa(nam, name, size) \ 5017 { nam.nam$l_rsa = name; nam.nam$b_rss = size; } 5018 #define rms_set_rsal(nam, s_name, s_size, l_name, l_size) \ 5019 { nam.nam$l_rsa = s_name; nam.nam$b_rss = s_size; } 5020 #define rms_nam_name_type_l_size(nam) \ 5021 (nam.nam$b_name + nam.nam$b_type) 5022 #else 5023 static int rms_free_search_context(struct FAB * fab) 5024 { 5025 struct NAML * nam; 5026 5027 nam = fab->fab$l_naml; 5028 nam->naml$b_nop |= NAM$M_SYNCHK; 5029 nam->naml$l_rlf = NULL; 5030 nam->naml$l_long_defname_size = 0; 5031 5032 fab->fab$b_dns = 0; 5033 return sys$parse(fab, NULL, NULL); 5034 } 5035 5036 #define rms_setup_nam(nam) struct NAML nam = cc$rms_naml 5037 #define rms_clear_nam_nop(nam) nam.naml$b_nop = 0; 5038 #define rms_set_nam_nop(nam, opt) nam.naml$b_nop |= (opt) 5039 #define rms_set_nam_fnb(nam, opt) nam.naml$l_fnb |= (opt) 5040 #define rms_is_nam_fnb(nam, opt) (nam.naml$l_fnb & (opt)) 5041 #define rms_nam_esll(nam) nam.naml$l_long_expand_size 5042 #define rms_nam_esl(nam) nam.naml$b_esl 5043 #define rms_nam_name(nam) nam.naml$l_name 5044 #define rms_nam_namel(nam) nam.naml$l_long_name 5045 #define rms_nam_type(nam) nam.naml$l_type 5046 #define rms_nam_typel(nam) nam.naml$l_long_type 5047 #define rms_nam_ver(nam) nam.naml$l_ver 5048 #define rms_nam_verl(nam) nam.naml$l_long_ver 5049 #define rms_nam_rsll(nam) nam.naml$l_long_result_size 5050 #define rms_nam_rsl(nam) nam.naml$b_rsl 5051 #define rms_bind_fab_nam(fab, nam) fab.fab$l_naml = &nam 5052 #define rms_set_fna(fab, nam, name, size) \ 5053 { fab.fab$b_fns = 0; fab.fab$l_fna = (char *) -1; \ 5054 nam.naml$l_long_filename_size = size; \ 5055 nam.naml$l_long_filename = name;} 5056 #define rms_get_fna(fab, nam) nam.naml$l_long_filename 5057 #define rms_set_dna(fab, nam, name, size) \ 5058 { fab.fab$b_dns = 0; fab.fab$l_dna = (char *) -1; \ 5059 nam.naml$l_long_defname_size = size; \ 5060 nam.naml$l_long_defname = name; } 5061 #define rms_nam_dns(fab, nam) nam.naml$l_long_defname_size 5062 #define rms_set_esa(nam, name, size) \ 5063 { nam.naml$b_ess = 0; nam.naml$l_esa = (char *) -1; \ 5064 nam.naml$l_long_expand_alloc = size; \ 5065 nam.naml$l_long_expand = name; } 5066 #define rms_set_esal(nam, s_name, s_size, l_name, l_size) \ 5067 { nam.naml$l_esa = s_name; nam.naml$b_ess = s_size; \ 5068 nam.naml$l_long_expand = l_name; \ 5069 nam.naml$l_long_expand_alloc = l_size; } 5070 #define rms_set_rsa(nam, name, size) \ 5071 { nam.naml$l_rsa = NULL; nam.naml$b_rss = 0; \ 5072 nam.naml$l_long_result = name; \ 5073 nam.naml$l_long_result_alloc = size; } 5074 #define rms_set_rsal(nam, s_name, s_size, l_name, l_size) \ 5075 { nam.naml$l_rsa = s_name; nam.naml$b_rss = s_size; \ 5076 nam.naml$l_long_result = l_name; \ 5077 nam.naml$l_long_result_alloc = l_size; } 5078 #define rms_nam_name_type_l_size(nam) \ 5079 (nam.naml$l_long_name_size + nam.naml$l_long_type_size) 5080 #endif 5081 5082 5083 /* rms_erase 5084 * The CRTL for 8.3 and later can create symbolic links in any mode, 5085 * however in 8.3 the unlink/remove/delete routines will only properly handle 5086 * them if one of the PCP modes is active. 5087 */ 5088 static int rms_erase(const char * vmsname) 5089 { 5090 int status; 5091 struct FAB myfab = cc$rms_fab; 5092 rms_setup_nam(mynam); 5093 5094 rms_set_fna(myfab, mynam, (char *)vmsname, strlen(vmsname)); /* cast ok */ 5095 rms_bind_fab_nam(myfab, mynam); 5096 5097 #ifdef NAML$M_OPEN_SPECIAL 5098 rms_set_nam_nop(mynam, NAML$M_OPEN_SPECIAL); 5099 #endif 5100 5101 status = sys$erase(&myfab, 0, 0); 5102 5103 return status; 5104 } 5105 5106 5107 static int 5108 vms_rename_with_acl(pTHX_ const struct dsc$descriptor_s * vms_src_dsc, 5109 const struct dsc$descriptor_s * vms_dst_dsc, 5110 unsigned long flags) 5111 { 5112 /* VMS and UNIX handle file permissions differently and the 5113 * the same ACL trick may be needed for renaming files, 5114 * especially if they are directories. 5115 */ 5116 5117 /* todo: get kill_file and rename to share common code */ 5118 /* I can not find online documentation for $change_acl 5119 * it appears to be replaced by $set_security some time ago */ 5120 5121 const unsigned int access_mode = 0; 5122 $DESCRIPTOR(obj_file_dsc,"FILE"); 5123 char *vmsname; 5124 char *rslt; 5125 unsigned long int jpicode = JPI$_UIC, type = ACL$C_FILE; 5126 int aclsts, fndsts, rnsts = -1; 5127 unsigned int ctx = 0; 5128 struct dsc$descriptor_s fildsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0}; 5129 struct dsc$descriptor_s * clean_dsc; 5130 5131 struct myacedef { 5132 unsigned char myace$b_length; 5133 unsigned char myace$b_type; 5134 unsigned short int myace$w_flags; 5135 unsigned long int myace$l_access; 5136 unsigned long int myace$l_ident; 5137 } newace = { sizeof(struct myacedef), ACE$C_KEYID, 0, 5138 ACE$M_READ | ACE$M_WRITE | ACE$M_DELETE | ACE$M_CONTROL, 5139 0}, 5140 oldace = { sizeof(struct myacedef), ACE$C_KEYID, 0, 0, 0}; 5141 5142 struct item_list_3 5143 findlst[3] = {{sizeof oldace, OSS$_ACL_FIND_ENTRY, &oldace, 0}, 5144 {sizeof oldace, OSS$_ACL_READ_ENTRY, &oldace, 0}, 5145 {0,0,0,0}}, 5146 addlst[2] = {{sizeof newace, OSS$_ACL_ADD_ENTRY, &newace, 0},{0,0,0,0}}, 5147 dellst[2] = {{sizeof newace, OSS$_ACL_DELETE_ENTRY, &newace, 0}, 5148 {0,0,0,0}}; 5149 5150 5151 /* Expand the input spec using RMS, since we do not want to put 5152 * ACLs on the target of a symbolic link */ 5153 vmsname = PerlMem_malloc(NAM$C_MAXRSS+1); 5154 if (vmsname == NULL) 5155 return SS$_INSFMEM; 5156 5157 rslt = int_rmsexpand_tovms(vms_src_dsc->dsc$a_pointer, 5158 vmsname, 5159 PERL_RMSEXPAND_M_SYMLINK); 5160 if (rslt == NULL) { 5161 PerlMem_free(vmsname); 5162 return SS$_INSFMEM; 5163 } 5164 5165 /* So we get our own UIC to use as a rights identifier, 5166 * and the insert an ACE at the head of the ACL which allows us 5167 * to delete the file. 5168 */ 5169 _ckvmssts_noperl(lib$getjpi(&jpicode,0,0,&(oldace.myace$l_ident),0,0)); 5170 5171 fildsc.dsc$w_length = strlen(vmsname); 5172 fildsc.dsc$a_pointer = vmsname; 5173 ctx = 0; 5174 newace.myace$l_ident = oldace.myace$l_ident; 5175 rnsts = SS$_ABORT; 5176 5177 /* Grab any existing ACEs with this identifier in case we fail */ 5178 clean_dsc = &fildsc; 5179 aclsts = fndsts = sys$get_security(&obj_file_dsc, 5180 &fildsc, 5181 NULL, 5182 OSS$M_WLOCK, 5183 findlst, 5184 &ctx, 5185 &access_mode); 5186 5187 if ($VMS_STATUS_SUCCESS(fndsts) || (fndsts == SS$_ACLEMPTY)) { 5188 /* Add the new ACE . . . */ 5189 5190 /* if the sys$get_security succeeded, then ctx is valid, and the 5191 * object/file descriptors will be ignored. But otherwise they 5192 * are needed 5193 */ 5194 aclsts = sys$set_security(&obj_file_dsc, &fildsc, NULL, 5195 OSS$M_RELCTX, addlst, &ctx, &access_mode); 5196 if (!$VMS_STATUS_SUCCESS(aclsts) && (aclsts != SS$_NOCLASS)) { 5197 set_errno(EVMSERR); 5198 set_vaxc_errno(aclsts); 5199 PerlMem_free(vmsname); 5200 return aclsts; 5201 } 5202 5203 rnsts = lib$rename_file(vms_src_dsc, vms_dst_dsc, 5204 NULL, NULL, 5205 &flags, 5206 NULL, NULL, NULL, NULL, NULL, NULL, NULL); 5207 5208 if ($VMS_STATUS_SUCCESS(rnsts)) { 5209 clean_dsc = (struct dsc$descriptor_s *)vms_dst_dsc; 5210 } 5211 5212 /* Put things back the way they were. */ 5213 ctx = 0; 5214 aclsts = sys$get_security(&obj_file_dsc, 5215 clean_dsc, 5216 NULL, 5217 OSS$M_WLOCK, 5218 findlst, 5219 &ctx, 5220 &access_mode); 5221 5222 if ($VMS_STATUS_SUCCESS(aclsts)) { 5223 int sec_flags; 5224 5225 sec_flags = 0; 5226 if (!$VMS_STATUS_SUCCESS(fndsts)) 5227 sec_flags = OSS$M_RELCTX; 5228 5229 /* Get rid of the new ACE */ 5230 aclsts = sys$set_security(NULL, NULL, NULL, 5231 sec_flags, dellst, &ctx, &access_mode); 5232 5233 /* If there was an old ACE, put it back */ 5234 if ($VMS_STATUS_SUCCESS(aclsts) && $VMS_STATUS_SUCCESS(fndsts)) { 5235 addlst[0].bufadr = &oldace; 5236 aclsts = sys$set_security(NULL, NULL, NULL, 5237 OSS$M_RELCTX, addlst, &ctx, &access_mode); 5238 if (!$VMS_STATUS_SUCCESS(aclsts) && (aclsts != SS$_NOCLASS)) { 5239 set_errno(EVMSERR); 5240 set_vaxc_errno(aclsts); 5241 rnsts = aclsts; 5242 } 5243 } else { 5244 int aclsts2; 5245 5246 /* Try to clear the lock on the ACL list */ 5247 aclsts2 = sys$set_security(NULL, NULL, NULL, 5248 OSS$M_RELCTX, NULL, &ctx, &access_mode); 5249 5250 /* Rename errors are most important */ 5251 if (!$VMS_STATUS_SUCCESS(rnsts)) 5252 aclsts = rnsts; 5253 set_errno(EVMSERR); 5254 set_vaxc_errno(aclsts); 5255 rnsts = aclsts; 5256 } 5257 } 5258 else { 5259 if (aclsts != SS$_ACLEMPTY) 5260 rnsts = aclsts; 5261 } 5262 } 5263 else 5264 rnsts = fndsts; 5265 5266 PerlMem_free(vmsname); 5267 return rnsts; 5268 } 5269 5270 5271 /*{{{int rename(const char *, const char * */ 5272 /* Not exactly what X/Open says to do, but doing it absolutely right 5273 * and efficiently would require a lot more work. This should be close 5274 * enough to pass all but the most strict X/Open compliance test. 5275 */ 5276 int 5277 Perl_rename(pTHX_ const char *src, const char * dst) 5278 { 5279 int retval; 5280 int pre_delete = 0; 5281 int src_sts; 5282 int dst_sts; 5283 Stat_t src_st; 5284 Stat_t dst_st; 5285 5286 /* Validate the source file */ 5287 src_sts = flex_lstat(src, &src_st); 5288 if (src_sts != 0) { 5289 5290 /* No source file or other problem */ 5291 return src_sts; 5292 } 5293 if (src_st.st_devnam[0] == 0) { 5294 /* This may be possible so fail if it is seen. */ 5295 errno = EIO; 5296 return -1; 5297 } 5298 5299 dst_sts = flex_lstat(dst, &dst_st); 5300 if (dst_sts == 0) { 5301 5302 if (dst_st.st_dev != src_st.st_dev) { 5303 /* Must be on the same device */ 5304 errno = EXDEV; 5305 return -1; 5306 } 5307 5308 /* VMS_INO_T_COMPARE is true if the inodes are different 5309 * to match the output of memcmp 5310 */ 5311 5312 if (!VMS_INO_T_COMPARE(src_st.st_ino, dst_st.st_ino)) { 5313 /* That was easy, the files are the same! */ 5314 return 0; 5315 } 5316 5317 if (S_ISDIR(src_st.st_mode) && !S_ISDIR(dst_st.st_mode)) { 5318 /* If source is a directory, so must be dest */ 5319 errno = EISDIR; 5320 return -1; 5321 } 5322 5323 } 5324 5325 5326 if ((dst_sts == 0) && 5327 (vms_unlink_all_versions || S_ISDIR(dst_st.st_mode))) { 5328 5329 /* We have issues here if vms_unlink_all_versions is set 5330 * If the destination exists, and is not a directory, then 5331 * we must delete in advance. 5332 * 5333 * If the src is a directory, then we must always pre-delete 5334 * the destination. 5335 * 5336 * If we successfully delete the dst in advance, and the rename fails 5337 * X/Open requires that errno be EIO. 5338 * 5339 */ 5340 5341 if (!S_ISDIR(dst_st.st_mode) || S_ISDIR(src_st.st_mode)) { 5342 int d_sts; 5343 d_sts = mp_do_kill_file(aTHX_ dst_st.st_devnam, 5344 S_ISDIR(dst_st.st_mode)); 5345 5346 /* Need to delete all versions ? */ 5347 if ((d_sts == 0) && (vms_unlink_all_versions == 1)) { 5348 int i = 0; 5349 5350 while (lstat(dst_st.st_devnam, &dst_st.crtl_stat) == 0) { 5351 d_sts = mp_do_kill_file(aTHX_ dst_st.st_devnam, 0); 5352 if (d_sts != 0) 5353 break; 5354 i++; 5355 5356 /* Make sure that we do not loop forever */ 5357 if (i > 32767) { 5358 errno = EIO; 5359 d_sts = -1; 5360 break; 5361 } 5362 } 5363 } 5364 5365 if (d_sts != 0) 5366 return d_sts; 5367 5368 /* We killed the destination, so only errno now is EIO */ 5369 pre_delete = 1; 5370 } 5371 } 5372 5373 /* Originally the idea was to call the CRTL rename() and only 5374 * try the lib$rename_file if it failed. 5375 * It turns out that there are too many variants in what the 5376 * the CRTL rename might do, so only use lib$rename_file 5377 */ 5378 retval = -1; 5379 5380 { 5381 /* Is the source and dest both in VMS format */ 5382 /* if the source is a directory, then need to fileify */ 5383 /* and dest must be a directory or non-existant. */ 5384 5385 char * vms_dst; 5386 int sts; 5387 char * ret_str; 5388 unsigned long flags; 5389 struct dsc$descriptor_s old_file_dsc; 5390 struct dsc$descriptor_s new_file_dsc; 5391 5392 /* We need to modify the src and dst depending 5393 * on if one or more of them are directories. 5394 */ 5395 5396 vms_dst = PerlMem_malloc(VMS_MAXRSS); 5397 if (vms_dst == NULL) 5398 _ckvmssts_noperl(SS$_INSFMEM); 5399 5400 if (S_ISDIR(src_st.st_mode)) { 5401 char * ret_str; 5402 char * vms_dir_file; 5403 5404 vms_dir_file = PerlMem_malloc(VMS_MAXRSS); 5405 if (vms_dir_file == NULL) 5406 _ckvmssts_noperl(SS$_INSFMEM); 5407 5408 /* If the dest is a directory, we must remove it 5409 if (dst_sts == 0) { 5410 int d_sts; 5411 d_sts = mp_do_kill_file(aTHX_ dst_st.st_devnam, 1); 5412 if (d_sts != 0) { 5413 PerlMem_free(vms_dst); 5414 errno = EIO; 5415 return sts; 5416 } 5417 5418 pre_delete = 1; 5419 } 5420 5421 /* The dest must be a VMS file specification */ 5422 ret_str = int_tovmsspec(dst, vms_dst, 0, NULL); 5423 if (ret_str == NULL) { 5424 PerlMem_free(vms_dst); 5425 errno = EIO; 5426 return -1; 5427 } 5428 5429 /* The source must be a file specification */ 5430 ret_str = do_fileify_dirspec(vms_dst, vms_dir_file, 0, NULL); 5431 if (ret_str == NULL) { 5432 PerlMem_free(vms_dst); 5433 PerlMem_free(vms_dir_file); 5434 errno = EIO; 5435 return -1; 5436 } 5437 PerlMem_free(vms_dst); 5438 vms_dst = vms_dir_file; 5439 5440 } else { 5441 /* File to file or file to new dir */ 5442 5443 if ((dst_sts == 0) && S_ISDIR(dst_st.st_mode)) { 5444 /* VMS pathify a dir target */ 5445 ret_str = int_tovmspath(dst, vms_dst, NULL); 5446 if (ret_str == NULL) { 5447 PerlMem_free(vms_dst); 5448 errno = EIO; 5449 return -1; 5450 } 5451 } else { 5452 char * v_spec, * r_spec, * d_spec, * n_spec; 5453 char * e_spec, * vs_spec; 5454 int sts, v_len, r_len, d_len, n_len, e_len, vs_len; 5455 5456 /* fileify a target VMS file specification */ 5457 ret_str = int_tovmsspec(dst, vms_dst, 0, NULL); 5458 if (ret_str == NULL) { 5459 PerlMem_free(vms_dst); 5460 errno = EIO; 5461 return -1; 5462 } 5463 5464 sts = vms_split_path(vms_dst, &v_spec, &v_len, &r_spec, &r_len, 5465 &d_spec, &d_len, &n_spec, &n_len, &e_spec, 5466 &e_len, &vs_spec, &vs_len); 5467 if (sts == 0) { 5468 if (e_len == 0) { 5469 /* Get rid of the version */ 5470 if (vs_len != 0) { 5471 *vs_spec = '\0'; 5472 } 5473 /* Need to specify a '.' so that the extension */ 5474 /* is not inherited */ 5475 strcat(vms_dst,"."); 5476 } 5477 } 5478 } 5479 } 5480 5481 old_file_dsc.dsc$a_pointer = src_st.st_devnam; 5482 old_file_dsc.dsc$w_length = strlen(src_st.st_devnam); 5483 old_file_dsc.dsc$b_dtype = DSC$K_DTYPE_T; 5484 old_file_dsc.dsc$b_class = DSC$K_CLASS_S; 5485 5486 new_file_dsc.dsc$a_pointer = vms_dst; 5487 new_file_dsc.dsc$w_length = strlen(vms_dst); 5488 new_file_dsc.dsc$b_dtype = DSC$K_DTYPE_T; 5489 new_file_dsc.dsc$b_class = DSC$K_CLASS_S; 5490 5491 flags = 0; 5492 #if !defined(__VAX) && defined(NAML$C_MAXRSS) 5493 flags |= 4; /* LIB$M_FIL_LONG_NAMES (bit 2) */ 5494 #endif 5495 5496 sts = lib$rename_file(&old_file_dsc, 5497 &new_file_dsc, 5498 NULL, NULL, 5499 &flags, 5500 NULL, NULL, NULL, NULL, NULL, NULL, NULL); 5501 if (!$VMS_STATUS_SUCCESS(sts)) { 5502 5503 /* We could have failed because VMS style permissions do not 5504 * permit renames that UNIX will allow. Just like the hack 5505 * in for kill_file. 5506 */ 5507 sts = vms_rename_with_acl(aTHX_ &old_file_dsc, &new_file_dsc, flags); 5508 } 5509 5510 PerlMem_free(vms_dst); 5511 if (!$VMS_STATUS_SUCCESS(sts)) { 5512 errno = EIO; 5513 return -1; 5514 } 5515 retval = 0; 5516 } 5517 5518 if (vms_unlink_all_versions) { 5519 /* Now get rid of any previous versions of the source file that 5520 * might still exist 5521 */ 5522 int i = 0; 5523 dSAVEDERRNO; 5524 SAVE_ERRNO; 5525 src_sts = mp_do_kill_file(aTHX_ src_st.st_devnam, 5526 S_ISDIR(src_st.st_mode)); 5527 while (lstat(src_st.st_devnam, &src_st.crtl_stat) == 0) { 5528 src_sts = mp_do_kill_file(aTHX_ src_st.st_devnam, 5529 S_ISDIR(src_st.st_mode)); 5530 if (src_sts != 0) 5531 break; 5532 i++; 5533 5534 /* Make sure that we do not loop forever */ 5535 if (i > 32767) { 5536 src_sts = -1; 5537 break; 5538 } 5539 } 5540 RESTORE_ERRNO; 5541 } 5542 5543 /* We deleted the destination, so must force the error to be EIO */ 5544 if ((retval != 0) && (pre_delete != 0)) 5545 errno = EIO; 5546 5547 return retval; 5548 } 5549 /*}}}*/ 5550 5551 5552 /*{{{char *do_rmsexpand(char *fspec, char *out, int ts, char *def, unsigned opts)*/ 5553 /* Shortcut for common case of simple calls to $PARSE and $SEARCH 5554 * to expand file specification. Allows for a single default file 5555 * specification and a simple mask of options. If outbuf is non-NULL, 5556 * it must point to a buffer at least NAM$C_MAXRSS bytes long, into which 5557 * the resultant file specification is placed. If outbuf is NULL, the 5558 * resultant file specification is placed into a static buffer. 5559 * The third argument, if non-NULL, is taken to be a default file 5560 * specification string. The fourth argument is unused at present. 5561 * rmesexpand() returns the address of the resultant string if 5562 * successful, and NULL on error. 5563 * 5564 * New functionality for previously unused opts value: 5565 * PERL_RMSEXPAND_M_VMS - Force output file specification to VMS format. 5566 * PERL_RMSEXPAND_M_LONG - Want output in long formst 5567 * PERL_RMSEXPAND_M_VMS_IN - Input is already in VMS, so do not vmsify 5568 * PERL_RMSEXPAND_M_SYMLINK - Use symbolic link, not target 5569 */ 5570 static char *mp_do_tounixspec(pTHX_ const char *, char *, int, int *); 5571 5572 static char * 5573 int_rmsexpand 5574 (const char *filespec, 5575 char *outbuf, 5576 const char *defspec, 5577 unsigned opts, 5578 int * fs_utf8, 5579 int * dfs_utf8) 5580 { 5581 char * ret_spec; 5582 const char * in_spec; 5583 char * spec_buf; 5584 const char * def_spec; 5585 char * vmsfspec, *vmsdefspec; 5586 char * esa; 5587 char * esal = NULL; 5588 char * outbufl; 5589 struct FAB myfab = cc$rms_fab; 5590 rms_setup_nam(mynam); 5591 STRLEN speclen; 5592 unsigned long int retsts, trimver, trimtype, haslower = 0, isunix = 0; 5593 int sts; 5594 5595 /* temp hack until UTF8 is actually implemented */ 5596 if (fs_utf8 != NULL) 5597 *fs_utf8 = 0; 5598 5599 if (!filespec || !*filespec) { 5600 set_vaxc_errno(LIB$_INVARG); set_errno(EINVAL); 5601 return NULL; 5602 } 5603 5604 vmsfspec = NULL; 5605 vmsdefspec = NULL; 5606 outbufl = NULL; 5607 5608 in_spec = filespec; 5609 isunix = 0; 5610 if ((opts & PERL_RMSEXPAND_M_VMS_IN) == 0) { 5611 char * v_spec, * r_spec, * d_spec, * n_spec, * e_spec, * vs_spec; 5612 int sts, v_len, r_len, d_len, n_len, e_len, vs_len; 5613 5614 /* If this is a UNIX file spec, convert it to VMS */ 5615 sts = vms_split_path(filespec, &v_spec, &v_len, &r_spec, &r_len, 5616 &d_spec, &d_len, &n_spec, &n_len, &e_spec, 5617 &e_len, &vs_spec, &vs_len); 5618 if (sts != 0) { 5619 isunix = 1; 5620 char * ret_spec; 5621 5622 vmsfspec = PerlMem_malloc(VMS_MAXRSS); 5623 if (vmsfspec == NULL) _ckvmssts_noperl(SS$_INSFMEM); 5624 ret_spec = int_tovmsspec(filespec, vmsfspec, 0, fs_utf8); 5625 if (ret_spec == NULL) { 5626 PerlMem_free(vmsfspec); 5627 return NULL; 5628 } 5629 in_spec = (const char *)vmsfspec; 5630 5631 /* Unless we are forcing to VMS format, a UNIX input means 5632 * UNIX output, and that requires long names to be used 5633 */ 5634 if ((opts & PERL_RMSEXPAND_M_VMS) == 0) 5635 #if !defined(__VAX) && defined(NAML$C_MAXRSS) 5636 opts |= PERL_RMSEXPAND_M_LONG; 5637 #else 5638 NOOP; 5639 #endif 5640 else 5641 isunix = 0; 5642 } 5643 5644 } 5645 5646 rms_set_fna(myfab, mynam, (char *)in_spec, strlen(in_spec)); /* cast ok */ 5647 rms_bind_fab_nam(myfab, mynam); 5648 5649 /* Process the default file specification if present */ 5650 def_spec = defspec; 5651 if (defspec && *defspec) { 5652 int t_isunix; 5653 t_isunix = is_unix_filespec(defspec); 5654 if (t_isunix) { 5655 vmsdefspec = PerlMem_malloc(VMS_MAXRSS); 5656 if (vmsdefspec == NULL) _ckvmssts_noperl(SS$_INSFMEM); 5657 ret_spec = int_tovmsspec(defspec, vmsdefspec, 0, dfs_utf8); 5658 5659 if (ret_spec == NULL) { 5660 /* Clean up and bail */ 5661 PerlMem_free(vmsdefspec); 5662 if (vmsfspec != NULL) 5663 PerlMem_free(vmsfspec); 5664 return NULL; 5665 } 5666 def_spec = (const char *)vmsdefspec; 5667 } 5668 rms_set_dna(myfab, mynam, 5669 (char *)def_spec, strlen(def_spec)); /* cast ok */ 5670 } 5671 5672 /* Now we need the expansion buffers */ 5673 esa = PerlMem_malloc(NAM$C_MAXRSS + 1); 5674 if (esa == NULL) _ckvmssts_noperl(SS$_INSFMEM); 5675 #if !defined(__VAX) && defined(NAML$C_MAXRSS) 5676 esal = PerlMem_malloc(VMS_MAXRSS); 5677 if (esal == NULL) _ckvmssts_noperl(SS$_INSFMEM); 5678 #endif 5679 rms_set_esal(mynam, esa, NAM$C_MAXRSS, esal, VMS_MAXRSS-1); 5680 5681 /* If a NAML block is used RMS always writes to the long and short 5682 * addresses unless you suppress the short name. 5683 */ 5684 #if !defined(__VAX) && defined(NAML$C_MAXRSS) 5685 outbufl = PerlMem_malloc(VMS_MAXRSS); 5686 if (outbufl == NULL) _ckvmssts_noperl(SS$_INSFMEM); 5687 #endif 5688 rms_set_rsal(mynam, outbuf, NAM$C_MAXRSS, outbufl, (VMS_MAXRSS - 1)); 5689 5690 #ifdef NAM$M_NO_SHORT_UPCASE 5691 if (decc_efs_case_preserve) 5692 rms_set_nam_nop(mynam, NAM$M_NO_SHORT_UPCASE); 5693 #endif 5694 5695 /* We may not want to follow symbolic links */ 5696 #ifdef NAML$M_OPEN_SPECIAL 5697 if ((opts & PERL_RMSEXPAND_M_SYMLINK) != 0) 5698 rms_set_nam_nop(mynam, NAML$M_OPEN_SPECIAL); 5699 #endif 5700 5701 /* First attempt to parse as an existing file */ 5702 retsts = sys$parse(&myfab,0,0); 5703 if (!(retsts & STS$K_SUCCESS)) { 5704 5705 /* Could not find the file, try as syntax only if error is not fatal */ 5706 rms_set_nam_nop(mynam, NAM$M_SYNCHK); 5707 if (retsts == RMS$_DNF || 5708 retsts == RMS$_DIR || 5709 retsts == RMS$_DEV || 5710 retsts == RMS$_PRV) { 5711 retsts = sys$parse(&myfab,0,0); 5712 if (retsts & STS$K_SUCCESS) goto int_expanded; 5713 } 5714 5715 /* Still could not parse the file specification */ 5716 /*----------------------------------------------*/ 5717 sts = rms_free_search_context(&myfab); /* Free search context */ 5718 if (vmsdefspec != NULL) 5719 PerlMem_free(vmsdefspec); 5720 if (vmsfspec != NULL) 5721 PerlMem_free(vmsfspec); 5722 if (outbufl != NULL) 5723 PerlMem_free(outbufl); 5724 PerlMem_free(esa); 5725 if (esal != NULL) 5726 PerlMem_free(esal); 5727 set_vaxc_errno(retsts); 5728 if (retsts == RMS$_PRV) set_errno(EACCES); 5729 else if (retsts == RMS$_DEV) set_errno(ENODEV); 5730 else if (retsts == RMS$_DIR) set_errno(ENOTDIR); 5731 else set_errno(EVMSERR); 5732 return NULL; 5733 } 5734 retsts = sys$search(&myfab,0,0); 5735 if (!(retsts & STS$K_SUCCESS) && retsts != RMS$_FNF) { 5736 sts = rms_free_search_context(&myfab); /* Free search context */ 5737 if (vmsdefspec != NULL) 5738 PerlMem_free(vmsdefspec); 5739 if (vmsfspec != NULL) 5740 PerlMem_free(vmsfspec); 5741 if (outbufl != NULL) 5742 PerlMem_free(outbufl); 5743 PerlMem_free(esa); 5744 if (esal != NULL) 5745 PerlMem_free(esal); 5746 set_vaxc_errno(retsts); 5747 if (retsts == RMS$_PRV) set_errno(EACCES); 5748 else set_errno(EVMSERR); 5749 return NULL; 5750 } 5751 5752 /* If the input filespec contained any lowercase characters, 5753 * downcase the result for compatibility with Unix-minded code. */ 5754 int_expanded: 5755 if (!decc_efs_case_preserve) { 5756 char * tbuf; 5757 for (tbuf = rms_get_fna(myfab, mynam); *tbuf; tbuf++) 5758 if (islower(*tbuf)) { haslower = 1; break; } 5759 } 5760 5761 /* Is a long or a short name expected */ 5762 /*------------------------------------*/ 5763 spec_buf = NULL; 5764 #if !defined(__VAX) && defined(NAML$C_MAXRSS) 5765 if ((opts & PERL_RMSEXPAND_M_LONG) != 0) { 5766 if (rms_nam_rsll(mynam)) { 5767 spec_buf = outbufl; 5768 speclen = rms_nam_rsll(mynam); 5769 } 5770 else { 5771 spec_buf = esal; /* Not esa */ 5772 speclen = rms_nam_esll(mynam); 5773 } 5774 } 5775 else { 5776 #endif 5777 if (rms_nam_rsl(mynam)) { 5778 spec_buf = outbuf; 5779 speclen = rms_nam_rsl(mynam); 5780 } 5781 else { 5782 spec_buf = esa; /* Not esal */ 5783 speclen = rms_nam_esl(mynam); 5784 } 5785 #if !defined(__VAX) && defined(NAML$C_MAXRSS) 5786 } 5787 #endif 5788 spec_buf[speclen] = '\0'; 5789 5790 /* Trim off null fields added by $PARSE 5791 * If type > 1 char, must have been specified in original or default spec 5792 * (not true for version; $SEARCH may have added version of existing file). 5793 */ 5794 trimver = !rms_is_nam_fnb(mynam, NAM$M_EXP_VER); 5795 if ((opts & PERL_RMSEXPAND_M_LONG) != 0) { 5796 trimtype = !rms_is_nam_fnb(mynam, NAM$M_EXP_TYPE) && 5797 ((rms_nam_verl(mynam) - rms_nam_typel(mynam)) == 1); 5798 } 5799 else { 5800 trimtype = !rms_is_nam_fnb(mynam, NAM$M_EXP_TYPE) && 5801 ((rms_nam_ver(mynam) - rms_nam_type(mynam)) == 1); 5802 } 5803 if (trimver || trimtype) { 5804 if (defspec && *defspec) { 5805 char *defesal = NULL; 5806 char *defesa = NULL; 5807 defesa = PerlMem_malloc(VMS_MAXRSS + 1); 5808 if (defesa != NULL) { 5809 struct FAB deffab = cc$rms_fab; 5810 #if !defined(__VAX) && defined(NAML$C_MAXRSS) 5811 defesal = PerlMem_malloc(VMS_MAXRSS + 1); 5812 if (defesal == NULL) _ckvmssts_noperl(SS$_INSFMEM); 5813 #endif 5814 rms_setup_nam(defnam); 5815 5816 rms_bind_fab_nam(deffab, defnam); 5817 5818 /* Cast ok */ 5819 rms_set_fna 5820 (deffab, defnam, (char *)defspec, rms_nam_dns(myfab, mynam)); 5821 5822 /* RMS needs the esa/esal as a work area if wildcards are involved */ 5823 rms_set_esal(defnam, defesa, NAM$C_MAXRSS, defesal, VMS_MAXRSS - 1); 5824 5825 rms_clear_nam_nop(defnam); 5826 rms_set_nam_nop(defnam, NAM$M_SYNCHK); 5827 #ifdef NAM$M_NO_SHORT_UPCASE 5828 if (decc_efs_case_preserve) 5829 rms_set_nam_nop(defnam, NAM$M_NO_SHORT_UPCASE); 5830 #endif 5831 #ifdef NAML$M_OPEN_SPECIAL 5832 if ((opts & PERL_RMSEXPAND_M_SYMLINK) != 0) 5833 rms_set_nam_nop(mynam, NAML$M_OPEN_SPECIAL); 5834 #endif 5835 if (sys$parse(&deffab,0,0) & STS$K_SUCCESS) { 5836 if (trimver) { 5837 trimver = !rms_is_nam_fnb(defnam, NAM$M_EXP_VER); 5838 } 5839 if (trimtype) { 5840 trimtype = !rms_is_nam_fnb(defnam, NAM$M_EXP_TYPE); 5841 } 5842 } 5843 if (defesal != NULL) 5844 PerlMem_free(defesal); 5845 PerlMem_free(defesa); 5846 } else { 5847 _ckvmssts_noperl(SS$_INSFMEM); 5848 } 5849 } 5850 if (trimver) { 5851 if ((opts & PERL_RMSEXPAND_M_LONG) != 0) { 5852 if (*(rms_nam_verl(mynam)) != '\"') 5853 speclen = rms_nam_verl(mynam) - spec_buf; 5854 } 5855 else { 5856 if (*(rms_nam_ver(mynam)) != '\"') 5857 speclen = rms_nam_ver(mynam) - spec_buf; 5858 } 5859 } 5860 if (trimtype) { 5861 /* If we didn't already trim version, copy down */ 5862 if ((opts & PERL_RMSEXPAND_M_LONG) != 0) { 5863 if (speclen > rms_nam_verl(mynam) - spec_buf) 5864 memmove 5865 (rms_nam_typel(mynam), 5866 rms_nam_verl(mynam), 5867 speclen - (rms_nam_verl(mynam) - spec_buf)); 5868 speclen -= rms_nam_verl(mynam) - rms_nam_typel(mynam); 5869 } 5870 else { 5871 if (speclen > rms_nam_ver(mynam) - spec_buf) 5872 memmove 5873 (rms_nam_type(mynam), 5874 rms_nam_ver(mynam), 5875 speclen - (rms_nam_ver(mynam) - spec_buf)); 5876 speclen -= rms_nam_ver(mynam) - rms_nam_type(mynam); 5877 } 5878 } 5879 } 5880 5881 /* Done with these copies of the input files */ 5882 /*-------------------------------------------*/ 5883 if (vmsfspec != NULL) 5884 PerlMem_free(vmsfspec); 5885 if (vmsdefspec != NULL) 5886 PerlMem_free(vmsdefspec); 5887 5888 /* If we just had a directory spec on input, $PARSE "helpfully" 5889 * adds an empty name and type for us */ 5890 #if !defined(__VAX) && defined(NAML$C_MAXRSS) 5891 if ((opts & PERL_RMSEXPAND_M_LONG) != 0) { 5892 if (rms_nam_namel(mynam) == rms_nam_typel(mynam) && 5893 rms_nam_verl(mynam) == rms_nam_typel(mynam) + 1 && 5894 !(rms_is_nam_fnb(mynam, NAM$M_EXP_NAME))) 5895 speclen = rms_nam_namel(mynam) - spec_buf; 5896 } 5897 else 5898 #endif 5899 { 5900 if (rms_nam_name(mynam) == rms_nam_type(mynam) && 5901 rms_nam_ver(mynam) == rms_nam_ver(mynam) + 1 && 5902 !(rms_is_nam_fnb(mynam, NAM$M_EXP_NAME))) 5903 speclen = rms_nam_name(mynam) - spec_buf; 5904 } 5905 5906 /* Posix format specifications must have matching quotes */ 5907 if (speclen < (VMS_MAXRSS - 1)) { 5908 if (decc_posix_compliant_pathnames && (spec_buf[0] == '\"')) { 5909 if ((speclen > 1) && (spec_buf[speclen-1] != '\"')) { 5910 spec_buf[speclen] = '\"'; 5911 speclen++; 5912 } 5913 } 5914 } 5915 spec_buf[speclen] = '\0'; 5916 if (haslower && !decc_efs_case_preserve) __mystrtolower(spec_buf); 5917 5918 /* Have we been working with an expanded, but not resultant, spec? */ 5919 /* Also, convert back to Unix syntax if necessary. */ 5920 { 5921 int rsl; 5922 5923 #if !defined(__VAX) && defined(NAML$C_MAXRSS) 5924 if ((opts & PERL_RMSEXPAND_M_LONG) != 0) { 5925 rsl = rms_nam_rsll(mynam); 5926 } else 5927 #endif 5928 { 5929 rsl = rms_nam_rsl(mynam); 5930 } 5931 if (!rsl) { 5932 /* rsl is not present, it means that spec_buf is either */ 5933 /* esa or esal, and needs to be copied to outbuf */ 5934 /* convert to Unix if desired */ 5935 if (isunix) { 5936 ret_spec = int_tounixspec(spec_buf, outbuf, fs_utf8); 5937 } else { 5938 /* VMS file specs are not in UTF-8 */ 5939 if (fs_utf8 != NULL) 5940 *fs_utf8 = 0; 5941 strcpy(outbuf, spec_buf); 5942 ret_spec = outbuf; 5943 } 5944 } 5945 else { 5946 /* Now spec_buf is either outbuf or outbufl */ 5947 /* We need the result into outbuf */ 5948 if (isunix) { 5949 /* If we need this in UNIX, then we need another buffer */ 5950 /* to keep things in order */ 5951 char * src; 5952 char * new_src = NULL; 5953 if (spec_buf == outbuf) { 5954 new_src = PerlMem_malloc(VMS_MAXRSS); 5955 strcpy(new_src, spec_buf); 5956 } else { 5957 src = spec_buf; 5958 } 5959 ret_spec = int_tounixspec(src, outbuf, fs_utf8); 5960 if (new_src) { 5961 PerlMem_free(new_src); 5962 } 5963 } else { 5964 /* VMS file specs are not in UTF-8 */ 5965 if (fs_utf8 != NULL) 5966 *fs_utf8 = 0; 5967 5968 /* Copy the buffer if needed */ 5969 if (outbuf != spec_buf) 5970 strcpy(outbuf, spec_buf); 5971 ret_spec = outbuf; 5972 } 5973 } 5974 } 5975 5976 /* Need to clean up the search context */ 5977 rms_set_rsal(mynam, NULL, 0, NULL, 0); 5978 sts = rms_free_search_context(&myfab); /* Free search context */ 5979 5980 /* Clean up the extra buffers */ 5981 if (esal != NULL) 5982 PerlMem_free(esal); 5983 PerlMem_free(esa); 5984 if (outbufl != NULL) 5985 PerlMem_free(outbufl); 5986 5987 /* Return the result */ 5988 return ret_spec; 5989 } 5990 5991 /* Common simple case - Expand an already VMS spec */ 5992 static char * 5993 int_rmsexpand_vms(const char * filespec, char * outbuf, unsigned opts) { 5994 opts |= PERL_RMSEXPAND_M_VMS_IN; 5995 return int_rmsexpand(filespec, outbuf, NULL, opts, NULL, NULL); 5996 } 5997 5998 /* Common simple case - Expand to a VMS spec */ 5999 static char * 6000 int_rmsexpand_tovms(const char * filespec, char * outbuf, unsigned opts) { 6001 opts |= PERL_RMSEXPAND_M_VMS; 6002 return int_rmsexpand(filespec, outbuf, NULL, opts, NULL, NULL); 6003 } 6004 6005 6006 /* Entry point used by perl routines */ 6007 static char * 6008 mp_do_rmsexpand 6009 (pTHX_ const char *filespec, 6010 char *outbuf, 6011 int ts, 6012 const char *defspec, 6013 unsigned opts, 6014 int * fs_utf8, 6015 int * dfs_utf8) 6016 { 6017 static char __rmsexpand_retbuf[VMS_MAXRSS]; 6018 char * expanded, *ret_spec, *ret_buf; 6019 6020 expanded = NULL; 6021 ret_buf = outbuf; 6022 if (ret_buf == NULL) { 6023 if (ts) { 6024 Newx(expanded, VMS_MAXRSS, char); 6025 if (expanded == NULL) 6026 _ckvmssts(SS$_INSFMEM); 6027 ret_buf = expanded; 6028 } else { 6029 ret_buf = __rmsexpand_retbuf; 6030 } 6031 } 6032 6033 6034 ret_spec = int_rmsexpand(filespec, ret_buf, defspec, 6035 opts, fs_utf8, dfs_utf8); 6036 6037 if (ret_spec == NULL) { 6038 /* Cleanup on isle 5, if this is thread specific we need to deallocate */ 6039 if (expanded) 6040 Safefree(expanded); 6041 } 6042 6043 return ret_spec; 6044 } 6045 /*}}}*/ 6046 /* External entry points */ 6047 char *Perl_rmsexpand(pTHX_ const char *spec, char *buf, const char *def, unsigned opt) 6048 { return do_rmsexpand(spec,buf,0,def,opt,NULL,NULL); } 6049 char *Perl_rmsexpand_ts(pTHX_ const char *spec, char *buf, const char *def, unsigned opt) 6050 { return do_rmsexpand(spec,buf,1,def,opt,NULL,NULL); } 6051 char *Perl_rmsexpand_utf8 6052 (pTHX_ const char *spec, char *buf, const char *def, 6053 unsigned opt, int * fs_utf8, int * dfs_utf8) 6054 { return do_rmsexpand(spec,buf,0,def,opt, fs_utf8, dfs_utf8); } 6055 char *Perl_rmsexpand_utf8_ts 6056 (pTHX_ const char *spec, char *buf, const char *def, 6057 unsigned opt, int * fs_utf8, int * dfs_utf8) 6058 { return do_rmsexpand(spec,buf,1,def,opt, fs_utf8, dfs_utf8); } 6059 6060 6061 /* 6062 ** The following routines are provided to make life easier when 6063 ** converting among VMS-style and Unix-style directory specifications. 6064 ** All will take input specifications in either VMS or Unix syntax. On 6065 ** failure, all return NULL. If successful, the routines listed below 6066 ** return a pointer to a buffer containing the appropriately 6067 ** reformatted spec (and, therefore, subsequent calls to that routine 6068 ** will clobber the result), while the routines of the same names with 6069 ** a _ts suffix appended will return a pointer to a mallocd string 6070 ** containing the appropriately reformatted spec. 6071 ** In all cases, only explicit syntax is altered; no check is made that 6072 ** the resulting string is valid or that the directory in question 6073 ** actually exists. 6074 ** 6075 ** fileify_dirspec() - convert a directory spec into the name of the 6076 ** directory file (i.e. what you can stat() to see if it's a dir). 6077 ** The style (VMS or Unix) of the result is the same as the style 6078 ** of the parameter passed in. 6079 ** pathify_dirspec() - convert a directory spec into a path (i.e. 6080 ** what you prepend to a filename to indicate what directory it's in). 6081 ** The style (VMS or Unix) of the result is the same as the style 6082 ** of the parameter passed in. 6083 ** tounixpath() - convert a directory spec into a Unix-style path. 6084 ** tovmspath() - convert a directory spec into a VMS-style path. 6085 ** tounixspec() - convert any file spec into a Unix-style file spec. 6086 ** tovmsspec() - convert any file spec into a VMS-style spec. 6087 ** xxxxx_utf8() - Variants that support UTF8 encoding of Unix-Style file spec. 6088 ** 6089 ** Copyright 1996 by Charles Bailey <bailey@newman.upenn.edu> 6090 ** Permission is given to distribute this code as part of the Perl 6091 ** standard distribution under the terms of the GNU General Public 6092 ** License or the Perl Artistic License. Copies of each may be 6093 ** found in the Perl standard distribution. 6094 */ 6095 6096 /*{{{ char * int_fileify_dirspec[_ts](char *dir, char *buf, int * utf8_fl)*/ 6097 static char * 6098 int_fileify_dirspec(const char *dir, char *buf, int *utf8_fl) 6099 { 6100 unsigned long int dirlen, retlen, addmfd = 0, hasfilename = 0; 6101 char *cp1, *cp2, *lastdir; 6102 char *trndir, *vmsdir; 6103 unsigned short int trnlnm_iter_count; 6104 int is_vms = 0; 6105 int is_unix = 0; 6106 int sts; 6107 if (utf8_fl != NULL) 6108 *utf8_fl = 0; 6109 6110 if (!dir || !*dir) { 6111 set_errno(EINVAL); set_vaxc_errno(SS$_BADPARAM); return NULL; 6112 } 6113 dirlen = strlen(dir); 6114 while (dirlen && dir[dirlen-1] == '/') --dirlen; 6115 if (!dirlen) { /* We had Unixish '/' -- substitute top of current tree */ 6116 if (!decc_posix_compliant_pathnames && decc_disable_posix_root) { 6117 dir = "/sys$disk"; 6118 dirlen = 9; 6119 } 6120 else 6121 dirlen = 1; 6122 } 6123 if (dirlen > (VMS_MAXRSS - 1)) { 6124 set_errno(ENAMETOOLONG); set_vaxc_errno(RMS$_SYN); 6125 return NULL; 6126 } 6127 trndir = PerlMem_malloc(VMS_MAXRSS + 1); 6128 if (trndir == NULL) _ckvmssts_noperl(SS$_INSFMEM); 6129 if (!strpbrk(dir+1,"/]>:") && 6130 (!decc_posix_compliant_pathnames && decc_disable_posix_root)) { 6131 strcpy(trndir,*dir == '/' ? dir + 1: dir); 6132 trnlnm_iter_count = 0; 6133 while (!strpbrk(trndir,"/]>:") && simple_trnlnm(trndir,trndir,VMS_MAXRSS-1)) { 6134 trnlnm_iter_count++; 6135 if (trnlnm_iter_count >= PERL_LNM_MAX_ITER) break; 6136 } 6137 dirlen = strlen(trndir); 6138 } 6139 else { 6140 strncpy(trndir,dir,dirlen); 6141 trndir[dirlen] = '\0'; 6142 } 6143 6144 /* At this point we are done with *dir and use *trndir which is a 6145 * copy that can be modified. *dir must not be modified. 6146 */ 6147 6148 /* If we were handed a rooted logical name or spec, treat it like a 6149 * simple directory, so that 6150 * $ Define myroot dev:[dir.] 6151 * ... do_fileify_dirspec("myroot",buf,1) ... 6152 * does something useful. 6153 */ 6154 if (dirlen >= 2 && !strcmp(trndir+dirlen-2,".]")) { 6155 trndir[--dirlen] = '\0'; 6156 trndir[dirlen-1] = ']'; 6157 } 6158 if (dirlen >= 2 && !strcmp(trndir+dirlen-2,".>")) { 6159 trndir[--dirlen] = '\0'; 6160 trndir[dirlen-1] = '>'; 6161 } 6162 6163 if ((cp1 = strrchr(trndir,']')) != NULL || (cp1 = strrchr(trndir,'>')) != NULL) { 6164 /* If we've got an explicit filename, we can just shuffle the string. */ 6165 if (*(cp1+1)) hasfilename = 1; 6166 /* Similarly, we can just back up a level if we've got multiple levels 6167 of explicit directories in a VMS spec which ends with directories. */ 6168 else { 6169 for (cp2 = cp1; cp2 > trndir; cp2--) { 6170 if (*cp2 == '.') { 6171 if ((cp2 - 1 > trndir) && (*(cp2 - 1) != '^')) { 6172 /* fix-me, can not scan EFS file specs backward like this */ 6173 *cp2 = *cp1; *cp1 = '\0'; 6174 hasfilename = 1; 6175 break; 6176 } 6177 } 6178 if (*cp2 == '[' || *cp2 == '<') break; 6179 } 6180 } 6181 } 6182 6183 vmsdir = PerlMem_malloc(VMS_MAXRSS + 1); 6184 if (vmsdir == NULL) _ckvmssts_noperl(SS$_INSFMEM); 6185 cp1 = strpbrk(trndir,"]:>"); 6186 if (hasfilename || !cp1) { /* filename present or not VMS */ 6187 6188 if (decc_efs_charset && !cp1) { 6189 6190 /* EFS handling for UNIX mode */ 6191 6192 /* Just remove the trailing '/' and we should be done */ 6193 STRLEN trndir_len; 6194 trndir_len = strlen(trndir); 6195 6196 if (trndir_len > 1) { 6197 trndir_len--; 6198 if (trndir[trndir_len] == '/') { 6199 trndir[trndir_len] = '\0'; 6200 } 6201 } 6202 strcpy(buf, trndir); 6203 PerlMem_free(trndir); 6204 PerlMem_free(vmsdir); 6205 return buf; 6206 } 6207 6208 /* For non-EFS mode, this is left for backwards compatibility */ 6209 /* For EFS mode, this is only done for VMS format filespecs as */ 6210 /* Perl programs generally have problems when a UNIX format spec */ 6211 /* returns a VMS format spec */ 6212 if (trndir[0] == '.') { 6213 if (trndir[1] == '\0' || (trndir[1] == '/' && trndir[2] == '\0')) { 6214 PerlMem_free(trndir); 6215 PerlMem_free(vmsdir); 6216 return int_fileify_dirspec("[]", buf, NULL); 6217 } 6218 else if (trndir[1] == '.' && 6219 (trndir[2] == '\0' || (trndir[2] == '/' && trndir[3] == '\0'))) { 6220 PerlMem_free(trndir); 6221 PerlMem_free(vmsdir); 6222 return int_fileify_dirspec("[-]", buf, NULL); 6223 } 6224 } 6225 if (dirlen && trndir[dirlen-1] == '/') { /* path ends with '/'; just add .dir;1 */ 6226 dirlen -= 1; /* to last element */ 6227 lastdir = strrchr(trndir,'/'); 6228 } 6229 else if ((cp1 = strstr(trndir,"/.")) != NULL) { 6230 /* If we have "/." or "/..", VMSify it and let the VMS code 6231 * below expand it, rather than repeating the code to handle 6232 * relative components of a filespec here */ 6233 do { 6234 if (*(cp1+2) == '.') cp1++; 6235 if (*(cp1+2) == '/' || *(cp1+2) == '\0') { 6236 char * ret_chr; 6237 if (int_tovmsspec(trndir, vmsdir, 0, utf8_fl) == NULL) { 6238 PerlMem_free(trndir); 6239 PerlMem_free(vmsdir); 6240 return NULL; 6241 } 6242 if (strchr(vmsdir,'/') != NULL) { 6243 /* If int_tovmsspec() returned it, it must have VMS syntax 6244 * delimiters in it, so it's a mixed VMS/Unix spec. We take 6245 * the time to check this here only so we avoid a recursion 6246 * loop; otherwise, gigo. 6247 */ 6248 PerlMem_free(trndir); 6249 PerlMem_free(vmsdir); 6250 set_errno(EINVAL); set_vaxc_errno(RMS$_SYN); 6251 return NULL; 6252 } 6253 if (int_fileify_dirspec(vmsdir, trndir, NULL) == NULL) { 6254 PerlMem_free(trndir); 6255 PerlMem_free(vmsdir); 6256 return NULL; 6257 } 6258 ret_chr = int_tounixspec(trndir, buf, utf8_fl); 6259 PerlMem_free(trndir); 6260 PerlMem_free(vmsdir); 6261 return ret_chr; 6262 } 6263 cp1++; 6264 } while ((cp1 = strstr(cp1,"/.")) != NULL); 6265 lastdir = strrchr(trndir,'/'); 6266 } 6267 else if (dirlen >= 7 && !strcmp(&trndir[dirlen-7],"/000000")) { 6268 char * ret_chr; 6269 /* Ditto for specs that end in an MFD -- let the VMS code 6270 * figure out whether it's a real device or a rooted logical. */ 6271 6272 /* This should not happen any more. Allowing the fake /000000 6273 * in a UNIX pathname causes all sorts of problems when trying 6274 * to run in UNIX emulation. So the VMS to UNIX conversions 6275 * now remove the fake /000000 directories. 6276 */ 6277 6278 trndir[dirlen] = '/'; trndir[dirlen+1] = '\0'; 6279 if (int_tovmsspec(trndir, vmsdir, 0, NULL) == NULL) { 6280 PerlMem_free(trndir); 6281 PerlMem_free(vmsdir); 6282 return NULL; 6283 } 6284 if (int_fileify_dirspec(vmsdir, trndir, NULL) == NULL) { 6285 PerlMem_free(trndir); 6286 PerlMem_free(vmsdir); 6287 return NULL; 6288 } 6289 ret_chr = int_tounixspec(trndir, buf, utf8_fl); 6290 PerlMem_free(trndir); 6291 PerlMem_free(vmsdir); 6292 return ret_chr; 6293 } 6294 else { 6295 6296 if ( !(lastdir = cp1 = strrchr(trndir,'/')) && 6297 !(lastdir = cp1 = strrchr(trndir,']')) && 6298 !(lastdir = cp1 = strrchr(trndir,'>'))) cp1 = trndir; 6299 6300 cp2 = strrchr(cp1,'.'); 6301 if (cp2) { 6302 int e_len, vs_len = 0; 6303 int is_dir = 0; 6304 char * cp3; 6305 cp3 = strchr(cp2,';'); 6306 e_len = strlen(cp2); 6307 if (cp3) { 6308 vs_len = strlen(cp3); 6309 e_len = e_len - vs_len; 6310 } 6311 is_dir = is_dir_ext(cp2, e_len, cp3, vs_len); 6312 if (!is_dir) { 6313 if (!decc_efs_charset) { 6314 /* If this is not EFS, then not a directory */ 6315 PerlMem_free(trndir); 6316 PerlMem_free(vmsdir); 6317 set_errno(ENOTDIR); 6318 set_vaxc_errno(RMS$_DIR); 6319 return NULL; 6320 } 6321 } else { 6322 /* Ok, here we have an issue, technically if a .dir shows */ 6323 /* from inside a directory, then we should treat it as */ 6324 /* xxx^.dir.dir. But we do not have that context at this */ 6325 /* point unless this is totally restructured, so we remove */ 6326 /* The .dir for now, and fix this better later */ 6327 dirlen = cp2 - trndir; 6328 } 6329 } 6330 6331 } 6332 6333 retlen = dirlen + 6; 6334 memcpy(buf, trndir, dirlen); 6335 buf[dirlen] = '\0'; 6336 6337 /* We've picked up everything up to the directory file name. 6338 Now just add the type and version, and we're set. */ 6339 6340 /* We should only add type for VMS syntax, but historically Perl 6341 has added it for UNIX style also */ 6342 6343 /* Fix me - we should not be using the same routine for VMS and 6344 UNIX format files. Things are too tangled so we need to lookup 6345 what syntax the output is */ 6346 6347 is_unix = 0; 6348 is_vms = 0; 6349 lastdir = strrchr(trndir,'/'); 6350 if (lastdir) { 6351 is_unix = 1; 6352 } else { 6353 lastdir = strpbrk(trndir,"]:>"); 6354 if (lastdir) { 6355 is_vms = 1; 6356 } 6357 } 6358 6359 if ((is_vms == 0) && (is_unix == 0)) { 6360 /* We still do not know? */ 6361 is_unix = decc_filename_unix_report; 6362 if (is_unix == 0) 6363 is_vms = 1; 6364 } 6365 6366 if ((is_unix && !decc_efs_charset) || is_vms) { 6367 6368 /* It is a bug to add a .dir to a UNIX format directory spec */ 6369 /* However Perl on VMS may have programs that expect this so */ 6370 /* If not using EFS character specifications allow it. */ 6371 6372 if ((!decc_efs_case_preserve) && vms_process_case_tolerant) { 6373 /* Traditionally Perl expects filenames in lower case */ 6374 strcat(buf, ".dir"); 6375 } else { 6376 /* VMS expects the .DIR to be in upper case */ 6377 strcat(buf, ".DIR"); 6378 } 6379 6380 /* It is also a bug to put a VMS format version on a UNIX file */ 6381 /* specification. Perl self tests are looking for this */ 6382 if (is_vms || !(decc_efs_charset || decc_filename_unix_report)) 6383 strcat(buf, ";1"); 6384 } 6385 PerlMem_free(trndir); 6386 PerlMem_free(vmsdir); 6387 return buf; 6388 } 6389 else { /* VMS-style directory spec */ 6390 6391 char *esa, *esal, term, *cp; 6392 char *my_esa; 6393 int my_esa_len; 6394 unsigned long int sts, cmplen, haslower = 0; 6395 unsigned int nam_fnb; 6396 char * nam_type; 6397 struct FAB dirfab = cc$rms_fab; 6398 rms_setup_nam(savnam); 6399 rms_setup_nam(dirnam); 6400 6401 esa = PerlMem_malloc(NAM$C_MAXRSS + 1); 6402 if (esa == NULL) _ckvmssts_noperl(SS$_INSFMEM); 6403 esal = NULL; 6404 #if !defined(__VAX) && defined(NAML$C_MAXRSS) 6405 esal = PerlMem_malloc(VMS_MAXRSS); 6406 if (esal == NULL) _ckvmssts_noperl(SS$_INSFMEM); 6407 #endif 6408 rms_set_fna(dirfab, dirnam, trndir, strlen(trndir)); 6409 rms_bind_fab_nam(dirfab, dirnam); 6410 rms_set_dna(dirfab, dirnam, ".DIR;1", 6); 6411 rms_set_esal(dirnam, esa, NAM$C_MAXRSS, esal, (VMS_MAXRSS - 1)); 6412 #ifdef NAM$M_NO_SHORT_UPCASE 6413 if (decc_efs_case_preserve) 6414 rms_set_nam_nop(dirnam, NAM$M_NO_SHORT_UPCASE); 6415 #endif 6416 6417 for (cp = trndir; *cp; cp++) 6418 if (islower(*cp)) { haslower = 1; break; } 6419 if (!((sts = sys$parse(&dirfab)) & STS$K_SUCCESS)) { 6420 if ((dirfab.fab$l_sts == RMS$_DIR) || 6421 (dirfab.fab$l_sts == RMS$_DNF) || 6422 (dirfab.fab$l_sts == RMS$_PRV)) { 6423 rms_set_nam_nop(dirnam, NAM$M_SYNCHK); 6424 sts = sys$parse(&dirfab); 6425 } 6426 if (!sts) { 6427 PerlMem_free(esa); 6428 if (esal != NULL) 6429 PerlMem_free(esal); 6430 PerlMem_free(trndir); 6431 PerlMem_free(vmsdir); 6432 set_errno(EVMSERR); 6433 set_vaxc_errno(dirfab.fab$l_sts); 6434 return NULL; 6435 } 6436 } 6437 else { 6438 savnam = dirnam; 6439 /* Does the file really exist? */ 6440 if (sys$search(&dirfab)& STS$K_SUCCESS) { 6441 /* Yes; fake the fnb bits so we'll check type below */ 6442 rms_set_nam_fnb(dirnam, (NAM$M_EXP_TYPE | NAM$M_EXP_VER)); 6443 } 6444 else { /* No; just work with potential name */ 6445 if (dirfab.fab$l_sts == RMS$_FNF) dirnam = savnam; 6446 else { 6447 int fab_sts; 6448 fab_sts = dirfab.fab$l_sts; 6449 sts = rms_free_search_context(&dirfab); 6450 PerlMem_free(esa); 6451 if (esal != NULL) 6452 PerlMem_free(esal); 6453 PerlMem_free(trndir); 6454 PerlMem_free(vmsdir); 6455 set_errno(EVMSERR); set_vaxc_errno(fab_sts); 6456 return NULL; 6457 } 6458 } 6459 } 6460 6461 /* Make sure we are using the right buffer */ 6462 #if !defined(__VAX) && defined(NAML$C_MAXRSS) 6463 if (esal != NULL) { 6464 my_esa = esal; 6465 my_esa_len = rms_nam_esll(dirnam); 6466 } else { 6467 #endif 6468 my_esa = esa; 6469 my_esa_len = rms_nam_esl(dirnam); 6470 #if !defined(__VAX) && defined(NAML$C_MAXRSS) 6471 } 6472 #endif 6473 my_esa[my_esa_len] = '\0'; 6474 if (!rms_is_nam_fnb(dirnam, (NAM$M_EXP_DEV | NAM$M_EXP_DIR))) { 6475 cp1 = strchr(my_esa,']'); 6476 if (!cp1) cp1 = strchr(my_esa,'>'); 6477 if (cp1) { /* Should always be true */ 6478 my_esa_len -= cp1 - my_esa - 1; 6479 memmove(my_esa, cp1 + 1, my_esa_len); 6480 } 6481 } 6482 if (rms_is_nam_fnb(dirnam, NAM$M_EXP_TYPE)) { /* Was type specified? */ 6483 /* Yep; check version while we're at it, if it's there. */ 6484 cmplen = rms_is_nam_fnb(dirnam, NAM$M_EXP_VER) ? 6 : 4; 6485 if (strncmp(rms_nam_typel(dirnam), ".DIR;1", cmplen)) { 6486 /* Something other than .DIR[;1]. Bzzt. */ 6487 sts = rms_free_search_context(&dirfab); 6488 PerlMem_free(esa); 6489 if (esal != NULL) 6490 PerlMem_free(esal); 6491 PerlMem_free(trndir); 6492 PerlMem_free(vmsdir); 6493 set_errno(ENOTDIR); 6494 set_vaxc_errno(RMS$_DIR); 6495 return NULL; 6496 } 6497 } 6498 6499 if (rms_is_nam_fnb(dirnam, NAM$M_EXP_NAME)) { 6500 /* They provided at least the name; we added the type, if necessary, */ 6501 strcpy(buf, my_esa); 6502 sts = rms_free_search_context(&dirfab); 6503 PerlMem_free(trndir); 6504 PerlMem_free(esa); 6505 if (esal != NULL) 6506 PerlMem_free(esal); 6507 PerlMem_free(vmsdir); 6508 return buf; 6509 } 6510 if ((cp1 = strstr(esa,".][000000]")) != NULL) { 6511 for (cp2 = cp1 + 9; *cp2; cp1++,cp2++) *cp1 = *cp2; 6512 *cp1 = '\0'; 6513 my_esa_len -= 9; 6514 } 6515 if ((cp1 = strrchr(my_esa,']')) == NULL) cp1 = strrchr(my_esa,'>'); 6516 if (cp1 == NULL) { /* should never happen */ 6517 sts = rms_free_search_context(&dirfab); 6518 PerlMem_free(trndir); 6519 PerlMem_free(esa); 6520 if (esal != NULL) 6521 PerlMem_free(esal); 6522 PerlMem_free(vmsdir); 6523 return NULL; 6524 } 6525 term = *cp1; 6526 *cp1 = '\0'; 6527 retlen = strlen(my_esa); 6528 cp1 = strrchr(my_esa,'.'); 6529 /* ODS-5 directory specifications can have extra "." in them. */ 6530 /* Fix-me, can not scan EFS file specifications backwards */ 6531 while (cp1 != NULL) { 6532 if ((cp1-1 == my_esa) || (*(cp1-1) != '^')) 6533 break; 6534 else { 6535 cp1--; 6536 while ((cp1 > my_esa) && (*cp1 != '.')) 6537 cp1--; 6538 } 6539 if (cp1 == my_esa) 6540 cp1 = NULL; 6541 } 6542 6543 if ((cp1) != NULL) { 6544 /* There's more than one directory in the path. Just roll back. */ 6545 *cp1 = term; 6546 strcpy(buf, my_esa); 6547 } 6548 else { 6549 if (rms_is_nam_fnb(dirnam, NAM$M_ROOT_DIR)) { 6550 /* Go back and expand rooted logical name */ 6551 rms_set_nam_nop(dirnam, NAM$M_SYNCHK | NAM$M_NOCONCEAL); 6552 #ifdef NAM$M_NO_SHORT_UPCASE 6553 if (decc_efs_case_preserve) 6554 rms_set_nam_nop(dirnam, NAM$M_NO_SHORT_UPCASE); 6555 #endif 6556 if (!(sys$parse(&dirfab) & STS$K_SUCCESS)) { 6557 sts = rms_free_search_context(&dirfab); 6558 PerlMem_free(esa); 6559 if (esal != NULL) 6560 PerlMem_free(esal); 6561 PerlMem_free(trndir); 6562 PerlMem_free(vmsdir); 6563 set_errno(EVMSERR); 6564 set_vaxc_errno(dirfab.fab$l_sts); 6565 return NULL; 6566 } 6567 6568 /* This changes the length of the string of course */ 6569 if (esal != NULL) { 6570 my_esa_len = rms_nam_esll(dirnam); 6571 } else { 6572 my_esa_len = rms_nam_esl(dirnam); 6573 } 6574 6575 retlen = my_esa_len - 9; /* esa - '][' - '].DIR;1' */ 6576 cp1 = strstr(my_esa,"]["); 6577 if (!cp1) cp1 = strstr(my_esa,"]<"); 6578 dirlen = cp1 - my_esa; 6579 memcpy(buf, my_esa, dirlen); 6580 if (!strncmp(cp1+2,"000000]",7)) { 6581 buf[dirlen-1] = '\0'; 6582 /* fix-me Not full ODS-5, just extra dots in directories for now */ 6583 cp1 = buf + dirlen - 1; 6584 while (cp1 > buf) 6585 { 6586 if (*cp1 == '[') 6587 break; 6588 if (*cp1 == '.') { 6589 if (*(cp1-1) != '^') 6590 break; 6591 } 6592 cp1--; 6593 } 6594 if (*cp1 == '.') *cp1 = ']'; 6595 else { 6596 memmove(cp1+8, cp1+1, buf+dirlen-cp1); 6597 memmove(cp1+1,"000000]",7); 6598 } 6599 } 6600 else { 6601 memmove(buf+dirlen, cp1+2, retlen-dirlen); 6602 buf[retlen] = '\0'; 6603 /* Convert last '.' to ']' */ 6604 cp1 = buf+retlen-1; 6605 while (*cp != '[') { 6606 cp1--; 6607 if (*cp1 == '.') { 6608 /* Do not trip on extra dots in ODS-5 directories */ 6609 if ((cp1 == buf) || (*(cp1-1) != '^')) 6610 break; 6611 } 6612 } 6613 if (*cp1 == '.') *cp1 = ']'; 6614 else { 6615 memmove(cp1+8, cp1+1, buf+dirlen-cp1); 6616 memmove(cp1+1,"000000]",7); 6617 } 6618 } 6619 } 6620 else { /* This is a top-level dir. Add the MFD to the path. */ 6621 cp1 = my_esa; 6622 cp2 = buf; 6623 while ((*cp1 != ':') && (*cp1 != '\0')) *(cp2++) = *(cp1++); 6624 strcpy(cp2,":[000000]"); 6625 cp1 += 2; 6626 strcpy(cp2+9,cp1); 6627 } 6628 } 6629 sts = rms_free_search_context(&dirfab); 6630 /* We've set up the string up through the filename. Add the 6631 type and version, and we're done. */ 6632 strcat(buf,".DIR;1"); 6633 6634 /* $PARSE may have upcased filespec, so convert output to lower 6635 * case if input contained any lowercase characters. */ 6636 if (haslower && !decc_efs_case_preserve) __mystrtolower(buf); 6637 PerlMem_free(trndir); 6638 PerlMem_free(esa); 6639 if (esal != NULL) 6640 PerlMem_free(esal); 6641 PerlMem_free(vmsdir); 6642 return buf; 6643 } 6644 } /* end of int_fileify_dirspec() */ 6645 6646 6647 /*{{{ char *fileify_dirspec[_ts](char *dir, char *buf, int * utf8_fl)*/ 6648 static char *mp_do_fileify_dirspec(pTHX_ const char *dir,char *buf,int ts, int *utf8_fl) 6649 { 6650 static char __fileify_retbuf[VMS_MAXRSS]; 6651 char * fileified, *ret_spec, *ret_buf; 6652 6653 fileified = NULL; 6654 ret_buf = buf; 6655 if (ret_buf == NULL) { 6656 if (ts) { 6657 Newx(fileified, VMS_MAXRSS, char); 6658 if (fileified == NULL) 6659 _ckvmssts(SS$_INSFMEM); 6660 ret_buf = fileified; 6661 } else { 6662 ret_buf = __fileify_retbuf; 6663 } 6664 } 6665 6666 ret_spec = int_fileify_dirspec(dir, ret_buf, utf8_fl); 6667 6668 if (ret_spec == NULL) { 6669 /* Cleanup on isle 5, if this is thread specific we need to deallocate */ 6670 if (fileified) 6671 Safefree(fileified); 6672 } 6673 6674 return ret_spec; 6675 } /* end of do_fileify_dirspec() */ 6676 /*}}}*/ 6677 6678 /* External entry points */ 6679 char *Perl_fileify_dirspec(pTHX_ const char *dir, char *buf) 6680 { return do_fileify_dirspec(dir,buf,0,NULL); } 6681 char *Perl_fileify_dirspec_ts(pTHX_ const char *dir, char *buf) 6682 { return do_fileify_dirspec(dir,buf,1,NULL); } 6683 char *Perl_fileify_dirspec_utf8(pTHX_ const char *dir, char *buf, int * utf8_fl) 6684 { return do_fileify_dirspec(dir,buf,0,utf8_fl); } 6685 char *Perl_fileify_dirspec_utf8_ts(pTHX_ const char *dir, char *buf, int * utf8_fl) 6686 { return do_fileify_dirspec(dir,buf,1,utf8_fl); } 6687 6688 static char * int_pathify_dirspec_simple(const char * dir, char * buf, 6689 char * v_spec, int v_len, char * r_spec, int r_len, 6690 char * d_spec, int d_len, char * n_spec, int n_len, 6691 char * e_spec, int e_len, char * vs_spec, int vs_len) { 6692 6693 /* VMS specification - Try to do this the simple way */ 6694 if ((v_len + r_len > 0) || (d_len > 0)) { 6695 int is_dir; 6696 6697 /* No name or extension component, already a directory */ 6698 if ((n_len + e_len + vs_len) == 0) { 6699 strcpy(buf, dir); 6700 return buf; 6701 } 6702 6703 /* Special case, we may get [.foo]bar instead of [.foo]bar.dir */ 6704 /* This results from catfile() being used instead of catdir() */ 6705 /* So even though it should not work, we need to allow it */ 6706 6707 /* If this is .DIR;1 then do a simple conversion */ 6708 is_dir = is_dir_ext(e_spec, e_len, vs_spec, vs_len); 6709 if (is_dir || (e_len == 0) && (d_len > 0)) { 6710 int len; 6711 len = v_len + r_len + d_len - 1; 6712 char dclose = d_spec[d_len - 1]; 6713 strncpy(buf, dir, len); 6714 buf[len] = '.'; 6715 len++; 6716 strncpy(&buf[len], n_spec, n_len); 6717 len += n_len; 6718 buf[len] = dclose; 6719 buf[len + 1] = '\0'; 6720 return buf; 6721 } 6722 6723 #ifdef HAS_SYMLINK 6724 else if (d_len > 0) { 6725 /* In the olden days, a directory needed to have a .DIR */ 6726 /* extension to be a valid directory, but now it could */ 6727 /* be a symbolic link */ 6728 int len; 6729 len = v_len + r_len + d_len - 1; 6730 char dclose = d_spec[d_len - 1]; 6731 strncpy(buf, dir, len); 6732 buf[len] = '.'; 6733 len++; 6734 strncpy(&buf[len], n_spec, n_len); 6735 len += n_len; 6736 if (e_len > 0) { 6737 if (decc_efs_charset) { 6738 buf[len] = '^'; 6739 len++; 6740 strncpy(&buf[len], e_spec, e_len); 6741 len += e_len; 6742 } else { 6743 set_vaxc_errno(RMS$_DIR); 6744 set_errno(ENOTDIR); 6745 return NULL; 6746 } 6747 } 6748 buf[len] = dclose; 6749 buf[len + 1] = '\0'; 6750 return buf; 6751 } 6752 #else 6753 else { 6754 set_vaxc_errno(RMS$_DIR); 6755 set_errno(ENOTDIR); 6756 return NULL; 6757 } 6758 #endif 6759 } 6760 set_vaxc_errno(RMS$_DIR); 6761 set_errno(ENOTDIR); 6762 return NULL; 6763 } 6764 6765 6766 /* Internal routine to make sure or convert a directory to be in a */ 6767 /* path specification. No utf8 flag because it is not changed or used */ 6768 static char *int_pathify_dirspec(const char *dir, char *buf) 6769 { 6770 char * v_spec, * r_spec, * d_spec, * n_spec, * e_spec, * vs_spec; 6771 int sts, v_len, r_len, d_len, n_len, e_len, vs_len; 6772 char * exp_spec, *ret_spec; 6773 char * trndir; 6774 unsigned short int trnlnm_iter_count; 6775 STRLEN trnlen; 6776 int need_to_lower; 6777 6778 if (vms_debug_fileify) { 6779 if (dir == NULL) 6780 fprintf(stderr, "int_pathify_dirspec: dir = NULL\n"); 6781 else 6782 fprintf(stderr, "int_pathify_dirspec: dir = %s\n", dir); 6783 } 6784 6785 /* We may need to lower case the result if we translated */ 6786 /* a logical name or got the current working directory */ 6787 need_to_lower = 0; 6788 6789 if (!dir || !*dir) { 6790 set_errno(EINVAL); 6791 set_vaxc_errno(SS$_BADPARAM); 6792 return NULL; 6793 } 6794 6795 trndir = PerlMem_malloc(VMS_MAXRSS); 6796 if (trndir == NULL) 6797 _ckvmssts_noperl(SS$_INSFMEM); 6798 6799 /* If no directory specified use the current default */ 6800 if (*dir) 6801 strcpy(trndir, dir); 6802 else { 6803 getcwd(trndir, VMS_MAXRSS - 1); 6804 need_to_lower = 1; 6805 } 6806 6807 /* now deal with bare names that could be logical names */ 6808 trnlnm_iter_count = 0; 6809 while (!strpbrk(trndir,"/]:>") && !no_translate_barewords 6810 && simple_trnlnm(trndir, trndir, VMS_MAXRSS)) { 6811 trnlnm_iter_count++; 6812 need_to_lower = 1; 6813 if (trnlnm_iter_count >= PERL_LNM_MAX_ITER) 6814 break; 6815 trnlen = strlen(trndir); 6816 6817 /* Trap simple rooted lnms, and return lnm:[000000] */ 6818 if (!strcmp(trndir+trnlen-2,".]")) { 6819 strcpy(buf, dir); 6820 strcat(buf, ":[000000]"); 6821 PerlMem_free(trndir); 6822 6823 if (vms_debug_fileify) { 6824 fprintf(stderr, "int_pathify_dirspec: buf = %s\n", buf); 6825 } 6826 return buf; 6827 } 6828 } 6829 6830 /* At this point we do not work with *dir, but the copy in *trndir */ 6831 6832 if (need_to_lower && !decc_efs_case_preserve) { 6833 /* Legacy mode, lower case the returned value */ 6834 __mystrtolower(trndir); 6835 } 6836 6837 6838 /* Some special cases, '..', '.' */ 6839 sts = 0; 6840 if ((trndir[0] == '.') && ((trndir[1] == '.') || (trndir[1] == '\0'))) { 6841 /* Force UNIX filespec */ 6842 sts = 1; 6843 6844 } else { 6845 /* Is this Unix or VMS format? */ 6846 sts = vms_split_path(trndir, &v_spec, &v_len, &r_spec, &r_len, 6847 &d_spec, &d_len, &n_spec, &n_len, &e_spec, 6848 &e_len, &vs_spec, &vs_len); 6849 if (sts == 0) { 6850 6851 /* Just a filename? */ 6852 if ((v_len + r_len + d_len) == 0) { 6853 6854 /* Now we have a problem, this could be Unix or VMS */ 6855 /* We have to guess. .DIR usually means VMS */ 6856 6857 /* In UNIX report mode, the .DIR extension is removed */ 6858 /* if one shows up, it is for a non-directory or a directory */ 6859 /* in EFS charset mode */ 6860 6861 /* So if we are in Unix report mode, assume that this */ 6862 /* is a relative Unix directory specification */ 6863 6864 sts = 1; 6865 if (!decc_filename_unix_report && decc_efs_charset) { 6866 int is_dir; 6867 is_dir = is_dir_ext(e_spec, e_len, vs_spec, vs_len); 6868 6869 if (is_dir) { 6870 /* Traditional mode, assume .DIR is directory */ 6871 buf[0] = '['; 6872 buf[1] = '.'; 6873 strncpy(&buf[2], n_spec, n_len); 6874 buf[n_len + 2] = ']'; 6875 buf[n_len + 3] = '\0'; 6876 PerlMem_free(trndir); 6877 if (vms_debug_fileify) { 6878 fprintf(stderr, 6879 "int_pathify_dirspec: buf = %s\n", 6880 buf); 6881 } 6882 return buf; 6883 } 6884 } 6885 } 6886 } 6887 } 6888 if (sts == 0) { 6889 ret_spec = int_pathify_dirspec_simple(trndir, buf, 6890 v_spec, v_len, r_spec, r_len, 6891 d_spec, d_len, n_spec, n_len, 6892 e_spec, e_len, vs_spec, vs_len); 6893 6894 if (ret_spec != NULL) { 6895 PerlMem_free(trndir); 6896 if (vms_debug_fileify) { 6897 fprintf(stderr, 6898 "int_pathify_dirspec: ret_spec = %s\n", ret_spec); 6899 } 6900 return ret_spec; 6901 } 6902 6903 /* Simple way did not work, which means that a logical name */ 6904 /* was present for the directory specification. */ 6905 /* Need to use an rmsexpand variant to decode it completely */ 6906 exp_spec = PerlMem_malloc(VMS_MAXRSS); 6907 if (exp_spec == NULL) 6908 _ckvmssts_noperl(SS$_INSFMEM); 6909 6910 ret_spec = int_rmsexpand_vms(trndir, exp_spec, PERL_RMSEXPAND_M_LONG); 6911 if (ret_spec != NULL) { 6912 sts = vms_split_path(exp_spec, &v_spec, &v_len, 6913 &r_spec, &r_len, &d_spec, &d_len, 6914 &n_spec, &n_len, &e_spec, 6915 &e_len, &vs_spec, &vs_len); 6916 if (sts == 0) { 6917 ret_spec = int_pathify_dirspec_simple( 6918 exp_spec, buf, v_spec, v_len, r_spec, r_len, 6919 d_spec, d_len, n_spec, n_len, 6920 e_spec, e_len, vs_spec, vs_len); 6921 6922 if ((ret_spec != NULL) && (!decc_efs_case_preserve)) { 6923 /* Legacy mode, lower case the returned value */ 6924 __mystrtolower(ret_spec); 6925 } 6926 } else { 6927 set_vaxc_errno(RMS$_DIR); 6928 set_errno(ENOTDIR); 6929 ret_spec = NULL; 6930 } 6931 } 6932 PerlMem_free(exp_spec); 6933 PerlMem_free(trndir); 6934 if (vms_debug_fileify) { 6935 if (ret_spec == NULL) 6936 fprintf(stderr, "int_pathify_dirspec: ret_spec = NULL\n"); 6937 else 6938 fprintf(stderr, 6939 "int_pathify_dirspec: ret_spec = %s\n", ret_spec); 6940 } 6941 return ret_spec; 6942 6943 } else { 6944 /* Unix specification, Could be trivial conversion */ 6945 STRLEN dir_len; 6946 dir_len = strlen(trndir); 6947 6948 /* If the extended file character set is in effect */ 6949 /* then pathify is simple */ 6950 6951 if (!decc_efs_charset) { 6952 /* Have to deal with traiing '.dir' or extra '.' */ 6953 /* that should not be there in legacy mode, but is */ 6954 6955 char * lastdot; 6956 char * lastslash; 6957 int is_dir; 6958 6959 lastslash = strrchr(trndir, '/'); 6960 if (lastslash == NULL) 6961 lastslash = trndir; 6962 else 6963 lastslash++; 6964 6965 lastdot = NULL; 6966 6967 /* '..' or '.' are valid directory components */ 6968 is_dir = 0; 6969 if (lastslash[0] == '.') { 6970 if (lastslash[1] == '\0') { 6971 is_dir = 1; 6972 } else if (lastslash[1] == '.') { 6973 if (lastslash[2] == '\0') { 6974 is_dir = 1; 6975 } else { 6976 /* And finally allow '...' */ 6977 if ((lastslash[2] == '.') && (lastslash[3] == '\0')) { 6978 is_dir = 1; 6979 } 6980 } 6981 } 6982 } 6983 6984 if (!is_dir) { 6985 lastdot = strrchr(lastslash, '.'); 6986 } 6987 if (lastdot != NULL) { 6988 STRLEN e_len; 6989 6990 /* '.dir' is discarded, and any other '.' is invalid */ 6991 e_len = strlen(lastdot); 6992 6993 is_dir = is_dir_ext(lastdot, e_len, NULL, 0); 6994 6995 if (is_dir) { 6996 dir_len = dir_len - 4; 6997 6998 } 6999 } 7000 } 7001 7002 strcpy(buf, trndir); 7003 if (buf[dir_len - 1] != '/') { 7004 buf[dir_len] = '/'; 7005 buf[dir_len + 1] = '\0'; 7006 } 7007 7008 /* Under ODS-2 rules, '.' becomes '_', so fix it up */ 7009 if (!decc_efs_charset) { 7010 int dir_start = 0; 7011 char * str = buf; 7012 if (str[0] == '.') { 7013 char * dots = str; 7014 int cnt = 1; 7015 while ((dots[cnt] == '.') && (cnt < 3)) 7016 cnt++; 7017 if (cnt <= 3) { 7018 if ((dots[cnt] == '\0') || (dots[cnt] == '/')) { 7019 dir_start = 1; 7020 str += cnt; 7021 } 7022 } 7023 } 7024 for (; *str; ++str) { 7025 while (*str == '/') { 7026 dir_start = 1; 7027 *str++; 7028 } 7029 if (dir_start) { 7030 7031 /* Have to skip up to three dots which could be */ 7032 /* directories, 3 dots being a VMS extension for Perl */ 7033 char * dots = str; 7034 int cnt = 0; 7035 while ((dots[cnt] == '.') && (cnt < 3)) { 7036 cnt++; 7037 } 7038 if (dots[cnt] == '\0') 7039 break; 7040 if ((cnt > 1) && (dots[cnt] != '/')) { 7041 dir_start = 0; 7042 } else { 7043 str += cnt; 7044 } 7045 7046 /* too many dots? */ 7047 if ((cnt == 0) || (cnt > 3)) { 7048 dir_start = 0; 7049 } 7050 } 7051 if (!dir_start && (*str == '.')) { 7052 *str = '_'; 7053 } 7054 } 7055 } 7056 PerlMem_free(trndir); 7057 ret_spec = buf; 7058 if (vms_debug_fileify) { 7059 if (ret_spec == NULL) 7060 fprintf(stderr, "int_pathify_dirspec: ret_spec = NULL\n"); 7061 else 7062 fprintf(stderr, 7063 "int_pathify_dirspec: ret_spec = %s\n", ret_spec); 7064 } 7065 return ret_spec; 7066 } 7067 } 7068 7069 /*{{{ char *pathify_dirspec[_ts](char *path, char *buf)*/ 7070 static char *mp_do_pathify_dirspec(pTHX_ const char *dir,char *buf, int ts, int * utf8_fl) 7071 { 7072 static char __pathify_retbuf[VMS_MAXRSS]; 7073 char * pathified, *ret_spec, *ret_buf; 7074 7075 pathified = NULL; 7076 ret_buf = buf; 7077 if (ret_buf == NULL) { 7078 if (ts) { 7079 Newx(pathified, VMS_MAXRSS, char); 7080 if (pathified == NULL) 7081 _ckvmssts(SS$_INSFMEM); 7082 ret_buf = pathified; 7083 } else { 7084 ret_buf = __pathify_retbuf; 7085 } 7086 } 7087 7088 ret_spec = int_pathify_dirspec(dir, ret_buf); 7089 7090 if (ret_spec == NULL) { 7091 /* Cleanup on isle 5, if this is thread specific we need to deallocate */ 7092 if (pathified) 7093 Safefree(pathified); 7094 } 7095 7096 return ret_spec; 7097 7098 } /* end of do_pathify_dirspec() */ 7099 7100 7101 /* External entry points */ 7102 char *Perl_pathify_dirspec(pTHX_ const char *dir, char *buf) 7103 { return do_pathify_dirspec(dir,buf,0,NULL); } 7104 char *Perl_pathify_dirspec_ts(pTHX_ const char *dir, char *buf) 7105 { return do_pathify_dirspec(dir,buf,1,NULL); } 7106 char *Perl_pathify_dirspec_utf8(pTHX_ const char *dir, char *buf, int *utf8_fl) 7107 { return do_pathify_dirspec(dir,buf,0,utf8_fl); } 7108 char *Perl_pathify_dirspec_utf8_ts(pTHX_ const char *dir, char *buf, int *utf8_fl) 7109 { return do_pathify_dirspec(dir,buf,1,utf8_fl); } 7110 7111 /* Internal tounixspec routine that does not use a thread context */ 7112 /*{{{ char *int_tounixspec[_ts](char *spec, char *buf, int *)*/ 7113 static char *int_tounixspec(const char *spec, char *rslt, int * utf8_fl) 7114 { 7115 char *dirend, *cp1, *cp3, *tmp; 7116 const char *cp2; 7117 int devlen, dirlen, retlen = VMS_MAXRSS; 7118 int expand = 1; /* guarantee room for leading and trailing slashes */ 7119 unsigned short int trnlnm_iter_count; 7120 int cmp_rslt; 7121 if (utf8_fl != NULL) 7122 *utf8_fl = 0; 7123 7124 if (vms_debug_fileify) { 7125 if (spec == NULL) 7126 fprintf(stderr, "int_tounixspec: spec = NULL\n"); 7127 else 7128 fprintf(stderr, "int_tounixspec: spec = %s\n", spec); 7129 } 7130 7131 7132 if (spec == NULL) { 7133 set_errno(EINVAL); 7134 set_vaxc_errno(SS$_BADPARAM); 7135 return NULL; 7136 } 7137 if (strlen(spec) > (VMS_MAXRSS-1)) { 7138 set_errno(E2BIG); 7139 set_vaxc_errno(SS$_BUFFEROVF); 7140 return NULL; 7141 } 7142 7143 /* New VMS specific format needs translation 7144 * glob passes filenames with trailing '\n' and expects this preserved. 7145 */ 7146 if (decc_posix_compliant_pathnames) { 7147 if (strncmp(spec, "\"^UP^", 5) == 0) { 7148 char * uspec; 7149 char *tunix; 7150 int tunix_len; 7151 int nl_flag; 7152 7153 tunix = PerlMem_malloc(VMS_MAXRSS); 7154 if (tunix == NULL) _ckvmssts_noperl(SS$_INSFMEM); 7155 strcpy(tunix, spec); 7156 tunix_len = strlen(tunix); 7157 nl_flag = 0; 7158 if (tunix[tunix_len - 1] == '\n') { 7159 tunix[tunix_len - 1] = '\"'; 7160 tunix[tunix_len] = '\0'; 7161 tunix_len--; 7162 nl_flag = 1; 7163 } 7164 uspec = decc$translate_vms(tunix); 7165 PerlMem_free(tunix); 7166 if ((int)uspec > 0) { 7167 strcpy(rslt,uspec); 7168 if (nl_flag) { 7169 strcat(rslt,"\n"); 7170 } 7171 else { 7172 /* If we can not translate it, makemaker wants as-is */ 7173 strcpy(rslt, spec); 7174 } 7175 return rslt; 7176 } 7177 } 7178 } 7179 7180 cmp_rslt = 0; /* Presume VMS */ 7181 cp1 = strchr(spec, '/'); 7182 if (cp1 == NULL) 7183 cmp_rslt = 0; 7184 7185 /* Look for EFS ^/ */ 7186 if (decc_efs_charset) { 7187 while (cp1 != NULL) { 7188 cp2 = cp1 - 1; 7189 if (*cp2 != '^') { 7190 /* Found illegal VMS, assume UNIX */ 7191 cmp_rslt = 1; 7192 break; 7193 } 7194 cp1++; 7195 cp1 = strchr(cp1, '/'); 7196 } 7197 } 7198 7199 /* Look for "." and ".." */ 7200 if (decc_filename_unix_report) { 7201 if (spec[0] == '.') { 7202 if ((spec[1] == '\0') || (spec[1] == '\n')) { 7203 cmp_rslt = 1; 7204 } 7205 else { 7206 if ((spec[1] == '.') && ((spec[2] == '\0') || (spec[2] == '\n'))) { 7207 cmp_rslt = 1; 7208 } 7209 } 7210 } 7211 } 7212 /* This is already UNIX or at least nothing VMS understands */ 7213 if (cmp_rslt) { 7214 strcpy(rslt,spec); 7215 if (vms_debug_fileify) { 7216 fprintf(stderr, "int_tounixspec: rslt = %s\n", rslt); 7217 } 7218 return rslt; 7219 } 7220 7221 cp1 = rslt; 7222 cp2 = spec; 7223 dirend = strrchr(spec,']'); 7224 if (dirend == NULL) dirend = strrchr(spec,'>'); 7225 if (dirend == NULL) dirend = strchr(spec,':'); 7226 if (dirend == NULL) { 7227 strcpy(rslt,spec); 7228 if (vms_debug_fileify) { 7229 fprintf(stderr, "int_tounixspec: rslt = %s\n", rslt); 7230 } 7231 return rslt; 7232 } 7233 7234 /* Special case 1 - sys$posix_root = / */ 7235 #if __CRTL_VER >= 70000000 7236 if (!decc_disable_posix_root) { 7237 if (strncasecmp(spec, "SYS$POSIX_ROOT:", 15) == 0) { 7238 *cp1 = '/'; 7239 cp1++; 7240 cp2 = cp2 + 15; 7241 } 7242 } 7243 #endif 7244 7245 /* Special case 2 - Convert NLA0: to /dev/null */ 7246 #if __CRTL_VER < 70000000 7247 cmp_rslt = strncmp(spec,"NLA0:", 5); 7248 if (cmp_rslt != 0) 7249 cmp_rslt = strncmp(spec,"nla0:", 5); 7250 #else 7251 cmp_rslt = strncasecmp(spec,"NLA0:", 5); 7252 #endif 7253 if (cmp_rslt == 0) { 7254 strcpy(rslt, "/dev/null"); 7255 cp1 = cp1 + 9; 7256 cp2 = cp2 + 5; 7257 if (spec[6] != '\0') { 7258 cp1[9] == '/'; 7259 cp1++; 7260 cp2++; 7261 } 7262 } 7263 7264 /* Also handle special case "SYS$SCRATCH:" */ 7265 #if __CRTL_VER < 70000000 7266 cmp_rslt = strncmp(spec,"SYS$SCRATCH:", 12); 7267 if (cmp_rslt != 0) 7268 cmp_rslt = strncmp(spec,"sys$scratch:", 12); 7269 #else 7270 cmp_rslt = strncasecmp(spec,"SYS$SCRATCH:", 12); 7271 #endif 7272 tmp = PerlMem_malloc(VMS_MAXRSS); 7273 if (tmp == NULL) _ckvmssts_noperl(SS$_INSFMEM); 7274 if (cmp_rslt == 0) { 7275 int islnm; 7276 7277 islnm = simple_trnlnm("TMP", tmp, VMS_MAXRSS-1); 7278 if (!islnm) { 7279 strcpy(rslt, "/tmp"); 7280 cp1 = cp1 + 4; 7281 cp2 = cp2 + 12; 7282 if (spec[12] != '\0') { 7283 cp1[4] == '/'; 7284 cp1++; 7285 cp2++; 7286 } 7287 } 7288 } 7289 7290 if (*cp2 != '[' && *cp2 != '<') { 7291 *(cp1++) = '/'; 7292 } 7293 else { /* the VMS spec begins with directories */ 7294 cp2++; 7295 if (*cp2 == ']' || *cp2 == '>') { 7296 *(cp1++) = '.'; *(cp1++) = '/'; *(cp1++) = '\0'; 7297 PerlMem_free(tmp); 7298 return rslt; 7299 } 7300 else if ( *cp2 != '^' && *cp2 != '.' && *cp2 != '-') { /* add the implied device */ 7301 if (getcwd(tmp, VMS_MAXRSS-1 ,1) == NULL) { 7302 PerlMem_free(tmp); 7303 if (vms_debug_fileify) { 7304 fprintf(stderr, "int_tounixspec: rslt = NULL\n"); 7305 } 7306 return NULL; 7307 } 7308 trnlnm_iter_count = 0; 7309 do { 7310 cp3 = tmp; 7311 while (*cp3 != ':' && *cp3) cp3++; 7312 *(cp3++) = '\0'; 7313 if (strchr(cp3,']') != NULL) break; 7314 trnlnm_iter_count++; 7315 if (trnlnm_iter_count >= PERL_LNM_MAX_ITER+1) break; 7316 } while (vmstrnenv(tmp,tmp,0,fildev,0)); 7317 cp1 = rslt; 7318 cp3 = tmp; 7319 *(cp1++) = '/'; 7320 while (*cp3) { 7321 *(cp1++) = *(cp3++); 7322 if (cp1 - rslt > (VMS_MAXRSS - 1)) { 7323 PerlMem_free(tmp); 7324 set_errno(ENAMETOOLONG); 7325 set_vaxc_errno(SS$_BUFFEROVF); 7326 if (vms_debug_fileify) { 7327 fprintf(stderr, "int_tounixspec: rslt = NULL\n"); 7328 } 7329 return NULL; /* No room */ 7330 } 7331 } 7332 *(cp1++) = '/'; 7333 } 7334 if ((*cp2 == '^')) { 7335 /* EFS file escape, pass the next character as is */ 7336 /* Fix me: HEX encoding for Unicode not implemented */ 7337 cp2++; 7338 } 7339 else if ( *cp2 == '.') { 7340 if (*(cp2+1) == '.' && *(cp2+2) == '.') { 7341 *(cp1++) = '.'; *(cp1++) = '.'; *(cp1++) = '.'; *(cp1++) = '/'; 7342 cp2 += 3; 7343 } 7344 else cp2++; 7345 } 7346 } 7347 PerlMem_free(tmp); 7348 for (; cp2 <= dirend; cp2++) { 7349 if ((*cp2 == '^')) { 7350 /* EFS file escape, pass the next character as is */ 7351 /* Fix me: HEX encoding for Unicode not implemented */ 7352 *(cp1++) = *(++cp2); 7353 /* An escaped dot stays as is -- don't convert to slash */ 7354 if (*cp2 == '.') cp2++; 7355 } 7356 if (*cp2 == ':') { 7357 *(cp1++) = '/'; 7358 if (*(cp2+1) == '[' || *(cp2+1) == '<') cp2++; 7359 } 7360 else if (*cp2 == ']' || *cp2 == '>') { 7361 if (*(cp1-1) != '/') *(cp1++) = '/'; /* Don't double after ellipsis */ 7362 } 7363 else if ((*cp2 == '.') && (*cp2-1 != '^')) { 7364 *(cp1++) = '/'; 7365 if (*(cp2+1) == ']' || *(cp2+1) == '>') { 7366 while (*(cp2+1) == ']' || *(cp2+1) == '>' || 7367 *(cp2+1) == '[' || *(cp2+1) == '<') cp2++; 7368 if (!strncmp(cp2,"[000000",7) && (*(cp2+7) == ']' || 7369 *(cp2+7) == '>' || *(cp2+7) == '.')) cp2 += 7; 7370 } 7371 else if ( *(cp2+1) == '.' && *(cp2+2) == '.') { 7372 *(cp1++) = '.'; *(cp1++) = '.'; *(cp1++) = '.'; *(cp1++) ='/'; 7373 cp2 += 2; 7374 } 7375 } 7376 else if (*cp2 == '-') { 7377 if (*(cp2-1) == '[' || *(cp2-1) == '<' || *(cp2-1) == '.') { 7378 while (*cp2 == '-') { 7379 cp2++; 7380 *(cp1++) = '.'; *(cp1++) = '.'; *(cp1++) = '/'; 7381 } 7382 if (*cp2 != '.' && *cp2 != ']' && *cp2 != '>') { /* we don't allow */ 7383 /* filespecs like */ 7384 set_errno(EINVAL); set_vaxc_errno(RMS$_SYN); /* [fred.--foo.bar] */ 7385 if (vms_debug_fileify) { 7386 fprintf(stderr, "int_tounixspec: rslt = NULL\n"); 7387 } 7388 return NULL; 7389 } 7390 } 7391 else *(cp1++) = *cp2; 7392 } 7393 else *(cp1++) = *cp2; 7394 } 7395 /* Translate the rest of the filename. */ 7396 while (*cp2) { 7397 int dot_seen; 7398 dot_seen = 0; 7399 switch(*cp2) { 7400 /* Fixme - for compatibility with the CRTL we should be removing */ 7401 /* spaces from the file specifications, but this may show that */ 7402 /* some tests that were appearing to pass are not really passing */ 7403 case '%': 7404 cp2++; 7405 *(cp1++) = '?'; 7406 break; 7407 case '^': 7408 /* Fix me hex expansions not implemented */ 7409 cp2++; /* '^.' --> '.' and other. */ 7410 if (*cp2) { 7411 if (*cp2 == '_') { 7412 cp2++; 7413 *(cp1++) = ' '; 7414 } else { 7415 *(cp1++) = *(cp2++); 7416 } 7417 } 7418 break; 7419 case ';': 7420 if (decc_filename_unix_no_version) { 7421 /* Easy, drop the version */ 7422 while (*cp2) 7423 cp2++; 7424 break; 7425 } else { 7426 /* Punt - passing the version as a dot will probably */ 7427 /* break perl in weird ways, but so did passing */ 7428 /* through the ; as a version. Follow the CRTL and */ 7429 /* hope for the best. */ 7430 cp2++; 7431 *(cp1++) = '.'; 7432 } 7433 break; 7434 case '.': 7435 if (dot_seen) { 7436 /* We will need to fix this properly later */ 7437 /* As Perl may be installed on an ODS-5 volume, but not */ 7438 /* have the EFS_CHARSET enabled, it still may encounter */ 7439 /* filenames with extra dots in them, and a precedent got */ 7440 /* set which allowed them to work, that we will uphold here */ 7441 /* If extra dots are present in a name and no ^ is on them */ 7442 /* VMS assumes that the first one is the extension delimiter */ 7443 /* the rest have an implied ^. */ 7444 7445 /* this is also a conflict as the . is also a version */ 7446 /* delimiter in VMS, */ 7447 7448 *(cp1++) = *(cp2++); 7449 break; 7450 } 7451 dot_seen = 1; 7452 /* This is an extension */ 7453 if (decc_readdir_dropdotnotype) { 7454 cp2++; 7455 if ((!*cp2) || (*cp2 == ';') || (*cp2 == '.')) { 7456 /* Drop the dot for the extension */ 7457 break; 7458 } else { 7459 *(cp1++) = '.'; 7460 } 7461 break; 7462 } 7463 default: 7464 *(cp1++) = *(cp2++); 7465 } 7466 } 7467 *cp1 = '\0'; 7468 7469 /* This still leaves /000000/ when working with a 7470 * VMS device root or concealed root. 7471 */ 7472 { 7473 int ulen; 7474 char * zeros; 7475 7476 ulen = strlen(rslt); 7477 7478 /* Get rid of "000000/ in rooted filespecs */ 7479 if (ulen > 7) { 7480 zeros = strstr(rslt, "/000000/"); 7481 if (zeros != NULL) { 7482 int mlen; 7483 mlen = ulen - (zeros - rslt) - 7; 7484 memmove(zeros, &zeros[7], mlen); 7485 ulen = ulen - 7; 7486 rslt[ulen] = '\0'; 7487 } 7488 } 7489 } 7490 7491 if (vms_debug_fileify) { 7492 fprintf(stderr, "int_tounixspec: rslt = %s\n", rslt); 7493 } 7494 return rslt; 7495 7496 } /* end of int_tounixspec() */ 7497 7498 7499 /*{{{ char *tounixspec[_ts](char *spec, char *buf, int *)*/ 7500 static char *mp_do_tounixspec(pTHX_ const char *spec, char *buf, int ts, int * utf8_fl) 7501 { 7502 static char __tounixspec_retbuf[VMS_MAXRSS]; 7503 char * unixspec, *ret_spec, *ret_buf; 7504 7505 unixspec = NULL; 7506 ret_buf = buf; 7507 if (ret_buf == NULL) { 7508 if (ts) { 7509 Newx(unixspec, VMS_MAXRSS, char); 7510 if (unixspec == NULL) 7511 _ckvmssts(SS$_INSFMEM); 7512 ret_buf = unixspec; 7513 } else { 7514 ret_buf = __tounixspec_retbuf; 7515 } 7516 } 7517 7518 ret_spec = int_tounixspec(spec, ret_buf, utf8_fl); 7519 7520 if (ret_spec == NULL) { 7521 /* Cleanup on isle 5, if this is thread specific we need to deallocate */ 7522 if (unixspec) 7523 Safefree(unixspec); 7524 } 7525 7526 return ret_spec; 7527 7528 } /* end of do_tounixspec() */ 7529 /*}}}*/ 7530 /* External entry points */ 7531 char *Perl_tounixspec(pTHX_ const char *spec, char *buf) 7532 { return do_tounixspec(spec,buf,0, NULL); } 7533 char *Perl_tounixspec_ts(pTHX_ const char *spec, char *buf) 7534 { return do_tounixspec(spec,buf,1, NULL); } 7535 char *Perl_tounixspec_utf8(pTHX_ const char *spec, char *buf, int * utf8_fl) 7536 { return do_tounixspec(spec,buf,0, utf8_fl); } 7537 char *Perl_tounixspec_utf8_ts(pTHX_ const char *spec, char *buf, int * utf8_fl) 7538 { return do_tounixspec(spec,buf,1, utf8_fl); } 7539 7540 #if __CRTL_VER >= 70200000 && !defined(__VAX) 7541 7542 /* 7543 This procedure is used to identify if a path is based in either 7544 the old SYS$POSIX_ROOT: or the new 8.3 RMS based POSIX root, and 7545 it returns the OpenVMS format directory for it. 7546 7547 It is expecting specifications of only '/' or '/xxxx/' 7548 7549 If a posix root does not exist, or 'xxxx' is not a directory 7550 in the posix root, it returns a failure. 7551 7552 FIX-ME: xxxx could be in UTF-8 and needs to be returned in VTF-7. 7553 7554 It is used only internally by posix_to_vmsspec_hardway(). 7555 */ 7556 7557 static int posix_root_to_vms 7558 (char *vmspath, int vmspath_len, 7559 const char *unixpath, 7560 const int * utf8_fl) 7561 { 7562 int sts; 7563 struct FAB myfab = cc$rms_fab; 7564 rms_setup_nam(mynam); 7565 struct dsc$descriptor_s dvidsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0}; 7566 struct dsc$descriptor_s specdsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0}; 7567 char * esa, * esal, * rsa, * rsal; 7568 char *vms_delim; 7569 int dir_flag; 7570 int unixlen; 7571 7572 dir_flag = 0; 7573 vmspath[0] = '\0'; 7574 unixlen = strlen(unixpath); 7575 if (unixlen == 0) { 7576 return RMS$_FNF; 7577 } 7578 7579 #if __CRTL_VER >= 80200000 7580 /* If not a posix spec already, convert it */ 7581 if (decc_posix_compliant_pathnames) { 7582 if (strncmp(unixpath,"\"^UP^",5) != 0) { 7583 sprintf(vmspath,"\"^UP^%s\"",unixpath); 7584 } 7585 else { 7586 /* This is already a VMS specification, no conversion */ 7587 unixlen--; 7588 strncpy(vmspath,unixpath, vmspath_len); 7589 } 7590 } 7591 else 7592 #endif 7593 { 7594 int path_len; 7595 int i,j; 7596 7597 /* Check to see if this is under the POSIX root */ 7598 if (decc_disable_posix_root) { 7599 return RMS$_FNF; 7600 } 7601 7602 /* Skip leading / */ 7603 if (unixpath[0] == '/') { 7604 unixpath++; 7605 unixlen--; 7606 } 7607 7608 7609 strcpy(vmspath,"SYS$POSIX_ROOT:"); 7610 7611 /* If this is only the / , or blank, then... */ 7612 if (unixpath[0] == '\0') { 7613 /* by definition, this is the answer */ 7614 return SS$_NORMAL; 7615 } 7616 7617 /* Need to look up a directory */ 7618 vmspath[15] = '['; 7619 vmspath[16] = '\0'; 7620 7621 /* Copy and add '^' escape characters as needed */ 7622 j = 16; 7623 i = 0; 7624 while (unixpath[i] != 0) { 7625 int k; 7626 7627 j += copy_expand_unix_filename_escape 7628 (&vmspath[j], &unixpath[i], &k, utf8_fl); 7629 i += k; 7630 } 7631 7632 path_len = strlen(vmspath); 7633 if (vmspath[path_len - 1] == '/') 7634 path_len--; 7635 vmspath[path_len] = ']'; 7636 path_len++; 7637 vmspath[path_len] = '\0'; 7638 7639 } 7640 vmspath[vmspath_len] = 0; 7641 if (unixpath[unixlen - 1] == '/') 7642 dir_flag = 1; 7643 esal = PerlMem_malloc(VMS_MAXRSS); 7644 if (esal == NULL) _ckvmssts_noperl(SS$_INSFMEM); 7645 esa = PerlMem_malloc(NAM$C_MAXRSS + 1); 7646 if (esa == NULL) _ckvmssts_noperl(SS$_INSFMEM); 7647 rsal = PerlMem_malloc(VMS_MAXRSS); 7648 if (rsal == NULL) _ckvmssts_noperl(SS$_INSFMEM); 7649 rsa = PerlMem_malloc(NAM$C_MAXRSS + 1); 7650 if (rsa == NULL) _ckvmssts_noperl(SS$_INSFMEM); 7651 rms_set_fna(myfab, mynam, (char *) vmspath, strlen(vmspath)); /* cast ok */ 7652 rms_bind_fab_nam(myfab, mynam); 7653 rms_set_esal(mynam, esa, NAM$C_MAXRSS, esal, VMS_MAXRSS - 1); 7654 rms_set_rsal(mynam, rsa, NAM$C_MAXRSS, rsal, VMS_MAXRSS - 1); 7655 if (decc_efs_case_preserve) 7656 mynam.naml$b_nop |= NAM$M_NO_SHORT_UPCASE; 7657 #ifdef NAML$M_OPEN_SPECIAL 7658 mynam.naml$l_input_flags |= NAML$M_OPEN_SPECIAL; 7659 #endif 7660 7661 /* Set up the remaining naml fields */ 7662 sts = sys$parse(&myfab); 7663 7664 /* It failed! Try again as a UNIX filespec */ 7665 if (!(sts & 1)) { 7666 PerlMem_free(esal); 7667 PerlMem_free(esa); 7668 PerlMem_free(rsal); 7669 PerlMem_free(rsa); 7670 return sts; 7671 } 7672 7673 /* get the Device ID and the FID */ 7674 sts = sys$search(&myfab); 7675 7676 /* These are no longer needed */ 7677 PerlMem_free(esa); 7678 PerlMem_free(rsal); 7679 PerlMem_free(rsa); 7680 7681 /* on any failure, returned the POSIX ^UP^ filespec */ 7682 if (!(sts & 1)) { 7683 PerlMem_free(esal); 7684 return sts; 7685 } 7686 specdsc.dsc$a_pointer = vmspath; 7687 specdsc.dsc$w_length = vmspath_len; 7688 7689 dvidsc.dsc$a_pointer = &mynam.naml$t_dvi[1]; 7690 dvidsc.dsc$w_length = mynam.naml$t_dvi[0]; 7691 sts = lib$fid_to_name 7692 (&dvidsc, mynam.naml$w_fid, &specdsc, &specdsc.dsc$w_length); 7693 7694 /* on any failure, returned the POSIX ^UP^ filespec */ 7695 if (!(sts & 1)) { 7696 /* This can happen if user does not have permission to read directories */ 7697 if (strncmp(unixpath,"\"^UP^",5) != 0) 7698 sprintf(vmspath,"\"^UP^%s\"",unixpath); 7699 else 7700 strcpy(vmspath, unixpath); 7701 } 7702 else { 7703 vmspath[specdsc.dsc$w_length] = 0; 7704 7705 /* Are we expecting a directory? */ 7706 if (dir_flag != 0) { 7707 int i; 7708 char *eptr; 7709 7710 eptr = NULL; 7711 7712 i = specdsc.dsc$w_length - 1; 7713 while (i > 0) { 7714 int zercnt; 7715 zercnt = 0; 7716 /* Version must be '1' */ 7717 if (vmspath[i--] != '1') 7718 break; 7719 /* Version delimiter is one of ".;" */ 7720 if ((vmspath[i] != '.') && (vmspath[i] != ';')) 7721 break; 7722 i--; 7723 if (vmspath[i--] != 'R') 7724 break; 7725 if (vmspath[i--] != 'I') 7726 break; 7727 if (vmspath[i--] != 'D') 7728 break; 7729 if (vmspath[i--] != '.') 7730 break; 7731 eptr = &vmspath[i+1]; 7732 while (i > 0) { 7733 if ((vmspath[i] == ']') || (vmspath[i] == '>')) { 7734 if (vmspath[i-1] != '^') { 7735 if (zercnt != 6) { 7736 *eptr = vmspath[i]; 7737 eptr[1] = '\0'; 7738 vmspath[i] = '.'; 7739 break; 7740 } 7741 else { 7742 /* Get rid of 6 imaginary zero directory filename */ 7743 vmspath[i+1] = '\0'; 7744 } 7745 } 7746 } 7747 if (vmspath[i] == '0') 7748 zercnt++; 7749 else 7750 zercnt = 10; 7751 i--; 7752 } 7753 break; 7754 } 7755 } 7756 } 7757 PerlMem_free(esal); 7758 return sts; 7759 } 7760 7761 /* /dev/mumble needs to be handled special. 7762 /dev/null becomes NLA0:, And there is the potential for other stuff 7763 like /dev/tty which may need to be mapped to something. 7764 */ 7765 7766 static int 7767 slash_dev_special_to_vms 7768 (const char * unixptr, 7769 char * vmspath, 7770 int vmspath_len) 7771 { 7772 char * nextslash; 7773 int len; 7774 int cmp; 7775 int islnm; 7776 7777 unixptr += 4; 7778 nextslash = strchr(unixptr, '/'); 7779 len = strlen(unixptr); 7780 if (nextslash != NULL) 7781 len = nextslash - unixptr; 7782 cmp = strncmp("null", unixptr, 5); 7783 if (cmp == 0) { 7784 if (vmspath_len >= 6) { 7785 strcpy(vmspath, "_NLA0:"); 7786 return SS$_NORMAL; 7787 } 7788 } 7789 } 7790 7791 7792 /* The built in routines do not understand perl's special needs, so 7793 doing a manual conversion from UNIX to VMS 7794 7795 If the utf8_fl is not null and points to a non-zero value, then 7796 treat 8 bit characters as UTF-8. 7797 7798 The sequence starting with '$(' and ending with ')' will be passed 7799 through with out interpretation instead of being escaped. 7800 7801 */ 7802 static int posix_to_vmsspec_hardway 7803 (char *vmspath, int vmspath_len, 7804 const char *unixpath, 7805 int dir_flag, 7806 int * utf8_fl) { 7807 7808 char *esa; 7809 const char *unixptr; 7810 const char *unixend; 7811 char *vmsptr; 7812 const char *lastslash; 7813 const char *lastdot; 7814 int unixlen; 7815 int vmslen; 7816 int dir_start; 7817 int dir_dot; 7818 int quoted; 7819 char * v_spec, * r_spec, * d_spec, * n_spec, * e_spec, * vs_spec; 7820 int sts, v_len, r_len, d_len, n_len, e_len, vs_len; 7821 7822 if (utf8_fl != NULL) 7823 *utf8_fl = 0; 7824 7825 unixptr = unixpath; 7826 dir_dot = 0; 7827 7828 /* Ignore leading "/" characters */ 7829 while((unixptr[0] == '/') && (unixptr[1] == '/')) { 7830 unixptr++; 7831 } 7832 unixlen = strlen(unixptr); 7833 7834 /* Do nothing with blank paths */ 7835 if (unixlen == 0) { 7836 vmspath[0] = '\0'; 7837 return SS$_NORMAL; 7838 } 7839 7840 quoted = 0; 7841 /* This could have a "^UP^ on the front */ 7842 if (strncmp(unixptr,"\"^UP^",5) == 0) { 7843 quoted = 1; 7844 unixptr+= 5; 7845 unixlen-= 5; 7846 } 7847 7848 lastslash = strrchr(unixptr,'/'); 7849 lastdot = strrchr(unixptr,'.'); 7850 unixend = strrchr(unixptr,'\"'); 7851 if (!quoted || !((unixend != NULL) && (unixend[1] == '\0'))) { 7852 unixend = unixptr + unixlen; 7853 } 7854 7855 /* last dot is last dot or past end of string */ 7856 if (lastdot == NULL) 7857 lastdot = unixptr + unixlen; 7858 7859 /* if no directories, set last slash to beginning of string */ 7860 if (lastslash == NULL) { 7861 lastslash = unixptr; 7862 } 7863 else { 7864 /* Watch out for trailing "." after last slash, still a directory */ 7865 if ((lastslash[1] == '.') && (lastslash[2] == '\0')) { 7866 lastslash = unixptr + unixlen; 7867 } 7868 7869 /* Watch out for traiing ".." after last slash, still a directory */ 7870 if ((lastslash[1] == '.')&&(lastslash[2] == '.')&&(lastslash[3] == '\0')) { 7871 lastslash = unixptr + unixlen; 7872 } 7873 7874 /* dots in directories are aways escaped */ 7875 if (lastdot < lastslash) 7876 lastdot = unixptr + unixlen; 7877 } 7878 7879 /* if (unixptr < lastslash) then we are in a directory */ 7880 7881 dir_start = 0; 7882 7883 vmsptr = vmspath; 7884 vmslen = 0; 7885 7886 /* Start with the UNIX path */ 7887 if (*unixptr != '/') { 7888 /* relative paths */ 7889 7890 /* If allowing logical names on relative pathnames, then handle here */ 7891 if ((unixptr[0] != '.') && !decc_disable_to_vms_logname_translation && 7892 !decc_posix_compliant_pathnames) { 7893 char * nextslash; 7894 int seg_len; 7895 char * trn; 7896 int islnm; 7897 7898 /* Find the next slash */ 7899 nextslash = strchr(unixptr,'/'); 7900 7901 esa = PerlMem_malloc(vmspath_len); 7902 if (esa == NULL) _ckvmssts_noperl(SS$_INSFMEM); 7903 7904 trn = PerlMem_malloc(VMS_MAXRSS); 7905 if (trn == NULL) _ckvmssts_noperl(SS$_INSFMEM); 7906 7907 if (nextslash != NULL) { 7908 7909 seg_len = nextslash - unixptr; 7910 strncpy(esa, unixptr, seg_len); 7911 esa[seg_len] = 0; 7912 } 7913 else { 7914 strcpy(esa, unixptr); 7915 seg_len = strlen(unixptr); 7916 } 7917 /* trnlnm(section) */ 7918 islnm = vmstrnenv(esa, trn, 0, fildev, 0); 7919 7920 if (islnm) { 7921 /* Now fix up the directory */ 7922 7923 /* Split up the path to find the components */ 7924 sts = vms_split_path 7925 (trn, 7926 &v_spec, 7927 &v_len, 7928 &r_spec, 7929 &r_len, 7930 &d_spec, 7931 &d_len, 7932 &n_spec, 7933 &n_len, 7934 &e_spec, 7935 &e_len, 7936 &vs_spec, 7937 &vs_len); 7938 7939 while (sts == 0) { 7940 char * strt; 7941 int cmp; 7942 7943 /* A logical name must be a directory or the full 7944 specification. It is only a full specification if 7945 it is the only component */ 7946 if ((unixptr[seg_len] == '\0') || 7947 (unixptr[seg_len+1] == '\0')) { 7948 7949 /* Is a directory being required? */ 7950 if (((n_len + e_len) != 0) && (dir_flag !=0)) { 7951 /* Not a logical name */ 7952 break; 7953 } 7954 7955 7956 if ((unixptr[seg_len] == '/') || (dir_flag != 0)) { 7957 /* This must be a directory */ 7958 if (((n_len + e_len) == 0)&&(seg_len <= vmspath_len)) { 7959 strcpy(vmsptr, esa); 7960 vmslen=strlen(vmsptr); 7961 vmsptr[vmslen] = ':'; 7962 vmslen++; 7963 vmsptr[vmslen] = '\0'; 7964 return SS$_NORMAL; 7965 } 7966 } 7967 7968 } 7969 7970 7971 /* must be dev/directory - ignore version */ 7972 if ((n_len + e_len) != 0) 7973 break; 7974 7975 /* transfer the volume */ 7976 if (v_len > 0 && ((v_len + vmslen) < vmspath_len)) { 7977 strncpy(vmsptr, v_spec, v_len); 7978 vmsptr += v_len; 7979 vmsptr[0] = '\0'; 7980 vmslen += v_len; 7981 } 7982 7983 /* unroot the rooted directory */ 7984 if ((r_len > 0) && ((r_len + d_len + vmslen) < vmspath_len)) { 7985 r_spec[0] = '['; 7986 r_spec[r_len - 1] = ']'; 7987 7988 /* This should not be there, but nothing is perfect */ 7989 if (r_len > 9) { 7990 cmp = strcmp(&r_spec[1], "000000."); 7991 if (cmp == 0) { 7992 r_spec += 7; 7993 r_spec[7] = '['; 7994 r_len -= 7; 7995 if (r_len == 2) 7996 r_len = 0; 7997 } 7998 } 7999 if (r_len > 0) { 8000 strncpy(vmsptr, r_spec, r_len); 8001 vmsptr += r_len; 8002 vmslen += r_len; 8003 vmsptr[0] = '\0'; 8004 } 8005 } 8006 /* Bring over the directory. */ 8007 if ((d_len > 0) && 8008 ((d_len + vmslen) < vmspath_len)) { 8009 d_spec[0] = '['; 8010 d_spec[d_len - 1] = ']'; 8011 if (d_len > 9) { 8012 cmp = strcmp(&d_spec[1], "000000."); 8013 if (cmp == 0) { 8014 d_spec += 7; 8015 d_spec[7] = '['; 8016 d_len -= 7; 8017 if (d_len == 2) 8018 d_len = 0; 8019 } 8020 } 8021 8022 if (r_len > 0) { 8023 /* Remove the redundant root */ 8024 if (r_len > 0) { 8025 /* remove the ][ */ 8026 vmsptr--; 8027 vmslen--; 8028 d_spec++; 8029 d_len--; 8030 } 8031 strncpy(vmsptr, d_spec, d_len); 8032 vmsptr += d_len; 8033 vmslen += d_len; 8034 vmsptr[0] = '\0'; 8035 } 8036 } 8037 break; 8038 } 8039 } 8040 8041 PerlMem_free(esa); 8042 PerlMem_free(trn); 8043 } 8044 8045 if (lastslash > unixptr) { 8046 int dotdir_seen; 8047 8048 /* skip leading ./ */ 8049 dotdir_seen = 0; 8050 while ((unixptr[0] == '.') && (unixptr[1] == '/')) { 8051 dotdir_seen = 1; 8052 unixptr++; 8053 unixptr++; 8054 } 8055 8056 /* Are we still in a directory? */ 8057 if (unixptr <= lastslash) { 8058 *vmsptr++ = '['; 8059 vmslen = 1; 8060 dir_start = 1; 8061 8062 /* if not backing up, then it is relative forward. */ 8063 if (!((*unixptr == '.') && (unixptr[1] == '.') && 8064 ((unixptr[2] == '/') || (&unixptr[2] == unixend)))) { 8065 *vmsptr++ = '.'; 8066 vmslen++; 8067 dir_dot = 1; 8068 } 8069 } 8070 else { 8071 if (dotdir_seen) { 8072 /* Perl wants an empty directory here to tell the difference 8073 * between a DCL commmand and a filename 8074 */ 8075 *vmsptr++ = '['; 8076 *vmsptr++ = ']'; 8077 vmslen = 2; 8078 } 8079 } 8080 } 8081 else { 8082 /* Handle two special files . and .. */ 8083 if (unixptr[0] == '.') { 8084 if (&unixptr[1] == unixend) { 8085 *vmsptr++ = '['; 8086 *vmsptr++ = ']'; 8087 vmslen += 2; 8088 *vmsptr++ = '\0'; 8089 return SS$_NORMAL; 8090 } 8091 if ((unixptr[1] == '.') && (&unixptr[2] == unixend)) { 8092 *vmsptr++ = '['; 8093 *vmsptr++ = '-'; 8094 *vmsptr++ = ']'; 8095 vmslen += 3; 8096 *vmsptr++ = '\0'; 8097 return SS$_NORMAL; 8098 } 8099 } 8100 } 8101 } 8102 else { /* Absolute PATH handling */ 8103 int sts; 8104 char * nextslash; 8105 int seg_len; 8106 /* Need to find out where root is */ 8107 8108 /* In theory, this procedure should never get an absolute POSIX pathname 8109 * that can not be found on the POSIX root. 8110 * In practice, that can not be relied on, and things will show up 8111 * here that are a VMS device name or concealed logical name instead. 8112 * So to make things work, this procedure must be tolerant. 8113 */ 8114 esa = PerlMem_malloc(vmspath_len); 8115 if (esa == NULL) _ckvmssts_noperl(SS$_INSFMEM); 8116 8117 sts = SS$_NORMAL; 8118 nextslash = strchr(&unixptr[1],'/'); 8119 seg_len = 0; 8120 if (nextslash != NULL) { 8121 int cmp; 8122 seg_len = nextslash - &unixptr[1]; 8123 strncpy(vmspath, unixptr, seg_len + 1); 8124 vmspath[seg_len+1] = 0; 8125 cmp = 1; 8126 if (seg_len == 3) { 8127 cmp = strncmp(vmspath, "dev", 4); 8128 if (cmp == 0) { 8129 sts = slash_dev_special_to_vms(unixptr, vmspath, vmspath_len); 8130 if (sts = SS$_NORMAL) 8131 return SS$_NORMAL; 8132 } 8133 } 8134 sts = posix_root_to_vms(esa, vmspath_len, vmspath, utf8_fl); 8135 } 8136 8137 if ($VMS_STATUS_SUCCESS(sts)) { 8138 /* This is verified to be a real path */ 8139 8140 sts = posix_root_to_vms(esa, vmspath_len, "/", NULL); 8141 if ($VMS_STATUS_SUCCESS(sts)) { 8142 strcpy(vmspath, esa); 8143 vmslen = strlen(vmspath); 8144 vmsptr = vmspath + vmslen; 8145 unixptr++; 8146 if (unixptr < lastslash) { 8147 char * rptr; 8148 vmsptr--; 8149 *vmsptr++ = '.'; 8150 dir_start = 1; 8151 dir_dot = 1; 8152 if (vmslen > 7) { 8153 int cmp; 8154 rptr = vmsptr - 7; 8155 cmp = strcmp(rptr,"000000."); 8156 if (cmp == 0) { 8157 vmslen -= 7; 8158 vmsptr -= 7; 8159 vmsptr[1] = '\0'; 8160 } /* removing 6 zeros */ 8161 } /* vmslen < 7, no 6 zeros possible */ 8162 } /* Not in a directory */ 8163 } /* Posix root found */ 8164 else { 8165 /* No posix root, fall back to default directory */ 8166 strcpy(vmspath, "SYS$DISK:["); 8167 vmsptr = &vmspath[10]; 8168 vmslen = 10; 8169 if (unixptr > lastslash) { 8170 *vmsptr = ']'; 8171 vmsptr++; 8172 vmslen++; 8173 } 8174 else { 8175 dir_start = 1; 8176 } 8177 } 8178 } /* end of verified real path handling */ 8179 else { 8180 int add_6zero; 8181 int islnm; 8182 8183 /* Ok, we have a device or a concealed root that is not in POSIX 8184 * or we have garbage. Make the best of it. 8185 */ 8186 8187 /* Posix to VMS destroyed this, so copy it again */ 8188 strncpy(vmspath, &unixptr[1], seg_len); 8189 vmspath[seg_len] = 0; 8190 vmslen = seg_len; 8191 vmsptr = &vmsptr[vmslen]; 8192 islnm = 0; 8193 8194 /* Now do we need to add the fake 6 zero directory to it? */ 8195 add_6zero = 1; 8196 if ((*lastslash == '/') && (nextslash < lastslash)) { 8197 /* No there is another directory */ 8198 add_6zero = 0; 8199 } 8200 else { 8201 int trnend; 8202 int cmp; 8203 8204 /* now we have foo:bar or foo:[000000]bar to decide from */ 8205 islnm = vmstrnenv(vmspath, esa, 0, fildev, 0); 8206 8207 if (!islnm && !decc_posix_compliant_pathnames) { 8208 8209 cmp = strncmp("bin", vmspath, 4); 8210 if (cmp == 0) { 8211 /* bin => SYS$SYSTEM: */ 8212 islnm = vmstrnenv("SYS$SYSTEM:", esa, 0, fildev, 0); 8213 } 8214 else { 8215 /* tmp => SYS$SCRATCH: */ 8216 cmp = strncmp("tmp", vmspath, 4); 8217 if (cmp == 0) { 8218 islnm = vmstrnenv("SYS$SCRATCH:", esa, 0, fildev, 0); 8219 } 8220 } 8221 } 8222 8223 trnend = islnm ? islnm - 1 : 0; 8224 8225 /* if this was a logical name, ']' or '>' must be present */ 8226 /* if not a logical name, then assume a device and hope. */ 8227 islnm = trnend ? (esa[trnend] == ']' || esa[trnend] == '>') : 0; 8228 8229 /* if log name and trailing '.' then rooted - treat as device */ 8230 add_6zero = islnm ? (esa[trnend-1] == '.') : 0; 8231 8232 /* Fix me, if not a logical name, a device lookup should be 8233 * done to see if the device is file structured. If the device 8234 * is not file structured, the 6 zeros should not be put on. 8235 * 8236 * As it is, perl is occasionally looking for dev:[000000]tty. 8237 * which looks a little strange. 8238 * 8239 * Not that easy to detect as "/dev" may be file structured with 8240 * special device files. 8241 */ 8242 8243 if (!islnm && (add_6zero == 0) && (*nextslash == '/') && 8244 (&nextslash[1] == unixend)) { 8245 /* No real directory present */ 8246 add_6zero = 1; 8247 } 8248 } 8249 8250 /* Put the device delimiter on */ 8251 *vmsptr++ = ':'; 8252 vmslen++; 8253 unixptr = nextslash; 8254 unixptr++; 8255 8256 /* Start directory if needed */ 8257 if (!islnm || add_6zero) { 8258 *vmsptr++ = '['; 8259 vmslen++; 8260 dir_start = 1; 8261 } 8262 8263 /* add fake 000000] if needed */ 8264 if (add_6zero) { 8265 *vmsptr++ = '0'; 8266 *vmsptr++ = '0'; 8267 *vmsptr++ = '0'; 8268 *vmsptr++ = '0'; 8269 *vmsptr++ = '0'; 8270 *vmsptr++ = '0'; 8271 *vmsptr++ = ']'; 8272 vmslen += 7; 8273 dir_start = 0; 8274 } 8275 8276 } /* non-POSIX translation */ 8277 PerlMem_free(esa); 8278 } /* End of relative/absolute path handling */ 8279 8280 while ((unixptr <= unixend) && (vmslen < vmspath_len)){ 8281 int dash_flag; 8282 int in_cnt; 8283 int out_cnt; 8284 8285 dash_flag = 0; 8286 8287 if (dir_start != 0) { 8288 8289 /* First characters in a directory are handled special */ 8290 while ((*unixptr == '/') || 8291 ((*unixptr == '.') && 8292 ((unixptr[1]=='.') || (unixptr[1]=='/') || 8293 (&unixptr[1]==unixend)))) { 8294 int loop_flag; 8295 8296 loop_flag = 0; 8297 8298 /* Skip redundant / in specification */ 8299 while ((*unixptr == '/') && (dir_start != 0)) { 8300 loop_flag = 1; 8301 unixptr++; 8302 if (unixptr == lastslash) 8303 break; 8304 } 8305 if (unixptr == lastslash) 8306 break; 8307 8308 /* Skip redundant ./ characters */ 8309 while ((*unixptr == '.') && 8310 ((unixptr[1] == '/')||(&unixptr[1] == unixend))) { 8311 loop_flag = 1; 8312 unixptr++; 8313 if (unixptr == lastslash) 8314 break; 8315 if (*unixptr == '/') 8316 unixptr++; 8317 } 8318 if (unixptr == lastslash) 8319 break; 8320 8321 /* Skip redundant ../ characters */ 8322 while ((*unixptr == '.') && (unixptr[1] == '.') && 8323 ((unixptr[2] == '/') || (&unixptr[2] == unixend))) { 8324 /* Set the backing up flag */ 8325 loop_flag = 1; 8326 dir_dot = 0; 8327 dash_flag = 1; 8328 *vmsptr++ = '-'; 8329 vmslen++; 8330 unixptr++; /* first . */ 8331 unixptr++; /* second . */ 8332 if (unixptr == lastslash) 8333 break; 8334 if (*unixptr == '/') /* The slash */ 8335 unixptr++; 8336 } 8337 if (unixptr == lastslash) 8338 break; 8339 8340 /* To do: Perl expects /.../ to be translated to [...] on VMS */ 8341 /* Not needed when VMS is pretending to be UNIX. */ 8342 8343 /* Is this loop stuck because of too many dots? */ 8344 if (loop_flag == 0) { 8345 /* Exit the loop and pass the rest through */ 8346 break; 8347 } 8348 } 8349 8350 /* Are we done with directories yet? */ 8351 if (unixptr >= lastslash) { 8352 8353 /* Watch out for trailing dots */ 8354 if (dir_dot != 0) { 8355 vmslen --; 8356 vmsptr--; 8357 } 8358 *vmsptr++ = ']'; 8359 vmslen++; 8360 dash_flag = 0; 8361 dir_start = 0; 8362 if (*unixptr == '/') 8363 unixptr++; 8364 } 8365 else { 8366 /* Have we stopped backing up? */ 8367 if (dash_flag) { 8368 *vmsptr++ = '.'; 8369 vmslen++; 8370 dash_flag = 0; 8371 /* dir_start continues to be = 1 */ 8372 } 8373 if (*unixptr == '-') { 8374 *vmsptr++ = '^'; 8375 *vmsptr++ = *unixptr++; 8376 vmslen += 2; 8377 dir_start = 0; 8378 8379 /* Now are we done with directories yet? */ 8380 if (unixptr >= lastslash) { 8381 8382 /* Watch out for trailing dots */ 8383 if (dir_dot != 0) { 8384 vmslen --; 8385 vmsptr--; 8386 } 8387 8388 *vmsptr++ = ']'; 8389 vmslen++; 8390 dash_flag = 0; 8391 dir_start = 0; 8392 } 8393 } 8394 } 8395 } 8396 8397 /* All done? */ 8398 if (unixptr >= unixend) 8399 break; 8400 8401 /* Normal characters - More EFS work probably needed */ 8402 dir_start = 0; 8403 dir_dot = 0; 8404 8405 switch(*unixptr) { 8406 case '/': 8407 /* remove multiple / */ 8408 while (unixptr[1] == '/') { 8409 unixptr++; 8410 } 8411 if (unixptr == lastslash) { 8412 /* Watch out for trailing dots */ 8413 if (dir_dot != 0) { 8414 vmslen --; 8415 vmsptr--; 8416 } 8417 *vmsptr++ = ']'; 8418 } 8419 else { 8420 dir_start = 1; 8421 *vmsptr++ = '.'; 8422 dir_dot = 1; 8423 8424 /* To do: Perl expects /.../ to be translated to [...] on VMS */ 8425 /* Not needed when VMS is pretending to be UNIX. */ 8426 8427 } 8428 dash_flag = 0; 8429 if (unixptr != unixend) 8430 unixptr++; 8431 vmslen++; 8432 break; 8433 case '.': 8434 if ((unixptr < lastdot) || (unixptr < lastslash) || 8435 (&unixptr[1] == unixend)) { 8436 *vmsptr++ = '^'; 8437 *vmsptr++ = '.'; 8438 vmslen += 2; 8439 unixptr++; 8440 8441 /* trailing dot ==> '^..' on VMS */ 8442 if (unixptr == unixend) { 8443 *vmsptr++ = '.'; 8444 vmslen++; 8445 unixptr++; 8446 } 8447 break; 8448 } 8449 8450 *vmsptr++ = *unixptr++; 8451 vmslen ++; 8452 break; 8453 case '"': 8454 if (quoted && (&unixptr[1] == unixend)) { 8455 unixptr++; 8456 break; 8457 } 8458 in_cnt = copy_expand_unix_filename_escape 8459 (vmsptr, unixptr, &out_cnt, utf8_fl); 8460 vmsptr += out_cnt; 8461 unixptr += in_cnt; 8462 break; 8463 case '~': 8464 case ';': 8465 case '\\': 8466 case '?': 8467 case ' ': 8468 default: 8469 in_cnt = copy_expand_unix_filename_escape 8470 (vmsptr, unixptr, &out_cnt, utf8_fl); 8471 vmsptr += out_cnt; 8472 unixptr += in_cnt; 8473 break; 8474 } 8475 } 8476 8477 /* Make sure directory is closed */ 8478 if (unixptr == lastslash) { 8479 char *vmsptr2; 8480 vmsptr2 = vmsptr - 1; 8481 8482 if (*vmsptr2 != ']') { 8483 *vmsptr2--; 8484 8485 /* directories do not end in a dot bracket */ 8486 if (*vmsptr2 == '.') { 8487 vmsptr2--; 8488 8489 /* ^. is allowed */ 8490 if (*vmsptr2 != '^') { 8491 vmsptr--; /* back up over the dot */ 8492 } 8493 } 8494 *vmsptr++ = ']'; 8495 } 8496 } 8497 else { 8498 char *vmsptr2; 8499 /* Add a trailing dot if a file with no extension */ 8500 vmsptr2 = vmsptr - 1; 8501 if ((vmslen > 1) && 8502 (*vmsptr2 != ']') && (*vmsptr2 != '*') && (*vmsptr2 != '%') && 8503 (*vmsptr2 != ')') && (*lastdot != '.') && (*vmsptr2 != ':')) { 8504 *vmsptr++ = '.'; 8505 vmslen++; 8506 } 8507 } 8508 8509 *vmsptr = '\0'; 8510 return SS$_NORMAL; 8511 } 8512 #endif 8513 8514 /* Eventual routine to convert a UTF-8 specification to VTF-7. */ 8515 static char * utf8_to_vtf7(char * rslt, const char * path, int *utf8_fl) 8516 { 8517 char * result; 8518 int utf8_flag; 8519 8520 /* If a UTF8 flag is being passed, honor it */ 8521 utf8_flag = 0; 8522 if (utf8_fl != NULL) { 8523 utf8_flag = *utf8_fl; 8524 *utf8_fl = 0; 8525 } 8526 8527 if (utf8_flag) { 8528 /* If there is a possibility of UTF8, then if any UTF8 characters 8529 are present, then they must be converted to VTF-7 8530 */ 8531 result = strcpy(rslt, path); /* FIX-ME */ 8532 } 8533 else 8534 result = strcpy(rslt, path); 8535 8536 return result; 8537 } 8538 8539 8540 8541 /*{{{ char *tovmsspec[_ts](char *path, char *buf, int * utf8_flag)*/ 8542 static char *int_tovmsspec 8543 (const char *path, char *rslt, int dir_flag, int * utf8_flag) { 8544 char *dirend; 8545 char *lastdot; 8546 char *vms_delim; 8547 register char *cp1; 8548 const char *cp2; 8549 unsigned long int infront = 0, hasdir = 1; 8550 int rslt_len; 8551 int no_type_seen; 8552 char * v_spec, * r_spec, * d_spec, * n_spec, * e_spec, * vs_spec; 8553 int sts, v_len, r_len, d_len, n_len, e_len, vs_len; 8554 8555 if (vms_debug_fileify) { 8556 if (path == NULL) 8557 fprintf(stderr, "int_tovmsspec: path = NULL\n"); 8558 else 8559 fprintf(stderr, "int_tovmsspec: path = %s\n", path); 8560 } 8561 8562 if (path == NULL) { 8563 /* If we fail, we should be setting errno */ 8564 set_errno(EINVAL); 8565 set_vaxc_errno(SS$_BADPARAM); 8566 return NULL; 8567 } 8568 rslt_len = VMS_MAXRSS-1; 8569 8570 /* '.' and '..' are "[]" and "[-]" for a quick check */ 8571 if (path[0] == '.') { 8572 if (path[1] == '\0') { 8573 strcpy(rslt,"[]"); 8574 if (utf8_flag != NULL) 8575 *utf8_flag = 0; 8576 return rslt; 8577 } 8578 else { 8579 if (path[1] == '.' && path[2] == '\0') { 8580 strcpy(rslt,"[-]"); 8581 if (utf8_flag != NULL) 8582 *utf8_flag = 0; 8583 return rslt; 8584 } 8585 } 8586 } 8587 8588 /* Posix specifications are now a native VMS format */ 8589 /*--------------------------------------------------*/ 8590 #if __CRTL_VER >= 80200000 && !defined(__VAX) 8591 if (decc_posix_compliant_pathnames) { 8592 if (strncmp(path,"\"^UP^",5) == 0) { 8593 posix_to_vmsspec_hardway(rslt, rslt_len, path, dir_flag, utf8_flag); 8594 return rslt; 8595 } 8596 } 8597 #endif 8598 8599 /* This is really the only way to see if this is already in VMS format */ 8600 sts = vms_split_path 8601 (path, 8602 &v_spec, 8603 &v_len, 8604 &r_spec, 8605 &r_len, 8606 &d_spec, 8607 &d_len, 8608 &n_spec, 8609 &n_len, 8610 &e_spec, 8611 &e_len, 8612 &vs_spec, 8613 &vs_len); 8614 if (sts == 0) { 8615 /* FIX-ME - If dir_flag is non-zero, then this is a mp_do_vmspath() 8616 replacement, because the above parse just took care of most of 8617 what is needed to do vmspath when the specification is already 8618 in VMS format. 8619 8620 And if it is not already, it is easier to do the conversion as 8621 part of this routine than to call this routine and then work on 8622 the result. 8623 */ 8624 8625 /* If VMS punctuation was found, it is already VMS format */ 8626 if ((v_len != 0) || (r_len != 0) || (d_len != 0) || (vs_len != 0)) { 8627 if (utf8_flag != NULL) 8628 *utf8_flag = 0; 8629 strcpy(rslt, path); 8630 if (vms_debug_fileify) { 8631 fprintf(stderr, "int_tovmsspec: rslt = %s\n", rslt); 8632 } 8633 return rslt; 8634 } 8635 /* Now, what to do with trailing "." cases where there is no 8636 extension? If this is a UNIX specification, and EFS characters 8637 are enabled, then the trailing "." should be converted to a "^.". 8638 But if this was already a VMS specification, then it should be 8639 left alone. 8640 8641 So in the case of ambiguity, leave the specification alone. 8642 */ 8643 8644 8645 /* If there is a possibility of UTF8, then if any UTF8 characters 8646 are present, then they must be converted to VTF-7 8647 */ 8648 if (utf8_flag != NULL) 8649 *utf8_flag = 0; 8650 strcpy(rslt, path); 8651 if (vms_debug_fileify) { 8652 fprintf(stderr, "int_tovmsspec: rslt = %s\n", rslt); 8653 } 8654 return rslt; 8655 } 8656 8657 dirend = strrchr(path,'/'); 8658 8659 if (dirend == NULL) { 8660 char *macro_start; 8661 int has_macro; 8662 8663 /* If we get here with no UNIX directory delimiters, then this is 8664 not a complete file specification, either garbage a UNIX glob 8665 specification that can not be converted to a VMS wildcard, or 8666 it a UNIX shell macro. MakeMaker wants shell macros passed 8667 through AS-IS, 8668 8669 utf8 flag setting needs to be preserved. 8670 */ 8671 hasdir = 0; 8672 8673 has_macro = 0; 8674 macro_start = strchr(path,'$'); 8675 if (macro_start != NULL) { 8676 if (macro_start[1] == '(') { 8677 has_macro = 1; 8678 } 8679 } 8680 if ((decc_efs_charset == 0) || (has_macro)) { 8681 strcpy(rslt, path); 8682 if (vms_debug_fileify) { 8683 fprintf(stderr, "int_tovmsspec: rslt = %s\n", rslt); 8684 } 8685 return rslt; 8686 } 8687 } 8688 8689 /* If EFS charset mode active, handle the conversion */ 8690 #if __CRTL_VER >= 80200000 && !defined(__VAX) 8691 if (decc_efs_charset) { 8692 posix_to_vmsspec_hardway(rslt, rslt_len, path, dir_flag, utf8_flag); 8693 if (vms_debug_fileify) { 8694 fprintf(stderr, "int_tovmsspec: rslt = %s\n", rslt); 8695 } 8696 return rslt; 8697 } 8698 #endif 8699 8700 if (*(dirend+1) == '.') { /* do we have trailing "/." or "/.." or "/..."? */ 8701 if (!*(dirend+2)) dirend +=2; 8702 if (*(dirend+2) == '.' && !*(dirend+3)) dirend += 3; 8703 if (decc_efs_charset == 0) { 8704 if (*(dirend+2) == '.' && *(dirend+3) == '.' && !*(dirend+4)) dirend += 4; 8705 } 8706 } 8707 8708 cp1 = rslt; 8709 cp2 = path; 8710 lastdot = strrchr(cp2,'.'); 8711 if (*cp2 == '/') { 8712 char *trndev; 8713 int islnm, rooted; 8714 STRLEN trnend; 8715 8716 while (*(cp2+1) == '/') cp2++; /* Skip multiple /s */ 8717 if (!*(cp2+1)) { 8718 if (decc_disable_posix_root) { 8719 strcpy(rslt,"sys$disk:[000000]"); 8720 } 8721 else { 8722 strcpy(rslt,"sys$posix_root:[000000]"); 8723 } 8724 if (utf8_flag != NULL) 8725 *utf8_flag = 0; 8726 if (vms_debug_fileify) { 8727 fprintf(stderr, "int_tovmsspec: rslt = %s\n", rslt); 8728 } 8729 return rslt; 8730 } 8731 while (*(++cp2) != '/' && *cp2) *(cp1++) = *cp2; 8732 *cp1 = '\0'; 8733 trndev = PerlMem_malloc(VMS_MAXRSS); 8734 if (trndev == NULL) _ckvmssts_noperl(SS$_INSFMEM); 8735 islnm = simple_trnlnm(rslt,trndev,VMS_MAXRSS-1); 8736 8737 /* DECC special handling */ 8738 if (!islnm) { 8739 if (strcmp(rslt,"bin") == 0) { 8740 strcpy(rslt,"sys$system"); 8741 cp1 = rslt + 10; 8742 *cp1 = 0; 8743 islnm = simple_trnlnm(rslt,trndev,VMS_MAXRSS-1); 8744 } 8745 else if (strcmp(rslt,"tmp") == 0) { 8746 strcpy(rslt,"sys$scratch"); 8747 cp1 = rslt + 11; 8748 *cp1 = 0; 8749 islnm = simple_trnlnm(rslt,trndev,VMS_MAXRSS-1); 8750 } 8751 else if (!decc_disable_posix_root) { 8752 strcpy(rslt, "sys$posix_root"); 8753 cp1 = rslt + 14; 8754 *cp1 = 0; 8755 cp2 = path; 8756 while (*(cp2+1) == '/') cp2++; /* Skip multiple /s */ 8757 islnm = simple_trnlnm(rslt,trndev,VMS_MAXRSS-1); 8758 } 8759 else if (strcmp(rslt,"dev") == 0) { 8760 if (strncmp(cp2,"/null", 5) == 0) { 8761 if ((cp2[5] == 0) || (cp2[5] == '/')) { 8762 strcpy(rslt,"NLA0"); 8763 cp1 = rslt + 4; 8764 *cp1 = 0; 8765 cp2 = cp2 + 5; 8766 islnm = simple_trnlnm(rslt,trndev,VMS_MAXRSS-1); 8767 } 8768 } 8769 } 8770 } 8771 8772 trnend = islnm ? strlen(trndev) - 1 : 0; 8773 islnm = trnend ? (trndev[trnend] == ']' || trndev[trnend] == '>') : 0; 8774 rooted = islnm ? (trndev[trnend-1] == '.') : 0; 8775 /* If the first element of the path is a logical name, determine 8776 * whether it has to be translated so we can add more directories. */ 8777 if (!islnm || rooted) { 8778 *(cp1++) = ':'; 8779 *(cp1++) = '['; 8780 if (cp2 == dirend) while (infront++ < 6) *(cp1++) = '0'; 8781 else cp2++; 8782 } 8783 else { 8784 if (cp2 != dirend) { 8785 strcpy(rslt,trndev); 8786 cp1 = rslt + trnend; 8787 if (*cp2 != 0) { 8788 *(cp1++) = '.'; 8789 cp2++; 8790 } 8791 } 8792 else { 8793 if (decc_disable_posix_root) { 8794 *(cp1++) = ':'; 8795 hasdir = 0; 8796 } 8797 } 8798 } 8799 PerlMem_free(trndev); 8800 } 8801 else { 8802 *(cp1++) = '['; 8803 if (*cp2 == '.') { 8804 if (*(cp2+1) == '/' || *(cp2+1) == '\0') { 8805 cp2 += 2; /* skip over "./" - it's redundant */ 8806 *(cp1++) = '.'; /* but it does indicate a relative dirspec */ 8807 } 8808 else if (*(cp2+1) == '.' && (*(cp2+2) == '/' || *(cp2+2) == '\0')) { 8809 *(cp1++) = '-'; /* "../" --> "-" */ 8810 cp2 += 3; 8811 } 8812 else if (*(cp2+1) == '.' && *(cp2+2) == '.' && 8813 (*(cp2+3) == '/' || *(cp2+3) == '\0')) { 8814 *(cp1++) = '.'; *(cp1++) = '.'; *(cp1++) = '.'; /* ".../" --> "..." */ 8815 if (!*(cp2+4)) *(cp1++) = '.'; /* Simulate trailing '/' for later */ 8816 cp2 += 4; 8817 } 8818 else if ((cp2 != lastdot) || (lastdot < dirend)) { 8819 /* Escape the extra dots in EFS file specifications */ 8820 *(cp1++) = '^'; 8821 } 8822 if (cp2 > dirend) cp2 = dirend; 8823 } 8824 else *(cp1++) = '.'; 8825 } 8826 for (; cp2 < dirend; cp2++) { 8827 if (*cp2 == '/') { 8828 if (*(cp2-1) == '/') continue; 8829 if (*(cp1-1) != '.') *(cp1++) = '.'; 8830 infront = 0; 8831 } 8832 else if (!infront && *cp2 == '.') { 8833 if (cp2+1 == dirend || *(cp2+1) == '\0') { cp2++; break; } 8834 else if (*(cp2+1) == '/') cp2++; /* skip over "./" - it's redundant */ 8835 else if (*(cp2+1) == '.' && (*(cp2+2) == '/' || *(cp2+2) == '\0')) { 8836 if (*(cp1-1) == '-' || *(cp1-1) == '[') *(cp1++) = '-'; /* handle "../" */ 8837 else if (*(cp1-2) == '[') *(cp1-1) = '-'; 8838 else { /* back up over previous directory name */ 8839 cp1--; 8840 while (*(cp1-1) != '.' && *(cp1-1) != '[') cp1--; 8841 if (*(cp1-1) == '[') { 8842 memcpy(cp1,"000000.",7); 8843 cp1 += 7; 8844 } 8845 } 8846 cp2 += 2; 8847 if (cp2 == dirend) break; 8848 } 8849 else if ( *(cp2+1) == '.' && *(cp2+2) == '.' && 8850 (*(cp2+3) == '/' || *(cp2+3) == '\0') ) { 8851 if (*(cp1-1) != '.') *(cp1++) = '.'; /* May already have 1 from '/' */ 8852 *(cp1++) = '.'; *(cp1++) = '.'; /* ".../" --> "..." */ 8853 if (!*(cp2+3)) { 8854 *(cp1++) = '.'; /* Simulate trailing '/' */ 8855 cp2 += 2; /* for loop will incr this to == dirend */ 8856 } 8857 else cp2 += 3; /* Trailing '/' was there, so skip it, too */ 8858 } 8859 else { 8860 if (decc_efs_charset == 0) 8861 *(cp1++) = '_'; /* fix up syntax - '.' in name not allowed */ 8862 else { 8863 *(cp1++) = '^'; /* fix up syntax - '.' in name is allowed */ 8864 *(cp1++) = '.'; 8865 } 8866 } 8867 } 8868 else { 8869 if (!infront && *(cp1-1) == '-') *(cp1++) = '.'; 8870 if (*cp2 == '.') { 8871 if (decc_efs_charset == 0) 8872 *(cp1++) = '_'; 8873 else { 8874 *(cp1++) = '^'; 8875 *(cp1++) = '.'; 8876 } 8877 } 8878 else *(cp1++) = *cp2; 8879 infront = 1; 8880 } 8881 } 8882 if (*(cp1-1) == '.') cp1--; /* Unix spec ending in '/' ==> trailing '.' */ 8883 if (hasdir) *(cp1++) = ']'; 8884 if (*cp2) cp2++; /* check in case we ended with trailing '..' */ 8885 /* fixme for ODS5 */ 8886 no_type_seen = 0; 8887 if (cp2 > lastdot) 8888 no_type_seen = 1; 8889 while (*cp2) { 8890 switch(*cp2) { 8891 case '?': 8892 if (decc_efs_charset == 0) 8893 *(cp1++) = '%'; 8894 else 8895 *(cp1++) = '?'; 8896 cp2++; 8897 case ' ': 8898 *(cp1)++ = '^'; 8899 *(cp1)++ = '_'; 8900 cp2++; 8901 break; 8902 case '.': 8903 if (((cp2 < lastdot) || (cp2[1] == '\0')) && 8904 decc_readdir_dropdotnotype) { 8905 *(cp1)++ = '^'; 8906 *(cp1)++ = '.'; 8907 cp2++; 8908 8909 /* trailing dot ==> '^..' on VMS */ 8910 if (*cp2 == '\0') { 8911 *(cp1++) = '.'; 8912 no_type_seen = 0; 8913 } 8914 } 8915 else { 8916 *(cp1++) = *(cp2++); 8917 no_type_seen = 0; 8918 } 8919 break; 8920 case '$': 8921 /* This could be a macro to be passed through */ 8922 *(cp1++) = *(cp2++); 8923 if (*cp2 == '(') { 8924 const char * save_cp2; 8925 char * save_cp1; 8926 int is_macro; 8927 8928 /* paranoid check */ 8929 save_cp2 = cp2; 8930 save_cp1 = cp1; 8931 is_macro = 0; 8932 8933 /* Test through */ 8934 *(cp1++) = *(cp2++); 8935 if (isalnum(*cp2) || (*cp2 == '.') || (*cp2 == '_')) { 8936 *(cp1++) = *(cp2++); 8937 while (isalnum(*cp2) || (*cp2 == '.') || (*cp2 == '_')) { 8938 *(cp1++) = *(cp2++); 8939 } 8940 if (*cp2 == ')') { 8941 *(cp1++) = *(cp2++); 8942 is_macro = 1; 8943 } 8944 } 8945 if (is_macro == 0) { 8946 /* Not really a macro - never mind */ 8947 cp2 = save_cp2; 8948 cp1 = save_cp1; 8949 } 8950 } 8951 break; 8952 case '\"': 8953 case '~': 8954 case '`': 8955 case '!': 8956 case '#': 8957 case '%': 8958 case '^': 8959 /* Don't escape again if following character is 8960 * already something we escape. 8961 */ 8962 if (strchr("\"~`!#%^&()=+\'@[]{}:\\|<>_.", *(cp2+1))) { 8963 *(cp1++) = *(cp2++); 8964 break; 8965 } 8966 /* But otherwise fall through and escape it. */ 8967 case '&': 8968 case '(': 8969 case ')': 8970 case '=': 8971 case '+': 8972 case '\'': 8973 case '@': 8974 case '[': 8975 case ']': 8976 case '{': 8977 case '}': 8978 case ':': 8979 case '\\': 8980 case '|': 8981 case '<': 8982 case '>': 8983 *(cp1++) = '^'; 8984 *(cp1++) = *(cp2++); 8985 break; 8986 case ';': 8987 /* FIXME: This needs fixing as Perl is putting ".dir;" on UNIX filespecs 8988 * which is wrong. UNIX notation should be ".dir." unless 8989 * the DECC$FILENAME_UNIX_NO_VERSION is enabled. 8990 * changing this behavior could break more things at this time. 8991 * efs character set effectively does not allow "." to be a version 8992 * delimiter as a further complication about changing this. 8993 */ 8994 if (decc_filename_unix_report != 0) { 8995 *(cp1++) = '^'; 8996 } 8997 *(cp1++) = *(cp2++); 8998 break; 8999 default: 9000 *(cp1++) = *(cp2++); 9001 } 9002 } 9003 if ((no_type_seen == 1) && decc_readdir_dropdotnotype) { 9004 char *lcp1; 9005 lcp1 = cp1; 9006 lcp1--; 9007 /* Fix me for "^]", but that requires making sure that you do 9008 * not back up past the start of the filename 9009 */ 9010 if ((*lcp1 != ']') && (*lcp1 != '*') && (*lcp1 != '%')) 9011 *cp1++ = '.'; 9012 } 9013 *cp1 = '\0'; 9014 9015 if (utf8_flag != NULL) 9016 *utf8_flag = 0; 9017 if (vms_debug_fileify) { 9018 fprintf(stderr, "int_tovmsspec: rslt = %s\n", rslt); 9019 } 9020 return rslt; 9021 9022 } /* end of int_tovmsspec() */ 9023 9024 9025 /*{{{ char *tovmsspec[_ts](char *path, char *buf, int * utf8_flag)*/ 9026 static char *mp_do_tovmsspec 9027 (pTHX_ const char *path, char *buf, int ts, int dir_flag, int * utf8_flag) { 9028 static char __tovmsspec_retbuf[VMS_MAXRSS]; 9029 char * vmsspec, *ret_spec, *ret_buf; 9030 9031 vmsspec = NULL; 9032 ret_buf = buf; 9033 if (ret_buf == NULL) { 9034 if (ts) { 9035 Newx(vmsspec, VMS_MAXRSS, char); 9036 if (vmsspec == NULL) 9037 _ckvmssts(SS$_INSFMEM); 9038 ret_buf = vmsspec; 9039 } else { 9040 ret_buf = __tovmsspec_retbuf; 9041 } 9042 } 9043 9044 ret_spec = int_tovmsspec(path, ret_buf, 0, utf8_flag); 9045 9046 if (ret_spec == NULL) { 9047 /* Cleanup on isle 5, if this is thread specific we need to deallocate */ 9048 if (vmsspec) 9049 Safefree(vmsspec); 9050 } 9051 9052 return ret_spec; 9053 9054 } /* end of mp_do_tovmsspec() */ 9055 /*}}}*/ 9056 /* External entry points */ 9057 char *Perl_tovmsspec(pTHX_ const char *path, char *buf) 9058 { return do_tovmsspec(path,buf,0,NULL); } 9059 char *Perl_tovmsspec_ts(pTHX_ const char *path, char *buf) 9060 { return do_tovmsspec(path,buf,1,NULL); } 9061 char *Perl_tovmsspec_utf8(pTHX_ const char *path, char *buf, int * utf8_fl) 9062 { return do_tovmsspec(path,buf,0,utf8_fl); } 9063 char *Perl_tovmsspec_utf8_ts(pTHX_ const char *path, char *buf, int * utf8_fl) 9064 { return do_tovmsspec(path,buf,1,utf8_fl); } 9065 9066 /*{{{ char *int_tovmspath(char *path, char *buf, const int *)*/ 9067 /* Internal routine for use with out an explict context present */ 9068 static char * int_tovmspath(const char *path, char *buf, int * utf8_fl) { 9069 9070 char * ret_spec, *pathified; 9071 9072 if (path == NULL) 9073 return NULL; 9074 9075 pathified = PerlMem_malloc(VMS_MAXRSS); 9076 if (pathified == NULL) 9077 _ckvmssts_noperl(SS$_INSFMEM); 9078 9079 ret_spec = int_pathify_dirspec(path, pathified); 9080 9081 if (ret_spec == NULL) { 9082 PerlMem_free(pathified); 9083 return NULL; 9084 } 9085 9086 ret_spec = int_tovmsspec(pathified, buf, 0, utf8_fl); 9087 9088 PerlMem_free(pathified); 9089 return ret_spec; 9090 9091 } 9092 9093 /*{{{ char *tovmspath[_ts](char *path, char *buf, const int *)*/ 9094 static char *mp_do_tovmspath(pTHX_ const char *path, char *buf, int ts, int * utf8_fl) { 9095 static char __tovmspath_retbuf[VMS_MAXRSS]; 9096 int vmslen; 9097 char *pathified, *vmsified, *cp; 9098 9099 if (path == NULL) return NULL; 9100 pathified = PerlMem_malloc(VMS_MAXRSS); 9101 if (pathified == NULL) _ckvmssts(SS$_INSFMEM); 9102 if (int_pathify_dirspec(path, pathified) == NULL) { 9103 PerlMem_free(pathified); 9104 return NULL; 9105 } 9106 9107 vmsified = NULL; 9108 if (buf == NULL) 9109 Newx(vmsified, VMS_MAXRSS, char); 9110 if (do_tovmsspec(pathified, buf ? buf : vmsified, 0, NULL) == NULL) { 9111 PerlMem_free(pathified); 9112 if (vmsified) Safefree(vmsified); 9113 return NULL; 9114 } 9115 PerlMem_free(pathified); 9116 if (buf) { 9117 return buf; 9118 } 9119 else if (ts) { 9120 vmslen = strlen(vmsified); 9121 Newx(cp,vmslen+1,char); 9122 memcpy(cp,vmsified,vmslen); 9123 cp[vmslen] = '\0'; 9124 Safefree(vmsified); 9125 return cp; 9126 } 9127 else { 9128 strcpy(__tovmspath_retbuf,vmsified); 9129 Safefree(vmsified); 9130 return __tovmspath_retbuf; 9131 } 9132 9133 } /* end of do_tovmspath() */ 9134 /*}}}*/ 9135 /* External entry points */ 9136 char *Perl_tovmspath(pTHX_ const char *path, char *buf) 9137 { return do_tovmspath(path,buf,0, NULL); } 9138 char *Perl_tovmspath_ts(pTHX_ const char *path, char *buf) 9139 { return do_tovmspath(path,buf,1, NULL); } 9140 char *Perl_tovmspath_utf8(pTHX_ const char *path, char *buf, int *utf8_fl) 9141 { return do_tovmspath(path,buf,0,utf8_fl); } 9142 char *Perl_tovmspath_utf8_ts(pTHX_ const char *path, char *buf, int *utf8_fl) 9143 { return do_tovmspath(path,buf,1,utf8_fl); } 9144 9145 9146 /*{{{ char *tounixpath[_ts](char *path, char *buf, int * utf8_fl)*/ 9147 static char *mp_do_tounixpath(pTHX_ const char *path, char *buf, int ts, int * utf8_fl) { 9148 static char __tounixpath_retbuf[VMS_MAXRSS]; 9149 int unixlen; 9150 char *pathified, *unixified, *cp; 9151 9152 if (path == NULL) return NULL; 9153 pathified = PerlMem_malloc(VMS_MAXRSS); 9154 if (pathified == NULL) _ckvmssts(SS$_INSFMEM); 9155 if (int_pathify_dirspec(path, pathified) == NULL) { 9156 PerlMem_free(pathified); 9157 return NULL; 9158 } 9159 9160 unixified = NULL; 9161 if (buf == NULL) { 9162 Newx(unixified, VMS_MAXRSS, char); 9163 } 9164 if (do_tounixspec(pathified,buf ? buf : unixified,0,NULL) == NULL) { 9165 PerlMem_free(pathified); 9166 if (unixified) Safefree(unixified); 9167 return NULL; 9168 } 9169 PerlMem_free(pathified); 9170 if (buf) { 9171 return buf; 9172 } 9173 else if (ts) { 9174 unixlen = strlen(unixified); 9175 Newx(cp,unixlen+1,char); 9176 memcpy(cp,unixified,unixlen); 9177 cp[unixlen] = '\0'; 9178 Safefree(unixified); 9179 return cp; 9180 } 9181 else { 9182 strcpy(__tounixpath_retbuf,unixified); 9183 Safefree(unixified); 9184 return __tounixpath_retbuf; 9185 } 9186 9187 } /* end of do_tounixpath() */ 9188 /*}}}*/ 9189 /* External entry points */ 9190 char *Perl_tounixpath(pTHX_ const char *path, char *buf) 9191 { return do_tounixpath(path,buf,0,NULL); } 9192 char *Perl_tounixpath_ts(pTHX_ const char *path, char *buf) 9193 { return do_tounixpath(path,buf,1,NULL); } 9194 char *Perl_tounixpath_utf8(pTHX_ const char *path, char *buf, int * utf8_fl) 9195 { return do_tounixpath(path,buf,0,utf8_fl); } 9196 char *Perl_tounixpath_utf8_ts(pTHX_ const char *path, char *buf, int * utf8_fl) 9197 { return do_tounixpath(path,buf,1,utf8_fl); } 9198 9199 /* 9200 * @(#)argproc.c 2.2 94/08/16 Mark Pizzolato (mark AT infocomm DOT com) 9201 * 9202 ***************************************************************************** 9203 * * 9204 * Copyright (C) 1989-1994, 2007 by * 9205 * Mark Pizzolato - INFO COMM, Danville, California (510) 837-5600 * 9206 * * 9207 * Permission is hereby granted for the reproduction of this software * 9208 * on condition that this copyright notice is included in source * 9209 * distributions of the software. The code may be modified and * 9210 * distributed under the same terms as Perl itself. * 9211 * * 9212 * 27-Aug-1994 Modified for inclusion in perl5 * 9213 * by Charles Bailey (bailey AT newman DOT upenn DOT edu) * 9214 ***************************************************************************** 9215 */ 9216 9217 /* 9218 * getredirection() is intended to aid in porting C programs 9219 * to VMS (Vax-11 C). The native VMS environment does not support 9220 * '>' and '<' I/O redirection, or command line wild card expansion, 9221 * or a command line pipe mechanism using the '|' AND background 9222 * command execution '&'. All of these capabilities are provided to any 9223 * C program which calls this procedure as the first thing in the 9224 * main program. 9225 * The piping mechanism will probably work with almost any 'filter' type 9226 * of program. With suitable modification, it may useful for other 9227 * portability problems as well. 9228 * 9229 * Author: Mark Pizzolato (mark AT infocomm DOT com) 9230 */ 9231 struct list_item 9232 { 9233 struct list_item *next; 9234 char *value; 9235 }; 9236 9237 static void add_item(struct list_item **head, 9238 struct list_item **tail, 9239 char *value, 9240 int *count); 9241 9242 static void mp_expand_wild_cards(pTHX_ char *item, 9243 struct list_item **head, 9244 struct list_item **tail, 9245 int *count); 9246 9247 static int background_process(pTHX_ int argc, char **argv); 9248 9249 static void pipe_and_fork(pTHX_ char **cmargv); 9250 9251 /*{{{ void getredirection(int *ac, char ***av)*/ 9252 static void 9253 mp_getredirection(pTHX_ int *ac, char ***av) 9254 /* 9255 * Process vms redirection arg's. Exit if any error is seen. 9256 * If getredirection() processes an argument, it is erased 9257 * from the vector. getredirection() returns a new argc and argv value. 9258 * In the event that a background command is requested (by a trailing "&"), 9259 * this routine creates a background subprocess, and simply exits the program. 9260 * 9261 * Warning: do not try to simplify the code for vms. The code 9262 * presupposes that getredirection() is called before any data is 9263 * read from stdin or written to stdout. 9264 * 9265 * Normal usage is as follows: 9266 * 9267 * main(argc, argv) 9268 * int argc; 9269 * char *argv[]; 9270 * { 9271 * getredirection(&argc, &argv); 9272 * } 9273 */ 9274 { 9275 int argc = *ac; /* Argument Count */ 9276 char **argv = *av; /* Argument Vector */ 9277 char *ap; /* Argument pointer */ 9278 int j; /* argv[] index */ 9279 int item_count = 0; /* Count of Items in List */ 9280 struct list_item *list_head = 0; /* First Item in List */ 9281 struct list_item *list_tail; /* Last Item in List */ 9282 char *in = NULL; /* Input File Name */ 9283 char *out = NULL; /* Output File Name */ 9284 char *outmode = "w"; /* Mode to Open Output File */ 9285 char *err = NULL; /* Error File Name */ 9286 char *errmode = "w"; /* Mode to Open Error File */ 9287 int cmargc = 0; /* Piped Command Arg Count */ 9288 char **cmargv = NULL;/* Piped Command Arg Vector */ 9289 9290 /* 9291 * First handle the case where the last thing on the line ends with 9292 * a '&'. This indicates the desire for the command to be run in a 9293 * subprocess, so we satisfy that desire. 9294 */ 9295 ap = argv[argc-1]; 9296 if (0 == strcmp("&", ap)) 9297 exit(background_process(aTHX_ --argc, argv)); 9298 if (*ap && '&' == ap[strlen(ap)-1]) 9299 { 9300 ap[strlen(ap)-1] = '\0'; 9301 exit(background_process(aTHX_ argc, argv)); 9302 } 9303 /* 9304 * Now we handle the general redirection cases that involve '>', '>>', 9305 * '<', and pipes '|'. 9306 */ 9307 for (j = 0; j < argc; ++j) 9308 { 9309 if (0 == strcmp("<", argv[j])) 9310 { 9311 if (j+1 >= argc) 9312 { 9313 fprintf(stderr,"No input file after < on command line"); 9314 exit(LIB$_WRONUMARG); 9315 } 9316 in = argv[++j]; 9317 continue; 9318 } 9319 if ('<' == *(ap = argv[j])) 9320 { 9321 in = 1 + ap; 9322 continue; 9323 } 9324 if (0 == strcmp(">", ap)) 9325 { 9326 if (j+1 >= argc) 9327 { 9328 fprintf(stderr,"No output file after > on command line"); 9329 exit(LIB$_WRONUMARG); 9330 } 9331 out = argv[++j]; 9332 continue; 9333 } 9334 if ('>' == *ap) 9335 { 9336 if ('>' == ap[1]) 9337 { 9338 outmode = "a"; 9339 if ('\0' == ap[2]) 9340 out = argv[++j]; 9341 else 9342 out = 2 + ap; 9343 } 9344 else 9345 out = 1 + ap; 9346 if (j >= argc) 9347 { 9348 fprintf(stderr,"No output file after > or >> on command line"); 9349 exit(LIB$_WRONUMARG); 9350 } 9351 continue; 9352 } 9353 if (('2' == *ap) && ('>' == ap[1])) 9354 { 9355 if ('>' == ap[2]) 9356 { 9357 errmode = "a"; 9358 if ('\0' == ap[3]) 9359 err = argv[++j]; 9360 else 9361 err = 3 + ap; 9362 } 9363 else 9364 if ('\0' == ap[2]) 9365 err = argv[++j]; 9366 else 9367 err = 2 + ap; 9368 if (j >= argc) 9369 { 9370 fprintf(stderr,"No output file after 2> or 2>> on command line"); 9371 exit(LIB$_WRONUMARG); 9372 } 9373 continue; 9374 } 9375 if (0 == strcmp("|", argv[j])) 9376 { 9377 if (j+1 >= argc) 9378 { 9379 fprintf(stderr,"No command into which to pipe on command line"); 9380 exit(LIB$_WRONUMARG); 9381 } 9382 cmargc = argc-(j+1); 9383 cmargv = &argv[j+1]; 9384 argc = j; 9385 continue; 9386 } 9387 if ('|' == *(ap = argv[j])) 9388 { 9389 ++argv[j]; 9390 cmargc = argc-j; 9391 cmargv = &argv[j]; 9392 argc = j; 9393 continue; 9394 } 9395 expand_wild_cards(ap, &list_head, &list_tail, &item_count); 9396 } 9397 /* 9398 * Allocate and fill in the new argument vector, Some Unix's terminate 9399 * the list with an extra null pointer. 9400 */ 9401 argv = (char **) PerlMem_malloc((item_count+1) * sizeof(char *)); 9402 if (argv == NULL) _ckvmssts_noperl(SS$_INSFMEM); 9403 *av = argv; 9404 for (j = 0; j < item_count; ++j, list_head = list_head->next) 9405 argv[j] = list_head->value; 9406 *ac = item_count; 9407 if (cmargv != NULL) 9408 { 9409 if (out != NULL) 9410 { 9411 fprintf(stderr,"'|' and '>' may not both be specified on command line"); 9412 exit(LIB$_INVARGORD); 9413 } 9414 pipe_and_fork(aTHX_ cmargv); 9415 } 9416 9417 /* Check for input from a pipe (mailbox) */ 9418 9419 if (in == NULL && 1 == isapipe(0)) 9420 { 9421 char mbxname[L_tmpnam]; 9422 long int bufsize; 9423 long int dvi_item = DVI$_DEVBUFSIZ; 9424 $DESCRIPTOR(mbxnam, ""); 9425 $DESCRIPTOR(mbxdevnam, ""); 9426 9427 /* Input from a pipe, reopen it in binary mode to disable */ 9428 /* carriage control processing. */ 9429 9430 fgetname(stdin, mbxname, 1); 9431 mbxnam.dsc$a_pointer = mbxname; 9432 mbxnam.dsc$w_length = strlen(mbxnam.dsc$a_pointer); 9433 lib$getdvi(&dvi_item, 0, &mbxnam, &bufsize, 0, 0); 9434 mbxdevnam.dsc$a_pointer = mbxname; 9435 mbxdevnam.dsc$w_length = sizeof(mbxname); 9436 dvi_item = DVI$_DEVNAM; 9437 lib$getdvi(&dvi_item, 0, &mbxnam, 0, &mbxdevnam, &mbxdevnam.dsc$w_length); 9438 mbxdevnam.dsc$a_pointer[mbxdevnam.dsc$w_length] = '\0'; 9439 set_errno(0); 9440 set_vaxc_errno(1); 9441 freopen(mbxname, "rb", stdin); 9442 if (errno != 0) 9443 { 9444 fprintf(stderr,"Can't reopen input pipe (name: %s) in binary mode",mbxname); 9445 exit(vaxc$errno); 9446 } 9447 } 9448 if ((in != NULL) && (NULL == freopen(in, "r", stdin, "mbc=32", "mbf=2"))) 9449 { 9450 fprintf(stderr,"Can't open input file %s as stdin",in); 9451 exit(vaxc$errno); 9452 } 9453 if ((out != NULL) && (NULL == freopen(out, outmode, stdout, "mbc=32", "mbf=2"))) 9454 { 9455 fprintf(stderr,"Can't open output file %s as stdout",out); 9456 exit(vaxc$errno); 9457 } 9458 if (out != NULL) Perl_vmssetuserlnm(aTHX_ "SYS$OUTPUT",out); 9459 9460 if (err != NULL) { 9461 if (strcmp(err,"&1") == 0) { 9462 dup2(fileno(stdout), fileno(stderr)); 9463 Perl_vmssetuserlnm(aTHX_ "SYS$ERROR","SYS$OUTPUT"); 9464 } else { 9465 FILE *tmperr; 9466 if (NULL == (tmperr = fopen(err, errmode, "mbc=32", "mbf=2"))) 9467 { 9468 fprintf(stderr,"Can't open error file %s as stderr",err); 9469 exit(vaxc$errno); 9470 } 9471 fclose(tmperr); 9472 if (NULL == freopen(err, "a", stderr, "mbc=32", "mbf=2")) 9473 { 9474 exit(vaxc$errno); 9475 } 9476 Perl_vmssetuserlnm(aTHX_ "SYS$ERROR",err); 9477 } 9478 } 9479 #ifdef ARGPROC_DEBUG 9480 PerlIO_printf(Perl_debug_log, "Arglist:\n"); 9481 for (j = 0; j < *ac; ++j) 9482 PerlIO_printf(Perl_debug_log, "argv[%d] = '%s'\n", j, argv[j]); 9483 #endif 9484 /* Clear errors we may have hit expanding wildcards, so they don't 9485 show up in Perl's $! later */ 9486 set_errno(0); set_vaxc_errno(1); 9487 } /* end of getredirection() */ 9488 /*}}}*/ 9489 9490 static void add_item(struct list_item **head, 9491 struct list_item **tail, 9492 char *value, 9493 int *count) 9494 { 9495 if (*head == 0) 9496 { 9497 *head = (struct list_item *) PerlMem_malloc(sizeof(struct list_item)); 9498 if (head == NULL) _ckvmssts_noperl(SS$_INSFMEM); 9499 *tail = *head; 9500 } 9501 else { 9502 (*tail)->next = (struct list_item *) PerlMem_malloc(sizeof(struct list_item)); 9503 if ((*tail)->next == NULL) _ckvmssts_noperl(SS$_INSFMEM); 9504 *tail = (*tail)->next; 9505 } 9506 (*tail)->value = value; 9507 ++(*count); 9508 } 9509 9510 static void mp_expand_wild_cards(pTHX_ char *item, 9511 struct list_item **head, 9512 struct list_item **tail, 9513 int *count) 9514 { 9515 int expcount = 0; 9516 unsigned long int context = 0; 9517 int isunix = 0; 9518 int item_len = 0; 9519 char *had_version; 9520 char *had_device; 9521 int had_directory; 9522 char *devdir,*cp; 9523 char *vmsspec; 9524 $DESCRIPTOR(filespec, ""); 9525 $DESCRIPTOR(defaultspec, "SYS$DISK:[]"); 9526 $DESCRIPTOR(resultspec, ""); 9527 unsigned long int lff_flags = 0; 9528 int sts; 9529 int rms_sts; 9530 9531 #ifdef VMS_LONGNAME_SUPPORT 9532 lff_flags = LIB$M_FIL_LONG_NAMES; 9533 #endif 9534 9535 for (cp = item; *cp; cp++) { 9536 if (*cp == '*' || *cp == '%' || isspace(*cp)) break; 9537 if (*cp == '.' && *(cp-1) == '.' && *(cp-2) =='.') break; 9538 } 9539 if (!*cp || isspace(*cp)) 9540 { 9541 add_item(head, tail, item, count); 9542 return; 9543 } 9544 else 9545 { 9546 /* "double quoted" wild card expressions pass as is */ 9547 /* From DCL that means using e.g.: */ 9548 /* perl program """perl.*""" */ 9549 item_len = strlen(item); 9550 if ( '"' == *item && '"' == item[item_len-1] ) 9551 { 9552 item++; 9553 item[item_len-2] = '\0'; 9554 add_item(head, tail, item, count); 9555 return; 9556 } 9557 } 9558 resultspec.dsc$b_dtype = DSC$K_DTYPE_T; 9559 resultspec.dsc$b_class = DSC$K_CLASS_D; 9560 resultspec.dsc$a_pointer = NULL; 9561 vmsspec = PerlMem_malloc(VMS_MAXRSS); 9562 if (vmsspec == NULL) _ckvmssts_noperl(SS$_INSFMEM); 9563 if ((isunix = (int) strchr(item,'/')) != (int) NULL) 9564 filespec.dsc$a_pointer = int_tovmsspec(item, vmsspec, 0, NULL); 9565 if (!isunix || !filespec.dsc$a_pointer) 9566 filespec.dsc$a_pointer = item; 9567 filespec.dsc$w_length = strlen(filespec.dsc$a_pointer); 9568 /* 9569 * Only return version specs, if the caller specified a version 9570 */ 9571 had_version = strchr(item, ';'); 9572 /* 9573 * Only return device and directory specs, if the caller specifed either. 9574 */ 9575 had_device = strchr(item, ':'); 9576 had_directory = (isunix || NULL != strchr(item, '[')) || (NULL != strchr(item, '<')); 9577 9578 while ($VMS_STATUS_SUCCESS(sts = lib$find_file 9579 (&filespec, &resultspec, &context, 9580 &defaultspec, 0, &rms_sts, &lff_flags))) 9581 { 9582 char *string; 9583 char *c; 9584 9585 string = PerlMem_malloc(resultspec.dsc$w_length+1); 9586 if (string == NULL) _ckvmssts_noperl(SS$_INSFMEM); 9587 strncpy(string, resultspec.dsc$a_pointer, resultspec.dsc$w_length); 9588 string[resultspec.dsc$w_length] = '\0'; 9589 if (NULL == had_version) 9590 *(strrchr(string, ';')) = '\0'; 9591 if ((!had_directory) && (had_device == NULL)) 9592 { 9593 if (NULL == (devdir = strrchr(string, ']'))) 9594 devdir = strrchr(string, '>'); 9595 strcpy(string, devdir + 1); 9596 } 9597 /* 9598 * Be consistent with what the C RTL has already done to the rest of 9599 * the argv items and lowercase all of these names. 9600 */ 9601 if (!decc_efs_case_preserve) { 9602 for (c = string; *c; ++c) 9603 if (isupper(*c)) 9604 *c = tolower(*c); 9605 } 9606 if (isunix) trim_unixpath(string,item,1); 9607 add_item(head, tail, string, count); 9608 ++expcount; 9609 } 9610 PerlMem_free(vmsspec); 9611 if (sts != RMS$_NMF) 9612 { 9613 set_vaxc_errno(sts); 9614 switch (sts) 9615 { 9616 case RMS$_FNF: case RMS$_DNF: 9617 set_errno(ENOENT); break; 9618 case RMS$_DIR: 9619 set_errno(ENOTDIR); break; 9620 case RMS$_DEV: 9621 set_errno(ENODEV); break; 9622 case RMS$_FNM: case RMS$_SYN: 9623 set_errno(EINVAL); break; 9624 case RMS$_PRV: 9625 set_errno(EACCES); break; 9626 default: 9627 _ckvmssts_noperl(sts); 9628 } 9629 } 9630 if (expcount == 0) 9631 add_item(head, tail, item, count); 9632 _ckvmssts_noperl(lib$sfree1_dd(&resultspec)); 9633 _ckvmssts_noperl(lib$find_file_end(&context)); 9634 } 9635 9636 static int child_st[2];/* Event Flag set when child process completes */ 9637 9638 static unsigned short child_chan;/* I/O Channel for Pipe Mailbox */ 9639 9640 static unsigned long int exit_handler(int *status) 9641 { 9642 short iosb[4]; 9643 9644 if (0 == child_st[0]) 9645 { 9646 #ifdef ARGPROC_DEBUG 9647 PerlIO_printf(Perl_debug_log, "Waiting for Child Process to Finish . . .\n"); 9648 #endif 9649 fflush(stdout); /* Have to flush pipe for binary data to */ 9650 /* terminate properly -- <tp@mccall.com> */ 9651 sys$qiow(0, child_chan, IO$_WRITEOF, iosb, 0, 0, 0, 0, 0, 0, 0, 0); 9652 sys$dassgn(child_chan); 9653 fclose(stdout); 9654 sys$synch(0, child_st); 9655 } 9656 return(1); 9657 } 9658 9659 static void sig_child(int chan) 9660 { 9661 #ifdef ARGPROC_DEBUG 9662 PerlIO_printf(Perl_debug_log, "Child Completion AST\n"); 9663 #endif 9664 if (child_st[0] == 0) 9665 child_st[0] = 1; 9666 } 9667 9668 static struct exit_control_block exit_block = 9669 { 9670 0, 9671 exit_handler, 9672 1, 9673 &exit_block.exit_status, 9674 0 9675 }; 9676 9677 static void 9678 pipe_and_fork(pTHX_ char **cmargv) 9679 { 9680 PerlIO *fp; 9681 struct dsc$descriptor_s *vmscmd; 9682 char subcmd[2*MAX_DCL_LINE_LENGTH], *p, *q; 9683 int sts, j, l, ismcr, quote, tquote = 0; 9684 9685 sts = setup_cmddsc(aTHX_ cmargv[0],0,"e,&vmscmd); 9686 vms_execfree(vmscmd); 9687 9688 j = l = 0; 9689 p = subcmd; 9690 q = cmargv[0]; 9691 ismcr = q && toupper(*q) == 'M' && toupper(*(q+1)) == 'C' 9692 && toupper(*(q+2)) == 'R' && !*(q+3); 9693 9694 while (q && l < MAX_DCL_LINE_LENGTH) { 9695 if (!*q) { 9696 if (j > 0 && quote) { 9697 *p++ = '"'; 9698 l++; 9699 } 9700 q = cmargv[++j]; 9701 if (q) { 9702 if (ismcr && j > 1) quote = 1; 9703 tquote = (strchr(q,' ')) != NULL || *q == '\0'; 9704 *p++ = ' '; 9705 l++; 9706 if (quote || tquote) { 9707 *p++ = '"'; 9708 l++; 9709 } 9710 } 9711 } else { 9712 if ((quote||tquote) && *q == '"') { 9713 *p++ = '"'; 9714 l++; 9715 } 9716 *p++ = *q++; 9717 l++; 9718 } 9719 } 9720 *p = '\0'; 9721 9722 fp = safe_popen(aTHX_ subcmd,"wbF",&sts); 9723 if (fp == NULL) { 9724 PerlIO_printf(Perl_debug_log,"Can't open output pipe (status %d)",sts); 9725 } 9726 } 9727 9728 static int background_process(pTHX_ int argc, char **argv) 9729 { 9730 char command[MAX_DCL_SYMBOL + 1] = "$"; 9731 $DESCRIPTOR(value, ""); 9732 static $DESCRIPTOR(cmd, "BACKGROUND$COMMAND"); 9733 static $DESCRIPTOR(null, "NLA0:"); 9734 static $DESCRIPTOR(pidsymbol, "SHELL_BACKGROUND_PID"); 9735 char pidstring[80]; 9736 $DESCRIPTOR(pidstr, ""); 9737 int pid; 9738 unsigned long int flags = 17, one = 1, retsts; 9739 int len; 9740 9741 strcat(command, argv[0]); 9742 len = strlen(command); 9743 while (--argc && (len < MAX_DCL_SYMBOL)) 9744 { 9745 strcat(command, " \""); 9746 strcat(command, *(++argv)); 9747 strcat(command, "\""); 9748 len = strlen(command); 9749 } 9750 value.dsc$a_pointer = command; 9751 value.dsc$w_length = strlen(value.dsc$a_pointer); 9752 _ckvmssts_noperl(lib$set_symbol(&cmd, &value)); 9753 retsts = lib$spawn(&cmd, &null, 0, &flags, 0, &pid); 9754 if (retsts == 0x38250) { /* DCL-W-NOTIFY - We must be BATCH, so retry */ 9755 _ckvmssts_noperl(lib$spawn(&cmd, &null, 0, &one, 0, &pid)); 9756 } 9757 else { 9758 _ckvmssts_noperl(retsts); 9759 } 9760 #ifdef ARGPROC_DEBUG 9761 PerlIO_printf(Perl_debug_log, "%s\n", command); 9762 #endif 9763 sprintf(pidstring, "%08X", pid); 9764 PerlIO_printf(Perl_debug_log, "%s\n", pidstring); 9765 pidstr.dsc$a_pointer = pidstring; 9766 pidstr.dsc$w_length = strlen(pidstr.dsc$a_pointer); 9767 lib$set_symbol(&pidsymbol, &pidstr); 9768 return(SS$_NORMAL); 9769 } 9770 /*}}}*/ 9771 /***** End of code taken from Mark Pizzolato's argproc.c package *****/ 9772 9773 9774 /* OS-specific initialization at image activation (not thread startup) */ 9775 /* Older VAXC header files lack these constants */ 9776 #ifndef JPI$_RIGHTS_SIZE 9777 # define JPI$_RIGHTS_SIZE 817 9778 #endif 9779 #ifndef KGB$M_SUBSYSTEM 9780 # define KGB$M_SUBSYSTEM 0x8 9781 #endif 9782 9783 /* Avoid Newx() in vms_image_init as thread context has not been initialized. */ 9784 9785 /*{{{void vms_image_init(int *, char ***)*/ 9786 void 9787 vms_image_init(int *argcp, char ***argvp) 9788 { 9789 int status; 9790 char eqv[LNM$C_NAMLENGTH+1] = ""; 9791 unsigned int len, tabct = 8, tabidx = 0; 9792 unsigned long int *mask, iosb[2], i, rlst[128], rsz; 9793 unsigned long int iprv[(sizeof(union prvdef) + sizeof(unsigned long int) - 1) / sizeof(unsigned long int)]; 9794 unsigned short int dummy, rlen; 9795 struct dsc$descriptor_s **tabvec; 9796 #if defined(PERL_IMPLICIT_CONTEXT) 9797 pTHX = NULL; 9798 #endif 9799 struct itmlst_3 jpilist[4] = { {sizeof iprv, JPI$_IMAGPRIV, iprv, &dummy}, 9800 {sizeof rlst, JPI$_RIGHTSLIST, rlst, &rlen}, 9801 { sizeof rsz, JPI$_RIGHTS_SIZE, &rsz, &dummy}, 9802 { 0, 0, 0, 0} }; 9803 9804 #ifdef KILL_BY_SIGPRC 9805 Perl_csighandler_init(); 9806 #endif 9807 9808 #if __CRTL_VER >= 70300000 && !defined(__VAX) 9809 /* This was moved from the pre-image init handler because on threaded */ 9810 /* Perl it was always returning 0 for the default value. */ 9811 status = simple_trnlnm("SYS$POSIX_ROOT", eqv, LNM$C_NAMLENGTH); 9812 if (status > 0) { 9813 int s; 9814 s = decc$feature_get_index("DECC$DISABLE_POSIX_ROOT"); 9815 if (s > 0) { 9816 int initial; 9817 initial = decc$feature_get_value(s, 4); 9818 if (initial > 0) { 9819 /* initial is: 0 if nothing has set the feature */ 9820 /* -1 if initialized to default */ 9821 /* 1 if set by logical name */ 9822 /* 2 if set by decc$feature_set_value */ 9823 decc_disable_posix_root = decc$feature_get_value(s, 1); 9824 9825 /* If the value is not valid, force the feature off */ 9826 if (decc_disable_posix_root < 0) { 9827 decc$feature_set_value(s, 1, 1); 9828 decc_disable_posix_root = 1; 9829 } 9830 } 9831 else { 9832 /* Nothing has asked for it explicitly, so use our own default. */ 9833 decc_disable_posix_root = 1; 9834 decc$feature_set_value(s, 1, 1); 9835 } 9836 } 9837 } 9838 #endif 9839 9840 _ckvmssts_noperl(sys$getjpiw(0,NULL,NULL,jpilist,iosb,NULL,NULL)); 9841 _ckvmssts_noperl(iosb[0]); 9842 for (i = 0; i < sizeof iprv / sizeof(unsigned long int); i++) { 9843 if (iprv[i]) { /* Running image installed with privs? */ 9844 _ckvmssts_noperl(sys$setprv(0,iprv,0,NULL)); /* Turn 'em off. */ 9845 will_taint = TRUE; 9846 break; 9847 } 9848 } 9849 /* Rights identifiers might trigger tainting as well. */ 9850 if (!will_taint && (rlen || rsz)) { 9851 while (rlen < rsz) { 9852 /* We didn't get all the identifiers on the first pass. Allocate a 9853 * buffer much larger than $GETJPI wants (rsz is size in bytes that 9854 * were needed to hold all identifiers at time of last call; we'll 9855 * allocate that many unsigned long ints), and go back and get 'em. 9856 * If it gave us less than it wanted to despite ample buffer space, 9857 * something's broken. Is your system missing a system identifier? 9858 */ 9859 if (rsz <= jpilist[1].buflen) { 9860 /* Perl_croak accvios when used this early in startup. */ 9861 fprintf(stderr, "vms_image_init: $getjpiw refuses to store RIGHTSLIST of %u bytes in buffer of %u bytes.\n%s", 9862 rsz, (unsigned long) jpilist[1].buflen, 9863 "Check your rights database for corruption.\n"); 9864 exit(SS$_ABORT); 9865 } 9866 if (jpilist[1].bufadr != rlst) PerlMem_free(jpilist[1].bufadr); 9867 jpilist[1].bufadr = mask = (unsigned long int *) PerlMem_malloc(rsz * sizeof(unsigned long int)); 9868 if (mask == NULL) _ckvmssts_noperl(SS$_INSFMEM); 9869 jpilist[1].buflen = rsz * sizeof(unsigned long int); 9870 _ckvmssts_noperl(sys$getjpiw(0,NULL,NULL,&jpilist[1],iosb,NULL,NULL)); 9871 _ckvmssts_noperl(iosb[0]); 9872 } 9873 mask = jpilist[1].bufadr; 9874 /* Check attribute flags for each identifier (2nd longword); protected 9875 * subsystem identifiers trigger tainting. 9876 */ 9877 for (i = 1; i < (rlen + sizeof(unsigned long int) - 1) / sizeof(unsigned long int); i += 2) { 9878 if (mask[i] & KGB$M_SUBSYSTEM) { 9879 will_taint = TRUE; 9880 break; 9881 } 9882 } 9883 if (mask != rlst) PerlMem_free(mask); 9884 } 9885 9886 /* When Perl is in decc_filename_unix_report mode and is run from a concealed 9887 * logical, some versions of the CRTL will add a phanthom /000000/ 9888 * directory. This needs to be removed. 9889 */ 9890 if (decc_filename_unix_report) { 9891 char * zeros; 9892 int ulen; 9893 ulen = strlen(argvp[0][0]); 9894 if (ulen > 7) { 9895 zeros = strstr(argvp[0][0], "/000000/"); 9896 if (zeros != NULL) { 9897 int mlen; 9898 mlen = ulen - (zeros - argvp[0][0]) - 7; 9899 memmove(zeros, &zeros[7], mlen); 9900 ulen = ulen - 7; 9901 argvp[0][0][ulen] = '\0'; 9902 } 9903 } 9904 /* It also may have a trailing dot that needs to be removed otherwise 9905 * it will be converted to VMS mode incorrectly. 9906 */ 9907 ulen--; 9908 if ((argvp[0][0][ulen] == '.') && (decc_readdir_dropdotnotype)) 9909 argvp[0][0][ulen] = '\0'; 9910 } 9911 9912 /* We need to use this hack to tell Perl it should run with tainting, 9913 * since its tainting flag may be part of the PL_curinterp struct, which 9914 * hasn't been allocated when vms_image_init() is called. 9915 */ 9916 if (will_taint) { 9917 char **newargv, **oldargv; 9918 oldargv = *argvp; 9919 newargv = (char **) PerlMem_malloc(((*argcp)+2) * sizeof(char *)); 9920 if (newargv == NULL) _ckvmssts_noperl(SS$_INSFMEM); 9921 newargv[0] = oldargv[0]; 9922 newargv[1] = PerlMem_malloc(3 * sizeof(char)); 9923 if (newargv[1] == NULL) _ckvmssts_noperl(SS$_INSFMEM); 9924 strcpy(newargv[1], "-T"); 9925 Copy(&oldargv[1],&newargv[2],(*argcp)-1,char **); 9926 (*argcp)++; 9927 newargv[*argcp] = NULL; 9928 /* We orphan the old argv, since we don't know where it's come from, 9929 * so we don't know how to free it. 9930 */ 9931 *argvp = newargv; 9932 } 9933 else { /* Did user explicitly request tainting? */ 9934 int i; 9935 char *cp, **av = *argvp; 9936 for (i = 1; i < *argcp; i++) { 9937 if (*av[i] != '-') break; 9938 for (cp = av[i]+1; *cp; cp++) { 9939 if (*cp == 'T') { will_taint = 1; break; } 9940 else if ( (*cp == 'd' || *cp == 'V') && *(cp+1) == ':' || 9941 strchr("DFIiMmx",*cp)) break; 9942 } 9943 if (will_taint) break; 9944 } 9945 } 9946 9947 for (tabidx = 0; 9948 len = my_trnlnm("PERL_ENV_TABLES",eqv,tabidx); 9949 tabidx++) { 9950 if (!tabidx) { 9951 tabvec = (struct dsc$descriptor_s **) 9952 PerlMem_malloc(tabct * sizeof(struct dsc$descriptor_s *)); 9953 if (tabvec == NULL) _ckvmssts_noperl(SS$_INSFMEM); 9954 } 9955 else if (tabidx >= tabct) { 9956 tabct += 8; 9957 tabvec = (struct dsc$descriptor_s **) PerlMem_realloc(tabvec, tabct * sizeof(struct dsc$descriptor_s *)); 9958 if (tabvec == NULL) _ckvmssts_noperl(SS$_INSFMEM); 9959 } 9960 tabvec[tabidx] = (struct dsc$descriptor_s *) PerlMem_malloc(sizeof(struct dsc$descriptor_s)); 9961 if (tabvec[tabidx] == NULL) _ckvmssts_noperl(SS$_INSFMEM); 9962 tabvec[tabidx]->dsc$w_length = 0; 9963 tabvec[tabidx]->dsc$b_dtype = DSC$K_DTYPE_T; 9964 tabvec[tabidx]->dsc$b_class = DSC$K_CLASS_D; 9965 tabvec[tabidx]->dsc$a_pointer = NULL; 9966 _ckvmssts_noperl(lib$scopy_r_dx(&len,eqv,tabvec[tabidx])); 9967 } 9968 if (tabidx) { tabvec[tabidx] = NULL; env_tables = tabvec; } 9969 9970 getredirection(argcp,argvp); 9971 #if defined(USE_ITHREADS) && ( defined(__DECC) || defined(__DECCXX) ) 9972 { 9973 # include <reentrancy.h> 9974 decc$set_reentrancy(C$C_MULTITHREAD); 9975 } 9976 #endif 9977 return; 9978 } 9979 /*}}}*/ 9980 9981 9982 /* trim_unixpath() 9983 * Trim Unix-style prefix off filespec, so it looks like what a shell 9984 * glob expansion would return (i.e. from specified prefix on, not 9985 * full path). Note that returned filespec is Unix-style, regardless 9986 * of whether input filespec was VMS-style or Unix-style. 9987 * 9988 * fspec is filespec to be trimmed, and wildspec is wildcard spec used to 9989 * determine prefix (both may be in VMS or Unix syntax). opts is a bit 9990 * vector of options; at present, only bit 0 is used, and if set tells 9991 * trim unixpath to try the current default directory as a prefix when 9992 * presented with a possibly ambiguous ... wildcard. 9993 * 9994 * Returns !=0 on success, with trimmed filespec replacing contents of 9995 * fspec, and 0 on failure, with contents of fpsec unchanged. 9996 */ 9997 /*{{{int trim_unixpath(char *fspec, char *wildspec, int opts)*/ 9998 int 9999 Perl_trim_unixpath(pTHX_ char *fspec, const char *wildspec, int opts) 10000 { 10001 char *unixified, *unixwild, 10002 *template, *base, *end, *cp1, *cp2; 10003 register int tmplen, reslen = 0, dirs = 0; 10004 10005 if (!wildspec || !fspec) return 0; 10006 10007 unixwild = PerlMem_malloc(VMS_MAXRSS); 10008 if (unixwild == NULL) _ckvmssts_noperl(SS$_INSFMEM); 10009 template = unixwild; 10010 if (strpbrk(wildspec,"]>:") != NULL) { 10011 if (int_tounixspec(wildspec, unixwild, NULL) == NULL) { 10012 PerlMem_free(unixwild); 10013 return 0; 10014 } 10015 } 10016 else { 10017 strncpy(unixwild, wildspec, VMS_MAXRSS-1); 10018 unixwild[VMS_MAXRSS-1] = 0; 10019 } 10020 unixified = PerlMem_malloc(VMS_MAXRSS); 10021 if (unixified == NULL) _ckvmssts_noperl(SS$_INSFMEM); 10022 if (strpbrk(fspec,"]>:") != NULL) { 10023 if (int_tounixspec(fspec, unixified, NULL) == NULL) { 10024 PerlMem_free(unixwild); 10025 PerlMem_free(unixified); 10026 return 0; 10027 } 10028 else base = unixified; 10029 /* reslen != 0 ==> we had to unixify resultant filespec, so we must 10030 * check to see that final result fits into (isn't longer than) fspec */ 10031 reslen = strlen(fspec); 10032 } 10033 else base = fspec; 10034 10035 /* No prefix or absolute path on wildcard, so nothing to remove */ 10036 if (!*template || *template == '/') { 10037 PerlMem_free(unixwild); 10038 if (base == fspec) { 10039 PerlMem_free(unixified); 10040 return 1; 10041 } 10042 tmplen = strlen(unixified); 10043 if (tmplen > reslen) { 10044 PerlMem_free(unixified); 10045 return 0; /* not enough space */ 10046 } 10047 /* Copy unixified resultant, including trailing NUL */ 10048 memmove(fspec,unixified,tmplen+1); 10049 PerlMem_free(unixified); 10050 return 1; 10051 } 10052 10053 for (end = base; *end; end++) ; /* Find end of resultant filespec */ 10054 if ((cp1 = strstr(template,".../")) == NULL) { /* No ...; just count elts */ 10055 for (cp1 = template; *cp1; cp1++) if (*cp1 == '/') dirs++; 10056 for (cp1 = end ;cp1 >= base; cp1--) 10057 if ((*cp1 == '/') && !dirs--) /* postdec so we get front of rel path */ 10058 { cp1++; break; } 10059 if (cp1 != fspec) memmove(fspec,cp1, end - cp1 + 1); 10060 PerlMem_free(unixified); 10061 PerlMem_free(unixwild); 10062 return 1; 10063 } 10064 else { 10065 char *tpl, *lcres; 10066 char *front, *nextell, *lcend, *lcfront, *ellipsis = cp1; 10067 int ells = 1, totells, segdirs, match; 10068 struct dsc$descriptor_s wilddsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL}, 10069 resdsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0}; 10070 10071 while ((cp1 = strstr(ellipsis+4,".../")) != NULL) {ellipsis = cp1; ells++;} 10072 totells = ells; 10073 for (cp1 = ellipsis+4; *cp1; cp1++) if (*cp1 == '/') dirs++; 10074 tpl = PerlMem_malloc(VMS_MAXRSS); 10075 if (tpl == NULL) _ckvmssts_noperl(SS$_INSFMEM); 10076 if (ellipsis == template && opts & 1) { 10077 /* Template begins with an ellipsis. Since we can't tell how many 10078 * directory names at the front of the resultant to keep for an 10079 * arbitrary starting point, we arbitrarily choose the current 10080 * default directory as a starting point. If it's there as a prefix, 10081 * clip it off. If not, fall through and act as if the leading 10082 * ellipsis weren't there (i.e. return shortest possible path that 10083 * could match template). 10084 */ 10085 if (getcwd(tpl, (VMS_MAXRSS - 1),0) == NULL) { 10086 PerlMem_free(tpl); 10087 PerlMem_free(unixified); 10088 PerlMem_free(unixwild); 10089 return 0; 10090 } 10091 if (!decc_efs_case_preserve) { 10092 for (cp1 = tpl, cp2 = base; *cp1 && *cp2; cp1++,cp2++) 10093 if (_tolower(*cp1) != _tolower(*cp2)) break; 10094 } 10095 segdirs = dirs - totells; /* Min # of dirs we must have left */ 10096 for (front = cp2+1; *front; front++) if (*front == '/') segdirs--; 10097 if (*cp1 == '\0' && *cp2 == '/' && segdirs < 1) { 10098 memmove(fspec,cp2+1,end - cp2); 10099 PerlMem_free(tpl); 10100 PerlMem_free(unixified); 10101 PerlMem_free(unixwild); 10102 return 1; 10103 } 10104 } 10105 /* First off, back up over constant elements at end of path */ 10106 if (dirs) { 10107 for (front = end ; front >= base; front--) 10108 if (*front == '/' && !dirs--) { front++; break; } 10109 } 10110 lcres = PerlMem_malloc(VMS_MAXRSS); 10111 if (lcres == NULL) _ckvmssts_noperl(SS$_INSFMEM); 10112 for (cp1=template,cp2=lcres; *cp1 && cp2 <= lcres + (VMS_MAXRSS - 1); 10113 cp1++,cp2++) { 10114 if (!decc_efs_case_preserve) { 10115 *cp2 = _tolower(*cp1); /* Make lc copy for match */ 10116 } 10117 else { 10118 *cp2 = *cp1; 10119 } 10120 } 10121 if (cp1 != '\0') { 10122 PerlMem_free(tpl); 10123 PerlMem_free(unixified); 10124 PerlMem_free(unixwild); 10125 PerlMem_free(lcres); 10126 return 0; /* Path too long. */ 10127 } 10128 lcend = cp2; 10129 *cp2 = '\0'; /* Pick up with memcpy later */ 10130 lcfront = lcres + (front - base); 10131 /* Now skip over each ellipsis and try to match the path in front of it. */ 10132 while (ells--) { 10133 for (cp1 = ellipsis - 2; cp1 >= template; cp1--) 10134 if (*(cp1) == '.' && *(cp1+1) == '.' && 10135 *(cp1+2) == '.' && *(cp1+3) == '/' ) break; 10136 if (cp1 < template) break; /* template started with an ellipsis */ 10137 if (cp1 + 4 == ellipsis) { /* Consecutive ellipses */ 10138 ellipsis = cp1; continue; 10139 } 10140 wilddsc.dsc$a_pointer = tpl; 10141 wilddsc.dsc$w_length = resdsc.dsc$w_length = ellipsis - 1 - cp1; 10142 nextell = cp1; 10143 for (segdirs = 0, cp2 = tpl; 10144 cp1 <= ellipsis - 1 && cp2 <= tpl + (VMS_MAXRSS-1); 10145 cp1++, cp2++) { 10146 if (*cp1 == '?') *cp2 = '%'; /* Substitute VMS' wildcard for Unix' */ 10147 else { 10148 if (!decc_efs_case_preserve) { 10149 *cp2 = _tolower(*cp1); /* else lowercase for match */ 10150 } 10151 else { 10152 *cp2 = *cp1; /* else preserve case for match */ 10153 } 10154 } 10155 if (*cp2 == '/') segdirs++; 10156 } 10157 if (cp1 != ellipsis - 1) { 10158 PerlMem_free(tpl); 10159 PerlMem_free(unixified); 10160 PerlMem_free(unixwild); 10161 PerlMem_free(lcres); 10162 return 0; /* Path too long */ 10163 } 10164 /* Back up at least as many dirs as in template before matching */ 10165 for (cp1 = lcfront - 1; segdirs && cp1 >= lcres; cp1--) 10166 if (*cp1 == '/' && !segdirs--) { cp1++; break; } 10167 for (match = 0; cp1 > lcres;) { 10168 resdsc.dsc$a_pointer = cp1; 10169 if (str$match_wild(&wilddsc,&resdsc) == STR$_MATCH) { 10170 match++; 10171 if (match == 1) lcfront = cp1; 10172 } 10173 for ( ; cp1 >= lcres; cp1--) if (*cp1 == '/') { cp1++; break; } 10174 } 10175 if (!match) { 10176 PerlMem_free(tpl); 10177 PerlMem_free(unixified); 10178 PerlMem_free(unixwild); 10179 PerlMem_free(lcres); 10180 return 0; /* Can't find prefix ??? */ 10181 } 10182 if (match > 1 && opts & 1) { 10183 /* This ... wildcard could cover more than one set of dirs (i.e. 10184 * a set of similar dir names is repeated). If the template 10185 * contains more than 1 ..., upstream elements could resolve the 10186 * ambiguity, but it's not worth a full backtracking setup here. 10187 * As a quick heuristic, clip off the current default directory 10188 * if it's present to find the trimmed spec, else use the 10189 * shortest string that this ... could cover. 10190 */ 10191 char def[NAM$C_MAXRSS+1], *st; 10192 10193 if (getcwd(def, sizeof def,0) == NULL) { 10194 PerlMem_free(unixified); 10195 PerlMem_free(unixwild); 10196 PerlMem_free(lcres); 10197 PerlMem_free(tpl); 10198 return 0; 10199 } 10200 if (!decc_efs_case_preserve) { 10201 for (cp1 = def, cp2 = base; *cp1 && *cp2; cp1++,cp2++) 10202 if (_tolower(*cp1) != _tolower(*cp2)) break; 10203 } 10204 segdirs = dirs - totells; /* Min # of dirs we must have left */ 10205 for (st = cp2+1; *st; st++) if (*st == '/') segdirs--; 10206 if (*cp1 == '\0' && *cp2 == '/') { 10207 memmove(fspec,cp2+1,end - cp2); 10208 PerlMem_free(tpl); 10209 PerlMem_free(unixified); 10210 PerlMem_free(unixwild); 10211 PerlMem_free(lcres); 10212 return 1; 10213 } 10214 /* Nope -- stick with lcfront from above and keep going. */ 10215 } 10216 } 10217 memmove(fspec,base + (lcfront - lcres), lcend - lcfront + 1); 10218 PerlMem_free(tpl); 10219 PerlMem_free(unixified); 10220 PerlMem_free(unixwild); 10221 PerlMem_free(lcres); 10222 return 1; 10223 ellipsis = nextell; 10224 } 10225 10226 } /* end of trim_unixpath() */ 10227 /*}}}*/ 10228 10229 10230 /* 10231 * VMS readdir() routines. 10232 * Written by Rich $alz, <rsalz@bbn.com> in August, 1990. 10233 * 10234 * 21-Jul-1994 Charles Bailey bailey@newman.upenn.edu 10235 * Minor modifications to original routines. 10236 */ 10237 10238 /* readdir may have been redefined by reentr.h, so make sure we get 10239 * the local version for what we do here. 10240 */ 10241 #ifdef readdir 10242 # undef readdir 10243 #endif 10244 #if !defined(PERL_IMPLICIT_CONTEXT) 10245 # define readdir Perl_readdir 10246 #else 10247 # define readdir(a) Perl_readdir(aTHX_ a) 10248 #endif 10249 10250 /* Number of elements in vms_versions array */ 10251 #define VERSIZE(e) (sizeof e->vms_versions / sizeof e->vms_versions[0]) 10252 10253 /* 10254 * Open a directory, return a handle for later use. 10255 */ 10256 /*{{{ DIR *opendir(char*name) */ 10257 DIR * 10258 Perl_opendir(pTHX_ const char *name) 10259 { 10260 DIR *dd; 10261 char *dir; 10262 Stat_t sb; 10263 10264 Newx(dir, VMS_MAXRSS, char); 10265 if (int_tovmspath(name, dir, NULL) == NULL) { 10266 Safefree(dir); 10267 return NULL; 10268 } 10269 /* Check access before stat; otherwise stat does not 10270 * accurately report whether it's a directory. 10271 */ 10272 if (!cando_by_name_int(S_IRUSR,0,dir,PERL_RMSEXPAND_M_VMS_IN)) { 10273 /* cando_by_name has already set errno */ 10274 Safefree(dir); 10275 return NULL; 10276 } 10277 if (flex_stat(dir,&sb) == -1) return NULL; 10278 if (!S_ISDIR(sb.st_mode)) { 10279 Safefree(dir); 10280 set_errno(ENOTDIR); set_vaxc_errno(RMS$_DIR); 10281 return NULL; 10282 } 10283 /* Get memory for the handle, and the pattern. */ 10284 Newx(dd,1,DIR); 10285 Newx(dd->pattern,strlen(dir)+sizeof "*.*" + 1,char); 10286 10287 /* Fill in the fields; mainly playing with the descriptor. */ 10288 sprintf(dd->pattern, "%s*.*",dir); 10289 Safefree(dir); 10290 dd->context = 0; 10291 dd->count = 0; 10292 dd->flags = 0; 10293 /* By saying we always want the result of readdir() in unix format, we 10294 * are really saying we want all the escapes removed. Otherwise the caller, 10295 * having no way to know whether it's already in VMS format, might send it 10296 * through tovmsspec again, thus double escaping. 10297 */ 10298 dd->flags = PERL_VMSDIR_M_UNIXSPECS; 10299 dd->pat.dsc$a_pointer = dd->pattern; 10300 dd->pat.dsc$w_length = strlen(dd->pattern); 10301 dd->pat.dsc$b_dtype = DSC$K_DTYPE_T; 10302 dd->pat.dsc$b_class = DSC$K_CLASS_S; 10303 #if defined(USE_ITHREADS) 10304 Newx(dd->mutex,1,perl_mutex); 10305 MUTEX_INIT( (perl_mutex *) dd->mutex ); 10306 #else 10307 dd->mutex = NULL; 10308 #endif 10309 10310 return dd; 10311 } /* end of opendir() */ 10312 /*}}}*/ 10313 10314 /* 10315 * Set the flag to indicate we want versions or not. 10316 */ 10317 /*{{{ void vmsreaddirversions(DIR *dd, int flag)*/ 10318 void 10319 vmsreaddirversions(DIR *dd, int flag) 10320 { 10321 if (flag) 10322 dd->flags |= PERL_VMSDIR_M_VERSIONS; 10323 else 10324 dd->flags &= ~PERL_VMSDIR_M_VERSIONS; 10325 } 10326 /*}}}*/ 10327 10328 /* 10329 * Free up an opened directory. 10330 */ 10331 /*{{{ void closedir(DIR *dd)*/ 10332 void 10333 Perl_closedir(DIR *dd) 10334 { 10335 int sts; 10336 10337 sts = lib$find_file_end(&dd->context); 10338 Safefree(dd->pattern); 10339 #if defined(USE_ITHREADS) 10340 MUTEX_DESTROY( (perl_mutex *) dd->mutex ); 10341 Safefree(dd->mutex); 10342 #endif 10343 Safefree(dd); 10344 } 10345 /*}}}*/ 10346 10347 /* 10348 * Collect all the version numbers for the current file. 10349 */ 10350 static void 10351 collectversions(pTHX_ DIR *dd) 10352 { 10353 struct dsc$descriptor_s pat; 10354 struct dsc$descriptor_s res; 10355 struct dirent *e; 10356 char *p, *text, *buff; 10357 int i; 10358 unsigned long context, tmpsts; 10359 10360 /* Convenient shorthand. */ 10361 e = &dd->entry; 10362 10363 /* Add the version wildcard, ignoring the "*.*" put on before */ 10364 i = strlen(dd->pattern); 10365 Newx(text,i + e->d_namlen + 3,char); 10366 strcpy(text, dd->pattern); 10367 sprintf(&text[i - 3], "%s;*", e->d_name); 10368 10369 /* Set up the pattern descriptor. */ 10370 pat.dsc$a_pointer = text; 10371 pat.dsc$w_length = i + e->d_namlen - 1; 10372 pat.dsc$b_dtype = DSC$K_DTYPE_T; 10373 pat.dsc$b_class = DSC$K_CLASS_S; 10374 10375 /* Set up result descriptor. */ 10376 Newx(buff, VMS_MAXRSS, char); 10377 res.dsc$a_pointer = buff; 10378 res.dsc$w_length = VMS_MAXRSS - 1; 10379 res.dsc$b_dtype = DSC$K_DTYPE_T; 10380 res.dsc$b_class = DSC$K_CLASS_S; 10381 10382 /* Read files, collecting versions. */ 10383 for (context = 0, e->vms_verscount = 0; 10384 e->vms_verscount < VERSIZE(e); 10385 e->vms_verscount++) { 10386 unsigned long rsts; 10387 unsigned long flags = 0; 10388 10389 #ifdef VMS_LONGNAME_SUPPORT 10390 flags = LIB$M_FIL_LONG_NAMES; 10391 #endif 10392 tmpsts = lib$find_file(&pat, &res, &context, NULL, NULL, &rsts, &flags); 10393 if (tmpsts == RMS$_NMF || context == 0) break; 10394 _ckvmssts(tmpsts); 10395 buff[VMS_MAXRSS - 1] = '\0'; 10396 if ((p = strchr(buff, ';'))) 10397 e->vms_versions[e->vms_verscount] = atoi(p + 1); 10398 else 10399 e->vms_versions[e->vms_verscount] = -1; 10400 } 10401 10402 _ckvmssts(lib$find_file_end(&context)); 10403 Safefree(text); 10404 Safefree(buff); 10405 10406 } /* end of collectversions() */ 10407 10408 /* 10409 * Read the next entry from the directory. 10410 */ 10411 /*{{{ struct dirent *readdir(DIR *dd)*/ 10412 struct dirent * 10413 Perl_readdir(pTHX_ DIR *dd) 10414 { 10415 struct dsc$descriptor_s res; 10416 char *p, *buff; 10417 unsigned long int tmpsts; 10418 unsigned long rsts; 10419 unsigned long flags = 0; 10420 char * v_spec, * r_spec, * d_spec, * n_spec, * e_spec, * vs_spec; 10421 int sts, v_len, r_len, d_len, n_len, e_len, vs_len; 10422 10423 /* Set up result descriptor, and get next file. */ 10424 Newx(buff, VMS_MAXRSS, char); 10425 res.dsc$a_pointer = buff; 10426 res.dsc$w_length = VMS_MAXRSS - 1; 10427 res.dsc$b_dtype = DSC$K_DTYPE_T; 10428 res.dsc$b_class = DSC$K_CLASS_S; 10429 10430 #ifdef VMS_LONGNAME_SUPPORT 10431 flags = LIB$M_FIL_LONG_NAMES; 10432 #endif 10433 10434 tmpsts = lib$find_file 10435 (&dd->pat, &res, &dd->context, NULL, NULL, &rsts, &flags); 10436 if ( tmpsts == RMS$_NMF || dd->context == 0) return NULL; /* None left. */ 10437 if (!(tmpsts & 1)) { 10438 set_vaxc_errno(tmpsts); 10439 switch (tmpsts) { 10440 case RMS$_PRV: 10441 set_errno(EACCES); break; 10442 case RMS$_DEV: 10443 set_errno(ENODEV); break; 10444 case RMS$_DIR: 10445 set_errno(ENOTDIR); break; 10446 case RMS$_FNF: case RMS$_DNF: 10447 set_errno(ENOENT); break; 10448 default: 10449 set_errno(EVMSERR); 10450 } 10451 Safefree(buff); 10452 return NULL; 10453 } 10454 dd->count++; 10455 /* Force the buffer to end with a NUL, and downcase name to match C convention. */ 10456 buff[res.dsc$w_length] = '\0'; 10457 p = buff + res.dsc$w_length; 10458 while (--p >= buff) if (!isspace(*p)) break; 10459 *p = '\0'; 10460 if (!decc_efs_case_preserve) { 10461 for (p = buff; *p; p++) *p = _tolower(*p); 10462 } 10463 10464 /* Skip any directory component and just copy the name. */ 10465 sts = vms_split_path 10466 (buff, 10467 &v_spec, 10468 &v_len, 10469 &r_spec, 10470 &r_len, 10471 &d_spec, 10472 &d_len, 10473 &n_spec, 10474 &n_len, 10475 &e_spec, 10476 &e_len, 10477 &vs_spec, 10478 &vs_len); 10479 10480 if (dd->flags & PERL_VMSDIR_M_UNIXSPECS) { 10481 10482 /* In Unix report mode, remove the ".dir;1" from the name */ 10483 /* if it is a real directory. */ 10484 if (decc_filename_unix_report || decc_efs_charset) { 10485 if (is_dir_ext(e_spec, e_len, vs_spec, vs_len)) { 10486 Stat_t statbuf; 10487 int ret_sts; 10488 10489 ret_sts = flex_lstat(buff, &statbuf); 10490 if ((ret_sts == 0) && S_ISDIR(statbuf.st_mode)) { 10491 e_len = 0; 10492 e_spec[0] = 0; 10493 } 10494 } 10495 } 10496 10497 /* Drop NULL extensions on UNIX file specification */ 10498 if ((e_len == 1) && decc_readdir_dropdotnotype) { 10499 e_len = 0; 10500 e_spec[0] = '\0'; 10501 } 10502 } 10503 10504 strncpy(dd->entry.d_name, n_spec, n_len + e_len); 10505 dd->entry.d_name[n_len + e_len] = '\0'; 10506 dd->entry.d_namlen = strlen(dd->entry.d_name); 10507 10508 /* Convert the filename to UNIX format if needed */ 10509 if (dd->flags & PERL_VMSDIR_M_UNIXSPECS) { 10510 10511 /* Translate the encoded characters. */ 10512 /* Fixme: Unicode handling could result in embedded 0 characters */ 10513 if (strchr(dd->entry.d_name, '^') != NULL) { 10514 char new_name[256]; 10515 char * q; 10516 p = dd->entry.d_name; 10517 q = new_name; 10518 while (*p != 0) { 10519 int inchars_read, outchars_added; 10520 inchars_read = copy_expand_vms_filename_escape(q, p, &outchars_added); 10521 p += inchars_read; 10522 q += outchars_added; 10523 /* fix-me */ 10524 /* if outchars_added > 1, then this is a wide file specification */ 10525 /* Wide file specifications need to be passed in Perl */ 10526 /* counted strings apparently with a Unicode flag */ 10527 } 10528 *q = 0; 10529 strcpy(dd->entry.d_name, new_name); 10530 dd->entry.d_namlen = strlen(dd->entry.d_name); 10531 } 10532 } 10533 10534 dd->entry.vms_verscount = 0; 10535 if (dd->flags & PERL_VMSDIR_M_VERSIONS) collectversions(aTHX_ dd); 10536 Safefree(buff); 10537 return &dd->entry; 10538 10539 } /* end of readdir() */ 10540 /*}}}*/ 10541 10542 /* 10543 * Read the next entry from the directory -- thread-safe version. 10544 */ 10545 /*{{{ int readdir_r(DIR *dd, struct dirent *entry, struct dirent **result)*/ 10546 int 10547 Perl_readdir_r(pTHX_ DIR *dd, struct dirent *entry, struct dirent **result) 10548 { 10549 int retval; 10550 10551 MUTEX_LOCK( (perl_mutex *) dd->mutex ); 10552 10553 entry = readdir(dd); 10554 *result = entry; 10555 retval = ( *result == NULL ? errno : 0 ); 10556 10557 MUTEX_UNLOCK( (perl_mutex *) dd->mutex ); 10558 10559 return retval; 10560 10561 } /* end of readdir_r() */ 10562 /*}}}*/ 10563 10564 /* 10565 * Return something that can be used in a seekdir later. 10566 */ 10567 /*{{{ long telldir(DIR *dd)*/ 10568 long 10569 Perl_telldir(DIR *dd) 10570 { 10571 return dd->count; 10572 } 10573 /*}}}*/ 10574 10575 /* 10576 * Return to a spot where we used to be. Brute force. 10577 */ 10578 /*{{{ void seekdir(DIR *dd,long count)*/ 10579 void 10580 Perl_seekdir(pTHX_ DIR *dd, long count) 10581 { 10582 int old_flags; 10583 10584 /* If we haven't done anything yet... */ 10585 if (dd->count == 0) 10586 return; 10587 10588 /* Remember some state, and clear it. */ 10589 old_flags = dd->flags; 10590 dd->flags &= ~PERL_VMSDIR_M_VERSIONS; 10591 _ckvmssts(lib$find_file_end(&dd->context)); 10592 dd->context = 0; 10593 10594 /* The increment is in readdir(). */ 10595 for (dd->count = 0; dd->count < count; ) 10596 readdir(dd); 10597 10598 dd->flags = old_flags; 10599 10600 } /* end of seekdir() */ 10601 /*}}}*/ 10602 10603 /* VMS subprocess management 10604 * 10605 * my_vfork() - just a vfork(), after setting a flag to record that 10606 * the current script is trying a Unix-style fork/exec. 10607 * 10608 * vms_do_aexec() and vms_do_exec() are called in response to the 10609 * perl 'exec' function. If this follows a vfork call, then they 10610 * call out the regular perl routines in doio.c which do an 10611 * execvp (for those who really want to try this under VMS). 10612 * Otherwise, they do exactly what the perl docs say exec should 10613 * do - terminate the current script and invoke a new command 10614 * (See below for notes on command syntax.) 10615 * 10616 * do_aspawn() and do_spawn() implement the VMS side of the perl 10617 * 'system' function. 10618 * 10619 * Note on command arguments to perl 'exec' and 'system': When handled 10620 * in 'VMSish fashion' (i.e. not after a call to vfork) The args 10621 * are concatenated to form a DCL command string. If the first non-numeric 10622 * arg begins with '$' (i.e. the perl script had "\$ Type" or some such), 10623 * the command string is handed off to DCL directly. Otherwise, 10624 * the first token of the command is taken as the filespec of an image 10625 * to run. The filespec is expanded using a default type of '.EXE' and 10626 * the process defaults for device, directory, etc., and if found, the resultant 10627 * filespec is invoked using the DCL verb 'MCR', and passed the rest of 10628 * the command string as parameters. This is perhaps a bit complicated, 10629 * but I hope it will form a happy medium between what VMS folks expect 10630 * from lib$spawn and what Unix folks expect from exec. 10631 */ 10632 10633 static int vfork_called; 10634 10635 /*{{{int my_vfork()*/ 10636 int 10637 my_vfork() 10638 { 10639 vfork_called++; 10640 return vfork(); 10641 } 10642 /*}}}*/ 10643 10644 10645 static void 10646 vms_execfree(struct dsc$descriptor_s *vmscmd) 10647 { 10648 if (vmscmd) { 10649 if (vmscmd->dsc$a_pointer) { 10650 PerlMem_free(vmscmd->dsc$a_pointer); 10651 } 10652 PerlMem_free(vmscmd); 10653 } 10654 } 10655 10656 static char * 10657 setup_argstr(pTHX_ SV *really, SV **mark, SV **sp) 10658 { 10659 char *junk, *tmps = NULL; 10660 register size_t cmdlen = 0; 10661 size_t rlen; 10662 register SV **idx; 10663 STRLEN n_a; 10664 10665 idx = mark; 10666 if (really) { 10667 tmps = SvPV(really,rlen); 10668 if (*tmps) { 10669 cmdlen += rlen + 1; 10670 idx++; 10671 } 10672 } 10673 10674 for (idx++; idx <= sp; idx++) { 10675 if (*idx) { 10676 junk = SvPVx(*idx,rlen); 10677 cmdlen += rlen ? rlen + 1 : 0; 10678 } 10679 } 10680 Newx(PL_Cmd, cmdlen+1, char); 10681 10682 if (tmps && *tmps) { 10683 strcpy(PL_Cmd,tmps); 10684 mark++; 10685 } 10686 else *PL_Cmd = '\0'; 10687 while (++mark <= sp) { 10688 if (*mark) { 10689 char *s = SvPVx(*mark,n_a); 10690 if (!*s) continue; 10691 if (*PL_Cmd) strcat(PL_Cmd," "); 10692 strcat(PL_Cmd,s); 10693 } 10694 } 10695 return PL_Cmd; 10696 10697 } /* end of setup_argstr() */ 10698 10699 10700 static unsigned long int 10701 setup_cmddsc(pTHX_ const char *incmd, int check_img, int *suggest_quote, 10702 struct dsc$descriptor_s **pvmscmd) 10703 { 10704 char * vmsspec; 10705 char * resspec; 10706 char image_name[NAM$C_MAXRSS+1]; 10707 char image_argv[NAM$C_MAXRSS+1]; 10708 $DESCRIPTOR(defdsc,".EXE"); 10709 $DESCRIPTOR(defdsc2,"."); 10710 struct dsc$descriptor_s resdsc; 10711 struct dsc$descriptor_s *vmscmd; 10712 struct dsc$descriptor_s imgdsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0}; 10713 unsigned long int cxt = 0, flags = 1, retsts = SS$_NORMAL; 10714 register char *s, *rest, *cp, *wordbreak; 10715 char * cmd; 10716 int cmdlen; 10717 register int isdcl; 10718 10719 vmscmd = PerlMem_malloc(sizeof(struct dsc$descriptor_s)); 10720 if (vmscmd == NULL) _ckvmssts_noperl(SS$_INSFMEM); 10721 10722 /* vmsspec is a DCL command buffer, not just a filename */ 10723 vmsspec = PerlMem_malloc(MAX_DCL_LINE_LENGTH + 1); 10724 if (vmsspec == NULL) 10725 _ckvmssts_noperl(SS$_INSFMEM); 10726 10727 resspec = PerlMem_malloc(VMS_MAXRSS); 10728 if (resspec == NULL) 10729 _ckvmssts_noperl(SS$_INSFMEM); 10730 10731 /* Make a copy for modification */ 10732 cmdlen = strlen(incmd); 10733 cmd = PerlMem_malloc(cmdlen+1); 10734 if (cmd == NULL) _ckvmssts_noperl(SS$_INSFMEM); 10735 strncpy(cmd, incmd, cmdlen); 10736 cmd[cmdlen] = 0; 10737 image_name[0] = 0; 10738 image_argv[0] = 0; 10739 10740 resdsc.dsc$a_pointer = resspec; 10741 resdsc.dsc$b_dtype = DSC$K_DTYPE_T; 10742 resdsc.dsc$b_class = DSC$K_CLASS_S; 10743 resdsc.dsc$w_length = VMS_MAXRSS - 1; 10744 10745 vmscmd->dsc$a_pointer = NULL; 10746 vmscmd->dsc$b_dtype = DSC$K_DTYPE_T; 10747 vmscmd->dsc$b_class = DSC$K_CLASS_S; 10748 vmscmd->dsc$w_length = 0; 10749 if (pvmscmd) *pvmscmd = vmscmd; 10750 10751 if (suggest_quote) *suggest_quote = 0; 10752 10753 if (strlen(cmd) > MAX_DCL_LINE_LENGTH) { 10754 PerlMem_free(cmd); 10755 PerlMem_free(vmsspec); 10756 PerlMem_free(resspec); 10757 return CLI$_BUFOVF; /* continuation lines currently unsupported */ 10758 } 10759 10760 s = cmd; 10761 10762 while (*s && isspace(*s)) s++; 10763 10764 if (*s == '@' || *s == '$') { 10765 vmsspec[0] = *s; rest = s + 1; 10766 for (cp = &vmsspec[1]; *rest && isspace(*rest); rest++,cp++) *cp = *rest; 10767 } 10768 else { cp = vmsspec; rest = s; } 10769 if (*rest == '.' || *rest == '/') { 10770 char *cp2; 10771 for (cp2 = resspec; 10772 *rest && !isspace(*rest) && cp2 - resspec < (VMS_MAXRSS - 1); 10773 rest++, cp2++) *cp2 = *rest; 10774 *cp2 = '\0'; 10775 if (int_tovmsspec(resspec, cp, 0, NULL)) { 10776 s = vmsspec; 10777 10778 /* When a UNIX spec with no file type is translated to VMS, */ 10779 /* A trailing '.' is appended under ODS-5 rules. */ 10780 /* Here we do not want that trailing "." as it prevents */ 10781 /* Looking for a implied ".exe" type. */ 10782 if (decc_efs_charset) { 10783 int i; 10784 i = strlen(vmsspec); 10785 if (vmsspec[i-1] == '.') { 10786 vmsspec[i-1] = '\0'; 10787 } 10788 } 10789 10790 if (*rest) { 10791 for (cp2 = vmsspec + strlen(vmsspec); 10792 *rest && cp2 - vmsspec < MAX_DCL_LINE_LENGTH; 10793 rest++, cp2++) *cp2 = *rest; 10794 *cp2 = '\0'; 10795 } 10796 } 10797 } 10798 /* Intuit whether verb (first word of cmd) is a DCL command: 10799 * - if first nonspace char is '@', it's a DCL indirection 10800 * otherwise 10801 * - if verb contains a filespec separator, it's not a DCL command 10802 * - if it doesn't, caller tells us whether to default to a DCL 10803 * command, or to a local image unless told it's DCL (by leading '$') 10804 */ 10805 if (*s == '@') { 10806 isdcl = 1; 10807 if (suggest_quote) *suggest_quote = 1; 10808 } else { 10809 register char *filespec = strpbrk(s,":<[.;"); 10810 rest = wordbreak = strpbrk(s," \"\t/"); 10811 if (!wordbreak) wordbreak = s + strlen(s); 10812 if (*s == '$') check_img = 0; 10813 if (filespec && (filespec < wordbreak)) isdcl = 0; 10814 else isdcl = !check_img; 10815 } 10816 10817 if (!isdcl) { 10818 int rsts; 10819 imgdsc.dsc$a_pointer = s; 10820 imgdsc.dsc$w_length = wordbreak - s; 10821 retsts = lib$find_file(&imgdsc,&resdsc,&cxt,&defdsc,0,&rsts,&flags); 10822 if (!(retsts&1)) { 10823 _ckvmssts_noperl(lib$find_file_end(&cxt)); 10824 retsts = lib$find_file(&imgdsc,&resdsc,&cxt,&defdsc2,0,&rsts,&flags); 10825 if (!(retsts & 1) && *s == '$') { 10826 _ckvmssts_noperl(lib$find_file_end(&cxt)); 10827 imgdsc.dsc$a_pointer++; imgdsc.dsc$w_length--; 10828 retsts = lib$find_file(&imgdsc,&resdsc,&cxt,&defdsc,0,&rsts,&flags); 10829 if (!(retsts&1)) { 10830 _ckvmssts_noperl(lib$find_file_end(&cxt)); 10831 retsts = lib$find_file(&imgdsc,&resdsc,&cxt,&defdsc2,0,&rsts,&flags); 10832 } 10833 } 10834 } 10835 _ckvmssts_noperl(lib$find_file_end(&cxt)); 10836 10837 if (retsts & 1) { 10838 FILE *fp; 10839 s = resspec; 10840 while (*s && !isspace(*s)) s++; 10841 *s = '\0'; 10842 10843 /* check that it's really not DCL with no file extension */ 10844 fp = fopen(resspec,"r","ctx=bin","ctx=rec","shr=get"); 10845 if (fp) { 10846 char b[256] = {0,0,0,0}; 10847 read(fileno(fp), b, 256); 10848 isdcl = isprint(b[0]) && isprint(b[1]) && isprint(b[2]) && isprint(b[3]); 10849 if (isdcl) { 10850 int shebang_len; 10851 10852 /* Check for script */ 10853 shebang_len = 0; 10854 if ((b[0] == '#') && (b[1] == '!')) 10855 shebang_len = 2; 10856 #ifdef ALTERNATE_SHEBANG 10857 else { 10858 shebang_len = strlen(ALTERNATE_SHEBANG); 10859 if (strncmp(b, ALTERNATE_SHEBANG, shebang_len) == 0) { 10860 char * perlstr; 10861 perlstr = strstr("perl",b); 10862 if (perlstr == NULL) 10863 shebang_len = 0; 10864 } 10865 else 10866 shebang_len = 0; 10867 } 10868 #endif 10869 10870 if (shebang_len > 0) { 10871 int i; 10872 int j; 10873 char tmpspec[NAM$C_MAXRSS + 1]; 10874 10875 i = shebang_len; 10876 /* Image is following after white space */ 10877 /*--------------------------------------*/ 10878 while (isprint(b[i]) && isspace(b[i])) 10879 i++; 10880 10881 j = 0; 10882 while (isprint(b[i]) && !isspace(b[i])) { 10883 tmpspec[j++] = b[i++]; 10884 if (j >= NAM$C_MAXRSS) 10885 break; 10886 } 10887 tmpspec[j] = '\0'; 10888 10889 /* There may be some default parameters to the image */ 10890 /*---------------------------------------------------*/ 10891 j = 0; 10892 while (isprint(b[i])) { 10893 image_argv[j++] = b[i++]; 10894 if (j >= NAM$C_MAXRSS) 10895 break; 10896 } 10897 while ((j > 0) && !isprint(image_argv[j-1])) 10898 j--; 10899 image_argv[j] = 0; 10900 10901 /* It will need to be converted to VMS format and validated */ 10902 if (tmpspec[0] != '\0') { 10903 char * iname; 10904 10905 /* Try to find the exact program requested to be run */ 10906 /*---------------------------------------------------*/ 10907 iname = int_rmsexpand 10908 (tmpspec, image_name, ".exe", 10909 PERL_RMSEXPAND_M_VMS, NULL, NULL); 10910 if (iname != NULL) { 10911 if (cando_by_name_int 10912 (S_IXUSR,0,image_name,PERL_RMSEXPAND_M_VMS_IN)) { 10913 /* MCR prefix needed */ 10914 isdcl = 0; 10915 } 10916 else { 10917 /* Try again with a null type */ 10918 /*----------------------------*/ 10919 iname = int_rmsexpand 10920 (tmpspec, image_name, ".", 10921 PERL_RMSEXPAND_M_VMS, NULL, NULL); 10922 if (iname != NULL) { 10923 if (cando_by_name_int 10924 (S_IXUSR,0,image_name, PERL_RMSEXPAND_M_VMS_IN)) { 10925 /* MCR prefix needed */ 10926 isdcl = 0; 10927 } 10928 } 10929 } 10930 10931 /* Did we find the image to run the script? */ 10932 /*------------------------------------------*/ 10933 if (isdcl) { 10934 char *tchr; 10935 10936 /* Assume DCL or foreign command exists */ 10937 /*--------------------------------------*/ 10938 tchr = strrchr(tmpspec, '/'); 10939 if (tchr != NULL) { 10940 tchr++; 10941 } 10942 else { 10943 tchr = tmpspec; 10944 } 10945 strcpy(image_name, tchr); 10946 } 10947 } 10948 } 10949 } 10950 } 10951 fclose(fp); 10952 } 10953 if (check_img && isdcl) { 10954 PerlMem_free(cmd); 10955 PerlMem_free(resspec); 10956 PerlMem_free(vmsspec); 10957 return RMS$_FNF; 10958 } 10959 10960 if (cando_by_name(S_IXUSR,0,resspec)) { 10961 vmscmd->dsc$a_pointer = PerlMem_malloc(MAX_DCL_LINE_LENGTH); 10962 if (vmscmd->dsc$a_pointer == NULL) _ckvmssts_noperl(SS$_INSFMEM); 10963 if (!isdcl) { 10964 strcpy(vmscmd->dsc$a_pointer,"$ MCR "); 10965 if (image_name[0] != 0) { 10966 strcat(vmscmd->dsc$a_pointer, image_name); 10967 strcat(vmscmd->dsc$a_pointer, " "); 10968 } 10969 } else if (image_name[0] != 0) { 10970 strcpy(vmscmd->dsc$a_pointer, image_name); 10971 strcat(vmscmd->dsc$a_pointer, " "); 10972 } else { 10973 strcpy(vmscmd->dsc$a_pointer,"@"); 10974 } 10975 if (suggest_quote) *suggest_quote = 1; 10976 10977 /* If there is an image name, use original command */ 10978 if (image_name[0] == 0) 10979 strcat(vmscmd->dsc$a_pointer,resspec); 10980 else { 10981 rest = cmd; 10982 while (*rest && isspace(*rest)) rest++; 10983 } 10984 10985 if (image_argv[0] != 0) { 10986 strcat(vmscmd->dsc$a_pointer,image_argv); 10987 strcat(vmscmd->dsc$a_pointer, " "); 10988 } 10989 if (rest) { 10990 int rest_len; 10991 int vmscmd_len; 10992 10993 rest_len = strlen(rest); 10994 vmscmd_len = strlen(vmscmd->dsc$a_pointer); 10995 if ((rest_len + vmscmd_len) < MAX_DCL_LINE_LENGTH) 10996 strcat(vmscmd->dsc$a_pointer,rest); 10997 else 10998 retsts = CLI$_BUFOVF; 10999 } 11000 vmscmd->dsc$w_length = strlen(vmscmd->dsc$a_pointer); 11001 PerlMem_free(cmd); 11002 PerlMem_free(vmsspec); 11003 PerlMem_free(resspec); 11004 return (vmscmd->dsc$w_length > MAX_DCL_LINE_LENGTH ? CLI$_BUFOVF : retsts); 11005 } 11006 else 11007 retsts = RMS$_PRV; 11008 } 11009 } 11010 /* It's either a DCL command or we couldn't find a suitable image */ 11011 vmscmd->dsc$w_length = strlen(cmd); 11012 11013 vmscmd->dsc$a_pointer = PerlMem_malloc(vmscmd->dsc$w_length + 1); 11014 strncpy(vmscmd->dsc$a_pointer,cmd,vmscmd->dsc$w_length); 11015 vmscmd->dsc$a_pointer[vmscmd->dsc$w_length] = 0; 11016 11017 PerlMem_free(cmd); 11018 PerlMem_free(resspec); 11019 PerlMem_free(vmsspec); 11020 11021 /* check if it's a symbol (for quoting purposes) */ 11022 if (suggest_quote && !*suggest_quote) { 11023 int iss; 11024 char equiv[LNM$C_NAMLENGTH]; 11025 struct dsc$descriptor_s eqvdsc = {sizeof(equiv), DSC$K_DTYPE_T, DSC$K_CLASS_S, 0}; 11026 eqvdsc.dsc$a_pointer = equiv; 11027 11028 iss = lib$get_symbol(vmscmd,&eqvdsc); 11029 if (iss&1 && (*equiv == '$' || *equiv == '@')) *suggest_quote = 1; 11030 } 11031 if (!(retsts & 1)) { 11032 /* just hand off status values likely to be due to user error */ 11033 if (retsts == RMS$_FNF || retsts == RMS$_DNF || retsts == RMS$_PRV || 11034 retsts == RMS$_DEV || retsts == RMS$_DIR || retsts == RMS$_SYN || 11035 (retsts & STS$M_CODE) == (SHR$_NOWILD & STS$M_CODE)) return retsts; 11036 else { _ckvmssts_noperl(retsts); } 11037 } 11038 11039 return (vmscmd->dsc$w_length > MAX_DCL_LINE_LENGTH ? CLI$_BUFOVF : retsts); 11040 11041 } /* end of setup_cmddsc() */ 11042 11043 11044 /* {{{ bool vms_do_aexec(SV *really,SV **mark,SV **sp) */ 11045 bool 11046 Perl_vms_do_aexec(pTHX_ SV *really,SV **mark,SV **sp) 11047 { 11048 bool exec_sts; 11049 char * cmd; 11050 11051 if (sp > mark) { 11052 if (vfork_called) { /* this follows a vfork - act Unixish */ 11053 vfork_called--; 11054 if (vfork_called < 0) { 11055 Perl_warn(aTHX_ "Internal inconsistency in tracking vforks"); 11056 vfork_called = 0; 11057 } 11058 else return do_aexec(really,mark,sp); 11059 } 11060 /* no vfork - act VMSish */ 11061 cmd = setup_argstr(aTHX_ really,mark,sp); 11062 exec_sts = vms_do_exec(cmd); 11063 Safefree(cmd); /* Clean up from setup_argstr() */ 11064 return exec_sts; 11065 } 11066 11067 return FALSE; 11068 } /* end of vms_do_aexec() */ 11069 /*}}}*/ 11070 11071 /* {{{bool vms_do_exec(char *cmd) */ 11072 bool 11073 Perl_vms_do_exec(pTHX_ const char *cmd) 11074 { 11075 struct dsc$descriptor_s *vmscmd; 11076 11077 if (vfork_called) { /* this follows a vfork - act Unixish */ 11078 vfork_called--; 11079 if (vfork_called < 0) { 11080 Perl_warn(aTHX_ "Internal inconsistency in tracking vforks"); 11081 vfork_called = 0; 11082 } 11083 else return do_exec(cmd); 11084 } 11085 11086 { /* no vfork - act VMSish */ 11087 unsigned long int retsts; 11088 11089 TAINT_ENV(); 11090 TAINT_PROPER("exec"); 11091 if ((retsts = setup_cmddsc(aTHX_ cmd,1,0,&vmscmd)) & 1) 11092 retsts = lib$do_command(vmscmd); 11093 11094 switch (retsts) { 11095 case RMS$_FNF: case RMS$_DNF: 11096 set_errno(ENOENT); break; 11097 case RMS$_DIR: 11098 set_errno(ENOTDIR); break; 11099 case RMS$_DEV: 11100 set_errno(ENODEV); break; 11101 case RMS$_PRV: 11102 set_errno(EACCES); break; 11103 case RMS$_SYN: 11104 set_errno(EINVAL); break; 11105 case CLI$_BUFOVF: case RMS$_RTB: case CLI$_TKNOVF: case CLI$_RSLOVF: 11106 set_errno(E2BIG); break; 11107 case LIB$_INVARG: case LIB$_INVSTRDES: case SS$_ACCVIO: /* shouldn't happen */ 11108 _ckvmssts_noperl(retsts); /* fall through */ 11109 default: /* SS$_DUPLNAM, SS$_CLI, resource exhaustion, etc. */ 11110 set_errno(EVMSERR); 11111 } 11112 set_vaxc_errno(retsts); 11113 if (ckWARN(WARN_EXEC)) { 11114 Perl_warner(aTHX_ packWARN(WARN_EXEC),"Can't exec \"%*s\": %s", 11115 vmscmd->dsc$w_length, vmscmd->dsc$a_pointer, Strerror(errno)); 11116 } 11117 vms_execfree(vmscmd); 11118 } 11119 11120 return FALSE; 11121 11122 } /* end of vms_do_exec() */ 11123 /*}}}*/ 11124 11125 int do_spawn2(pTHX_ const char *, int); 11126 11127 int 11128 Perl_do_aspawn(pTHX_ SV* really, SV** mark, SV** sp) 11129 { 11130 unsigned long int sts; 11131 char * cmd; 11132 int flags = 0; 11133 11134 if (sp > mark) { 11135 11136 /* We'll copy the (undocumented?) Win32 behavior and allow a 11137 * numeric first argument. But the only value we'll support 11138 * through do_aspawn is a value of 1, which means spawn without 11139 * waiting for completion -- other values are ignored. 11140 */ 11141 if (SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) { 11142 ++mark; 11143 flags = SvIVx(*mark); 11144 } 11145 11146 if (flags && flags == 1) /* the Win32 P_NOWAIT value */ 11147 flags = CLI$M_NOWAIT; 11148 else 11149 flags = 0; 11150 11151 cmd = setup_argstr(aTHX_ really, mark, sp); 11152 sts = do_spawn2(aTHX_ cmd, flags); 11153 /* pp_sys will clean up cmd */ 11154 return sts; 11155 } 11156 return SS$_ABORT; 11157 } /* end of do_aspawn() */ 11158 /*}}}*/ 11159 11160 11161 /* {{{int do_spawn(char* cmd) */ 11162 int 11163 Perl_do_spawn(pTHX_ char* cmd) 11164 { 11165 PERL_ARGS_ASSERT_DO_SPAWN; 11166 11167 return do_spawn2(aTHX_ cmd, 0); 11168 } 11169 /*}}}*/ 11170 11171 /* {{{int do_spawn_nowait(char* cmd) */ 11172 int 11173 Perl_do_spawn_nowait(pTHX_ char* cmd) 11174 { 11175 PERL_ARGS_ASSERT_DO_SPAWN_NOWAIT; 11176 11177 return do_spawn2(aTHX_ cmd, CLI$M_NOWAIT); 11178 } 11179 /*}}}*/ 11180 11181 /* {{{int do_spawn2(char *cmd) */ 11182 int 11183 do_spawn2(pTHX_ const char *cmd, int flags) 11184 { 11185 unsigned long int sts, substs; 11186 11187 /* The caller of this routine expects to Safefree(PL_Cmd) */ 11188 Newx(PL_Cmd,10,char); 11189 11190 TAINT_ENV(); 11191 TAINT_PROPER("spawn"); 11192 if (!cmd || !*cmd) { 11193 sts = lib$spawn(0,0,0,&flags,0,0,&substs,0,0,0,0,0,0); 11194 if (!(sts & 1)) { 11195 switch (sts) { 11196 case RMS$_FNF: case RMS$_DNF: 11197 set_errno(ENOENT); break; 11198 case RMS$_DIR: 11199 set_errno(ENOTDIR); break; 11200 case RMS$_DEV: 11201 set_errno(ENODEV); break; 11202 case RMS$_PRV: 11203 set_errno(EACCES); break; 11204 case RMS$_SYN: 11205 set_errno(EINVAL); break; 11206 case CLI$_BUFOVF: case RMS$_RTB: case CLI$_TKNOVF: case CLI$_RSLOVF: 11207 set_errno(E2BIG); break; 11208 case LIB$_INVARG: case LIB$_INVSTRDES: case SS$_ACCVIO: /* shouldn't happen */ 11209 _ckvmssts_noperl(sts); /* fall through */ 11210 default: /* SS$_DUPLNAM, SS$_CLI, resource exhaustion, etc. */ 11211 set_errno(EVMSERR); 11212 } 11213 set_vaxc_errno(sts); 11214 if (ckWARN(WARN_EXEC)) { 11215 Perl_warner(aTHX_ packWARN(WARN_EXEC),"Can't spawn: %s", 11216 Strerror(errno)); 11217 } 11218 } 11219 sts = substs; 11220 } 11221 else { 11222 char mode[3]; 11223 PerlIO * fp; 11224 if (flags & CLI$M_NOWAIT) 11225 strcpy(mode, "n"); 11226 else 11227 strcpy(mode, "nW"); 11228 11229 fp = safe_popen(aTHX_ cmd, mode, (int *)&sts); 11230 if (fp != NULL) 11231 my_pclose(fp); 11232 /* sts will be the pid in the nowait case */ 11233 } 11234 return sts; 11235 } /* end of do_spawn2() */ 11236 /*}}}*/ 11237 11238 11239 static unsigned int *sockflags, sockflagsize; 11240 11241 /* 11242 * Shim fdopen to identify sockets for my_fwrite later, since the stdio 11243 * routines found in some versions of the CRTL can't deal with sockets. 11244 * We don't shim the other file open routines since a socket isn't 11245 * likely to be opened by a name. 11246 */ 11247 /*{{{ FILE *my_fdopen(int fd, const char *mode)*/ 11248 FILE *my_fdopen(int fd, const char *mode) 11249 { 11250 FILE *fp = fdopen(fd, mode); 11251 11252 if (fp) { 11253 unsigned int fdoff = fd / sizeof(unsigned int); 11254 Stat_t sbuf; /* native stat; we don't need flex_stat */ 11255 if (!sockflagsize || fdoff > sockflagsize) { 11256 if (sockflags) Renew( sockflags,fdoff+2,unsigned int); 11257 else Newx (sockflags,fdoff+2,unsigned int); 11258 memset(sockflags+sockflagsize,0,fdoff + 2 - sockflagsize); 11259 sockflagsize = fdoff + 2; 11260 } 11261 if (fstat(fd, &sbuf.crtl_stat) == 0 && S_ISSOCK(sbuf.st_mode)) 11262 sockflags[fdoff] |= 1 << (fd % sizeof(unsigned int)); 11263 } 11264 return fp; 11265 11266 } 11267 /*}}}*/ 11268 11269 11270 /* 11271 * Clear the corresponding bit when the (possibly) socket stream is closed. 11272 * There still a small hole: we miss an implicit close which might occur 11273 * via freopen(). >> Todo 11274 */ 11275 /*{{{ int my_fclose(FILE *fp)*/ 11276 int my_fclose(FILE *fp) { 11277 if (fp) { 11278 unsigned int fd = fileno(fp); 11279 unsigned int fdoff = fd / sizeof(unsigned int); 11280 11281 if (sockflagsize && fdoff < sockflagsize) 11282 sockflags[fdoff] &= ~(1 << fd % sizeof(unsigned int)); 11283 } 11284 return fclose(fp); 11285 } 11286 /*}}}*/ 11287 11288 11289 /* 11290 * A simple fwrite replacement which outputs itmsz*nitm chars without 11291 * introducing record boundaries every itmsz chars. 11292 * We are using fputs, which depends on a terminating null. We may 11293 * well be writing binary data, so we need to accommodate not only 11294 * data with nulls sprinkled in the middle but also data with no null 11295 * byte at the end. 11296 */ 11297 /*{{{ int my_fwrite(const void *src, size_t itmsz, size_t nitm, FILE *dest)*/ 11298 int 11299 my_fwrite(const void *src, size_t itmsz, size_t nitm, FILE *dest) 11300 { 11301 register char *cp, *end, *cpd; 11302 char *data; 11303 register unsigned int fd = fileno(dest); 11304 register unsigned int fdoff = fd / sizeof(unsigned int); 11305 int retval; 11306 int bufsize = itmsz * nitm + 1; 11307 11308 if (fdoff < sockflagsize && 11309 (sockflags[fdoff] | 1 << (fd % sizeof(unsigned int)))) { 11310 if (write(fd, src, itmsz * nitm) == EOF) return EOF; 11311 return nitm; 11312 } 11313 11314 _ckvmssts_noperl(lib$get_vm(&bufsize, &data)); 11315 memcpy( data, src, itmsz*nitm ); 11316 data[itmsz*nitm] = '\0'; 11317 11318 end = data + itmsz * nitm; 11319 retval = (int) nitm; /* on success return # items written */ 11320 11321 cpd = data; 11322 while (cpd <= end) { 11323 for (cp = cpd; cp <= end; cp++) if (!*cp) break; 11324 if (fputs(cpd,dest) == EOF) { retval = EOF; break; } 11325 if (cp < end) 11326 if (fputc('\0',dest) == EOF) { retval = EOF; break; } 11327 cpd = cp + 1; 11328 } 11329 11330 if (data) _ckvmssts_noperl(lib$free_vm(&bufsize, &data)); 11331 return retval; 11332 11333 } /* end of my_fwrite() */ 11334 /*}}}*/ 11335 11336 /*{{{ int my_flush(FILE *fp)*/ 11337 int 11338 Perl_my_flush(pTHX_ FILE *fp) 11339 { 11340 int res; 11341 if ((res = fflush(fp)) == 0 && fp) { 11342 #ifdef VMS_DO_SOCKETS 11343 Stat_t s; 11344 if (fstat(fileno(fp), &s.crtl_stat) == 0 && !S_ISSOCK(s.st_mode)) 11345 #endif 11346 res = fsync(fileno(fp)); 11347 } 11348 /* 11349 * If the flush succeeded but set end-of-file, we need to clear 11350 * the error because our caller may check ferror(). BTW, this 11351 * probably means we just flushed an empty file. 11352 */ 11353 if (res == 0 && vaxc$errno == RMS$_EOF) clearerr(fp); 11354 11355 return res; 11356 } 11357 /*}}}*/ 11358 11359 /* fgetname() is not returning the correct file specifications when 11360 * decc_filename_unix_report mode is active. So we have to have it 11361 * aways return filenames in VMS mode and convert it ourselves. 11362 */ 11363 11364 /*{{{ char * my_fgetname(FILE *fp, buf)*/ 11365 char * 11366 Perl_my_fgetname(FILE *fp, char * buf) { 11367 char * retname; 11368 char * vms_name; 11369 11370 retname = fgetname(fp, buf, 1); 11371 11372 /* If we are in VMS mode, then we are done */ 11373 if (!decc_filename_unix_report || (retname == NULL)) { 11374 return retname; 11375 } 11376 11377 /* Convert this to Unix format */ 11378 vms_name = PerlMem_malloc(VMS_MAXRSS + 1); 11379 strcpy(vms_name, retname); 11380 retname = int_tounixspec(vms_name, buf, NULL); 11381 PerlMem_free(vms_name); 11382 11383 return retname; 11384 } 11385 /*}}}*/ 11386 11387 /* 11388 * Here are replacements for the following Unix routines in the VMS environment: 11389 * getpwuid Get information for a particular UIC or UID 11390 * getpwnam Get information for a named user 11391 * getpwent Get information for each user in the rights database 11392 * setpwent Reset search to the start of the rights database 11393 * endpwent Finish searching for users in the rights database 11394 * 11395 * getpwuid, getpwnam, and getpwent return a pointer to the passwd structure 11396 * (defined in pwd.h), which contains the following fields:- 11397 * struct passwd { 11398 * char *pw_name; Username (in lower case) 11399 * char *pw_passwd; Hashed password 11400 * unsigned int pw_uid; UIC 11401 * unsigned int pw_gid; UIC group number 11402 * char *pw_unixdir; Default device/directory (VMS-style) 11403 * char *pw_gecos; Owner name 11404 * char *pw_dir; Default device/directory (Unix-style) 11405 * char *pw_shell; Default CLI name (eg. DCL) 11406 * }; 11407 * If the specified user does not exist, getpwuid and getpwnam return NULL. 11408 * 11409 * pw_uid is the full UIC (eg. what's returned by stat() in st_uid). 11410 * not the UIC member number (eg. what's returned by getuid()), 11411 * getpwuid() can accept either as input (if uid is specified, the caller's 11412 * UIC group is used), though it won't recognise gid=0. 11413 * 11414 * Note that in VMS it is necessary to have GRPPRV or SYSPRV to return 11415 * information about other users in your group or in other groups, respectively. 11416 * If the required privilege is not available, then these routines fill only 11417 * the pw_name, pw_uid, and pw_gid fields (the others point to an empty 11418 * string). 11419 * 11420 * By Tim Adye (T.J.Adye@rl.ac.uk), 10th February 1995. 11421 */ 11422 11423 /* sizes of various UAF record fields */ 11424 #define UAI$S_USERNAME 12 11425 #define UAI$S_IDENT 31 11426 #define UAI$S_OWNER 31 11427 #define UAI$S_DEFDEV 31 11428 #define UAI$S_DEFDIR 63 11429 #define UAI$S_DEFCLI 31 11430 #define UAI$S_PWD 8 11431 11432 #define valid_uic(uic) ((uic).uic$v_format == UIC$K_UIC_FORMAT && \ 11433 (uic).uic$v_member != UIC$K_WILD_MEMBER && \ 11434 (uic).uic$v_group != UIC$K_WILD_GROUP) 11435 11436 static char __empty[]= ""; 11437 static struct passwd __passwd_empty= 11438 {(char *) __empty, (char *) __empty, 0, 0, 11439 (char *) __empty, (char *) __empty, (char *) __empty, (char *) __empty}; 11440 static int contxt= 0; 11441 static struct passwd __pwdcache; 11442 static char __pw_namecache[UAI$S_IDENT+1]; 11443 11444 /* 11445 * This routine does most of the work extracting the user information. 11446 */ 11447 static int fillpasswd (pTHX_ const char *name, struct passwd *pwd) 11448 { 11449 static struct { 11450 unsigned char length; 11451 char pw_gecos[UAI$S_OWNER+1]; 11452 } owner; 11453 static union uicdef uic; 11454 static struct { 11455 unsigned char length; 11456 char pw_dir[UAI$S_DEFDEV+UAI$S_DEFDIR+1]; 11457 } defdev; 11458 static struct { 11459 unsigned char length; 11460 char unixdir[UAI$_DEFDEV+UAI$S_DEFDIR+1]; 11461 } defdir; 11462 static struct { 11463 unsigned char length; 11464 char pw_shell[UAI$S_DEFCLI+1]; 11465 } defcli; 11466 static char pw_passwd[UAI$S_PWD+1]; 11467 11468 static unsigned short lowner, luic, ldefdev, ldefdir, ldefcli, lpwd; 11469 struct dsc$descriptor_s name_desc; 11470 unsigned long int sts; 11471 11472 static struct itmlst_3 itmlst[]= { 11473 {UAI$S_OWNER+1, UAI$_OWNER, &owner, &lowner}, 11474 {sizeof(uic), UAI$_UIC, &uic, &luic}, 11475 {UAI$S_DEFDEV+1, UAI$_DEFDEV, &defdev, &ldefdev}, 11476 {UAI$S_DEFDIR+1, UAI$_DEFDIR, &defdir, &ldefdir}, 11477 {UAI$S_DEFCLI+1, UAI$_DEFCLI, &defcli, &ldefcli}, 11478 {UAI$S_PWD, UAI$_PWD, pw_passwd, &lpwd}, 11479 {0, 0, NULL, NULL}}; 11480 11481 name_desc.dsc$w_length= strlen(name); 11482 name_desc.dsc$b_dtype= DSC$K_DTYPE_T; 11483 name_desc.dsc$b_class= DSC$K_CLASS_S; 11484 name_desc.dsc$a_pointer= (char *) name; /* read only pointer */ 11485 11486 /* Note that sys$getuai returns many fields as counted strings. */ 11487 sts= sys$getuai(0, 0, &name_desc, &itmlst, 0, 0, 0); 11488 if (sts == SS$_NOSYSPRV || sts == SS$_NOGRPPRV || sts == RMS$_RNF) { 11489 set_vaxc_errno(sts); set_errno(sts == RMS$_RNF ? EINVAL : EACCES); 11490 } 11491 else { _ckvmssts(sts); } 11492 if (!(sts & 1)) return 0; /* out here in case _ckvmssts() doesn't abort */ 11493 11494 if ((int) owner.length < lowner) lowner= (int) owner.length; 11495 if ((int) defdev.length < ldefdev) ldefdev= (int) defdev.length; 11496 if ((int) defdir.length < ldefdir) ldefdir= (int) defdir.length; 11497 if ((int) defcli.length < ldefcli) ldefcli= (int) defcli.length; 11498 memcpy(&defdev.pw_dir[ldefdev], &defdir.unixdir[0], ldefdir); 11499 owner.pw_gecos[lowner]= '\0'; 11500 defdev.pw_dir[ldefdev+ldefdir]= '\0'; 11501 defcli.pw_shell[ldefcli]= '\0'; 11502 if (valid_uic(uic)) { 11503 pwd->pw_uid= uic.uic$l_uic; 11504 pwd->pw_gid= uic.uic$v_group; 11505 } 11506 else 11507 Perl_warn(aTHX_ "getpwnam returned invalid UIC %#o for user \"%s\""); 11508 pwd->pw_passwd= pw_passwd; 11509 pwd->pw_gecos= owner.pw_gecos; 11510 pwd->pw_dir= defdev.pw_dir; 11511 pwd->pw_unixdir= do_tounixpath(defdev.pw_dir, defdir.unixdir,1,NULL); 11512 pwd->pw_shell= defcli.pw_shell; 11513 if (pwd->pw_unixdir && pwd->pw_unixdir[0]) { 11514 int ldir; 11515 ldir= strlen(pwd->pw_unixdir) - 1; 11516 if (pwd->pw_unixdir[ldir]=='/') pwd->pw_unixdir[ldir]= '\0'; 11517 } 11518 else 11519 strcpy(pwd->pw_unixdir, pwd->pw_dir); 11520 if (!decc_efs_case_preserve) 11521 __mystrtolower(pwd->pw_unixdir); 11522 return 1; 11523 } 11524 11525 /* 11526 * Get information for a named user. 11527 */ 11528 /*{{{struct passwd *getpwnam(char *name)*/ 11529 struct passwd *Perl_my_getpwnam(pTHX_ const char *name) 11530 { 11531 struct dsc$descriptor_s name_desc; 11532 union uicdef uic; 11533 unsigned long int status, sts; 11534 11535 __pwdcache = __passwd_empty; 11536 if (!fillpasswd(aTHX_ name, &__pwdcache)) { 11537 /* We still may be able to determine pw_uid and pw_gid */ 11538 name_desc.dsc$w_length= strlen(name); 11539 name_desc.dsc$b_dtype= DSC$K_DTYPE_T; 11540 name_desc.dsc$b_class= DSC$K_CLASS_S; 11541 name_desc.dsc$a_pointer= (char *) name; 11542 if ((sts = sys$asctoid(&name_desc, &uic, 0)) == SS$_NORMAL) { 11543 __pwdcache.pw_uid= uic.uic$l_uic; 11544 __pwdcache.pw_gid= uic.uic$v_group; 11545 } 11546 else { 11547 if (sts == SS$_NOSUCHID || sts == SS$_IVIDENT || sts == RMS$_PRV) { 11548 set_vaxc_errno(sts); 11549 set_errno(sts == RMS$_PRV ? EACCES : EINVAL); 11550 return NULL; 11551 } 11552 else { _ckvmssts(sts); } 11553 } 11554 } 11555 strncpy(__pw_namecache, name, sizeof(__pw_namecache)); 11556 __pw_namecache[sizeof __pw_namecache - 1] = '\0'; 11557 __pwdcache.pw_name= __pw_namecache; 11558 return &__pwdcache; 11559 } /* end of my_getpwnam() */ 11560 /*}}}*/ 11561 11562 /* 11563 * Get information for a particular UIC or UID. 11564 * Called by my_getpwent with uid=-1 to list all users. 11565 */ 11566 /*{{{struct passwd *my_getpwuid(Uid_t uid)*/ 11567 struct passwd *Perl_my_getpwuid(pTHX_ Uid_t uid) 11568 { 11569 const $DESCRIPTOR(name_desc,__pw_namecache); 11570 unsigned short lname; 11571 union uicdef uic; 11572 unsigned long int status; 11573 11574 if (uid == (unsigned int) -1) { 11575 do { 11576 status = sys$idtoasc(-1, &lname, &name_desc, &uic, 0, &contxt); 11577 if (status == SS$_NOSUCHID || status == RMS$_PRV) { 11578 set_vaxc_errno(status); 11579 set_errno(status == RMS$_PRV ? EACCES : EINVAL); 11580 my_endpwent(); 11581 return NULL; 11582 } 11583 else { _ckvmssts(status); } 11584 } while (!valid_uic (uic)); 11585 } 11586 else { 11587 uic.uic$l_uic= uid; 11588 if (!uic.uic$v_group) 11589 uic.uic$v_group= PerlProc_getgid(); 11590 if (valid_uic(uic)) 11591 status = sys$idtoasc(uic.uic$l_uic, &lname, &name_desc, 0, 0, 0); 11592 else status = SS$_IVIDENT; 11593 if (status == SS$_IVIDENT || status == SS$_NOSUCHID || 11594 status == RMS$_PRV) { 11595 set_vaxc_errno(status); set_errno(status == RMS$_PRV ? EACCES : EINVAL); 11596 return NULL; 11597 } 11598 else { _ckvmssts(status); } 11599 } 11600 __pw_namecache[lname]= '\0'; 11601 __mystrtolower(__pw_namecache); 11602 11603 __pwdcache = __passwd_empty; 11604 __pwdcache.pw_name = __pw_namecache; 11605 11606 /* Fill in the uid and gid in case fillpasswd can't (eg. no privilege). 11607 The identifier's value is usually the UIC, but it doesn't have to be, 11608 so if we can, we let fillpasswd update this. */ 11609 __pwdcache.pw_uid = uic.uic$l_uic; 11610 __pwdcache.pw_gid = uic.uic$v_group; 11611 11612 fillpasswd(aTHX_ __pw_namecache, &__pwdcache); 11613 return &__pwdcache; 11614 11615 } /* end of my_getpwuid() */ 11616 /*}}}*/ 11617 11618 /* 11619 * Get information for next user. 11620 */ 11621 /*{{{struct passwd *my_getpwent()*/ 11622 struct passwd *Perl_my_getpwent(pTHX) 11623 { 11624 return (my_getpwuid((unsigned int) -1)); 11625 } 11626 /*}}}*/ 11627 11628 /* 11629 * Finish searching rights database for users. 11630 */ 11631 /*{{{void my_endpwent()*/ 11632 void Perl_my_endpwent(pTHX) 11633 { 11634 if (contxt) { 11635 _ckvmssts(sys$finish_rdb(&contxt)); 11636 contxt= 0; 11637 } 11638 } 11639 /*}}}*/ 11640 11641 #ifdef HOMEGROWN_POSIX_SIGNALS 11642 /* Signal handling routines, pulled into the core from POSIX.xs. 11643 * 11644 * We need these for threads, so they've been rolled into the core, 11645 * rather than left in POSIX.xs. 11646 * 11647 * (DRS, Oct 23, 1997) 11648 */ 11649 11650 /* sigset_t is atomic under VMS, so these routines are easy */ 11651 /*{{{int my_sigemptyset(sigset_t *) */ 11652 int my_sigemptyset(sigset_t *set) { 11653 if (!set) { SETERRNO(EFAULT,SS$_ACCVIO); return -1; } 11654 *set = 0; return 0; 11655 } 11656 /*}}}*/ 11657 11658 11659 /*{{{int my_sigfillset(sigset_t *)*/ 11660 int my_sigfillset(sigset_t *set) { 11661 int i; 11662 if (!set) { SETERRNO(EFAULT,SS$_ACCVIO); return -1; } 11663 for (i = 0; i < NSIG; i++) *set |= (1 << i); 11664 return 0; 11665 } 11666 /*}}}*/ 11667 11668 11669 /*{{{int my_sigaddset(sigset_t *set, int sig)*/ 11670 int my_sigaddset(sigset_t *set, int sig) { 11671 if (!set) { SETERRNO(EFAULT,SS$_ACCVIO); return -1; } 11672 if (sig > NSIG) { SETERRNO(EINVAL,LIB$_INVARG); return -1; } 11673 *set |= (1 << (sig - 1)); 11674 return 0; 11675 } 11676 /*}}}*/ 11677 11678 11679 /*{{{int my_sigdelset(sigset_t *set, int sig)*/ 11680 int my_sigdelset(sigset_t *set, int sig) { 11681 if (!set) { SETERRNO(EFAULT,SS$_ACCVIO); return -1; } 11682 if (sig > NSIG) { SETERRNO(EINVAL,LIB$_INVARG); return -1; } 11683 *set &= ~(1 << (sig - 1)); 11684 return 0; 11685 } 11686 /*}}}*/ 11687 11688 11689 /*{{{int my_sigismember(sigset_t *set, int sig)*/ 11690 int my_sigismember(sigset_t *set, int sig) { 11691 if (!set) { SETERRNO(EFAULT,SS$_ACCVIO); return -1; } 11692 if (sig > NSIG) { SETERRNO(EINVAL,LIB$_INVARG); return -1; } 11693 return *set & (1 << (sig - 1)); 11694 } 11695 /*}}}*/ 11696 11697 11698 /*{{{int my_sigprocmask(int how, sigset_t *set, sigset_t *oset)*/ 11699 int my_sigprocmask(int how, sigset_t *set, sigset_t *oset) { 11700 sigset_t tempmask; 11701 11702 /* If set and oset are both null, then things are badly wrong. Bail out. */ 11703 if ((oset == NULL) && (set == NULL)) { 11704 set_errno(EFAULT); set_vaxc_errno(SS$_ACCVIO); 11705 return -1; 11706 } 11707 11708 /* If set's null, then we're just handling a fetch. */ 11709 if (set == NULL) { 11710 tempmask = sigblock(0); 11711 } 11712 else { 11713 switch (how) { 11714 case SIG_SETMASK: 11715 tempmask = sigsetmask(*set); 11716 break; 11717 case SIG_BLOCK: 11718 tempmask = sigblock(*set); 11719 break; 11720 case SIG_UNBLOCK: 11721 tempmask = sigblock(0); 11722 sigsetmask(*oset & ~tempmask); 11723 break; 11724 default: 11725 set_errno(EINVAL); set_vaxc_errno(LIB$_INVARG); 11726 return -1; 11727 } 11728 } 11729 11730 /* Did they pass us an oset? If so, stick our holding mask into it */ 11731 if (oset) 11732 *oset = tempmask; 11733 11734 return 0; 11735 } 11736 /*}}}*/ 11737 #endif /* HOMEGROWN_POSIX_SIGNALS */ 11738 11739 11740 /* Used for UTC calculation in my_gmtime(), my_localtime(), my_time(), 11741 * my_utime(), and flex_stat(), all of which operate on UTC unless 11742 * VMSISH_TIMES is true. 11743 */ 11744 /* method used to handle UTC conversions: 11745 * 1 == CRTL gmtime(); 2 == SYS$TIMEZONE_DIFFERENTIAL; 3 == no correction 11746 */ 11747 static int gmtime_emulation_type; 11748 /* number of secs to add to UTC POSIX-style time to get local time */ 11749 static long int utc_offset_secs; 11750 11751 /* We #defined 'gmtime', 'localtime', and 'time' as 'my_gmtime' etc. 11752 * in vmsish.h. #undef them here so we can call the CRTL routines 11753 * directly. 11754 */ 11755 #undef gmtime 11756 #undef localtime 11757 #undef time 11758 11759 11760 /* 11761 * DEC C previous to 6.0 corrupts the behavior of the /prefix 11762 * qualifier with the extern prefix pragma. This provisional 11763 * hack circumvents this prefix pragma problem in previous 11764 * precompilers. 11765 */ 11766 #if defined(__VMS_VER) && __VMS_VER >= 70000000 11767 # if defined(VMS_WE_ARE_CASE_SENSITIVE) && (__DECC_VER < 60000000) 11768 # pragma __extern_prefix save 11769 # pragma __extern_prefix "" /* set to empty to prevent prefixing */ 11770 # define gmtime decc$__utctz_gmtime 11771 # define localtime decc$__utctz_localtime 11772 # define time decc$__utc_time 11773 # pragma __extern_prefix restore 11774 11775 struct tm *gmtime(), *localtime(); 11776 11777 # endif 11778 #endif 11779 11780 11781 static time_t toutc_dst(time_t loc) { 11782 struct tm *rsltmp; 11783 11784 if ((rsltmp = localtime(&loc)) == NULL) return -1; 11785 loc -= utc_offset_secs; 11786 if (rsltmp->tm_isdst) loc -= 3600; 11787 return loc; 11788 } 11789 #define _toutc(secs) ((secs) == (time_t) -1 ? (time_t) -1 : \ 11790 ((gmtime_emulation_type || my_time(NULL)), \ 11791 (gmtime_emulation_type == 1 ? toutc_dst(secs) : \ 11792 ((secs) - utc_offset_secs)))) 11793 11794 static time_t toloc_dst(time_t utc) { 11795 struct tm *rsltmp; 11796 11797 utc += utc_offset_secs; 11798 if ((rsltmp = localtime(&utc)) == NULL) return -1; 11799 if (rsltmp->tm_isdst) utc += 3600; 11800 return utc; 11801 } 11802 #define _toloc(secs) ((secs) == (time_t) -1 ? (time_t) -1 : \ 11803 ((gmtime_emulation_type || my_time(NULL)), \ 11804 (gmtime_emulation_type == 1 ? toloc_dst(secs) : \ 11805 ((secs) + utc_offset_secs)))) 11806 11807 #ifndef RTL_USES_UTC 11808 /* 11809 11810 ucx$tz = "EST5EDT4,M4.1.0,M10.5.0" typical 11811 DST starts on 1st sun of april at 02:00 std time 11812 ends on last sun of october at 02:00 dst time 11813 see the UCX management command reference, SET CONFIG TIMEZONE 11814 for formatting info. 11815 11816 No, it's not as general as it should be, but then again, NOTHING 11817 will handle UK times in a sensible way. 11818 */ 11819 11820 11821 /* 11822 parse the DST start/end info: 11823 (Jddd|ddd|Mmon.nth.dow)[/hh:mm:ss] 11824 */ 11825 11826 static char * 11827 tz_parse_startend(char *s, struct tm *w, int *past) 11828 { 11829 int dinm[] = {31,28,31,30,31,30,31,31,30,31,30,31}; 11830 int ly, dozjd, d, m, n, hour, min, sec, j, k; 11831 time_t g; 11832 11833 if (!s) return 0; 11834 if (!w) return 0; 11835 if (!past) return 0; 11836 11837 ly = 0; 11838 if (w->tm_year % 4 == 0) ly = 1; 11839 if (w->tm_year % 100 == 0) ly = 0; 11840 if (w->tm_year+1900 % 400 == 0) ly = 1; 11841 if (ly) dinm[1]++; 11842 11843 dozjd = isdigit(*s); 11844 if (*s == 'J' || *s == 'j' || dozjd) { 11845 if (!dozjd && !isdigit(*++s)) return 0; 11846 d = *s++ - '0'; 11847 if (isdigit(*s)) { 11848 d = d*10 + *s++ - '0'; 11849 if (isdigit(*s)) { 11850 d = d*10 + *s++ - '0'; 11851 } 11852 } 11853 if (d == 0) return 0; 11854 if (d > 366) return 0; 11855 d--; 11856 if (!dozjd && d > 58 && ly) d++; /* after 28 feb */ 11857 g = d * 86400; 11858 dozjd = 1; 11859 } else if (*s == 'M' || *s == 'm') { 11860 if (!isdigit(*++s)) return 0; 11861 m = *s++ - '0'; 11862 if (isdigit(*s)) m = 10*m + *s++ - '0'; 11863 if (*s != '.') return 0; 11864 if (!isdigit(*++s)) return 0; 11865 n = *s++ - '0'; 11866 if (n < 1 || n > 5) return 0; 11867 if (*s != '.') return 0; 11868 if (!isdigit(*++s)) return 0; 11869 d = *s++ - '0'; 11870 if (d > 6) return 0; 11871 } 11872 11873 if (*s == '/') { 11874 if (!isdigit(*++s)) return 0; 11875 hour = *s++ - '0'; 11876 if (isdigit(*s)) hour = 10*hour + *s++ - '0'; 11877 if (*s == ':') { 11878 if (!isdigit(*++s)) return 0; 11879 min = *s++ - '0'; 11880 if (isdigit(*s)) min = 10*min + *s++ - '0'; 11881 if (*s == ':') { 11882 if (!isdigit(*++s)) return 0; 11883 sec = *s++ - '0'; 11884 if (isdigit(*s)) sec = 10*sec + *s++ - '0'; 11885 } 11886 } 11887 } else { 11888 hour = 2; 11889 min = 0; 11890 sec = 0; 11891 } 11892 11893 if (dozjd) { 11894 if (w->tm_yday < d) goto before; 11895 if (w->tm_yday > d) goto after; 11896 } else { 11897 if (w->tm_mon+1 < m) goto before; 11898 if (w->tm_mon+1 > m) goto after; 11899 11900 j = (42 + w->tm_wday - w->tm_mday)%7; /*dow of mday 0 */ 11901 k = d - j; /* mday of first d */ 11902 if (k <= 0) k += 7; 11903 k += 7 * ((n>4?4:n)-1); /* mday of n'th d */ 11904 if (n == 5 && k+7 <= dinm[w->tm_mon]) k += 7; 11905 if (w->tm_mday < k) goto before; 11906 if (w->tm_mday > k) goto after; 11907 } 11908 11909 if (w->tm_hour < hour) goto before; 11910 if (w->tm_hour > hour) goto after; 11911 if (w->tm_min < min) goto before; 11912 if (w->tm_min > min) goto after; 11913 if (w->tm_sec < sec) goto before; 11914 goto after; 11915 11916 before: 11917 *past = 0; 11918 return s; 11919 after: 11920 *past = 1; 11921 return s; 11922 } 11923 11924 11925 11926 11927 /* parse the offset: (+|-)hh[:mm[:ss]] */ 11928 11929 static char * 11930 tz_parse_offset(char *s, int *offset) 11931 { 11932 int hour = 0, min = 0, sec = 0; 11933 int neg = 0; 11934 if (!s) return 0; 11935 if (!offset) return 0; 11936 11937 if (*s == '-') {neg++; s++;} 11938 if (*s == '+') s++; 11939 if (!isdigit(*s)) return 0; 11940 hour = *s++ - '0'; 11941 if (isdigit(*s)) hour = hour*10+(*s++ - '0'); 11942 if (hour > 24) return 0; 11943 if (*s == ':') { 11944 if (!isdigit(*++s)) return 0; 11945 min = *s++ - '0'; 11946 if (isdigit(*s)) min = min*10 + (*s++ - '0'); 11947 if (min > 59) return 0; 11948 if (*s == ':') { 11949 if (!isdigit(*++s)) return 0; 11950 sec = *s++ - '0'; 11951 if (isdigit(*s)) sec = sec*10 + (*s++ - '0'); 11952 if (sec > 59) return 0; 11953 } 11954 } 11955 11956 *offset = (hour*60+min)*60 + sec; 11957 if (neg) *offset = -*offset; 11958 return s; 11959 } 11960 11961 /* 11962 input time is w, whatever type of time the CRTL localtime() uses. 11963 sets dst, the zone, and the gmtoff (seconds) 11964 11965 caches the value of TZ and UCX$TZ env variables; note that 11966 my_setenv looks for these and sets a flag if they're changed 11967 for efficiency. 11968 11969 We have to watch out for the "australian" case (dst starts in 11970 october, ends in april)...flagged by "reverse" and checked by 11971 scanning through the months of the previous year. 11972 11973 */ 11974 11975 static int 11976 tz_parse(pTHX_ time_t *w, int *dst, char *zone, int *gmtoff) 11977 { 11978 time_t when; 11979 struct tm *w2; 11980 char *s,*s2; 11981 char *dstzone, *tz, *s_start, *s_end; 11982 int std_off, dst_off, isdst; 11983 int y, dststart, dstend; 11984 static char envtz[1025]; /* longer than any logical, symbol, ... */ 11985 static char ucxtz[1025]; 11986 static char reversed = 0; 11987 11988 if (!w) return 0; 11989 11990 if (tz_updated) { 11991 tz_updated = 0; 11992 reversed = -1; /* flag need to check */ 11993 envtz[0] = ucxtz[0] = '\0'; 11994 tz = my_getenv("TZ",0); 11995 if (tz) strcpy(envtz, tz); 11996 tz = my_getenv("UCX$TZ",0); 11997 if (tz) strcpy(ucxtz, tz); 11998 if (!envtz[0] && !ucxtz[0]) return 0; /* we give up */ 11999 } 12000 tz = envtz; 12001 if (!*tz) tz = ucxtz; 12002 12003 s = tz; 12004 while (isalpha(*s)) s++; 12005 s = tz_parse_offset(s, &std_off); 12006 if (!s) return 0; 12007 if (!*s) { /* no DST, hurray we're done! */ 12008 isdst = 0; 12009 goto done; 12010 } 12011 12012 dstzone = s; 12013 while (isalpha(*s)) s++; 12014 s2 = tz_parse_offset(s, &dst_off); 12015 if (s2) { 12016 s = s2; 12017 } else { 12018 dst_off = std_off - 3600; 12019 } 12020 12021 if (!*s) { /* default dst start/end?? */ 12022 if (tz != ucxtz) { /* if TZ tells zone only, UCX$TZ tells rule */ 12023 s = strchr(ucxtz,','); 12024 } 12025 if (!s || !*s) s = ",M4.1.0,M10.5.0"; /* we know we do dst, default rule */ 12026 } 12027 if (*s != ',') return 0; 12028 12029 when = *w; 12030 when = _toutc(when); /* convert to utc */ 12031 when = when - std_off; /* convert to pseudolocal time*/ 12032 12033 w2 = localtime(&when); 12034 y = w2->tm_year; 12035 s_start = s+1; 12036 s = tz_parse_startend(s_start,w2,&dststart); 12037 if (!s) return 0; 12038 if (*s != ',') return 0; 12039 12040 when = *w; 12041 when = _toutc(when); /* convert to utc */ 12042 when = when - dst_off; /* convert to pseudolocal time*/ 12043 w2 = localtime(&when); 12044 if (w2->tm_year != y) { /* spans a year, just check one time */ 12045 when += dst_off - std_off; 12046 w2 = localtime(&when); 12047 } 12048 s_end = s+1; 12049 s = tz_parse_startend(s_end,w2,&dstend); 12050 if (!s) return 0; 12051 12052 if (reversed == -1) { /* need to check if start later than end */ 12053 int j, ds, de; 12054 12055 when = *w; 12056 if (when < 2*365*86400) { 12057 when += 2*365*86400; 12058 } else { 12059 when -= 365*86400; 12060 } 12061 w2 =localtime(&when); 12062 when = when + (15 - w2->tm_yday) * 86400; /* jan 15 */ 12063 12064 for (j = 0; j < 12; j++) { 12065 w2 =localtime(&when); 12066 tz_parse_startend(s_start,w2,&ds); 12067 tz_parse_startend(s_end,w2,&de); 12068 if (ds != de) break; 12069 when += 30*86400; 12070 } 12071 reversed = 0; 12072 if (de && !ds) reversed = 1; 12073 } 12074 12075 isdst = dststart && !dstend; 12076 if (reversed) isdst = dststart || !dstend; 12077 12078 done: 12079 if (dst) *dst = isdst; 12080 if (gmtoff) *gmtoff = isdst ? dst_off : std_off; 12081 if (isdst) tz = dstzone; 12082 if (zone) { 12083 while(isalpha(*tz)) *zone++ = *tz++; 12084 *zone = '\0'; 12085 } 12086 return 1; 12087 } 12088 12089 #endif /* !RTL_USES_UTC */ 12090 12091 /* my_time(), my_localtime(), my_gmtime() 12092 * By default traffic in UTC time values, using CRTL gmtime() or 12093 * SYS$TIMEZONE_DIFFERENTIAL to determine offset from local time zone. 12094 * Note: We need to use these functions even when the CRTL has working 12095 * UTC support, since they also handle C<use vmsish qw(times);> 12096 * 12097 * Contributed by Chuck Lane <lane@duphy4.physics.drexel.edu> 12098 * Modified by Charles Bailey <bailey@newman.upenn.edu> 12099 */ 12100 12101 /*{{{time_t my_time(time_t *timep)*/ 12102 time_t Perl_my_time(pTHX_ time_t *timep) 12103 { 12104 time_t when; 12105 struct tm *tm_p; 12106 12107 if (gmtime_emulation_type == 0) { 12108 int dstnow; 12109 time_t base = 15 * 86400; /* 15jan71; to avoid month/year ends between */ 12110 /* results of calls to gmtime() and localtime() */ 12111 /* for same &base */ 12112 12113 gmtime_emulation_type++; 12114 if ((tm_p = gmtime(&base)) == NULL) { /* CRTL gmtime() is a fake */ 12115 char off[LNM$C_NAMLENGTH+1];; 12116 12117 gmtime_emulation_type++; 12118 if (!vmstrnenv("SYS$TIMEZONE_DIFFERENTIAL",off,0,fildev,0)) { 12119 gmtime_emulation_type++; 12120 utc_offset_secs = 0; 12121 Perl_warn(aTHX_ "no UTC offset information; assuming local time is UTC"); 12122 } 12123 else { utc_offset_secs = atol(off); } 12124 } 12125 else { /* We've got a working gmtime() */ 12126 struct tm gmt, local; 12127 12128 gmt = *tm_p; 12129 tm_p = localtime(&base); 12130 local = *tm_p; 12131 utc_offset_secs = (local.tm_mday - gmt.tm_mday) * 86400; 12132 utc_offset_secs += (local.tm_hour - gmt.tm_hour) * 3600; 12133 utc_offset_secs += (local.tm_min - gmt.tm_min) * 60; 12134 utc_offset_secs += (local.tm_sec - gmt.tm_sec); 12135 } 12136 } 12137 12138 when = time(NULL); 12139 # ifdef VMSISH_TIME 12140 # ifdef RTL_USES_UTC 12141 if (VMSISH_TIME) when = _toloc(when); 12142 # else 12143 if (!VMSISH_TIME) when = _toutc(when); 12144 # endif 12145 # endif 12146 if (timep != NULL) *timep = when; 12147 return when; 12148 12149 } /* end of my_time() */ 12150 /*}}}*/ 12151 12152 12153 /*{{{struct tm *my_gmtime(const time_t *timep)*/ 12154 struct tm * 12155 Perl_my_gmtime(pTHX_ const time_t *timep) 12156 { 12157 char *p; 12158 time_t when; 12159 struct tm *rsltmp; 12160 12161 if (timep == NULL) { 12162 set_errno(EINVAL); set_vaxc_errno(LIB$_INVARG); 12163 return NULL; 12164 } 12165 if (*timep == 0) gmtime_emulation_type = 0; /* possibly reset TZ */ 12166 12167 when = *timep; 12168 # ifdef VMSISH_TIME 12169 if (VMSISH_TIME) when = _toutc(when); /* Input was local time */ 12170 # endif 12171 # ifdef RTL_USES_UTC /* this implies that the CRTL has a working gmtime() */ 12172 return gmtime(&when); 12173 # else 12174 /* CRTL localtime() wants local time as input, so does no tz correction */ 12175 rsltmp = localtime(&when); 12176 if (rsltmp) rsltmp->tm_isdst = 0; /* We already took DST into account */ 12177 return rsltmp; 12178 #endif 12179 } /* end of my_gmtime() */ 12180 /*}}}*/ 12181 12182 12183 /*{{{struct tm *my_localtime(const time_t *timep)*/ 12184 struct tm * 12185 Perl_my_localtime(pTHX_ const time_t *timep) 12186 { 12187 time_t when, whenutc; 12188 struct tm *rsltmp; 12189 int dst, offset; 12190 12191 if (timep == NULL) { 12192 set_errno(EINVAL); set_vaxc_errno(LIB$_INVARG); 12193 return NULL; 12194 } 12195 if (*timep == 0) gmtime_emulation_type = 0; /* possibly reset TZ */ 12196 if (gmtime_emulation_type == 0) my_time(NULL); /* Init UTC */ 12197 12198 when = *timep; 12199 # ifdef RTL_USES_UTC 12200 # ifdef VMSISH_TIME 12201 if (VMSISH_TIME) when = _toutc(when); 12202 # endif 12203 /* CRTL localtime() wants UTC as input, does tz correction itself */ 12204 return localtime(&when); 12205 12206 # else /* !RTL_USES_UTC */ 12207 whenutc = when; 12208 # ifdef VMSISH_TIME 12209 if (!VMSISH_TIME) when = _toloc(whenutc); /* input was UTC */ 12210 if (VMSISH_TIME) whenutc = _toutc(when); /* input was truelocal */ 12211 # endif 12212 dst = -1; 12213 #ifndef RTL_USES_UTC 12214 if (tz_parse(aTHX_ &when, &dst, 0, &offset)) { /* truelocal determines DST*/ 12215 when = whenutc - offset; /* pseudolocal time*/ 12216 } 12217 # endif 12218 /* CRTL localtime() wants local time as input, so does no tz correction */ 12219 rsltmp = localtime(&when); 12220 if (rsltmp && gmtime_emulation_type != 1) rsltmp->tm_isdst = dst; 12221 return rsltmp; 12222 # endif 12223 12224 } /* end of my_localtime() */ 12225 /*}}}*/ 12226 12227 /* Reset definitions for later calls */ 12228 #define gmtime(t) my_gmtime(t) 12229 #define localtime(t) my_localtime(t) 12230 #define time(t) my_time(t) 12231 12232 12233 /* my_utime - update modification/access time of a file 12234 * 12235 * VMS 7.3 and later implementation 12236 * Only the UTC translation is home-grown. The rest is handled by the 12237 * CRTL utime(), which will take into account the relevant feature 12238 * logicals and ODS-5 volume characteristics for true access times. 12239 * 12240 * pre VMS 7.3 implementation: 12241 * The calling sequence is identical to POSIX utime(), but under 12242 * VMS with ODS-2, only the modification time is changed; ODS-2 does 12243 * not maintain access times. Restrictions differ from the POSIX 12244 * definition in that the time can be changed as long as the 12245 * caller has permission to execute the necessary IO$_MODIFY $QIO; 12246 * no separate checks are made to insure that the caller is the 12247 * owner of the file or has special privs enabled. 12248 * Code here is based on Joe Meadows' FILE utility. 12249 * 12250 */ 12251 12252 /* Adjustment from Unix epoch (01-JAN-1970 00:00:00.00) 12253 * to VMS epoch (01-JAN-1858 00:00:00.00) 12254 * in 100 ns intervals. 12255 */ 12256 static const long int utime_baseadjust[2] = { 0x4beb4000, 0x7c9567 }; 12257 12258 /*{{{int my_utime(const char *path, const struct utimbuf *utimes)*/ 12259 int Perl_my_utime(pTHX_ const char *file, const struct utimbuf *utimes) 12260 { 12261 #if __CRTL_VER >= 70300000 12262 struct utimbuf utc_utimes, *utc_utimesp; 12263 12264 if (utimes != NULL) { 12265 utc_utimes.actime = utimes->actime; 12266 utc_utimes.modtime = utimes->modtime; 12267 # ifdef VMSISH_TIME 12268 /* If input was local; convert to UTC for sys svc */ 12269 if (VMSISH_TIME) { 12270 utc_utimes.actime = _toutc(utimes->actime); 12271 utc_utimes.modtime = _toutc(utimes->modtime); 12272 } 12273 # endif 12274 utc_utimesp = &utc_utimes; 12275 } 12276 else { 12277 utc_utimesp = NULL; 12278 } 12279 12280 return utime(file, utc_utimesp); 12281 12282 #else /* __CRTL_VER < 70300000 */ 12283 12284 register int i; 12285 int sts; 12286 long int bintime[2], len = 2, lowbit, unixtime, 12287 secscale = 10000000; /* seconds --> 100 ns intervals */ 12288 unsigned long int chan, iosb[2], retsts; 12289 char vmsspec[NAM$C_MAXRSS+1], rsa[NAM$C_MAXRSS], esa[NAM$C_MAXRSS]; 12290 struct FAB myfab = cc$rms_fab; 12291 struct NAM mynam = cc$rms_nam; 12292 #if defined (__DECC) && defined (__VAX) 12293 /* VAX DEC C atrdef.h has unsigned type for pointer member atr$l_addr, 12294 * at least through VMS V6.1, which causes a type-conversion warning. 12295 */ 12296 # pragma message save 12297 # pragma message disable cvtdiftypes 12298 #endif 12299 struct atrdef myatr[2] = {{sizeof bintime, ATR$C_REVDATE, bintime}, {0,0,0}}; 12300 struct fibdef myfib; 12301 #if defined (__DECC) && defined (__VAX) 12302 /* This should be right after the declaration of myatr, but due 12303 * to a bug in VAX DEC C, this takes effect a statement early. 12304 */ 12305 # pragma message restore 12306 #endif 12307 /* cast ok for read only parameter */ 12308 struct dsc$descriptor fibdsc = {sizeof(myfib), DSC$K_DTYPE_Z, DSC$K_CLASS_S,(char *) &myfib}, 12309 devdsc = {0,DSC$K_DTYPE_T, DSC$K_CLASS_S,0}, 12310 fnmdsc = {0,DSC$K_DTYPE_T, DSC$K_CLASS_S,0}; 12311 12312 if (file == NULL || *file == '\0') { 12313 SETERRNO(ENOENT, LIB$_INVARG); 12314 return -1; 12315 } 12316 12317 /* Convert to VMS format ensuring that it will fit in 255 characters */ 12318 if (int_rmsexpand_tovms(file, vmsspec, 0) == NULL) { 12319 SETERRNO(ENOENT, LIB$_INVARG); 12320 return -1; 12321 } 12322 if (utimes != NULL) { 12323 /* Convert Unix time (seconds since 01-JAN-1970 00:00:00.00) 12324 * to VMS quadword time (100 nsec intervals since 01-JAN-1858 00:00:00.00). 12325 * Since time_t is unsigned long int, and lib$emul takes a signed long int 12326 * as input, we force the sign bit to be clear by shifting unixtime right 12327 * one bit, then multiplying by an extra factor of 2 in lib$emul(). 12328 */ 12329 lowbit = (utimes->modtime & 1) ? secscale : 0; 12330 unixtime = (long int) utimes->modtime; 12331 # ifdef VMSISH_TIME 12332 /* If input was UTC; convert to local for sys svc */ 12333 if (!VMSISH_TIME) unixtime = _toloc(unixtime); 12334 # endif 12335 unixtime >>= 1; secscale <<= 1; 12336 retsts = lib$emul(&secscale, &unixtime, &lowbit, bintime); 12337 if (!(retsts & 1)) { 12338 SETERRNO(EVMSERR, retsts); 12339 return -1; 12340 } 12341 retsts = lib$addx(bintime,utime_baseadjust,bintime,&len); 12342 if (!(retsts & 1)) { 12343 SETERRNO(EVMSERR, retsts); 12344 return -1; 12345 } 12346 } 12347 else { 12348 /* Just get the current time in VMS format directly */ 12349 retsts = sys$gettim(bintime); 12350 if (!(retsts & 1)) { 12351 SETERRNO(EVMSERR, retsts); 12352 return -1; 12353 } 12354 } 12355 12356 myfab.fab$l_fna = vmsspec; 12357 myfab.fab$b_fns = (unsigned char) strlen(vmsspec); 12358 myfab.fab$l_nam = &mynam; 12359 mynam.nam$l_esa = esa; 12360 mynam.nam$b_ess = (unsigned char) sizeof esa; 12361 mynam.nam$l_rsa = rsa; 12362 mynam.nam$b_rss = (unsigned char) sizeof rsa; 12363 if (decc_efs_case_preserve) 12364 mynam.nam$b_nop |= NAM$M_NO_SHORT_UPCASE; 12365 12366 /* Look for the file to be affected, letting RMS parse the file 12367 * specification for us as well. I have set errno using only 12368 * values documented in the utime() man page for VMS POSIX. 12369 */ 12370 retsts = sys$parse(&myfab,0,0); 12371 if (!(retsts & 1)) { 12372 set_vaxc_errno(retsts); 12373 if (retsts == RMS$_PRV) set_errno(EACCES); 12374 else if (retsts == RMS$_DIR) set_errno(ENOTDIR); 12375 else set_errno(EVMSERR); 12376 return -1; 12377 } 12378 retsts = sys$search(&myfab,0,0); 12379 if (!(retsts & 1)) { 12380 mynam.nam$b_nop |= NAM$M_SYNCHK; mynam.nam$l_rlf = NULL; 12381 myfab.fab$b_dns = 0; sts = sys$parse(&myfab,0,0); 12382 set_vaxc_errno(retsts); 12383 if (retsts == RMS$_PRV) set_errno(EACCES); 12384 else if (retsts == RMS$_FNF) set_errno(ENOENT); 12385 else set_errno(EVMSERR); 12386 return -1; 12387 } 12388 12389 devdsc.dsc$w_length = mynam.nam$b_dev; 12390 /* cast ok for read only parameter */ 12391 devdsc.dsc$a_pointer = (char *) mynam.nam$l_dev; 12392 12393 retsts = sys$assign(&devdsc,&chan,0,0); 12394 if (!(retsts & 1)) { 12395 mynam.nam$b_nop |= NAM$M_SYNCHK; mynam.nam$l_rlf = NULL; 12396 myfab.fab$b_dns = 0; sts = sys$parse(&myfab,0,0); 12397 set_vaxc_errno(retsts); 12398 if (retsts == SS$_IVDEVNAM) set_errno(ENOTDIR); 12399 else if (retsts == SS$_NOPRIV) set_errno(EACCES); 12400 else if (retsts == SS$_NOSUCHDEV) set_errno(ENOTDIR); 12401 else set_errno(EVMSERR); 12402 return -1; 12403 } 12404 12405 fnmdsc.dsc$a_pointer = mynam.nam$l_name; 12406 fnmdsc.dsc$w_length = mynam.nam$b_name + mynam.nam$b_type + mynam.nam$b_ver; 12407 12408 memset((void *) &myfib, 0, sizeof myfib); 12409 #if defined(__DECC) || defined(__DECCXX) 12410 for (i=0;i<3;i++) myfib.fib$w_fid[i] = mynam.nam$w_fid[i]; 12411 for (i=0;i<3;i++) myfib.fib$w_did[i] = mynam.nam$w_did[i]; 12412 /* This prevents the revision time of the file being reset to the current 12413 * time as a result of our IO$_MODIFY $QIO. */ 12414 myfib.fib$l_acctl = FIB$M_NORECORD; 12415 #else 12416 for (i=0;i<3;i++) myfib.fib$r_fid_overlay.fib$w_fid[i] = mynam.nam$w_fid[i]; 12417 for (i=0;i<3;i++) myfib.fib$r_did_overlay.fib$w_did[i] = mynam.nam$w_did[i]; 12418 myfib.fib$r_acctl_overlay.fib$l_acctl = FIB$M_NORECORD; 12419 #endif 12420 retsts = sys$qiow(0,chan,IO$_MODIFY,iosb,0,0,&fibdsc,&fnmdsc,0,0,myatr,0); 12421 mynam.nam$b_nop |= NAM$M_SYNCHK; mynam.nam$l_rlf = NULL; 12422 myfab.fab$b_dns = 0; sts = sys$parse(&myfab,0,0); 12423 _ckvmssts(sys$dassgn(chan)); 12424 if (retsts & 1) retsts = iosb[0]; 12425 if (!(retsts & 1)) { 12426 set_vaxc_errno(retsts); 12427 if (retsts == SS$_NOPRIV) set_errno(EACCES); 12428 else set_errno(EVMSERR); 12429 return -1; 12430 } 12431 12432 return 0; 12433 12434 #endif /* #if __CRTL_VER >= 70300000 */ 12435 12436 } /* end of my_utime() */ 12437 /*}}}*/ 12438 12439 /* 12440 * flex_stat, flex_lstat, flex_fstat 12441 * basic stat, but gets it right when asked to stat 12442 * a Unix-style path ending in a directory name (e.g. dir1/dir2/dir3) 12443 */ 12444 12445 #ifndef _USE_STD_STAT 12446 /* encode_dev packs a VMS device name string into an integer to allow 12447 * simple comparisons. This can be used, for example, to check whether two 12448 * files are located on the same device, by comparing their encoded device 12449 * names. Even a string comparison would not do, because stat() reuses the 12450 * device name buffer for each call; so without encode_dev, it would be 12451 * necessary to save the buffer and use strcmp (this would mean a number of 12452 * changes to the standard Perl code, to say nothing of what a Perl script 12453 * would have to do. 12454 * 12455 * The device lock id, if it exists, should be unique (unless perhaps compared 12456 * with lock ids transferred from other nodes). We have a lock id if the disk is 12457 * mounted cluster-wide, which is when we tend to get long (host-qualified) 12458 * device names. Thus we use the lock id in preference, and only if that isn't 12459 * available, do we try to pack the device name into an integer (flagged by 12460 * the sign bit (LOCKID_MASK) being set). 12461 * 12462 * Note that encode_dev cannot guarantee an 1-to-1 correspondence twixt device 12463 * name and its encoded form, but it seems very unlikely that we will find 12464 * two files on different disks that share the same encoded device names, 12465 * and even more remote that they will share the same file id (if the test 12466 * is to check for the same file). 12467 * 12468 * A better method might be to use sys$device_scan on the first call, and to 12469 * search for the device, returning an index into the cached array. 12470 * The number returned would be more intelligible. 12471 * This is probably not worth it, and anyway would take quite a bit longer 12472 * on the first call. 12473 */ 12474 #define LOCKID_MASK 0x80000000 /* Use 0 to force device name use only */ 12475 static mydev_t encode_dev (pTHX_ const char *dev) 12476 { 12477 int i; 12478 unsigned long int f; 12479 mydev_t enc; 12480 char c; 12481 const char *q; 12482 12483 if (!dev || !dev[0]) return 0; 12484 12485 #if LOCKID_MASK 12486 { 12487 struct dsc$descriptor_s dev_desc; 12488 unsigned long int status, lockid = 0, item = DVI$_LOCKID; 12489 12490 /* For cluster-mounted disks, the disk lock identifier is unique, so we 12491 can try that first. */ 12492 dev_desc.dsc$w_length = strlen (dev); 12493 dev_desc.dsc$b_dtype = DSC$K_DTYPE_T; 12494 dev_desc.dsc$b_class = DSC$K_CLASS_S; 12495 dev_desc.dsc$a_pointer = (char *) dev; /* Read only parameter */ 12496 status = lib$getdvi(&item, 0, &dev_desc, &lockid, 0, 0); 12497 if (!$VMS_STATUS_SUCCESS(status)) { 12498 switch (status) { 12499 case SS$_NOSUCHDEV: 12500 SETERRNO(ENODEV, status); 12501 return 0; 12502 default: 12503 _ckvmssts(status); 12504 } 12505 } 12506 if (lockid) return (lockid & ~LOCKID_MASK); 12507 } 12508 #endif 12509 12510 /* Otherwise we try to encode the device name */ 12511 enc = 0; 12512 f = 1; 12513 i = 0; 12514 for (q = dev + strlen(dev); q--; q >= dev) { 12515 if (*q == ':') 12516 break; 12517 if (isdigit (*q)) 12518 c= (*q) - '0'; 12519 else if (isalpha (toupper (*q))) 12520 c= toupper (*q) - 'A' + (char)10; 12521 else 12522 continue; /* Skip '$'s */ 12523 i++; 12524 if (i>6) break; /* 36^7 is too large to fit in an unsigned long int */ 12525 if (i>1) f *= 36; 12526 enc += f * (unsigned long int) c; 12527 } 12528 return (enc | LOCKID_MASK); /* May have already overflowed into bit 31 */ 12529 12530 } /* end of encode_dev() */ 12531 #define VMS_DEVICE_ENCODE(device_no, devname, new_dev_no) \ 12532 device_no = encode_dev(aTHX_ devname) 12533 #else 12534 #define VMS_DEVICE_ENCODE(device_no, devname, new_dev_no) \ 12535 device_no = new_dev_no 12536 #endif 12537 12538 static int 12539 is_null_device(name) 12540 const char *name; 12541 { 12542 if (decc_bug_devnull != 0) { 12543 if (strncmp("/dev/null", name, 9) == 0) 12544 return 1; 12545 } 12546 /* The VMS null device is named "_NLA0:", usually abbreviated as "NL:". 12547 The underscore prefix, controller letter, and unit number are 12548 independently optional; for our purposes, the colon punctuation 12549 is not. The colon can be trailed by optional directory and/or 12550 filename, but two consecutive colons indicates a nodename rather 12551 than a device. [pr] */ 12552 if (*name == '_') ++name; 12553 if (tolower(*name++) != 'n') return 0; 12554 if (tolower(*name++) != 'l') return 0; 12555 if (tolower(*name) == 'a') ++name; 12556 if (*name == '0') ++name; 12557 return (*name++ == ':') && (*name != ':'); 12558 } 12559 12560 static int 12561 Perl_flex_stat_int(pTHX_ const char *fspec, Stat_t *statbufp, int lstat_flag); 12562 12563 #define flex_stat_int(a,b,c) Perl_flex_stat_int(aTHX_ a,b,c) 12564 12565 static I32 12566 Perl_cando_by_name_int 12567 (pTHX_ I32 bit, bool effective, const char *fname, int opts) 12568 { 12569 char usrname[L_cuserid]; 12570 struct dsc$descriptor_s usrdsc = 12571 {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, usrname}; 12572 char *vmsname = NULL, *fileified = NULL; 12573 unsigned long int objtyp = ACL$C_FILE, access, retsts, privused, iosb[2], flags; 12574 unsigned short int retlen, trnlnm_iter_count; 12575 struct dsc$descriptor_s namdsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0}; 12576 union prvdef curprv; 12577 struct itmlst_3 armlst[4] = {{sizeof access, CHP$_ACCESS, &access, &retlen}, 12578 {sizeof privused, CHP$_PRIVUSED, &privused, &retlen}, 12579 {sizeof flags, CHP$_FLAGS, &flags, &retlen},{0,0,0,0}}; 12580 struct itmlst_3 jpilst[3] = {{sizeof curprv, JPI$_CURPRIV, &curprv, &retlen}, 12581 {sizeof usrname, JPI$_USERNAME, &usrname, &usrdsc.dsc$w_length}, 12582 {0,0,0,0}}; 12583 struct itmlst_3 usrprolst[2] = {{sizeof curprv, CHP$_PRIV, &curprv, &retlen}, 12584 {0,0,0,0}}; 12585 struct dsc$descriptor_s usrprodsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0}; 12586 Stat_t st; 12587 static int profile_context = -1; 12588 12589 if (!fname || !*fname) return FALSE; 12590 12591 /* Make sure we expand logical names, since sys$check_access doesn't */ 12592 fileified = PerlMem_malloc(VMS_MAXRSS); 12593 if (fileified == NULL) _ckvmssts_noperl(SS$_INSFMEM); 12594 if (!strpbrk(fname,"/]>:")) { 12595 strcpy(fileified,fname); 12596 trnlnm_iter_count = 0; 12597 while (!strpbrk(fileified,"/]>:") && my_trnlnm(fileified,fileified,0)) { 12598 trnlnm_iter_count++; 12599 if (trnlnm_iter_count >= PERL_LNM_MAX_ITER) break; 12600 } 12601 fname = fileified; 12602 } 12603 12604 vmsname = PerlMem_malloc(VMS_MAXRSS); 12605 if (vmsname == NULL) _ckvmssts_noperl(SS$_INSFMEM); 12606 if ( !(opts & PERL_RMSEXPAND_M_VMS_IN) ) { 12607 /* Don't know if already in VMS format, so make sure */ 12608 if (!do_rmsexpand(fname, vmsname, 0, NULL, PERL_RMSEXPAND_M_VMS, NULL, NULL)) { 12609 PerlMem_free(fileified); 12610 PerlMem_free(vmsname); 12611 return FALSE; 12612 } 12613 } 12614 else { 12615 strcpy(vmsname,fname); 12616 } 12617 12618 /* sys$check_access needs a file spec, not a directory spec. 12619 * flex_stat now will handle a null thread context during startup. 12620 */ 12621 12622 retlen = namdsc.dsc$w_length = strlen(vmsname); 12623 if (vmsname[retlen-1] == ']' 12624 || vmsname[retlen-1] == '>' 12625 || vmsname[retlen-1] == ':' 12626 || (!flex_stat_int(vmsname, &st, 1) && 12627 S_ISDIR(st.st_mode))) { 12628 12629 if (!int_fileify_dirspec(vmsname, fileified, NULL)) { 12630 PerlMem_free(fileified); 12631 PerlMem_free(vmsname); 12632 return FALSE; 12633 } 12634 fname = fileified; 12635 } 12636 else { 12637 fname = vmsname; 12638 } 12639 12640 retlen = namdsc.dsc$w_length = strlen(fname); 12641 namdsc.dsc$a_pointer = (char *)fname; 12642 12643 switch (bit) { 12644 case S_IXUSR: case S_IXGRP: case S_IXOTH: 12645 access = ARM$M_EXECUTE; 12646 flags = CHP$M_READ; 12647 break; 12648 case S_IRUSR: case S_IRGRP: case S_IROTH: 12649 access = ARM$M_READ; 12650 flags = CHP$M_READ | CHP$M_USEREADALL; 12651 break; 12652 case S_IWUSR: case S_IWGRP: case S_IWOTH: 12653 access = ARM$M_WRITE; 12654 flags = CHP$M_READ | CHP$M_WRITE; 12655 break; 12656 case S_IDUSR: case S_IDGRP: case S_IDOTH: 12657 access = ARM$M_DELETE; 12658 flags = CHP$M_READ | CHP$M_WRITE; 12659 break; 12660 default: 12661 if (fileified != NULL) 12662 PerlMem_free(fileified); 12663 if (vmsname != NULL) 12664 PerlMem_free(vmsname); 12665 return FALSE; 12666 } 12667 12668 /* Before we call $check_access, create a user profile with the current 12669 * process privs since otherwise it just uses the default privs from the 12670 * UAF and might give false positives or negatives. This only works on 12671 * VMS versions v6.0 and later since that's when sys$create_user_profile 12672 * became available. 12673 */ 12674 12675 /* get current process privs and username */ 12676 _ckvmssts_noperl(sys$getjpiw(0,0,0,jpilst,iosb,0,0)); 12677 _ckvmssts_noperl(iosb[0]); 12678 12679 #if defined(__VMS_VER) && __VMS_VER >= 60000000 12680 12681 /* find out the space required for the profile */ 12682 _ckvmssts_noperl(sys$create_user_profile(&usrdsc,&usrprolst,0,0, 12683 &usrprodsc.dsc$w_length,&profile_context)); 12684 12685 /* allocate space for the profile and get it filled in */ 12686 usrprodsc.dsc$a_pointer = PerlMem_malloc(usrprodsc.dsc$w_length); 12687 if (usrprodsc.dsc$a_pointer == NULL) _ckvmssts_noperl(SS$_INSFMEM); 12688 _ckvmssts_noperl(sys$create_user_profile(&usrdsc,&usrprolst,0,usrprodsc.dsc$a_pointer, 12689 &usrprodsc.dsc$w_length,&profile_context)); 12690 12691 /* use the profile to check access to the file; free profile & analyze results */ 12692 retsts = sys$check_access(&objtyp,&namdsc,0,armlst,&profile_context,0,0,&usrprodsc); 12693 PerlMem_free(usrprodsc.dsc$a_pointer); 12694 if (retsts == SS$_NOCALLPRIV) retsts = SS$_NOPRIV; /* not really 3rd party */ 12695 12696 #else 12697 12698 retsts = sys$check_access(&objtyp,&namdsc,&usrdsc,armlst); 12699 12700 #endif 12701 12702 if (retsts == SS$_NOPRIV || retsts == SS$_NOSUCHOBJECT || 12703 retsts == SS$_INVFILFOROP || retsts == RMS$_FNF || retsts == RMS$_SYN || 12704 retsts == RMS$_DIR || retsts == RMS$_DEV || retsts == RMS$_DNF) { 12705 set_vaxc_errno(retsts); 12706 if (retsts == SS$_NOPRIV) set_errno(EACCES); 12707 else if (retsts == SS$_INVFILFOROP) set_errno(EINVAL); 12708 else set_errno(ENOENT); 12709 if (fileified != NULL) 12710 PerlMem_free(fileified); 12711 if (vmsname != NULL) 12712 PerlMem_free(vmsname); 12713 return FALSE; 12714 } 12715 if (retsts == SS$_NORMAL || retsts == SS$_ACCONFLICT) { 12716 if (fileified != NULL) 12717 PerlMem_free(fileified); 12718 if (vmsname != NULL) 12719 PerlMem_free(vmsname); 12720 return TRUE; 12721 } 12722 _ckvmssts_noperl(retsts); 12723 12724 if (fileified != NULL) 12725 PerlMem_free(fileified); 12726 if (vmsname != NULL) 12727 PerlMem_free(vmsname); 12728 return FALSE; /* Should never get here */ 12729 12730 } 12731 12732 /* Do the permissions allow some operation? Assumes PL_statcache already set. */ 12733 /* Do this via $Check_Access on VMS, since the CRTL stat() returns only a 12734 * subset of the applicable information. 12735 */ 12736 bool 12737 Perl_cando(pTHX_ Mode_t bit, bool effective, const Stat_t *statbufp) 12738 { 12739 return cando_by_name_int 12740 (bit, effective, statbufp->st_devnam, PERL_RMSEXPAND_M_VMS_IN); 12741 } /* end of cando() */ 12742 /*}}}*/ 12743 12744 12745 /*{{{I32 cando_by_name(I32 bit, bool effective, char *fname)*/ 12746 I32 12747 Perl_cando_by_name(pTHX_ I32 bit, bool effective, const char *fname) 12748 { 12749 return cando_by_name_int(bit, effective, fname, 0); 12750 12751 } /* end of cando_by_name() */ 12752 /*}}}*/ 12753 12754 12755 /*{{{ int flex_fstat(int fd, Stat_t *statbuf)*/ 12756 int 12757 Perl_flex_fstat(pTHX_ int fd, Stat_t *statbufp) 12758 { 12759 if (!fstat(fd, &statbufp->crtl_stat)) { 12760 char *cptr; 12761 char *vms_filename; 12762 vms_filename = PerlMem_malloc(VMS_MAXRSS); 12763 if (vms_filename == NULL) _ckvmssts(SS$_INSFMEM); 12764 12765 /* Save name for cando by name in VMS format */ 12766 cptr = getname(fd, vms_filename, 1); 12767 12768 /* This should not happen, but just in case */ 12769 if (cptr == NULL) { 12770 statbufp->st_devnam[0] = 0; 12771 } 12772 else { 12773 /* Make sure that the saved name fits in 255 characters */ 12774 cptr = int_rmsexpand_vms 12775 (vms_filename, 12776 statbufp->st_devnam, 12777 0); 12778 if (cptr == NULL) 12779 statbufp->st_devnam[0] = 0; 12780 } 12781 PerlMem_free(vms_filename); 12782 12783 VMS_INO_T_COPY(statbufp->st_ino, statbufp->crtl_stat.st_ino); 12784 VMS_DEVICE_ENCODE 12785 (statbufp->st_dev, statbufp->st_devnam, statbufp->crtl_stat.st_dev); 12786 12787 # ifdef RTL_USES_UTC 12788 # ifdef VMSISH_TIME 12789 if (VMSISH_TIME) { 12790 statbufp->st_mtime = _toloc(statbufp->st_mtime); 12791 statbufp->st_atime = _toloc(statbufp->st_atime); 12792 statbufp->st_ctime = _toloc(statbufp->st_ctime); 12793 } 12794 # endif 12795 # else 12796 # ifdef VMSISH_TIME 12797 if (!VMSISH_TIME) { /* Return UTC instead of local time */ 12798 # else 12799 if (1) { 12800 # endif 12801 statbufp->st_mtime = _toutc(statbufp->st_mtime); 12802 statbufp->st_atime = _toutc(statbufp->st_atime); 12803 statbufp->st_ctime = _toutc(statbufp->st_ctime); 12804 } 12805 #endif 12806 return 0; 12807 } 12808 return -1; 12809 12810 } /* end of flex_fstat() */ 12811 /*}}}*/ 12812 12813 static int 12814 Perl_flex_stat_int(pTHX_ const char *fspec, Stat_t *statbufp, int lstat_flag) 12815 { 12816 char *fileified; 12817 char *temp_fspec; 12818 const char *save_spec; 12819 char *ret_spec; 12820 int retval = -1; 12821 int efs_hack = 0; 12822 dSAVEDERRNO; 12823 12824 if (!fspec) { 12825 errno = EINVAL; 12826 return retval; 12827 } 12828 12829 if (decc_bug_devnull != 0) { 12830 if (is_null_device(fspec)) { /* Fake a stat() for the null device */ 12831 memset(statbufp,0,sizeof *statbufp); 12832 VMS_DEVICE_ENCODE(statbufp->st_dev, "_NLA0:", 0); 12833 statbufp->st_mode = S_IFBLK | S_IREAD | S_IWRITE | S_IEXEC; 12834 statbufp->st_uid = 0x00010001; 12835 statbufp->st_gid = 0x0001; 12836 time((time_t *)&statbufp->st_mtime); 12837 statbufp->st_atime = statbufp->st_ctime = statbufp->st_mtime; 12838 return 0; 12839 } 12840 } 12841 12842 /* Try for a directory name first. If fspec contains a filename without 12843 * a type (e.g. sea:[wine.dark]water), and both sea:[wine.dark]water.dir 12844 * and sea:[wine.dark]water. exist, we prefer the directory here. 12845 * Similarly, sea:[wine.dark] returns the result for sea:[wine]dark.dir, 12846 * not sea:[wine.dark]., if the latter exists. If the intended target is 12847 * the file with null type, specify this by calling flex_stat() with 12848 * a '.' at the end of fspec. 12849 * 12850 * If we are in Posix filespec mode, accept the filename as is. 12851 */ 12852 12853 12854 fileified = PerlMem_malloc(VMS_MAXRSS); 12855 if (fileified == NULL) 12856 _ckvmssts_noperl(SS$_INSFMEM); 12857 12858 temp_fspec = PerlMem_malloc(VMS_MAXRSS); 12859 if (temp_fspec == NULL) 12860 _ckvmssts_noperl(SS$_INSFMEM); 12861 12862 strcpy(temp_fspec, fspec); 12863 12864 SAVE_ERRNO; 12865 12866 #if __CRTL_VER >= 80200000 && !defined(__VAX) 12867 if (decc_posix_compliant_pathnames == 0) { 12868 #endif 12869 12870 /* We may be able to optimize this, but in order for fileify_dirspec to 12871 * always return a usuable answer, we have to call vmspath first to 12872 * make sure that it is in VMS directory format, as stat/lstat on 8.3 12873 * can not handle directories in unix format that it does not have read 12874 * access to. Vmspath handles the case where a bare name which could be 12875 * a logical name gets passed. 12876 */ 12877 ret_spec = int_tovmspath(fspec, temp_fspec, NULL); 12878 if (ret_spec != NULL) { 12879 ret_spec = int_fileify_dirspec(temp_fspec, fileified, NULL); 12880 if (ret_spec != NULL) { 12881 if (lstat_flag == 0) 12882 retval = stat(fileified, &statbufp->crtl_stat); 12883 else 12884 retval = lstat(fileified, &statbufp->crtl_stat); 12885 save_spec = fileified; 12886 } 12887 } 12888 12889 if (retval && vms_bug_stat_filename) { 12890 12891 /* We should try again as a vmsified file specification */ 12892 /* However Perl traditionally has not done this, which */ 12893 /* causes problems with existing tests */ 12894 12895 ret_spec = int_tovmsspec(fspec, temp_fspec, 0, NULL); 12896 if (ret_spec != NULL) { 12897 if (lstat_flag == 0) 12898 retval = stat(temp_fspec, &statbufp->crtl_stat); 12899 else 12900 retval = lstat(temp_fspec, &statbufp->crtl_stat); 12901 save_spec = temp_fspec; 12902 } 12903 } 12904 12905 if (retval) { 12906 /* Last chance - allow multiple dots with out EFS CHARSET */ 12907 /* The CRTL stat() falls down hard on multi-dot filenames in unix 12908 * format unless * DECC$EFS_CHARSET is in effect, so temporarily 12909 * enable it if it isn't already. 12910 */ 12911 #if __CRTL_VER >= 70300000 && !defined(__VAX) 12912 if (!decc_efs_charset && (decc_efs_charset_index > 0)) 12913 decc$feature_set_value(decc_efs_charset_index, 1, 1); 12914 #endif 12915 if (lstat_flag == 0) 12916 retval = stat(fspec, &statbufp->crtl_stat); 12917 else 12918 retval = lstat(fspec, &statbufp->crtl_stat); 12919 save_spec = fspec; 12920 #if __CRTL_VER >= 70300000 && !defined(__VAX) 12921 if (!decc_efs_charset && (decc_efs_charset_index > 0)) { 12922 decc$feature_set_value(decc_efs_charset_index, 1, 0); 12923 efs_hack = 1; 12924 } 12925 #endif 12926 } 12927 12928 #if __CRTL_VER >= 80200000 && !defined(__VAX) 12929 } else { 12930 if (lstat_flag == 0) 12931 retval = stat(temp_fspec, &statbufp->crtl_stat); 12932 else 12933 retval = lstat(temp_fspec, &statbufp->crtl_stat); 12934 save_spec = temp_fspec; 12935 } 12936 #endif 12937 12938 #if __CRTL_VER >= 70300000 && !defined(__VAX) 12939 /* As you were... */ 12940 if (!decc_efs_charset) 12941 decc$feature_set_value(decc$feature_get_index("DECC$EFS_CHARSET"),1,0); 12942 #endif 12943 12944 if (!retval) { 12945 char * cptr; 12946 int rmsex_flags = PERL_RMSEXPAND_M_VMS; 12947 12948 /* If this is an lstat, do not follow the link */ 12949 if (lstat_flag) 12950 rmsex_flags |= PERL_RMSEXPAND_M_SYMLINK; 12951 12952 #if __CRTL_VER >= 70300000 && !defined(__VAX) 12953 /* If we used the efs_hack above, we must also use it here for */ 12954 /* perl_cando to work */ 12955 if (efs_hack && (decc_efs_charset_index > 0)) { 12956 decc$feature_set_value(decc_efs_charset_index, 1, 1); 12957 } 12958 #endif 12959 cptr = int_rmsexpand_tovms(save_spec, statbufp->st_devnam, rmsex_flags); 12960 #if __CRTL_VER >= 70300000 && !defined(__VAX) 12961 if (efs_hack && (decc_efs_charset_index > 0)) { 12962 decc$feature_set_value(decc_efs_charset, 1, 0); 12963 } 12964 #endif 12965 12966 /* Fix me: If this is NULL then stat found a file, and we could */ 12967 /* not convert the specification to VMS - Should never happen */ 12968 if (cptr == NULL) 12969 statbufp->st_devnam[0] = 0; 12970 12971 VMS_INO_T_COPY(statbufp->st_ino, statbufp->crtl_stat.st_ino); 12972 VMS_DEVICE_ENCODE 12973 (statbufp->st_dev, statbufp->st_devnam, statbufp->crtl_stat.st_dev); 12974 # ifdef RTL_USES_UTC 12975 # ifdef VMSISH_TIME 12976 if (VMSISH_TIME) { 12977 statbufp->st_mtime = _toloc(statbufp->st_mtime); 12978 statbufp->st_atime = _toloc(statbufp->st_atime); 12979 statbufp->st_ctime = _toloc(statbufp->st_ctime); 12980 } 12981 # endif 12982 # else 12983 # ifdef VMSISH_TIME 12984 if (!VMSISH_TIME) { /* Return UTC instead of local time */ 12985 # else 12986 if (1) { 12987 # endif 12988 statbufp->st_mtime = _toutc(statbufp->st_mtime); 12989 statbufp->st_atime = _toutc(statbufp->st_atime); 12990 statbufp->st_ctime = _toutc(statbufp->st_ctime); 12991 } 12992 # endif 12993 } 12994 /* If we were successful, leave errno where we found it */ 12995 if (retval == 0) RESTORE_ERRNO; 12996 PerlMem_free(temp_fspec); 12997 PerlMem_free(fileified); 12998 return retval; 12999 13000 } /* end of flex_stat_int() */ 13001 13002 13003 /*{{{ int flex_stat(const char *fspec, Stat_t *statbufp)*/ 13004 int 13005 Perl_flex_stat(pTHX_ const char *fspec, Stat_t *statbufp) 13006 { 13007 return flex_stat_int(fspec, statbufp, 0); 13008 } 13009 /*}}}*/ 13010 13011 /*{{{ int flex_lstat(const char *fspec, Stat_t *statbufp)*/ 13012 int 13013 Perl_flex_lstat(pTHX_ const char *fspec, Stat_t *statbufp) 13014 { 13015 return flex_stat_int(fspec, statbufp, 1); 13016 } 13017 /*}}}*/ 13018 13019 13020 /*{{{char *my_getlogin()*/ 13021 /* VMS cuserid == Unix getlogin, except calling sequence */ 13022 char * 13023 my_getlogin(void) 13024 { 13025 static char user[L_cuserid]; 13026 return cuserid(user); 13027 } 13028 /*}}}*/ 13029 13030 13031 /* rmscopy - copy a file using VMS RMS routines 13032 * 13033 * Copies contents and attributes of spec_in to spec_out, except owner 13034 * and protection information. Name and type of spec_in are used as 13035 * defaults for spec_out. The third parameter specifies whether rmscopy() 13036 * should try to propagate timestamps from the input file to the output file. 13037 * If it is less than 0, no timestamps are preserved. If it is 0, then 13038 * rmscopy() will behave similarly to the DCL COPY command: timestamps are 13039 * propagated to the output file at creation iff the output file specification 13040 * did not contain an explicit name or type, and the revision date is always 13041 * updated at the end of the copy operation. If it is greater than 0, then 13042 * it is interpreted as a bitmask, in which bit 0 indicates that timestamps 13043 * other than the revision date should be propagated, and bit 1 indicates 13044 * that the revision date should be propagated. 13045 * 13046 * Returns 1 on success; returns 0 and sets errno and vaxc$errno on failure. 13047 * 13048 * Copyright 1996 by Charles Bailey <bailey@newman.upenn.edu>. 13049 * Incorporates, with permission, some code from EZCOPY by Tim Adye 13050 * <T.J.Adye@rl.ac.uk>. Permission is given to distribute this code 13051 * as part of the Perl standard distribution under the terms of the 13052 * GNU General Public License or the Perl Artistic License. Copies 13053 * of each may be found in the Perl standard distribution. 13054 */ /* FIXME */ 13055 /*{{{int rmscopy(char *src, char *dst, int preserve_dates)*/ 13056 int 13057 Perl_rmscopy(pTHX_ const char *spec_in, const char *spec_out, int preserve_dates) 13058 { 13059 char *vmsin, * vmsout, *esa, *esal, *esa_out, *esal_out, 13060 *rsa, *rsal, *rsa_out, *rsal_out, *ubf; 13061 unsigned long int i, sts, sts2; 13062 int dna_len; 13063 struct FAB fab_in, fab_out; 13064 struct RAB rab_in, rab_out; 13065 rms_setup_nam(nam); 13066 rms_setup_nam(nam_out); 13067 struct XABDAT xabdat; 13068 struct XABFHC xabfhc; 13069 struct XABRDT xabrdt; 13070 struct XABSUM xabsum; 13071 13072 vmsin = PerlMem_malloc(VMS_MAXRSS); 13073 if (vmsin == NULL) _ckvmssts_noperl(SS$_INSFMEM); 13074 vmsout = PerlMem_malloc(VMS_MAXRSS); 13075 if (vmsout == NULL) _ckvmssts_noperl(SS$_INSFMEM); 13076 if (!spec_in || !*spec_in || !int_tovmsspec(spec_in, vmsin, 1, NULL) || 13077 !spec_out || !*spec_out || !int_tovmsspec(spec_out, vmsout, 1, NULL)) { 13078 PerlMem_free(vmsin); 13079 PerlMem_free(vmsout); 13080 set_errno(EINVAL); set_vaxc_errno(LIB$_INVARG); 13081 return 0; 13082 } 13083 13084 esa = PerlMem_malloc(VMS_MAXRSS); 13085 if (esa == NULL) _ckvmssts_noperl(SS$_INSFMEM); 13086 esal = NULL; 13087 #if !defined(__VAX) && defined(NAML$C_MAXRSS) 13088 esal = PerlMem_malloc(VMS_MAXRSS); 13089 if (esal == NULL) _ckvmssts_noperl(SS$_INSFMEM); 13090 #endif 13091 fab_in = cc$rms_fab; 13092 rms_set_fna(fab_in, nam, vmsin, strlen(vmsin)); 13093 fab_in.fab$b_shr = FAB$M_SHRPUT | FAB$M_UPI; 13094 fab_in.fab$b_fac = FAB$M_BIO | FAB$M_GET; 13095 fab_in.fab$l_fop = FAB$M_SQO; 13096 rms_bind_fab_nam(fab_in, nam); 13097 fab_in.fab$l_xab = (void *) &xabdat; 13098 13099 rsa = PerlMem_malloc(VMS_MAXRSS); 13100 if (rsa == NULL) _ckvmssts_noperl(SS$_INSFMEM); 13101 rsal = NULL; 13102 #if !defined(__VAX) && defined(NAML$C_MAXRSS) 13103 rsal = PerlMem_malloc(VMS_MAXRSS); 13104 if (rsal == NULL) _ckvmssts_noperl(SS$_INSFMEM); 13105 #endif 13106 rms_set_rsal(nam, rsa, NAM$C_MAXRSS, rsal, (VMS_MAXRSS - 1)); 13107 rms_set_esal(nam, esa, NAM$C_MAXRSS, esal, (VMS_MAXRSS - 1)); 13108 rms_nam_esl(nam) = 0; 13109 rms_nam_rsl(nam) = 0; 13110 rms_nam_esll(nam) = 0; 13111 rms_nam_rsll(nam) = 0; 13112 #ifdef NAM$M_NO_SHORT_UPCASE 13113 if (decc_efs_case_preserve) 13114 rms_set_nam_nop(nam, NAM$M_NO_SHORT_UPCASE); 13115 #endif 13116 13117 xabdat = cc$rms_xabdat; /* To get creation date */ 13118 xabdat.xab$l_nxt = (void *) &xabfhc; 13119 13120 xabfhc = cc$rms_xabfhc; /* To get record length */ 13121 xabfhc.xab$l_nxt = (void *) &xabsum; 13122 13123 xabsum = cc$rms_xabsum; /* To get key and area information */ 13124 13125 if (!((sts = sys$open(&fab_in)) & 1)) { 13126 PerlMem_free(vmsin); 13127 PerlMem_free(vmsout); 13128 PerlMem_free(esa); 13129 if (esal != NULL) 13130 PerlMem_free(esal); 13131 PerlMem_free(rsa); 13132 if (rsal != NULL) 13133 PerlMem_free(rsal); 13134 set_vaxc_errno(sts); 13135 switch (sts) { 13136 case RMS$_FNF: case RMS$_DNF: 13137 set_errno(ENOENT); break; 13138 case RMS$_DIR: 13139 set_errno(ENOTDIR); break; 13140 case RMS$_DEV: 13141 set_errno(ENODEV); break; 13142 case RMS$_SYN: 13143 set_errno(EINVAL); break; 13144 case RMS$_PRV: 13145 set_errno(EACCES); break; 13146 default: 13147 set_errno(EVMSERR); 13148 } 13149 return 0; 13150 } 13151 13152 nam_out = nam; 13153 fab_out = fab_in; 13154 fab_out.fab$w_ifi = 0; 13155 fab_out.fab$b_fac = FAB$M_BIO | FAB$M_PUT; 13156 fab_out.fab$b_shr = FAB$M_SHRGET | FAB$M_UPI; 13157 fab_out.fab$l_fop = FAB$M_SQO; 13158 rms_bind_fab_nam(fab_out, nam_out); 13159 rms_set_fna(fab_out, nam_out, vmsout, strlen(vmsout)); 13160 dna_len = rms_nam_namel(nam) ? rms_nam_name_type_l_size(nam) : 0; 13161 rms_set_dna(fab_out, nam_out, rms_nam_namel(nam), dna_len); 13162 esa_out = PerlMem_malloc(NAM$C_MAXRSS + 1); 13163 if (esa_out == NULL) _ckvmssts_noperl(SS$_INSFMEM); 13164 rsa_out = PerlMem_malloc(NAM$C_MAXRSS + 1); 13165 if (rsa_out == NULL) _ckvmssts_noperl(SS$_INSFMEM); 13166 esal_out = NULL; 13167 rsal_out = NULL; 13168 #if !defined(__VAX) && defined(NAML$C_MAXRSS) 13169 esal_out = PerlMem_malloc(VMS_MAXRSS); 13170 if (esal_out == NULL) _ckvmssts_noperl(SS$_INSFMEM); 13171 rsal_out = PerlMem_malloc(VMS_MAXRSS); 13172 if (rsal_out == NULL) _ckvmssts_noperl(SS$_INSFMEM); 13173 #endif 13174 rms_set_rsal(nam_out, rsa_out, NAM$C_MAXRSS, rsal_out, (VMS_MAXRSS - 1)); 13175 rms_set_esal(nam_out, esa_out, NAM$C_MAXRSS, esal_out, (VMS_MAXRSS - 1)); 13176 13177 if (preserve_dates == 0) { /* Act like DCL COPY */ 13178 rms_set_nam_nop(nam_out, NAM$M_SYNCHK); 13179 fab_out.fab$l_xab = NULL; /* Don't disturb data from input file */ 13180 if (!((sts = sys$parse(&fab_out)) & STS$K_SUCCESS)) { 13181 PerlMem_free(vmsin); 13182 PerlMem_free(vmsout); 13183 PerlMem_free(esa); 13184 if (esal != NULL) 13185 PerlMem_free(esal); 13186 PerlMem_free(rsa); 13187 if (rsal != NULL) 13188 PerlMem_free(rsal); 13189 PerlMem_free(esa_out); 13190 if (esal_out != NULL) 13191 PerlMem_free(esal_out); 13192 PerlMem_free(rsa_out); 13193 if (rsal_out != NULL) 13194 PerlMem_free(rsal_out); 13195 set_errno(sts == RMS$_SYN ? EINVAL : EVMSERR); 13196 set_vaxc_errno(sts); 13197 return 0; 13198 } 13199 fab_out.fab$l_xab = (void *) &xabdat; 13200 if (rms_is_nam_fnb(nam, NAM$M_EXP_NAME | NAM$M_EXP_TYPE)) 13201 preserve_dates = 1; 13202 } 13203 if (preserve_dates < 0) /* Clear all bits; we'll use it as a */ 13204 preserve_dates =0; /* bitmask from this point forward */ 13205 13206 if (!(preserve_dates & 1)) fab_out.fab$l_xab = (void *) &xabfhc; 13207 if (!((sts = sys$create(&fab_out)) & STS$K_SUCCESS)) { 13208 PerlMem_free(vmsin); 13209 PerlMem_free(vmsout); 13210 PerlMem_free(esa); 13211 if (esal != NULL) 13212 PerlMem_free(esal); 13213 PerlMem_free(rsa); 13214 if (rsal != NULL) 13215 PerlMem_free(rsal); 13216 PerlMem_free(esa_out); 13217 if (esal_out != NULL) 13218 PerlMem_free(esal_out); 13219 PerlMem_free(rsa_out); 13220 if (rsal_out != NULL) 13221 PerlMem_free(rsal_out); 13222 set_vaxc_errno(sts); 13223 switch (sts) { 13224 case RMS$_DNF: 13225 set_errno(ENOENT); break; 13226 case RMS$_DIR: 13227 set_errno(ENOTDIR); break; 13228 case RMS$_DEV: 13229 set_errno(ENODEV); break; 13230 case RMS$_SYN: 13231 set_errno(EINVAL); break; 13232 case RMS$_PRV: 13233 set_errno(EACCES); break; 13234 default: 13235 set_errno(EVMSERR); 13236 } 13237 return 0; 13238 } 13239 fab_out.fab$l_fop |= FAB$M_DLT; /* in case we have to bail out */ 13240 if (preserve_dates & 2) { 13241 /* sys$close() will process xabrdt, not xabdat */ 13242 xabrdt = cc$rms_xabrdt; 13243 #ifndef __GNUC__ 13244 xabrdt.xab$q_rdt = xabdat.xab$q_rdt; 13245 #else 13246 /* gcc doesn't like the assignment, since its prototype for xab$q_rdt 13247 * is unsigned long[2], while DECC & VAXC use a struct */ 13248 memcpy(xabrdt.xab$q_rdt,xabdat.xab$q_rdt,sizeof xabrdt.xab$q_rdt); 13249 #endif 13250 fab_out.fab$l_xab = (void *) &xabrdt; 13251 } 13252 13253 ubf = PerlMem_malloc(32256); 13254 if (ubf == NULL) _ckvmssts_noperl(SS$_INSFMEM); 13255 rab_in = cc$rms_rab; 13256 rab_in.rab$l_fab = &fab_in; 13257 rab_in.rab$l_rop = RAB$M_BIO; 13258 rab_in.rab$l_ubf = ubf; 13259 rab_in.rab$w_usz = 32256; 13260 if (!((sts = sys$connect(&rab_in)) & 1)) { 13261 sys$close(&fab_in); sys$close(&fab_out); 13262 PerlMem_free(vmsin); 13263 PerlMem_free(vmsout); 13264 PerlMem_free(ubf); 13265 PerlMem_free(esa); 13266 if (esal != NULL) 13267 PerlMem_free(esal); 13268 PerlMem_free(rsa); 13269 if (rsal != NULL) 13270 PerlMem_free(rsal); 13271 PerlMem_free(esa_out); 13272 if (esal_out != NULL) 13273 PerlMem_free(esal_out); 13274 PerlMem_free(rsa_out); 13275 if (rsal_out != NULL) 13276 PerlMem_free(rsal_out); 13277 set_errno(EVMSERR); set_vaxc_errno(sts); 13278 return 0; 13279 } 13280 13281 rab_out = cc$rms_rab; 13282 rab_out.rab$l_fab = &fab_out; 13283 rab_out.rab$l_rbf = ubf; 13284 if (!((sts = sys$connect(&rab_out)) & 1)) { 13285 sys$close(&fab_in); sys$close(&fab_out); 13286 PerlMem_free(vmsin); 13287 PerlMem_free(vmsout); 13288 PerlMem_free(ubf); 13289 PerlMem_free(esa); 13290 if (esal != NULL) 13291 PerlMem_free(esal); 13292 PerlMem_free(rsa); 13293 if (rsal != NULL) 13294 PerlMem_free(rsal); 13295 PerlMem_free(esa_out); 13296 if (esal_out != NULL) 13297 PerlMem_free(esal_out); 13298 PerlMem_free(rsa_out); 13299 if (rsal_out != NULL) 13300 PerlMem_free(rsal_out); 13301 set_errno(EVMSERR); set_vaxc_errno(sts); 13302 return 0; 13303 } 13304 13305 while ((sts = sys$read(&rab_in))) { /* always true */ 13306 if (sts == RMS$_EOF) break; 13307 rab_out.rab$w_rsz = rab_in.rab$w_rsz; 13308 if (!(sts & 1) || !((sts = sys$write(&rab_out)) & 1)) { 13309 sys$close(&fab_in); sys$close(&fab_out); 13310 PerlMem_free(vmsin); 13311 PerlMem_free(vmsout); 13312 PerlMem_free(ubf); 13313 PerlMem_free(esa); 13314 if (esal != NULL) 13315 PerlMem_free(esal); 13316 PerlMem_free(rsa); 13317 if (rsal != NULL) 13318 PerlMem_free(rsal); 13319 PerlMem_free(esa_out); 13320 if (esal_out != NULL) 13321 PerlMem_free(esal_out); 13322 PerlMem_free(rsa_out); 13323 if (rsal_out != NULL) 13324 PerlMem_free(rsal_out); 13325 set_errno(EVMSERR); set_vaxc_errno(sts); 13326 return 0; 13327 } 13328 } 13329 13330 13331 fab_out.fab$l_fop &= ~FAB$M_DLT; /* We got this far; keep the output */ 13332 sys$close(&fab_in); sys$close(&fab_out); 13333 sts = (fab_in.fab$l_sts & 1) ? fab_out.fab$l_sts : fab_in.fab$l_sts; 13334 13335 PerlMem_free(vmsin); 13336 PerlMem_free(vmsout); 13337 PerlMem_free(ubf); 13338 PerlMem_free(esa); 13339 if (esal != NULL) 13340 PerlMem_free(esal); 13341 PerlMem_free(rsa); 13342 if (rsal != NULL) 13343 PerlMem_free(rsal); 13344 PerlMem_free(esa_out); 13345 if (esal_out != NULL) 13346 PerlMem_free(esal_out); 13347 PerlMem_free(rsa_out); 13348 if (rsal_out != NULL) 13349 PerlMem_free(rsal_out); 13350 13351 if (!(sts & 1)) { 13352 set_errno(EVMSERR); set_vaxc_errno(sts); 13353 return 0; 13354 } 13355 13356 return 1; 13357 13358 } /* end of rmscopy() */ 13359 /*}}}*/ 13360 13361 13362 /*** The following glue provides 'hooks' to make some of the routines 13363 * from this file available from Perl. These routines are sufficiently 13364 * basic, and are required sufficiently early in the build process, 13365 * that's it's nice to have them available to miniperl as well as the 13366 * full Perl, so they're set up here instead of in an extension. The 13367 * Perl code which handles importation of these names into a given 13368 * package lives in [.VMS]Filespec.pm in @INC. 13369 */ 13370 13371 void 13372 rmsexpand_fromperl(pTHX_ CV *cv) 13373 { 13374 dXSARGS; 13375 char *fspec, *defspec = NULL, *rslt; 13376 STRLEN n_a; 13377 int fs_utf8, dfs_utf8; 13378 13379 fs_utf8 = 0; 13380 dfs_utf8 = 0; 13381 if (!items || items > 2) 13382 Perl_croak(aTHX_ "Usage: VMS::Filespec::rmsexpand(spec[,defspec])"); 13383 fspec = SvPV(ST(0),n_a); 13384 fs_utf8 = SvUTF8(ST(0)); 13385 if (!fspec || !*fspec) XSRETURN_UNDEF; 13386 if (items == 2) { 13387 defspec = SvPV(ST(1),n_a); 13388 dfs_utf8 = SvUTF8(ST(1)); 13389 } 13390 rslt = do_rmsexpand(fspec,NULL,1,defspec,0,&fs_utf8,&dfs_utf8); 13391 ST(0) = sv_newmortal(); 13392 if (rslt != NULL) { 13393 sv_usepvn(ST(0),rslt,strlen(rslt)); 13394 if (fs_utf8) { 13395 SvUTF8_on(ST(0)); 13396 } 13397 } 13398 XSRETURN(1); 13399 } 13400 13401 void 13402 vmsify_fromperl(pTHX_ CV *cv) 13403 { 13404 dXSARGS; 13405 char *vmsified; 13406 STRLEN n_a; 13407 int utf8_fl; 13408 13409 if (items != 1) Perl_croak(aTHX_ "Usage: VMS::Filespec::vmsify(spec)"); 13410 utf8_fl = SvUTF8(ST(0)); 13411 vmsified = do_tovmsspec(SvPV(ST(0),n_a),NULL,1,&utf8_fl); 13412 ST(0) = sv_newmortal(); 13413 if (vmsified != NULL) { 13414 sv_usepvn(ST(0),vmsified,strlen(vmsified)); 13415 if (utf8_fl) { 13416 SvUTF8_on(ST(0)); 13417 } 13418 } 13419 XSRETURN(1); 13420 } 13421 13422 void 13423 unixify_fromperl(pTHX_ CV *cv) 13424 { 13425 dXSARGS; 13426 char *unixified; 13427 STRLEN n_a; 13428 int utf8_fl; 13429 13430 if (items != 1) Perl_croak(aTHX_ "Usage: VMS::Filespec::unixify(spec)"); 13431 utf8_fl = SvUTF8(ST(0)); 13432 unixified = do_tounixspec(SvPV(ST(0),n_a),NULL,1,&utf8_fl); 13433 ST(0) = sv_newmortal(); 13434 if (unixified != NULL) { 13435 sv_usepvn(ST(0),unixified,strlen(unixified)); 13436 if (utf8_fl) { 13437 SvUTF8_on(ST(0)); 13438 } 13439 } 13440 XSRETURN(1); 13441 } 13442 13443 void 13444 fileify_fromperl(pTHX_ CV *cv) 13445 { 13446 dXSARGS; 13447 char *fileified; 13448 STRLEN n_a; 13449 int utf8_fl; 13450 13451 if (items != 1) Perl_croak(aTHX_ "Usage: VMS::Filespec::fileify(spec)"); 13452 utf8_fl = SvUTF8(ST(0)); 13453 fileified = do_fileify_dirspec(SvPV(ST(0),n_a),NULL,1,&utf8_fl); 13454 ST(0) = sv_newmortal(); 13455 if (fileified != NULL) { 13456 sv_usepvn(ST(0),fileified,strlen(fileified)); 13457 if (utf8_fl) { 13458 SvUTF8_on(ST(0)); 13459 } 13460 } 13461 XSRETURN(1); 13462 } 13463 13464 void 13465 pathify_fromperl(pTHX_ CV *cv) 13466 { 13467 dXSARGS; 13468 char *pathified; 13469 STRLEN n_a; 13470 int utf8_fl; 13471 13472 if (items != 1) Perl_croak(aTHX_ "Usage: VMS::Filespec::pathify(spec)"); 13473 utf8_fl = SvUTF8(ST(0)); 13474 pathified = do_pathify_dirspec(SvPV(ST(0),n_a),NULL,1,&utf8_fl); 13475 ST(0) = sv_newmortal(); 13476 if (pathified != NULL) { 13477 sv_usepvn(ST(0),pathified,strlen(pathified)); 13478 if (utf8_fl) { 13479 SvUTF8_on(ST(0)); 13480 } 13481 } 13482 XSRETURN(1); 13483 } 13484 13485 void 13486 vmspath_fromperl(pTHX_ CV *cv) 13487 { 13488 dXSARGS; 13489 char *vmspath; 13490 STRLEN n_a; 13491 int utf8_fl; 13492 13493 if (items != 1) Perl_croak(aTHX_ "Usage: VMS::Filespec::vmspath(spec)"); 13494 utf8_fl = SvUTF8(ST(0)); 13495 vmspath = do_tovmspath(SvPV(ST(0),n_a),NULL,1,&utf8_fl); 13496 ST(0) = sv_newmortal(); 13497 if (vmspath != NULL) { 13498 sv_usepvn(ST(0),vmspath,strlen(vmspath)); 13499 if (utf8_fl) { 13500 SvUTF8_on(ST(0)); 13501 } 13502 } 13503 XSRETURN(1); 13504 } 13505 13506 void 13507 unixpath_fromperl(pTHX_ CV *cv) 13508 { 13509 dXSARGS; 13510 char *unixpath; 13511 STRLEN n_a; 13512 int utf8_fl; 13513 13514 if (items != 1) Perl_croak(aTHX_ "Usage: VMS::Filespec::unixpath(spec)"); 13515 utf8_fl = SvUTF8(ST(0)); 13516 unixpath = do_tounixpath(SvPV(ST(0),n_a),NULL,1,&utf8_fl); 13517 ST(0) = sv_newmortal(); 13518 if (unixpath != NULL) { 13519 sv_usepvn(ST(0),unixpath,strlen(unixpath)); 13520 if (utf8_fl) { 13521 SvUTF8_on(ST(0)); 13522 } 13523 } 13524 XSRETURN(1); 13525 } 13526 13527 void 13528 candelete_fromperl(pTHX_ CV *cv) 13529 { 13530 dXSARGS; 13531 char *fspec, *fsp; 13532 SV *mysv; 13533 IO *io; 13534 STRLEN n_a; 13535 13536 if (items != 1) Perl_croak(aTHX_ "Usage: VMS::Filespec::candelete(spec)"); 13537 13538 mysv = SvROK(ST(0)) ? SvRV(ST(0)) : ST(0); 13539 Newx(fspec, VMS_MAXRSS, char); 13540 if (fspec == NULL) _ckvmssts(SS$_INSFMEM); 13541 if (SvTYPE(mysv) == SVt_PVGV) { 13542 if (!(io = GvIOp(mysv)) || !PerlIO_getname(IoIFP(io),fspec)) { 13543 set_errno(EINVAL); set_vaxc_errno(LIB$_INVARG); 13544 ST(0) = &PL_sv_no; 13545 Safefree(fspec); 13546 XSRETURN(1); 13547 } 13548 fsp = fspec; 13549 } 13550 else { 13551 if (mysv != ST(0) || !(fsp = SvPV(mysv,n_a)) || !*fsp) { 13552 set_errno(EINVAL); set_vaxc_errno(LIB$_INVARG); 13553 ST(0) = &PL_sv_no; 13554 Safefree(fspec); 13555 XSRETURN(1); 13556 } 13557 } 13558 13559 ST(0) = boolSV(cando_by_name(S_IDUSR,0,fsp)); 13560 Safefree(fspec); 13561 XSRETURN(1); 13562 } 13563 13564 void 13565 rmscopy_fromperl(pTHX_ CV *cv) 13566 { 13567 dXSARGS; 13568 char *inspec, *outspec, *inp, *outp; 13569 int date_flag; 13570 struct dsc$descriptor indsc = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0}, 13571 outdsc = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0}; 13572 unsigned long int sts; 13573 SV *mysv; 13574 IO *io; 13575 STRLEN n_a; 13576 13577 if (items < 2 || items > 3) 13578 Perl_croak(aTHX_ "Usage: File::Copy::rmscopy(from,to[,date_flag])"); 13579 13580 mysv = SvROK(ST(0)) ? SvRV(ST(0)) : ST(0); 13581 Newx(inspec, VMS_MAXRSS, char); 13582 if (SvTYPE(mysv) == SVt_PVGV) { 13583 if (!(io = GvIOp(mysv)) || !PerlIO_getname(IoIFP(io),inspec)) { 13584 set_errno(EINVAL); set_vaxc_errno(LIB$_INVARG); 13585 ST(0) = sv_2mortal(newSViv(0)); 13586 Safefree(inspec); 13587 XSRETURN(1); 13588 } 13589 inp = inspec; 13590 } 13591 else { 13592 if (mysv != ST(0) || !(inp = SvPV(mysv,n_a)) || !*inp) { 13593 set_errno(EINVAL); set_vaxc_errno(LIB$_INVARG); 13594 ST(0) = sv_2mortal(newSViv(0)); 13595 Safefree(inspec); 13596 XSRETURN(1); 13597 } 13598 } 13599 mysv = SvROK(ST(1)) ? SvRV(ST(1)) : ST(1); 13600 Newx(outspec, VMS_MAXRSS, char); 13601 if (SvTYPE(mysv) == SVt_PVGV) { 13602 if (!(io = GvIOp(mysv)) || !PerlIO_getname(IoIFP(io),outspec)) { 13603 set_errno(EINVAL); set_vaxc_errno(LIB$_INVARG); 13604 ST(0) = sv_2mortal(newSViv(0)); 13605 Safefree(inspec); 13606 Safefree(outspec); 13607 XSRETURN(1); 13608 } 13609 outp = outspec; 13610 } 13611 else { 13612 if (mysv != ST(1) || !(outp = SvPV(mysv,n_a)) || !*outp) { 13613 set_errno(EINVAL); set_vaxc_errno(LIB$_INVARG); 13614 ST(0) = sv_2mortal(newSViv(0)); 13615 Safefree(inspec); 13616 Safefree(outspec); 13617 XSRETURN(1); 13618 } 13619 } 13620 date_flag = (items == 3) ? SvIV(ST(2)) : 0; 13621 13622 ST(0) = sv_2mortal(newSViv(rmscopy(inp,outp,date_flag))); 13623 Safefree(inspec); 13624 Safefree(outspec); 13625 XSRETURN(1); 13626 } 13627 13628 /* The mod2fname is limited to shorter filenames by design, so it should 13629 * not be modified to support longer EFS pathnames 13630 */ 13631 void 13632 mod2fname(pTHX_ CV *cv) 13633 { 13634 dXSARGS; 13635 char ultimate_name[NAM$C_MAXRSS+1], work_name[NAM$C_MAXRSS*8 + 1], 13636 workbuff[NAM$C_MAXRSS*1 + 1]; 13637 int total_namelen = 3, counter, num_entries; 13638 /* ODS-5 ups this, but we want to be consistent, so... */ 13639 int max_name_len = 39; 13640 AV *in_array = (AV *)SvRV(ST(0)); 13641 13642 num_entries = av_len(in_array); 13643 13644 /* All the names start with PL_. */ 13645 strcpy(ultimate_name, "PL_"); 13646 13647 /* Clean up our working buffer */ 13648 Zero(work_name, sizeof(work_name), char); 13649 13650 /* Run through the entries and build up a working name */ 13651 for(counter = 0; counter <= num_entries; counter++) { 13652 /* If it's not the first name then tack on a __ */ 13653 if (counter) { 13654 strcat(work_name, "__"); 13655 } 13656 strcat(work_name, SvPV_nolen(*av_fetch(in_array, counter, FALSE))); 13657 } 13658 13659 /* Check to see if we actually have to bother...*/ 13660 if (strlen(work_name) + 3 <= max_name_len) { 13661 strcat(ultimate_name, work_name); 13662 } else { 13663 /* It's too darned big, so we need to go strip. We use the same */ 13664 /* algorithm as xsubpp does. First, strip out doubled __ */ 13665 char *source, *dest, last; 13666 dest = workbuff; 13667 last = 0; 13668 for (source = work_name; *source; source++) { 13669 if (last == *source && last == '_') { 13670 continue; 13671 } 13672 *dest++ = *source; 13673 last = *source; 13674 } 13675 /* Go put it back */ 13676 strcpy(work_name, workbuff); 13677 /* Is it still too big? */ 13678 if (strlen(work_name) + 3 > max_name_len) { 13679 /* Strip duplicate letters */ 13680 last = 0; 13681 dest = workbuff; 13682 for (source = work_name; *source; source++) { 13683 if (last == toupper(*source)) { 13684 continue; 13685 } 13686 *dest++ = *source; 13687 last = toupper(*source); 13688 } 13689 strcpy(work_name, workbuff); 13690 } 13691 13692 /* Is it *still* too big? */ 13693 if (strlen(work_name) + 3 > max_name_len) { 13694 /* Too bad, we truncate */ 13695 work_name[max_name_len - 2] = 0; 13696 } 13697 strcat(ultimate_name, work_name); 13698 } 13699 13700 /* Okay, return it */ 13701 ST(0) = sv_2mortal(newSVpv(ultimate_name, 0)); 13702 XSRETURN(1); 13703 } 13704 13705 void 13706 hushexit_fromperl(pTHX_ CV *cv) 13707 { 13708 dXSARGS; 13709 13710 if (items > 0) { 13711 VMSISH_HUSHED = SvTRUE(ST(0)); 13712 } 13713 ST(0) = boolSV(VMSISH_HUSHED); 13714 XSRETURN(1); 13715 } 13716 13717 13718 PerlIO * 13719 Perl_vms_start_glob 13720 (pTHX_ SV *tmpglob, 13721 IO *io) 13722 { 13723 PerlIO *fp; 13724 struct vs_str_st *rslt; 13725 char *vmsspec; 13726 char *rstr; 13727 char *begin, *cp; 13728 $DESCRIPTOR(dfltdsc,"SYS$DISK:[]*.*;"); 13729 PerlIO *tmpfp; 13730 STRLEN i; 13731 struct dsc$descriptor_s wilddsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0}; 13732 struct dsc$descriptor_vs rsdsc; 13733 unsigned long int cxt = 0, sts = 0, ok = 1, hasdir = 0; 13734 unsigned long hasver = 0, isunix = 0; 13735 unsigned long int lff_flags = 0; 13736 int rms_sts; 13737 int vms_old_glob = 1; 13738 13739 if (!SvOK(tmpglob)) { 13740 SETERRNO(ENOENT,RMS$_FNF); 13741 return NULL; 13742 } 13743 13744 vms_old_glob = !decc_filename_unix_report; 13745 13746 #ifdef VMS_LONGNAME_SUPPORT 13747 lff_flags = LIB$M_FIL_LONG_NAMES; 13748 #endif 13749 /* The Newx macro will not allow me to assign a smaller array 13750 * to the rslt pointer, so we will assign it to the begin char pointer 13751 * and then copy the value into the rslt pointer. 13752 */ 13753 Newx(begin, VMS_MAXRSS + sizeof(unsigned short int), char); 13754 rslt = (struct vs_str_st *)begin; 13755 rslt->length = 0; 13756 rstr = &rslt->str[0]; 13757 rsdsc.dsc$a_pointer = (char *) rslt; /* cast required */ 13758 rsdsc.dsc$w_maxstrlen = VMS_MAXRSS + sizeof(unsigned short int); 13759 rsdsc.dsc$b_dtype = DSC$K_DTYPE_VT; 13760 rsdsc.dsc$b_class = DSC$K_CLASS_VS; 13761 13762 Newx(vmsspec, VMS_MAXRSS, char); 13763 13764 /* We could find out if there's an explicit dev/dir or version 13765 by peeking into lib$find_file's internal context at 13766 ((struct NAM *)((struct FAB *)cxt)->fab$l_nam)->nam$l_fnb 13767 but that's unsupported, so I don't want to do it now and 13768 have it bite someone in the future. */ 13769 /* Fix-me: vms_split_path() is the only way to do this, the 13770 existing method will fail with many legal EFS or UNIX specifications 13771 */ 13772 13773 cp = SvPV(tmpglob,i); 13774 13775 for (; i; i--) { 13776 if (cp[i] == ';') hasver = 1; 13777 if (cp[i] == '.') { 13778 if (sts) hasver = 1; 13779 else sts = 1; 13780 } 13781 if (cp[i] == '/') { 13782 hasdir = isunix = 1; 13783 break; 13784 } 13785 if (cp[i] == ']' || cp[i] == '>' || cp[i] == ':') { 13786 hasdir = 1; 13787 break; 13788 } 13789 } 13790 13791 /* In UNIX report mode, assume UNIX unless VMS directory delimiters seen */ 13792 if ((hasdir == 0) && decc_filename_unix_report) { 13793 isunix = 1; 13794 } 13795 13796 if ((tmpfp = PerlIO_tmpfile()) != NULL) { 13797 char * wv_spec, * wr_spec, * wd_spec, * wn_spec, * we_spec, * wvs_spec; 13798 int wv_sts, wv_len, wr_len, wd_len, wn_len, we_len, wvs_len; 13799 int wildstar = 0; 13800 int wildquery = 0; 13801 int found = 0; 13802 Stat_t st; 13803 int stat_sts; 13804 stat_sts = PerlLIO_stat(SvPVX_const(tmpglob),&st); 13805 if (!stat_sts && S_ISDIR(st.st_mode)) { 13806 char * vms_dir; 13807 const char * fname; 13808 STRLEN fname_len; 13809 13810 /* Test to see if SvPVX_const(tmpglob) ends with a VMS */ 13811 /* path delimiter of ':>]', if so, then the old behavior has */ 13812 /* obviously been specificially requested */ 13813 13814 fname = SvPVX_const(tmpglob); 13815 fname_len = strlen(fname); 13816 vms_dir = strpbrk(&fname[fname_len - 1], ":>]"); 13817 if (vms_old_glob || (vms_dir != NULL)) { 13818 wilddsc.dsc$a_pointer = tovmspath_utf8( 13819 SvPVX(tmpglob),vmsspec,NULL); 13820 ok = (wilddsc.dsc$a_pointer != NULL); 13821 /* maybe passed 'foo' rather than '[.foo]', thus not 13822 detected above */ 13823 hasdir = 1; 13824 } else { 13825 /* Operate just on the directory, the special stat/fstat for */ 13826 /* leaves the fileified specification in the st_devnam */ 13827 /* member. */ 13828 wilddsc.dsc$a_pointer = st.st_devnam; 13829 ok = 1; 13830 } 13831 } 13832 else { 13833 wilddsc.dsc$a_pointer = tovmsspec_utf8(SvPVX(tmpglob),vmsspec,NULL); 13834 ok = (wilddsc.dsc$a_pointer != NULL); 13835 } 13836 if (ok) 13837 wilddsc.dsc$w_length = strlen(wilddsc.dsc$a_pointer); 13838 13839 /* If not extended character set, replace ? with % */ 13840 /* With extended character set, ? is a wildcard single character */ 13841 for (cp=wilddsc.dsc$a_pointer; ok && cp && *cp; cp++) { 13842 if (*cp == '?') { 13843 wildquery = 1; 13844 if (!decc_efs_case_preserve) 13845 *cp = '%'; 13846 } else if (*cp == '%') { 13847 wildquery = 1; 13848 } else if (*cp == '*') { 13849 wildstar = 1; 13850 } 13851 } 13852 13853 if (ok) { 13854 wv_sts = vms_split_path( 13855 wilddsc.dsc$a_pointer, &wv_spec, &wv_len, &wr_spec, &wr_len, 13856 &wd_spec, &wd_len, &wn_spec, &wn_len, &we_spec, &we_len, 13857 &wvs_spec, &wvs_len); 13858 } else { 13859 wn_spec = NULL; 13860 wn_len = 0; 13861 we_spec = NULL; 13862 we_len = 0; 13863 } 13864 13865 sts = SS$_NORMAL; 13866 while (ok && $VMS_STATUS_SUCCESS(sts)) { 13867 char * v_spec, * r_spec, * d_spec, * n_spec, * e_spec, * vs_spec; 13868 int v_sts, v_len, r_len, d_len, n_len, e_len, vs_len; 13869 int valid_find; 13870 13871 valid_find = 0; 13872 sts = lib$find_file(&wilddsc,&rsdsc,&cxt, 13873 &dfltdsc,NULL,&rms_sts,&lff_flags); 13874 if (!$VMS_STATUS_SUCCESS(sts)) 13875 break; 13876 13877 /* with varying string, 1st word of buffer contains result length */ 13878 rstr[rslt->length] = '\0'; 13879 13880 /* Find where all the components are */ 13881 v_sts = vms_split_path 13882 (rstr, 13883 &v_spec, 13884 &v_len, 13885 &r_spec, 13886 &r_len, 13887 &d_spec, 13888 &d_len, 13889 &n_spec, 13890 &n_len, 13891 &e_spec, 13892 &e_len, 13893 &vs_spec, 13894 &vs_len); 13895 13896 /* If no version on input, truncate the version on output */ 13897 if (!hasver && (vs_len > 0)) { 13898 *vs_spec = '\0'; 13899 vs_len = 0; 13900 } 13901 13902 if (isunix) { 13903 13904 /* In Unix report mode, remove the ".dir;1" from the name */ 13905 /* if it is a real directory */ 13906 if (decc_filename_unix_report || decc_efs_charset) { 13907 if (is_dir_ext(e_spec, e_len, vs_spec, vs_len)) { 13908 Stat_t statbuf; 13909 int ret_sts; 13910 13911 ret_sts = flex_lstat(rstr, &statbuf); 13912 if ((ret_sts == 0) && 13913 S_ISDIR(statbuf.st_mode)) { 13914 e_len = 0; 13915 e_spec[0] = 0; 13916 } 13917 } 13918 } 13919 13920 /* No version & a null extension on UNIX handling */ 13921 if ((e_len == 1) && decc_readdir_dropdotnotype) { 13922 e_len = 0; 13923 *e_spec = '\0'; 13924 } 13925 } 13926 13927 if (!decc_efs_case_preserve) { 13928 for (cp = rstr; *cp; cp++) *cp = _tolower(*cp); 13929 } 13930 13931 /* Find File treats a Null extension as return all extensions */ 13932 /* This is contrary to Perl expectations */ 13933 13934 if (wildstar || wildquery || vms_old_glob) { 13935 /* really need to see if the returned file name matched */ 13936 /* but for now will assume that it matches */ 13937 valid_find = 1; 13938 } else { 13939 /* Exact Match requested */ 13940 /* How are directories handled? - like a file */ 13941 if ((e_len == we_len) && (n_len == wn_len)) { 13942 int t1; 13943 t1 = e_len; 13944 if (t1 > 0) 13945 t1 = strncmp(e_spec, we_spec, e_len); 13946 if (t1 == 0) { 13947 t1 = n_len; 13948 if (t1 > 0) 13949 t1 = strncmp(n_spec, we_spec, n_len); 13950 if (t1 == 0) 13951 valid_find = 1; 13952 } 13953 } 13954 } 13955 13956 if (valid_find) { 13957 found++; 13958 13959 if (hasdir) { 13960 if (isunix) trim_unixpath(rstr,SvPVX(tmpglob),1); 13961 begin = rstr; 13962 } 13963 else { 13964 /* Start with the name */ 13965 begin = n_spec; 13966 } 13967 strcat(begin,"\n"); 13968 ok = (PerlIO_puts(tmpfp,begin) != EOF); 13969 } 13970 } 13971 if (cxt) (void)lib$find_file_end(&cxt); 13972 13973 if (!found) { 13974 /* Be POSIXish: return the input pattern when no matches */ 13975 strcpy(rstr,SvPVX(tmpglob)); 13976 strcat(rstr,"\n"); 13977 ok = (PerlIO_puts(tmpfp,rstr) != EOF); 13978 } 13979 13980 if (ok && sts != RMS$_NMF && 13981 sts != RMS$_DNF && sts != RMS_FNF) ok = 0; 13982 if (!ok) { 13983 if (!(sts & 1)) { 13984 SETERRNO((sts == RMS$_SYN ? EINVAL : EVMSERR),sts); 13985 } 13986 PerlIO_close(tmpfp); 13987 fp = NULL; 13988 } 13989 else { 13990 PerlIO_rewind(tmpfp); 13991 IoTYPE(io) = IoTYPE_RDONLY; 13992 IoIFP(io) = fp = tmpfp; 13993 IoFLAGS(io) &= ~IOf_UNTAINT; /* maybe redundant */ 13994 } 13995 } 13996 Safefree(vmsspec); 13997 Safefree(rslt); 13998 return fp; 13999 } 14000 14001 14002 static char * 14003 mp_do_vms_realpath(pTHX_ const char *filespec, char * rslt_spec, 14004 int *utf8_fl); 14005 14006 void 14007 unixrealpath_fromperl(pTHX_ CV *cv) 14008 { 14009 dXSARGS; 14010 char *fspec, *rslt_spec, *rslt; 14011 STRLEN n_a; 14012 14013 if (!items || items != 1) 14014 Perl_croak(aTHX_ "Usage: VMS::Filespec::unixrealpath(spec)"); 14015 14016 fspec = SvPV(ST(0),n_a); 14017 if (!fspec || !*fspec) XSRETURN_UNDEF; 14018 14019 Newx(rslt_spec, VMS_MAXRSS + 1, char); 14020 rslt = do_vms_realpath(fspec, rslt_spec, NULL); 14021 14022 ST(0) = sv_newmortal(); 14023 if (rslt != NULL) 14024 sv_usepvn(ST(0),rslt,strlen(rslt)); 14025 else 14026 Safefree(rslt_spec); 14027 XSRETURN(1); 14028 } 14029 14030 static char * 14031 mp_do_vms_realname(pTHX_ const char *filespec, char * rslt_spec, 14032 int *utf8_fl); 14033 14034 void 14035 vmsrealpath_fromperl(pTHX_ CV *cv) 14036 { 14037 dXSARGS; 14038 char *fspec, *rslt_spec, *rslt; 14039 STRLEN n_a; 14040 14041 if (!items || items != 1) 14042 Perl_croak(aTHX_ "Usage: VMS::Filespec::vmsrealpath(spec)"); 14043 14044 fspec = SvPV(ST(0),n_a); 14045 if (!fspec || !*fspec) XSRETURN_UNDEF; 14046 14047 Newx(rslt_spec, VMS_MAXRSS + 1, char); 14048 rslt = do_vms_realname(fspec, rslt_spec, NULL); 14049 14050 ST(0) = sv_newmortal(); 14051 if (rslt != NULL) 14052 sv_usepvn(ST(0),rslt,strlen(rslt)); 14053 else 14054 Safefree(rslt_spec); 14055 XSRETURN(1); 14056 } 14057 14058 #ifdef HAS_SYMLINK 14059 /* 14060 * A thin wrapper around decc$symlink to make sure we follow the 14061 * standard and do not create a symlink with a zero-length name. 14062 * 14063 * Also in ODS-2 mode, existing tests assume that the link target 14064 * will be converted to UNIX format. 14065 */ 14066 /*{{{ int my_symlink(pTHX_ const char *contents, const char *link_name)*/ 14067 int Perl_my_symlink(pTHX_ const char *contents, const char *link_name) { 14068 if (!link_name || !*link_name) { 14069 SETERRNO(ENOENT, SS$_NOSUCHFILE); 14070 return -1; 14071 } 14072 14073 if (decc_efs_charset) { 14074 return symlink(contents, link_name); 14075 } else { 14076 int sts; 14077 char * utarget; 14078 14079 /* Unless we are in ODS-5 mode, convert the symlink target to UNIX */ 14080 /* because in order to work, the symlink target must be in UNIX format */ 14081 14082 /* As symbolic links can hold things other than files, we will only do */ 14083 /* the conversion in in ODS-2 mode */ 14084 14085 utarget = PerlMem_malloc(VMS_MAXRSS + 1); 14086 if (int_tounixspec(contents, utarget, NULL) == NULL) { 14087 14088 /* This should not fail, as an untranslatable filename */ 14089 /* should be passed through */ 14090 utarget = (char *)contents; 14091 } 14092 sts = symlink(utarget, link_name); 14093 PerlMem_free(utarget); 14094 return sts; 14095 } 14096 14097 } 14098 /*}}}*/ 14099 14100 #endif /* HAS_SYMLINK */ 14101 14102 int do_vms_case_tolerant(void); 14103 14104 void 14105 case_tolerant_process_fromperl(pTHX_ CV *cv) 14106 { 14107 dXSARGS; 14108 ST(0) = boolSV(do_vms_case_tolerant()); 14109 XSRETURN(1); 14110 } 14111 14112 #ifdef USE_ITHREADS 14113 14114 void 14115 Perl_sys_intern_dup(pTHX_ struct interp_intern *src, 14116 struct interp_intern *dst) 14117 { 14118 PERL_ARGS_ASSERT_SYS_INTERN_DUP; 14119 14120 memcpy(dst,src,sizeof(struct interp_intern)); 14121 } 14122 14123 #endif 14124 14125 void 14126 Perl_sys_intern_clear(pTHX) 14127 { 14128 } 14129 14130 void 14131 Perl_sys_intern_init(pTHX) 14132 { 14133 unsigned int ix = RAND_MAX; 14134 double x; 14135 14136 VMSISH_HUSHED = 0; 14137 14138 MY_POSIX_EXIT = vms_posix_exit; 14139 14140 x = (float)ix; 14141 MY_INV_RAND_MAX = 1./x; 14142 } 14143 14144 void 14145 init_os_extras(void) 14146 { 14147 dTHX; 14148 char* file = __FILE__; 14149 if (decc_disable_to_vms_logname_translation) { 14150 no_translate_barewords = TRUE; 14151 } else { 14152 no_translate_barewords = FALSE; 14153 } 14154 14155 newXSproto("VMS::Filespec::rmsexpand",rmsexpand_fromperl,file,"$;$"); 14156 newXSproto("VMS::Filespec::vmsify",vmsify_fromperl,file,"$"); 14157 newXSproto("VMS::Filespec::unixify",unixify_fromperl,file,"$"); 14158 newXSproto("VMS::Filespec::pathify",pathify_fromperl,file,"$"); 14159 newXSproto("VMS::Filespec::fileify",fileify_fromperl,file,"$"); 14160 newXSproto("VMS::Filespec::vmspath",vmspath_fromperl,file,"$"); 14161 newXSproto("VMS::Filespec::unixpath",unixpath_fromperl,file,"$"); 14162 newXSproto("VMS::Filespec::candelete",candelete_fromperl,file,"$"); 14163 newXSproto("DynaLoader::mod2fname", mod2fname, file, "$"); 14164 newXS("File::Copy::rmscopy",rmscopy_fromperl,file); 14165 newXSproto("vmsish::hushed",hushexit_fromperl,file,";$"); 14166 newXSproto("VMS::Filespec::unixrealpath",unixrealpath_fromperl,file,"$;$"); 14167 newXSproto("VMS::Filespec::vmsrealpath",vmsrealpath_fromperl,file,"$;$"); 14168 newXSproto("VMS::Filespec::case_tolerant_process", 14169 case_tolerant_process_fromperl,file,""); 14170 14171 store_pipelocs(aTHX); /* will redo any earlier attempts */ 14172 14173 return; 14174 } 14175 14176 #if __CRTL_VER == 80200000 14177 /* This missed getting in to the DECC SDK for 8.2 */ 14178 char *realpath(const char *file_name, char * resolved_name, ...); 14179 #endif 14180 14181 /*{{{char *do_vms_realpath(const char *file_name, char *resolved_name)*/ 14182 /* wrapper for the realpath() function added with 8.2 RMS SYMLINK SDK. 14183 * The perl fallback routine to provide realpath() is not as efficient 14184 * on OpenVMS. 14185 */ 14186 14187 /* Hack, use old stat() as fastest way of getting ino_t and device */ 14188 int decc$stat(const char *name, void * statbuf); 14189 #if !defined(__VAX) && __CRTL_VER >= 80200000 14190 int decc$lstat(const char *name, void * statbuf); 14191 #else 14192 #define decc$lstat decc$stat 14193 #endif 14194 14195 14196 /* Realpath is fragile. In 8.3 it does not work if the feature 14197 * DECC$POSIX_COMPLIANT_PATHNAMES is not enabled, even though symbolic 14198 * links are implemented in RMS, not the CRTL. It also can fail if the 14199 * user does not have read/execute access to some of the directories. 14200 * So in order for Do What I Mean mode to work, if realpath() fails, 14201 * fall back to looking up the filename by the device name and FID. 14202 */ 14203 14204 int vms_fid_to_name(char * outname, int outlen, 14205 const char * name, int lstat_flag, mode_t * mode) 14206 { 14207 #pragma message save 14208 #pragma message disable MISALGNDSTRCT 14209 #pragma message disable MISALGNDMEM 14210 #pragma member_alignment save 14211 #pragma nomember_alignment 14212 struct statbuf_t { 14213 char * st_dev; 14214 unsigned short st_ino[3]; 14215 unsigned short old_st_mode; 14216 unsigned long padl[30]; /* plenty of room */ 14217 } statbuf; 14218 #pragma message restore 14219 #pragma member_alignment restore 14220 14221 int sts; 14222 struct dsc$descriptor_s dvidsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0}; 14223 struct dsc$descriptor_s specdsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0}; 14224 char *fileified; 14225 char *temp_fspec; 14226 char *ret_spec; 14227 14228 /* Need to follow the mostly the same rules as flex_stat_int, or we may get 14229 * unexpected answers 14230 */ 14231 14232 fileified = PerlMem_malloc(VMS_MAXRSS); 14233 if (fileified == NULL) 14234 _ckvmssts_noperl(SS$_INSFMEM); 14235 14236 temp_fspec = PerlMem_malloc(VMS_MAXRSS); 14237 if (temp_fspec == NULL) 14238 _ckvmssts_noperl(SS$_INSFMEM); 14239 14240 sts = -1; 14241 /* First need to try as a directory */ 14242 ret_spec = int_tovmspath(name, temp_fspec, NULL); 14243 if (ret_spec != NULL) { 14244 ret_spec = int_fileify_dirspec(temp_fspec, fileified, NULL); 14245 if (ret_spec != NULL) { 14246 if (lstat_flag == 0) 14247 sts = decc$stat(fileified, &statbuf); 14248 else 14249 sts = decc$lstat(fileified, &statbuf); 14250 } 14251 } 14252 14253 /* Then as a VMS file spec */ 14254 if (sts != 0) { 14255 ret_spec = int_tovmsspec(name, temp_fspec, 0, NULL); 14256 if (ret_spec != NULL) { 14257 if (lstat_flag == 0) { 14258 sts = decc$stat(temp_fspec, &statbuf); 14259 } else { 14260 sts = decc$lstat(temp_fspec, &statbuf); 14261 } 14262 } 14263 } 14264 14265 if (sts) { 14266 /* Next try - allow multiple dots with out EFS CHARSET */ 14267 /* The CRTL stat() falls down hard on multi-dot filenames in unix 14268 * format unless * DECC$EFS_CHARSET is in effect, so temporarily 14269 * enable it if it isn't already. 14270 */ 14271 #if __CRTL_VER >= 70300000 && !defined(__VAX) 14272 if (!decc_efs_charset && (decc_efs_charset_index > 0)) 14273 decc$feature_set_value(decc_efs_charset_index, 1, 1); 14274 #endif 14275 ret_spec = int_tovmspath(name, temp_fspec, NULL); 14276 if (lstat_flag == 0) { 14277 sts = decc$stat(name, &statbuf); 14278 } else { 14279 sts = decc$lstat(name, &statbuf); 14280 } 14281 #if __CRTL_VER >= 70300000 && !defined(__VAX) 14282 if (!decc_efs_charset && (decc_efs_charset_index > 0)) 14283 decc$feature_set_value(decc_efs_charset_index, 1, 0); 14284 #endif 14285 } 14286 14287 14288 /* and then because the Perl Unix to VMS conversion is not perfect */ 14289 /* Specifically the CRTL removes spaces and possibly other illegal ODS-2 */ 14290 /* characters from filenames so we need to try it as-is */ 14291 if (sts) { 14292 if (lstat_flag == 0) { 14293 sts = decc$stat(name, &statbuf); 14294 } else { 14295 sts = decc$lstat(name, &statbuf); 14296 } 14297 } 14298 14299 if (sts == 0) { 14300 int vms_sts; 14301 14302 dvidsc.dsc$a_pointer=statbuf.st_dev; 14303 dvidsc.dsc$w_length=strlen(statbuf.st_dev); 14304 14305 specdsc.dsc$a_pointer = outname; 14306 specdsc.dsc$w_length = outlen-1; 14307 14308 vms_sts = lib$fid_to_name 14309 (&dvidsc, statbuf.st_ino, &specdsc, &specdsc.dsc$w_length); 14310 if ($VMS_STATUS_SUCCESS(vms_sts)) { 14311 outname[specdsc.dsc$w_length] = 0; 14312 14313 /* Return the mode */ 14314 if (mode) { 14315 *mode = statbuf.old_st_mode; 14316 } 14317 } 14318 } 14319 PerlMem_free(temp_fspec); 14320 PerlMem_free(fileified); 14321 return sts; 14322 } 14323 14324 14325 14326 static char * 14327 mp_do_vms_realpath(pTHX_ const char *filespec, char *outbuf, 14328 int *utf8_fl) 14329 { 14330 char * rslt = NULL; 14331 14332 #ifdef HAS_SYMLINK 14333 if (decc_posix_compliant_pathnames > 0 ) { 14334 /* realpath currently only works if posix compliant pathnames are 14335 * enabled. It may start working when they are not, but in that 14336 * case we still want the fallback behavior for backwards compatibility 14337 */ 14338 rslt = realpath(filespec, outbuf); 14339 } 14340 #endif 14341 14342 if (rslt == NULL) { 14343 char * vms_spec; 14344 char * v_spec, * r_spec, * d_spec, * n_spec, * e_spec, * vs_spec; 14345 int sts, v_len, r_len, d_len, n_len, e_len, vs_len; 14346 int file_len; 14347 mode_t my_mode; 14348 14349 /* Fall back to fid_to_name */ 14350 14351 Newx(vms_spec, VMS_MAXRSS + 1, char); 14352 14353 sts = vms_fid_to_name(vms_spec, VMS_MAXRSS + 1, filespec, 0, &my_mode); 14354 if (sts == 0) { 14355 14356 14357 /* Now need to trim the version off */ 14358 sts = vms_split_path 14359 (vms_spec, 14360 &v_spec, 14361 &v_len, 14362 &r_spec, 14363 &r_len, 14364 &d_spec, 14365 &d_len, 14366 &n_spec, 14367 &n_len, 14368 &e_spec, 14369 &e_len, 14370 &vs_spec, 14371 &vs_len); 14372 14373 14374 if (sts == 0) { 14375 int haslower = 0; 14376 const char *cp; 14377 14378 /* Trim off the version */ 14379 int file_len = v_len + r_len + d_len + n_len + e_len; 14380 vms_spec[file_len] = 0; 14381 14382 /* Trim off the .DIR if this is a directory */ 14383 if (is_dir_ext(e_spec, e_len, vs_spec, vs_len)) { 14384 if (S_ISDIR(my_mode)) { 14385 e_len = 0; 14386 e_spec[0] = 0; 14387 } 14388 } 14389 14390 /* Drop NULL extensions on UNIX file specification */ 14391 if ((e_len == 1) && decc_readdir_dropdotnotype) { 14392 e_len = 0; 14393 e_spec[0] = '\0'; 14394 } 14395 14396 /* The result is expected to be in UNIX format */ 14397 rslt = int_tounixspec(vms_spec, outbuf, utf8_fl); 14398 14399 /* Downcase if input had any lower case letters and 14400 * case preservation is not in effect. 14401 */ 14402 if (!decc_efs_case_preserve) { 14403 for (cp = filespec; *cp; cp++) 14404 if (islower(*cp)) { haslower = 1; break; } 14405 14406 if (haslower) __mystrtolower(rslt); 14407 } 14408 } 14409 } else { 14410 14411 /* Now for some hacks to deal with backwards and forward */ 14412 /* compatibilty */ 14413 if (!decc_efs_charset) { 14414 14415 /* 1. ODS-2 mode wants to do a syntax only translation */ 14416 rslt = int_rmsexpand(filespec, outbuf, 14417 NULL, 0, NULL, utf8_fl); 14418 14419 } else { 14420 if (decc_filename_unix_report) { 14421 char * dir_name; 14422 char * vms_dir_name; 14423 char * file_name; 14424 14425 /* 2. ODS-5 / UNIX report mode should return a failure */ 14426 /* if the parent directory also does not exist */ 14427 /* Otherwise, get the real path for the parent */ 14428 /* and add the child to it. 14429 14430 /* basename / dirname only available for VMS 7.0+ */ 14431 /* So we may need to implement them as common routines */ 14432 14433 Newx(dir_name, VMS_MAXRSS + 1, char); 14434 Newx(vms_dir_name, VMS_MAXRSS + 1, char); 14435 dir_name[0] = '\0'; 14436 file_name = NULL; 14437 14438 /* First try a VMS parse */ 14439 sts = vms_split_path 14440 (filespec, 14441 &v_spec, 14442 &v_len, 14443 &r_spec, 14444 &r_len, 14445 &d_spec, 14446 &d_len, 14447 &n_spec, 14448 &n_len, 14449 &e_spec, 14450 &e_len, 14451 &vs_spec, 14452 &vs_len); 14453 14454 if (sts == 0) { 14455 /* This is VMS */ 14456 14457 int dir_len = v_len + r_len + d_len + n_len; 14458 if (dir_len > 0) { 14459 strncpy(dir_name, filespec, dir_len); 14460 dir_name[dir_len] = '\0'; 14461 file_name = (char *)&filespec[dir_len + 1]; 14462 } 14463 } else { 14464 /* This must be UNIX */ 14465 char * tchar; 14466 14467 tchar = strrchr(filespec, '/'); 14468 14469 if (tchar != NULL) { 14470 int dir_len = tchar - filespec; 14471 strncpy(dir_name, filespec, dir_len); 14472 dir_name[dir_len] = '\0'; 14473 file_name = (char *) &filespec[dir_len + 1]; 14474 } 14475 } 14476 14477 /* Dir name is defaulted */ 14478 if (dir_name[0] == 0) { 14479 dir_name[0] = '.'; 14480 dir_name[1] = '\0'; 14481 } 14482 14483 /* Need realpath for the directory */ 14484 sts = vms_fid_to_name(vms_dir_name, 14485 VMS_MAXRSS + 1, 14486 dir_name, 0, NULL); 14487 14488 if (sts == 0) { 14489 /* Now need to pathify it. 14490 char *tdir = int_pathify_dirspec(vms_dir_name, 14491 outbuf); 14492 14493 /* And now add the original filespec to it */ 14494 if (file_name != NULL) { 14495 strcat(outbuf, file_name); 14496 } 14497 return outbuf; 14498 } 14499 Safefree(vms_dir_name); 14500 Safefree(dir_name); 14501 } 14502 } 14503 } 14504 Safefree(vms_spec); 14505 } 14506 return rslt; 14507 } 14508 14509 static char * 14510 mp_do_vms_realname(pTHX_ const char *filespec, char *outbuf, 14511 int *utf8_fl) 14512 { 14513 char * v_spec, * r_spec, * d_spec, * n_spec, * e_spec, * vs_spec; 14514 int sts, v_len, r_len, d_len, n_len, e_len, vs_len; 14515 int file_len; 14516 14517 /* Fall back to fid_to_name */ 14518 14519 sts = vms_fid_to_name(outbuf, VMS_MAXRSS + 1, filespec, 0, NULL); 14520 if (sts != 0) { 14521 return NULL; 14522 } 14523 else { 14524 14525 14526 /* Now need to trim the version off */ 14527 sts = vms_split_path 14528 (outbuf, 14529 &v_spec, 14530 &v_len, 14531 &r_spec, 14532 &r_len, 14533 &d_spec, 14534 &d_len, 14535 &n_spec, 14536 &n_len, 14537 &e_spec, 14538 &e_len, 14539 &vs_spec, 14540 &vs_len); 14541 14542 14543 if (sts == 0) { 14544 int haslower = 0; 14545 const char *cp; 14546 14547 /* Trim off the version */ 14548 int file_len = v_len + r_len + d_len + n_len + e_len; 14549 outbuf[file_len] = 0; 14550 14551 /* Downcase if input had any lower case letters and 14552 * case preservation is not in effect. 14553 */ 14554 if (!decc_efs_case_preserve) { 14555 for (cp = filespec; *cp; cp++) 14556 if (islower(*cp)) { haslower = 1; break; } 14557 14558 if (haslower) __mystrtolower(outbuf); 14559 } 14560 } 14561 } 14562 return outbuf; 14563 } 14564 14565 14566 /*}}}*/ 14567 /* External entry points */ 14568 char *Perl_vms_realpath(pTHX_ const char *filespec, char *outbuf, int *utf8_fl) 14569 { return do_vms_realpath(filespec, outbuf, utf8_fl); } 14570 14571 char *Perl_vms_realname(pTHX_ const char *filespec, char *outbuf, int *utf8_fl) 14572 { return do_vms_realname(filespec, outbuf, utf8_fl); } 14573 14574 /* case_tolerant */ 14575 14576 /*{{{int do_vms_case_tolerant(void)*/ 14577 /* OpenVMS provides a case sensitive implementation of ODS-5 and this is 14578 * controlled by a process setting. 14579 */ 14580 int do_vms_case_tolerant(void) 14581 { 14582 return vms_process_case_tolerant; 14583 } 14584 /*}}}*/ 14585 /* External entry points */ 14586 #if __CRTL_VER >= 70301000 && !defined(__VAX) 14587 int Perl_vms_case_tolerant(void) 14588 { return do_vms_case_tolerant(); } 14589 #else 14590 int Perl_vms_case_tolerant(void) 14591 { return vms_process_case_tolerant; } 14592 #endif 14593 14594 14595 /* Start of DECC RTL Feature handling */ 14596 14597 static int sys_trnlnm 14598 (const char * logname, 14599 char * value, 14600 int value_len) 14601 { 14602 const $DESCRIPTOR(table_dsc, "LNM$FILE_DEV"); 14603 const unsigned long attr = LNM$M_CASE_BLIND; 14604 struct dsc$descriptor_s name_dsc; 14605 int status; 14606 unsigned short result; 14607 struct itmlst_3 itlst[2] = {{value_len, LNM$_STRING, value, &result}, 14608 {0, 0, 0, 0}}; 14609 14610 name_dsc.dsc$w_length = strlen(logname); 14611 name_dsc.dsc$a_pointer = (char *)logname; 14612 name_dsc.dsc$b_dtype = DSC$K_DTYPE_T; 14613 name_dsc.dsc$b_class = DSC$K_CLASS_S; 14614 14615 status = sys$trnlnm(&attr, &table_dsc, &name_dsc, 0, itlst); 14616 14617 if ($VMS_STATUS_SUCCESS(status)) { 14618 14619 /* Null terminate and return the string */ 14620 /*--------------------------------------*/ 14621 value[result] = 0; 14622 } 14623 14624 return status; 14625 } 14626 14627 static int sys_crelnm 14628 (const char * logname, 14629 const char * value) 14630 { 14631 int ret_val; 14632 const char * proc_table = "LNM$PROCESS_TABLE"; 14633 struct dsc$descriptor_s proc_table_dsc; 14634 struct dsc$descriptor_s logname_dsc; 14635 struct itmlst_3 item_list[2]; 14636 14637 proc_table_dsc.dsc$a_pointer = (char *) proc_table; 14638 proc_table_dsc.dsc$w_length = strlen(proc_table); 14639 proc_table_dsc.dsc$b_dtype = DSC$K_DTYPE_T; 14640 proc_table_dsc.dsc$b_class = DSC$K_CLASS_S; 14641 14642 logname_dsc.dsc$a_pointer = (char *) logname; 14643 logname_dsc.dsc$w_length = strlen(logname); 14644 logname_dsc.dsc$b_dtype = DSC$K_DTYPE_T; 14645 logname_dsc.dsc$b_class = DSC$K_CLASS_S; 14646 14647 item_list[0].buflen = strlen(value); 14648 item_list[0].itmcode = LNM$_STRING; 14649 item_list[0].bufadr = (char *)value; 14650 item_list[0].retlen = NULL; 14651 14652 item_list[1].buflen = 0; 14653 item_list[1].itmcode = 0; 14654 14655 ret_val = sys$crelnm 14656 (NULL, 14657 (const struct dsc$descriptor_s *)&proc_table_dsc, 14658 (const struct dsc$descriptor_s *)&logname_dsc, 14659 NULL, 14660 (const struct item_list_3 *) item_list); 14661 14662 return ret_val; 14663 } 14664 14665 /* C RTL Feature settings */ 14666 14667 static int set_features 14668 (int (* init_coroutine)(int *, int *, void *), /* Needs casts if used */ 14669 int (* cli_routine)(void), /* Not documented */ 14670 void *image_info) /* Not documented */ 14671 { 14672 int status; 14673 int s; 14674 char* str; 14675 char val_str[10]; 14676 #if defined(JPI$_CASE_LOOKUP_PERM) && !defined(__VAX) 14677 const unsigned long int jpicode1 = JPI$_CASE_LOOKUP_PERM; 14678 const unsigned long int jpicode2 = JPI$_CASE_LOOKUP_IMAGE; 14679 unsigned long case_perm; 14680 unsigned long case_image; 14681 #endif 14682 14683 /* Allow an exception to bring Perl into the VMS debugger */ 14684 vms_debug_on_exception = 0; 14685 status = sys_trnlnm("PERL_VMS_EXCEPTION_DEBUG", val_str, sizeof(val_str)); 14686 if ($VMS_STATUS_SUCCESS(status)) { 14687 val_str[0] = _toupper(val_str[0]); 14688 if ((val_str[0] == 'E') || (val_str[0] == '1') || (val_str[0] == 'T')) 14689 vms_debug_on_exception = 1; 14690 else 14691 vms_debug_on_exception = 0; 14692 } 14693 14694 /* Debug unix/vms file translation routines */ 14695 vms_debug_fileify = 0; 14696 status = sys_trnlnm("PERL_VMS_FILEIFY_DEBUG", val_str, sizeof(val_str)); 14697 if ($VMS_STATUS_SUCCESS(status)) { 14698 val_str[0] = _toupper(val_str[0]); 14699 if ((val_str[0] == 'E') || (val_str[0] == '1') || (val_str[0] == 'T')) 14700 vms_debug_fileify = 1; 14701 else 14702 vms_debug_fileify = 0; 14703 } 14704 14705 14706 /* Historically PERL has been doing vmsify / stat differently than */ 14707 /* the CRTL. In particular, under some conditions the CRTL will */ 14708 /* remove some illegal characters like spaces from filenames */ 14709 /* resulting in some differences. The stat()/lstat() wrapper has */ 14710 /* been reporting such file names as invalid and fails to stat them */ 14711 /* fixing this bug so that stat()/lstat() accept these like the */ 14712 /* CRTL does will result in several tests failing. */ 14713 /* This should really be fixed, but for now, set up a feature to */ 14714 /* enable it so that the impact can be studied. */ 14715 vms_bug_stat_filename = 0; 14716 status = sys_trnlnm("PERL_VMS_BUG_STAT_FILENAME", val_str, sizeof(val_str)); 14717 if ($VMS_STATUS_SUCCESS(status)) { 14718 val_str[0] = _toupper(val_str[0]); 14719 if ((val_str[0] == 'E') || (val_str[0] == '1') || (val_str[0] == 'T')) 14720 vms_bug_stat_filename = 1; 14721 else 14722 vms_bug_stat_filename = 0; 14723 } 14724 14725 14726 /* Create VTF-7 filenames from Unicode instead of UTF-8 */ 14727 vms_vtf7_filenames = 0; 14728 status = sys_trnlnm("PERL_VMS_VTF7_FILENAMES", val_str, sizeof(val_str)); 14729 if ($VMS_STATUS_SUCCESS(status)) { 14730 val_str[0] = _toupper(val_str[0]); 14731 if ((val_str[0] == 'E') || (val_str[0] == '1') || (val_str[0] == 'T')) 14732 vms_vtf7_filenames = 1; 14733 else 14734 vms_vtf7_filenames = 0; 14735 } 14736 14737 /* unlink all versions on unlink() or rename() */ 14738 vms_unlink_all_versions = 0; 14739 status = sys_trnlnm 14740 ("PERL_VMS_UNLINK_ALL_VERSIONS", val_str, sizeof(val_str)); 14741 if ($VMS_STATUS_SUCCESS(status)) { 14742 val_str[0] = _toupper(val_str[0]); 14743 if ((val_str[0] == 'E') || (val_str[0] == '1') || (val_str[0] == 'T')) 14744 vms_unlink_all_versions = 1; 14745 else 14746 vms_unlink_all_versions = 0; 14747 } 14748 14749 /* Dectect running under GNV Bash or other UNIX like shell */ 14750 #if __CRTL_VER >= 70300000 && !defined(__VAX) 14751 gnv_unix_shell = 0; 14752 status = sys_trnlnm("GNV$UNIX_SHELL", val_str, sizeof(val_str)); 14753 if ($VMS_STATUS_SUCCESS(status)) { 14754 gnv_unix_shell = 1; 14755 set_feature_default("DECC$EFS_CASE_PRESERVE", 1); 14756 set_feature_default("DECC$EFS_CHARSET", 1); 14757 set_feature_default("DECC$FILENAME_UNIX_NO_VERSION", 1); 14758 set_feature_default("DECC$FILENAME_UNIX_REPORT", 1); 14759 set_feature_default("DECC$READDIR_DROPDOTNOTYPE", 1); 14760 set_feature_default("DECC$DISABLE_POSIX_ROOT", 0); 14761 vms_unlink_all_versions = 1; 14762 vms_posix_exit = 1; 14763 } 14764 #endif 14765 14766 /* hacks to see if known bugs are still present for testing */ 14767 14768 /* PCP mode requires creating /dev/null special device file */ 14769 decc_bug_devnull = 0; 14770 status = sys_trnlnm("DECC_BUG_DEVNULL", val_str, sizeof(val_str)); 14771 if ($VMS_STATUS_SUCCESS(status)) { 14772 val_str[0] = _toupper(val_str[0]); 14773 if ((val_str[0] == 'E') || (val_str[0] == '1') || (val_str[0] == 'T')) 14774 decc_bug_devnull = 1; 14775 else 14776 decc_bug_devnull = 0; 14777 } 14778 14779 /* UNIX directory names with no paths are broken in a lot of places */ 14780 decc_dir_barename = 1; 14781 status = sys_trnlnm("DECC_DIR_BARENAME", val_str, sizeof(val_str)); 14782 if ($VMS_STATUS_SUCCESS(status)) { 14783 val_str[0] = _toupper(val_str[0]); 14784 if ((val_str[0] == 'E') || (val_str[0] == '1') || (val_str[0] == 'T')) 14785 decc_dir_barename = 1; 14786 else 14787 decc_dir_barename = 0; 14788 } 14789 14790 #if __CRTL_VER >= 70300000 && !defined(__VAX) 14791 s = decc$feature_get_index("DECC$DISABLE_TO_VMS_LOGNAME_TRANSLATION"); 14792 if (s >= 0) { 14793 decc_disable_to_vms_logname_translation = decc$feature_get_value(s, 1); 14794 if (decc_disable_to_vms_logname_translation < 0) 14795 decc_disable_to_vms_logname_translation = 0; 14796 } 14797 14798 s = decc$feature_get_index("DECC$EFS_CASE_PRESERVE"); 14799 if (s >= 0) { 14800 decc_efs_case_preserve = decc$feature_get_value(s, 1); 14801 if (decc_efs_case_preserve < 0) 14802 decc_efs_case_preserve = 0; 14803 } 14804 14805 s = decc$feature_get_index("DECC$EFS_CHARSET"); 14806 decc_efs_charset_index = s; 14807 if (s >= 0) { 14808 decc_efs_charset = decc$feature_get_value(s, 1); 14809 if (decc_efs_charset < 0) 14810 decc_efs_charset = 0; 14811 } 14812 14813 s = decc$feature_get_index("DECC$FILENAME_UNIX_REPORT"); 14814 if (s >= 0) { 14815 decc_filename_unix_report = decc$feature_get_value(s, 1); 14816 if (decc_filename_unix_report > 0) { 14817 decc_filename_unix_report = 1; 14818 vms_posix_exit = 1; 14819 } 14820 else 14821 decc_filename_unix_report = 0; 14822 } 14823 14824 s = decc$feature_get_index("DECC$FILENAME_UNIX_ONLY"); 14825 if (s >= 0) { 14826 decc_filename_unix_only = decc$feature_get_value(s, 1); 14827 if (decc_filename_unix_only > 0) { 14828 decc_filename_unix_only = 1; 14829 } 14830 else { 14831 decc_filename_unix_only = 0; 14832 } 14833 } 14834 14835 s = decc$feature_get_index("DECC$FILENAME_UNIX_NO_VERSION"); 14836 if (s >= 0) { 14837 decc_filename_unix_no_version = decc$feature_get_value(s, 1); 14838 if (decc_filename_unix_no_version < 0) 14839 decc_filename_unix_no_version = 0; 14840 } 14841 14842 s = decc$feature_get_index("DECC$READDIR_DROPDOTNOTYPE"); 14843 if (s >= 0) { 14844 decc_readdir_dropdotnotype = decc$feature_get_value(s, 1); 14845 if (decc_readdir_dropdotnotype < 0) 14846 decc_readdir_dropdotnotype = 0; 14847 } 14848 14849 #if __CRTL_VER >= 80200000 14850 s = decc$feature_get_index("DECC$POSIX_COMPLIANT_PATHNAMES"); 14851 if (s >= 0) { 14852 decc_posix_compliant_pathnames = decc$feature_get_value(s, 1); 14853 if (decc_posix_compliant_pathnames < 0) 14854 decc_posix_compliant_pathnames = 0; 14855 if (decc_posix_compliant_pathnames > 4) 14856 decc_posix_compliant_pathnames = 0; 14857 } 14858 14859 #endif 14860 #else 14861 status = sys_trnlnm 14862 ("DECC$DISABLE_TO_VMS_LOGNAME_TRANSLATION", val_str, sizeof(val_str)); 14863 if ($VMS_STATUS_SUCCESS(status)) { 14864 val_str[0] = _toupper(val_str[0]); 14865 if ((val_str[0] == 'E') || (val_str[0] == '1') || (val_str[0] == 'T')) { 14866 decc_disable_to_vms_logname_translation = 1; 14867 } 14868 } 14869 14870 #ifndef __VAX 14871 status = sys_trnlnm("DECC$EFS_CASE_PRESERVE", val_str, sizeof(val_str)); 14872 if ($VMS_STATUS_SUCCESS(status)) { 14873 val_str[0] = _toupper(val_str[0]); 14874 if ((val_str[0] == 'E') || (val_str[0] == '1') || (val_str[0] == 'T')) { 14875 decc_efs_case_preserve = 1; 14876 } 14877 } 14878 #endif 14879 14880 status = sys_trnlnm("DECC$FILENAME_UNIX_REPORT", val_str, sizeof(val_str)); 14881 if ($VMS_STATUS_SUCCESS(status)) { 14882 val_str[0] = _toupper(val_str[0]); 14883 if ((val_str[0] == 'E') || (val_str[0] == '1') || (val_str[0] == 'T')) { 14884 decc_filename_unix_report = 1; 14885 } 14886 } 14887 status = sys_trnlnm("DECC$FILENAME_UNIX_ONLY", val_str, sizeof(val_str)); 14888 if ($VMS_STATUS_SUCCESS(status)) { 14889 val_str[0] = _toupper(val_str[0]); 14890 if ((val_str[0] == 'E') || (val_str[0] == '1') || (val_str[0] == 'T')) { 14891 decc_filename_unix_only = 1; 14892 decc_filename_unix_report = 1; 14893 } 14894 } 14895 status = sys_trnlnm("DECC$FILENAME_UNIX_NO_VERSION", val_str, sizeof(val_str)); 14896 if ($VMS_STATUS_SUCCESS(status)) { 14897 val_str[0] = _toupper(val_str[0]); 14898 if ((val_str[0] == 'E') || (val_str[0] == '1') || (val_str[0] == 'T')) { 14899 decc_filename_unix_no_version = 1; 14900 } 14901 } 14902 status = sys_trnlnm("DECC$READDIR_DROPDOTNOTYPE", val_str, sizeof(val_str)); 14903 if ($VMS_STATUS_SUCCESS(status)) { 14904 val_str[0] = _toupper(val_str[0]); 14905 if ((val_str[0] == 'E') || (val_str[0] == '1') || (val_str[0] == 'T')) { 14906 decc_readdir_dropdotnotype = 1; 14907 } 14908 } 14909 #endif 14910 14911 #if defined(JPI$_CASE_LOOKUP_PERM) && defined(PPROP$K_CASE_BLIND) && !defined(__VAX) 14912 14913 /* Report true case tolerance */ 14914 /*----------------------------*/ 14915 status = lib$getjpi(&jpicode1, 0, 0, &case_perm, 0, 0); 14916 if (!$VMS_STATUS_SUCCESS(status)) 14917 case_perm = PPROP$K_CASE_BLIND; 14918 status = lib$getjpi(&jpicode2, 0, 0, &case_image, 0, 0); 14919 if (!$VMS_STATUS_SUCCESS(status)) 14920 case_image = PPROP$K_CASE_BLIND; 14921 if ((case_perm == PPROP$K_CASE_SENSITIVE) || 14922 (case_image == PPROP$K_CASE_SENSITIVE)) 14923 vms_process_case_tolerant = 0; 14924 14925 #endif 14926 14927 /* USE POSIX/DCL Exit codes - Recommended, but needs to default to */ 14928 /* for strict backward compatibilty */ 14929 status = sys_trnlnm 14930 ("PERL_VMS_POSIX_EXIT", val_str, sizeof(val_str)); 14931 if ($VMS_STATUS_SUCCESS(status)) { 14932 val_str[0] = _toupper(val_str[0]); 14933 if ((val_str[0] == 'E') || (val_str[0] == '1') || (val_str[0] == 'T')) 14934 vms_posix_exit = 1; 14935 else 14936 vms_posix_exit = 0; 14937 } 14938 14939 14940 /* CRTL can be initialized past this point, but not before. */ 14941 /* DECC$CRTL_INIT(); */ 14942 14943 return SS$_NORMAL; 14944 } 14945 14946 #ifdef __DECC 14947 #pragma nostandard 14948 #pragma extern_model save 14949 #pragma extern_model strict_refdef "LIB$INITIALIZ" nowrt 14950 const __align (LONGWORD) int spare[8] = {0}; 14951 14952 /* .psect LIB$INITIALIZE, NOPIC, USR, CON, REL, GBL, NOSHR, NOEXE, RD, NOWRT, LONG */ 14953 #if __DECC_VER >= 60560002 14954 #pragma extern_model strict_refdef "LIB$INITIALIZE" nopic, con, rel, gbl, noshr, noexe, nowrt, long 14955 #else 14956 #pragma extern_model strict_refdef "LIB$INITIALIZE" nopic, con, gbl, noshr, nowrt, long 14957 #endif 14958 #endif /* __DECC */ 14959 14960 const long vms_cc_features = (const long)set_features; 14961 14962 /* 14963 ** Force a reference to LIB$INITIALIZE to ensure it 14964 ** exists in the image. 14965 */ 14966 int lib$initialize(void); 14967 #ifdef __DECC 14968 #pragma extern_model strict_refdef 14969 #endif 14970 int lib_init_ref = (int) lib$initialize; 14971 14972 #ifdef __DECC 14973 #pragma extern_model restore 14974 #pragma standard 14975 #endif 14976 14977 /* End of vms.c */ 14978