]> sjero.net Git - wget/blob - vms/vms.c
Space before closing brace. Fixes paramcheck.pl output.
[wget] / vms / vms.c
1 /*
2  *    VMS supplement for "wget".
3  *
4  *======================================================================
5  *
6  *       vms_init()
7  *
8  *    On non-VAX systems, uses LIB$INITIALIZE to set a collection of C
9  *    RTL features without using the DECC$* logical name method.
10  *
11  *----------------------------------------------------------------------
12  *
13  *       vms_arch()
14  *
15  *    Returns (run-time) VMS architecture string.
16  *
17  *----------------------------------------------------------------------
18  *
19  *       vms_ver()
20  *
21  *    Returns (run-time) VMS version string.
22  *
23  *----------------------------------------------------------------------
24  *
25  *       set_ods5_dest()
26  *
27  *    Sets a global flag ("ods5_dest") according to the file system type
28  *    of the destination device.
29  *
30  *----------------------------------------------------------------------
31  *
32  *       ods_conform()
33  *
34  *   Simplifies a fancy URL-derived file name into an ODS2- or
35  *   ODS5-compatible file name.
36  *    
37  *----------------------------------------------------------------------
38  *
39  *       utime()
40  *
41  *    VMS C RTL before V7.3 lacks utime().  In V7.3, utime() sets only
42  *    the modified (revised) date, not the created date of a file.
43  *
44  *    UNIX "ls -l" reports the modified time.  VMS "DIRECTORY /DATE"
45  *    reports the creation time.  Reconciling these in FTP DIR reports
46  *    is non-trivial.
47  *
48  *    UNIX utime() sets revision and access times.  VMS does not always
49  *    maintain access times, so this utime() replacement sets the
50  *    creation and revision times to the specified revision (or
51  *    creation?) time.  Any access time is ignored.
52  *
53  *----------------------------------------------------------------------
54  *
55  *       getpwuid()
56  *
57  *    VMS C RTL before V7.0 lacks getpwuid().
58  *
59  *----------------------------------------------------------------------
60  *
61  */
62
63 #include "vms.h"
64
65 #include <ctype.h>
66 #include <errno.h>
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <string.h>
70 #include <time.h>
71 #include <unixlib.h>
72
73 #include <atrdef.h>
74 #include <descrip.h>
75 #include <dvidef.h>
76 #include <fibdef.h>
77 #include <iodef.h>
78 #include <rms.h>
79 #include <stsdef.h>
80 #include <syidef.h>
81 #include <lib$routines.h>
82 #include <starlet.h>
83
84 /* Use <iosbdef.h> if available.  Otherwise declare IOSB here. */
85
86 #if !defined( __VAX) && (__CRTL_VER >= 70000000)
87 #include <iosbdef.h>
88 #else /* __CRTL_VER >= 70000000 */
89 typedef struct _iosb {
90         unsigned short int iosb$w_status; /* Final I/O status   */
91         unsigned short int iosb$w_bcnt; /* 16-bit byte count    */
92         unsigned int iosb$l_dev_depend; /* 32-bit dev dependent */
93     } IOSB;
94 #endif /* !defined( __VAX) && (__CRTL_VER >= 70000000) */
95
96 /* Ugly work-around for bad type in VAX <atrdef.h>. */
97
98 #ifdef __VAX
99 #define UWA (unsigned int)
100 #else /* def __VAX */
101 #define UWA
102 #endif /* def __VAX */
103
104 #include "config.h"
105 #include "wget.h"
106 #include "utils.h"
107
108 /*--------------------------------------------------------------------*/
109
110 /* Global storage. */
111
112 /*    Flag for an ODS5 destination directory. */
113
114 int ods5_dest = -1;
115
116 /*    Flag to sense if vms_init() was called. */
117
118 int vms_init_done = -1;
119
120 /*--------------------------------------------------------------------*/
121
122 #if !defined( __VAX) && (__CRTL_VER >= 70301000)
123
124 /* vms_init()
125
126       Uses LIB$INITIALIZE to set a collection of C RTL features without
127       requiring the user to define the corresponding logical names.
128 */
129
130 /* Structure to hold a DECC$* feature name and its desired value. */
131
132 typedef struct
133    {
134    char *name;
135    int value;
136    } decc_feat_t;
137
138 /* Array of DECC$* feature names and their desired values. */
139
140 decc_feat_t decc_feat_array[] = {
141    /* Preserve command-line case with SET PROCESS/PARSE_STYLE=EXTENDED */
142  { "DECC$ARGV_PARSE_STYLE", 1 },
143    /* Preserve case for file names on ODS5 disks. */
144  { "DECC$EFS_CASE_PRESERVE", 1 },
145    /* Enable multiple dots (and most characters) in ODS5 file names,
146       while preserving VMS-ness of ";version". */
147  { "DECC$EFS_CHARSET", 1 },
148    /* List terminator. */
149  { (char *)NULL, 0 } };
150
151 /* LIB$INITIALIZE initialization function. */
152
153 static void vms_init( void)
154 {
155 int feat_index;
156 int feat_value;
157 int feat_value_max;
158 int feat_value_min;
159 int i;
160 int sts;
161
162 /* Set the global flag to indicate that LIB$INITIALIZE worked. */
163
164 vms_init_done = 1;
165
166 /* Loop through all items in the decc_feat_array[]. */
167
168 for (i = 0; decc_feat_array[ i].name != NULL; i++)
169    {
170    /* Get the feature index. */
171    feat_index = decc$feature_get_index( decc_feat_array[ i].name);
172    if (feat_index >= 0)
173       {
174       /* Valid item.  Collect its properties. */
175       feat_value = decc$feature_get_value( feat_index, 1);
176       feat_value_min = decc$feature_get_value( feat_index, 2);
177       feat_value_max = decc$feature_get_value( feat_index, 3);
178
179       if ((decc_feat_array[ i].value >= feat_value_min) &&
180        (decc_feat_array[ i].value <= feat_value_max))
181          {
182          /* Valid value.  Set it if necessary. */
183          if (feat_value != decc_feat_array[ i].value)
184             {
185             sts = decc$feature_set_value( feat_index,
186              1,
187              decc_feat_array[ i].value);
188             }
189          }
190       else
191          {
192          /* Invalid DECC feature value. */
193          printf( " INVALID DECC FEATURE VALUE, %d: %d <= %s <= %d.\n",
194           feat_value,
195           feat_value_min, decc_feat_array[ i].name, feat_value_max);
196          }
197       }
198    else
199       {
200       /* Invalid DECC feature name. */
201       printf( " UNKNOWN DECC FEATURE: %s.\n", decc_feat_array[ i].name);
202       }
203    }
204 }
205
206 /* Get "vms_init()" into a valid, loaded LIB$INITIALIZE PSECT. */
207
208 #pragma nostandard
209
210 /* Establish the LIB$INITIALIZE PSECTs, with proper alignment and
211    other attributes.  Note that "nopic" is significant only on VAX.
212 */
213 #pragma extern_model save
214
215 #pragma extern_model strict_refdef "LIB$INITIALIZE" 2, nopic, nowrt
216 void (*const x_vms_init)() = vms_init;
217
218 #pragma extern_model strict_refdef "LIB$INITIALIZ" 2, nopic, nowrt
219 const int spare[ 8] = { 0 };
220
221 #pragma extern_model restore
222
223 /* Fake reference to ensure loading the LIB$INITIALIZE PSECT. */
224
225 #pragma extern_model save
226 int lib$initialize(void);
227 #pragma extern_model strict_refdef
228 int dmy_lib$initialize = (int) lib$initialize;
229 #pragma extern_model restore
230
231 #pragma standard
232
233 #endif /* !defined( __VAX) && (__CRTL_VER >= 70301000) */
234
235 /*--------------------------------------------------------------------*/
236
237 /* vms_arch()
238   
239       Returns (run-time) VMS architecture string.
240 */
241
242 char *vms_arch( void)
243 {
244 #define ARCH_SIZE 15
245
246 static int sts = 0;
247 static char arch[ ARCH_SIZE+ 1] = "VAX";        /* Only VAX could fail. */
248 unsigned short arch_len;
249
250 struct dsc$descriptor_s arch_descr =
251  { ARCH_SIZE, DSC$K_DTYPE_T, DSC$K_CLASS_S, arch };
252
253 if (sts == 0)
254    {
255    sts = lib$getsyi( &SYI$_ARCH_NAME, 0, &arch_descr, &arch_len, 0, 0);
256    if ((sts& STS$M_SEVERITY) == STS$K_SUCCESS)
257       {
258       arch[ arch_len] = '\0';
259
260       /* Trim trailing spaces. */
261       while ((arch_len > 0) && (arch[ arch_len- 1] == ' '))
262          {
263          arch[ --arch_len] = '\0';
264          }
265       }
266    }
267 return arch;
268 }
269
270 /*--------------------------------------------------------------------*/
271
272 /* vms_vers()
273   
274       Returns (run-time) VMS version string.
275 */
276
277 char *vms_vers( void)
278 {
279 #define VERS_SIZE 8
280
281 static int sts = 0;
282 static char vers[ VERS_SIZE+ 1] = "";
283 unsigned short vers_len;
284
285 struct dsc$descriptor_s vers_descr =
286  { VERS_SIZE, DSC$K_DTYPE_T, DSC$K_CLASS_S, vers };
287
288 if (sts == 0)
289    {
290    sts = lib$getsyi( &SYI$_VERSION, 0, &vers_descr, &vers_len, 0, 0);
291    if ((sts& STS$M_SEVERITY) == STS$K_SUCCESS)
292    {
293       vers[ vers_len] = '\0';
294
295       /* Trim trailing spaces. */
296       while ((vers_len > 0) && (vers[ vers_len- 1] == ' '))
297          {
298          vers[ --vers_len] = '\0';
299          }
300       }
301    }
302 return vers;
303 }
304
305 /*--------------------------------------------------------------------*/
306
307 /* set_ods5_dest()
308
309       Sets global "ods5_dest" according to the file system type of the
310       argument: 0 for ODS2, 1 for ODS5.  (No change if other/unknown or
311       failure.)
312
313       Return value:  Status from sys$getdvi().
314 */
315
316 int set_ods5_dest( char *path)
317 {
318 #ifdef DVI$C_ACP_F11V5
319
320 /* Should know about ODS5 file system.  Do actual check.
321    (This should be non-VAX with __CRTL_VER >= 70200000.)
322 */
323
324 struct dsc$descriptor_s dev_descr =
325  { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0 };
326
327 int acp_code;
328 int sts;
329
330 /* Load path argument into device descriptor.
331    Default to current default device.
332 */
333 if (path == NULL)
334    {
335    dev_descr.dsc$a_pointer = "SYS$DISK";
336    }
337 else
338    {
339    dev_descr.dsc$a_pointer = path;
340    }
341 dev_descr.dsc$w_length = strlen( dev_descr.dsc$a_pointer);
342
343 /* Get filesystem type code.
344    (Text results for this item code have been unreliable.)
345 */
346 sts = lib$getdvi( &((int) DVI$_ACPTYPE),
347                   0,
348                   &dev_descr,
349                   &acp_code,
350                   0,
351                   0);
352
353 if ((sts& STS$M_SEVERITY) == STS$K_SUCCESS)
354    {
355    if (acp_code == DVI$C_ACP_F11V2)
356       {
357       ods5_dest = 0;
358       }
359    else if (acp_code == DVI$C_ACP_F11V5)
360       {
361       ods5_dest = 1;
362       }
363    }
364
365 return sts;
366
367 #else /* def DVI$C_ACP_F11V5 */
368
369 /* Too old for ODS5 file system.  Do nothing. */
370
371 return STS$K_SUCCESS;
372
373 #endif /* def DVI$C_ACP_F11V5 */
374 }
375
376 /*--------------------------------------------------------------------*/
377
378 /* ods2_conform()
379
380    Replace ODS2-troublesome characters in the argument, overwriting the
381    original string.  Replace "~" with "-", "@" with "$", and invalid
382    dots and other characters with "_".  (Invalid dots are any in a
383    directory name, and all but the last in a file name.)
384
385    Return value: path.  (Someday this function could be written to leave
386    the original string unchanged, and to return a freshly allocated
387    string, possibly of a dfferent length.)
388
389    2005-02-23 SMS.
390    Changed to use char_prop[] look-up table, and to convert more invalid
391    characters to "_".
392 */
393
394 static
395 char *ods2_conform( char *path)
396 {
397 char *p;
398 char *prd;
399 char *prs;
400 char *prv;
401 unsigned char uchr;
402 unsigned char prop;
403
404 /* Locate the last slash. */
405 prs = rindex( path, '/');
406 if (prs == NULL)
407    {
408    prs = path;
409    }
410
411 /* Locate the last dot after the last slash. */
412 prd = rindex( prs, '.');
413 if (prd == NULL)
414    {
415    prd = prs;
416    }
417
418 /* Locate the version (after the last slash and dot). */
419 for (prv = prs+ strlen( prs) ; (--prv > prs) && isdigit( *prv); );
420 if ((*prv != ';') || (*(prv- 1) == '^'))
421    {
422    prv = prs+ strlen( prs);
423    }
424
425 for (p = path ; p < prv; p++)
426    {
427    prop = char_prop[ uchr = *p];
428    if ((prop& 4))
429       {                                 /* Dot. */
430       if (p < prd)
431          {                              /* Before last dot in name. */
432          *p = '_';                      /* Convert to "_". */
433          }
434       }
435    else if ((prop& (32+ 16)) == 0)
436       {                                 /* ODS2-invalid. */
437       if (uchr == '~')
438          {
439          *p = '-';                      /* Convert to "-". */
440          }
441       else if (uchr == '@')
442          {
443          *p = '$';                      /* Convert to "$". */
444          }
445       else if (uchr != '/')             /* Leave "/" as-is. */
446          {
447          *p = '_';                      /* Convert to "_". */
448          }
449       }
450    }
451 return path;
452 }
453
454 /*--------------------------------------------------------------------*/
455
456 /* ods_conform()
457
458    Replace troublesome characters for the destination file system (ODS2
459    or ODS5) with more legal characters.
460
461    For ODS5, this is simply "?" -> "!" and "*" -> "#".
462
463    For ODS2, see ods2_conform().
464
465    Return value: path.  (Someday this function could be written to leave
466    the original string unchanged, and to return a freshly allocated
467    string, possibly of a dfferent length.)
468 */
469
470 char *ods_conform( char *path)
471 {
472 char *p;
473
474 /* Replacements for invalid (printing) ODS5 characters. */
475 #define ODS5_QUESTION '!'
476 #define ODS5_ASTERISK '#'
477
478 if (ods5_dest <= 0)
479    {
480    /* Return ODS2-conformant file name. */
481    return ods2_conform( path);
482    }
483 else
484    {
485    /* Return ODS5-conformant file name.  ("?" -> "!", "*" -> "#".) */
486    for (p = path; *p != '\0'; p++)
487       {
488       if (*p == '?')
489          {
490          *p = ODS5_QUESTION;
491          }
492       else if (*p == '*')
493          {
494          *p = ODS5_ASTERISK;
495          }
496       }
497    return path;
498    }
499 }
500
501 /*--------------------------------------------------------------------*/
502
503 /* Wget-private utime() code. */
504
505 /* Use long name (NAML) structure only where available.
506    (This should be non-VAX with __CRTL_VER >= 70200000.)
507 */
508
509 #ifdef NAML$C_BID
510
511 /* Use long name (NAML) structure. */
512
513 #define FAB$L_NAMX fab$l_naml
514 #define NAMX NAML
515 #define NAMX$C_MAXRSS NAML$C_MAXRSS
516 #define NAMX$B_DEV naml$l_long_dev_size
517 #define NAMX$L_DEV naml$l_long_dev
518 #define NAMX$L_ESA naml$l_long_expand
519 #define NAMX$B_ESL naml$l_long_expand_size
520 #define NAMX$B_ESS naml$l_long_expand_alloc
521 #define NAMX$W_FID naml$w_fid
522 #define NAMX$L_RSA naml$l_long_result
523 #define NAMX$B_RSL naml$l_long_result_size
524 #define NAMX$B_RSS naml$l_long_result_alloc
525 #define CC$RMS_NAMX cc$rms_naml
526
527 #else /* def NAML$C_BID */
528
529 /* Use short name (NAM) structure. */
530
531 #define FAB$L_NAMX fab$l_nam
532 #define NAMX NAM
533 #define NAMX$C_MAXRSS NAM$C_MAXRSS
534 #define NAMX$B_DEV nam$b_dev
535 #define NAMX$L_DEV nam$l_dev
536 #define NAMX$L_ESA nam$l_esa
537 #define NAMX$B_ESL nam$b_esl
538 #define NAMX$B_ESS nam$b_ess
539 #define NAMX$W_FID nam$w_fid
540 #define NAMX$L_RSA nam$l_rsa
541 #define NAMX$B_RSL nam$b_rsl
542 #define NAMX$B_RSS nam$b_rss
543 #define CC$RMS_NAMX cc$rms_nam
544
545 #endif /* def NAML$C_BID */
546
547 /*--------------------------------------------------------------------*/
548
549 /* Wget-private utime() code. */
550
551 /* Action routine for decc$to_vms(), in utime(). */
552
553 char vms_path[ NAMX$C_MAXRSS+ 1];
554
555 int set_vms_name( char *name, int type)
556 {
557    strncpy( vms_path, name, NAMX$C_MAXRSS);
558    vms_path[ NAMX$C_MAXRSS] = '\0';
559    return 1;
560 }
561
562 /*--------------------------------------------------------------------*/
563
564 /* utime() replacement. */
565
566 int utime( const char *path, const struct utimbuf *times)
567 {
568 time_t utc_unsigned;
569
570 int chan, i;
571 int sts, sts2;
572
573 unsigned short int vms_num_vec_time[ 7];
574 static unsigned int vms_abs_time[ 2];
575 struct tm *tms;
576 struct _iosb iosb_q;
577
578 /* QIOW item list used to set creation and revision dates. */
579
580 struct atrdef ut_atr[ 3] = {
581  {sizeof( vms_abs_time), ATR$C_CREDATE, UWA vms_abs_time},
582  {sizeof( vms_abs_time), ATR$C_REVDATE, UWA vms_abs_time},
583  {0,0,0}};
584
585 /* Various RMS structures used for file access. */
586
587 struct FAB ut_fab = cc$rms_fab;
588 struct RAB ut_rab = cc$rms_rab;
589 struct NAMX ut_namx = CC$RMS_NAMX;
590 static struct fibdef ut_fib;
591
592 /* Device and file name buffers and their descriptors. */
593
594 static char dev_namx[ NAMX$C_MAXRSS+ 1];
595 char esa_namx[ NAMX$C_MAXRSS+ 1];
596 char rsa_namx[ NAMX$C_MAXRSS+ 1];
597
598 struct dsc$descriptor dev_dsc =
599  {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, dev_namx};
600
601 struct dsc$descriptor fib_dsc =
602  {sizeof( ut_fib), DSC$K_DTYPE_T, DSC$K_CLASS_S, (char *) &ut_fib};
603
604 /* "wget" provides a UNIX-like path name.  With "-O", a user may provide
605    a VMS-like path name.  If a slash is found in the name, assume that
606    it's UNIX-like, and convert it to VMS form.  Otherwise, use it as-is.
607 */
608
609 if (strchr( path, '/') != NULL)
610    {
611    sts = decc$to_vms( path, set_vms_name, 0, 0);
612    path = vms_path;
613    }
614
615 /* Install the VMS file specification into the FAB. */
616
617 ut_fab.fab$l_fna = (char *) path;
618 ut_fab.fab$b_fns = (unsigned char) strlen( path);
619
620 ut_fab.fab$l_dna = "";
621 ut_fab.fab$b_dns = 0;
622
623 /* Point the FAB to the NAMX. */
624
625 ut_fab.FAB$L_NAMX = &ut_namx;
626
627 /* Install the name buffers into the NAM. */
628
629 ut_namx.NAMX$L_ESA = esa_namx;
630 ut_namx.NAMX$B_ESL = 0;
631 ut_namx.NAMX$B_ESS = sizeof( esa_namx)- 1;
632
633 ut_namx.NAMX$L_RSA = rsa_namx;
634 ut_namx.NAMX$B_RSL = 0;
635 ut_namx.NAMX$B_RSS = sizeof( rsa_namx)- 1;
636
637 /* Convert the modification time (UTC time_t) to local "tm" time. */
638
639 tms = localtime( &(times-> modtime));
640
641 /* Move (translate) "tm" structure local time to VMS vector time. */
642
643 if (tms != NULL)
644    {
645    vms_num_vec_time[ 0] = tms-> tm_year+ 1900;
646    vms_num_vec_time[ 1] = tms-> tm_mon+ 1;
647    vms_num_vec_time[ 2] = tms-> tm_mday;
648    vms_num_vec_time[ 3] = tms-> tm_hour;
649    vms_num_vec_time[ 4] = tms-> tm_min;
650    vms_num_vec_time[ 5] = tms-> tm_sec;
651    vms_num_vec_time[ 6] = 0;  /* centiseconds */
652
653 /* Convert VMS vector time to VMS absolute time (quadword). */
654
655    sts = lib$cvt_vectim( vms_num_vec_time, vms_abs_time);
656
657    if ((sts& STS$M_SEVERITY) == STS$K_SUCCESS)
658       {
659 /* Parse the file specification. */
660
661       sts = sys$parse( &ut_fab, 0, 0);
662
663       if ((sts& STS$M_SEVERITY) == STS$K_SUCCESS)
664          {
665 /* Locate the file. (Gets the FID.) */
666
667          sts = sys$search( &ut_fab, 0, 0);
668
669          if ((sts& STS$M_SEVERITY) == STS$K_SUCCESS)
670             {
671 /* Form the device name descriptor. */
672
673             dev_dsc.dsc$w_length = ut_namx.NAMX$B_DEV;
674             dev_dsc.dsc$a_pointer = (char *) ut_namx.NAMX$L_DEV;
675
676 /* Assign a channel to the disk device. */
677
678             sts = sys$assign( &dev_dsc, &chan, 0, 0);
679
680             if ((sts& STS$M_SEVERITY) == STS$K_SUCCESS)
681                {
682 /* Move the FID (and not the DID) into the FIB. */
683
684                memset( (void *) &ut_fib, 0, sizeof( ut_fib));
685
686                for (i = 0; i < 3; i++)
687                   {
688                   ut_fib.fib$w_fid[ i] = ut_namx.NAMX$W_FID[ i];
689                   ut_fib.fib$w_did[ i] = 0;
690                   }
691
692 /* Prevent this QIOW from setting the revision time to now. */
693
694                ut_fib.fib$l_acctl = FIB$M_NORECORD;
695
696 /* Set the file dates. */
697
698                sts = sys$qiow( 0,
699                                chan,
700                                IO$_MODIFY,
701                                &iosb_q,
702                                0,
703                                0,
704                                &fib_dsc,
705                                0,
706                                0,
707                                0,
708                                ut_atr,
709                                0);
710
711                if ((sts& STS$M_SEVERITY) == STS$K_SUCCESS)
712                   {
713                    sts = iosb_q.iosb$w_status;
714                   }
715                sts2 = sys$dassgn( chan);
716
717                if ((sts& STS$M_SEVERITY) == STS$K_SUCCESS)
718                   {
719                   sts = sts2;
720                   }
721                }
722             }
723          }
724       }
725    }
726
727 /* Convert successful VMS status to zero = success status.
728    If failure, set errno and vaxc$errno, and return -1 = failure status.
729 */
730
731 if ((sts& STS$M_SEVERITY) == STS$K_SUCCESS)
732    {
733    sts = 0;
734    }
735 else
736    {
737    errno = EVMSERR;
738    vaxc$errno = sts;
739    sts = -1;
740    }
741
742 return sts;
743 }
744
745 /*--------------------------------------------------------------------*/
746
747 /* 2005-04-14 SMS.
748  *
749  *       vms_init_diag().
750  *
751  *    Get Wget debug option value.
752  */
753
754 int vms_init_diag( void)
755 {
756 #ifdef ENABLE_DEBUG
757 return (opt.debug > 0);
758 #else /* def ENABLE_DEBUG */
759 return 0;
760 #endif /* def ENABLE_DEBUG */
761 }
762
763 /*--------------------------------------------------------------------*/
764
765 /* 2004-11-23 SMS.
766  *
767  *       get_rms_defaults().
768  *
769  *    Get user-specified values from (DCL) SET RMS_DEFAULT.  FAB/RAB
770  *    items of particular interest are:
771  *
772  *       fab$w_deq         default extension quantity (blocks) (write).
773  *       rab$b_mbc         multi-block count.
774  *       rab$b_mbf         multi-buffer count (used with rah and wbh).
775  */
776
777 /* Default RMS parameter values. */
778
779 #define RMS_DEQ_DEFAULT 16384   /* About 1/4 the max (65535 blocks). */
780 #define RMS_MBC_DEFAULT 127     /* The max, */
781 #define RMS_MBF_DEFAULT 2       /* Enough to enable rah and wbh. */
782
783 /* GETJPI item descriptor structure. */
784 typedef struct
785     {
786     short buf_len;
787     short itm_cod;
788     void *buf;
789     int *ret_len;
790     } jpi_item_t;
791
792 /* Durable storage */
793
794 static int rms_defaults_known = 0;
795
796 /* JPI item buffers. */
797 static unsigned short rms_ext;
798 static char rms_mbc;
799 static unsigned char rms_mbf;
800
801 /* Active RMS item values. */
802 unsigned short rms_ext_active;
803 char rms_mbc_active;
804 unsigned char rms_mbf_active;
805
806 /* GETJPI item lengths. */
807 static int rms_ext_len;         /* Should come back 2. */
808 static int rms_mbc_len;         /* Should come back 1. */
809 static int rms_mbf_len;         /* Should come back 1. */
810
811 /* Desperation attempts to define unknown macros.  Probably doomed.
812  * If these get used, expect sys$getjpiw() to return %x00000014 =
813  * %SYSTEM-F-BADPARAM, bad parameter value.
814  * They keep compilers with old header files quiet, though.
815  */
816 #ifndef JPI$_RMS_EXTEND_SIZE
817 #  define JPI$_RMS_EXTEND_SIZE 542
818 #endif /* ndef JPI$_RMS_EXTEND_SIZE */
819
820 #ifndef JPI$_RMS_DFMBC
821 #  define JPI$_RMS_DFMBC 535
822 #endif /* ndef JPI$_RMS_DFMBC */
823
824 #ifndef JPI$_RMS_DFMBFSDK
825 #  define JPI$_RMS_DFMBFSDK 536
826 #endif /* ndef JPI$_RMS_DFMBFSDK */
827
828 /* GETJPI item descriptor set. */
829
830 struct
831     {
832     jpi_item_t rms_ext_itm;
833     jpi_item_t rms_mbc_itm;
834     jpi_item_t rms_mbf_itm;
835     int term;
836     } jpi_itm_lst =
837      { { 2, JPI$_RMS_EXTEND_SIZE, &rms_ext, &rms_ext_len },
838        { 1, JPI$_RMS_DFMBC, &rms_mbc, &rms_mbc_len },
839        { 1, JPI$_RMS_DFMBFSDK, &rms_mbf, &rms_mbf_len },
840        0
841      };
842
843 int get_rms_defaults()
844 {
845 int sts;
846
847 /* Get process RMS_DEFAULT values. */
848
849 sts = sys$getjpiw( 0, 0, 0, &jpi_itm_lst, 0, 0, 0);
850 if ((sts& STS$M_SEVERITY) != STS$M_SUCCESS)
851     {
852     /* Failed.  Don't try again. */
853     rms_defaults_known = -1;
854     }
855 else
856     {
857     /* Fine, but don't come back. */
858     rms_defaults_known = 1;
859     }
860
861 /* Limit the active values according to the RMS_DEFAULT values. */
862
863 if (rms_defaults_known > 0)
864     {
865     /* Set the default values. */
866
867     rms_ext_active = RMS_DEQ_DEFAULT;
868     rms_mbc_active = RMS_MBC_DEFAULT;
869     rms_mbf_active = RMS_MBF_DEFAULT;
870
871     /* Default extend quantity.  Use the user value, if set. */
872     if (rms_ext > 0)
873         {
874         rms_ext_active = rms_ext;
875         }
876
877     /* Default multi-block count.  Use the user value, if set. */
878     if (rms_mbc > 0)
879         {
880         rms_mbc_active = rms_mbc;
881         }
882
883     /* Default multi-buffer count.  Use the user value, if set. */
884     if (rms_mbf > 0)
885         {
886         rms_mbf_active = rms_mbf;
887         }
888     }
889
890 if (vms_init_diag() > 0)
891     {
892     fprintf( stderr,
893      "Get RMS defaults.  getjpi sts = %%x%08x.\n",
894      sts);
895
896     if (rms_defaults_known > 0)
897         {
898         fprintf( stderr,
899          "               Default: deq = %6d, mbc = %3d, mbf = %3d.\n",
900          rms_ext, rms_mbc, rms_mbf);
901         }
902     }
903 return sts;
904 }
905
906 /*--------------------------------------------------------------------*/
907
908 /* 2004-11-23 SMS.
909  *
910  *       acc_cb(), access callback function for DEC C [f]open().
911  *
912  *    Set some RMS FAB/RAB items, with consideration of user-specified
913  * values from (DCL) SET RMS_DEFAULT.  Items of particular interest are:
914  *
915  *       fab$w_deq         default extension quantity (blocks).
916  *       rab$b_mbc         multi-block count.
917  *       rab$b_mbf         multi-buffer count (used with rah and wbh).
918  *
919  *    See also the FOP* macros in OSDEP.H.  Currently, no notice is
920  * taken of the caller-ID value, but options could be set differently
921  * for read versus write access.  (I assume that specifying fab$w_deq,
922  * for example, for a read-only file has no ill effects.)
923  */
924
925 /* acc_cb() */
926
927 int acc_cb( int *id_arg, struct FAB *fab, struct RAB *rab)
928 {
929 int sts;
930
931 /* Get process RMS_DEFAULT values, if not already done. */
932 if (rms_defaults_known == 0)
933     {
934     get_rms_defaults();
935     }
936
937 /* If RMS_DEFAULT (and adjusted active) values are available, then set
938  * the FAB/RAB parameters.  If RMS_DEFAULT values are not available,
939  * suffer with the default parameters.
940  */
941 if (rms_defaults_known > 0)
942     {
943     /* Set the FAB/RAB parameters accordingly. */
944     fab-> fab$w_deq = rms_ext_active;
945     rab-> rab$b_mbc = rms_mbc_active;
946     rab-> rab$b_mbf = rms_mbf_active;
947
948     /* Truncate at EOF on close, as we'll probably over-extend. */
949     fab-> fab$v_tef = 1;
950
951     /* If using multiple buffers, enable read-ahead and write-behind. */
952     if (rms_mbf_active > 1)
953         {
954         rab-> rab$v_rah = 1;
955         rab-> rab$v_wbh = 1;
956         }
957
958     if (vms_init_diag() > 0)
959         {
960         fprintf( stderr,
961          "Open callback.  ID = %d, deq = %6d, mbc = %3d, mbf = %3d.\n",
962          *id_arg, fab-> fab$w_deq, rab-> rab$b_mbc, rab-> rab$b_mbf);
963         }
964     }
965
966 /* Declare success. */
967 return 0;
968 }
969
970 /*--------------------------------------------------------------------*/
971
972 /* Added J.Lauret 05-Dec-1999 . Copied from Mosaic distribution */
973
974 /*
975  * Here is a replacement for getpwuid for VMS.  It returns pointers
976  * to userid (*pw_name) and owner (*pw_gecos) only.  Other fields
977  * may be added later.
978  * Note that sys$getuai returns owner as a counted string.
979  */
980
981 #if __CRTL_VER < 70000000
982
983 #include <uaidef.h>
984
985 static struct passwd vms_passwd;
986 static char vms_userid[16];
987 static char vms_owner[40];
988
989 struct passwd *getpwuid()
990 {
991 struct  dsc$descriptor_s
992 {
993   unsigned short  dsc$w_length;
994   unsigned char   dsc$b_dtype;
995   unsigned char   dsc$b_class;
996   char            *dsc$a_pointer;
997 } user_desc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL};
998
999   char *t_userid, owner[40];
1000   int status, length;
1001   struct {
1002     short buffer_length;
1003     short item_code;
1004     int buffer_address;
1005     int return_length_address;
1006     int terminator;
1007   } itmlst;
1008
1009 #ifdef __GNUC__
1010   (int)t_userid = cuserid((char *) NULL);
1011 #else
1012   t_userid = cuserid((char *) NULL);
1013 #endif /* GNU C is strange, GEC */
1014   user_desc.dsc$w_length       = strlen(t_userid);
1015   user_desc.dsc$a_pointer      = t_userid;
1016   itmlst.buffer_length         = sizeof(owner);
1017   itmlst.item_code             = UAI$_OWNER;
1018   itmlst.buffer_address        = (int)owner;
1019   itmlst.return_length_address = (int)&length;
1020   itmlst.terminator            = 0;
1021   status = sys$getuai(0, 0, &user_desc, &itmlst, 0, 0, 0);
1022   if ((stats& STS$M_SEVERITY) == STS$K_SUCCESS) {
1023     length = (int)owner[0];
1024     owner[length+1] = '\0';
1025     strcpy(vms_userid, t_userid);
1026     strcpy(vms_owner, &owner[1]);
1027   } else {
1028     vms_userid[0] = '\0';
1029     vms_owner[0] = '\0';
1030   }
1031   vms_passwd.pw_name = vms_userid;
1032   vms_passwd.pw_gecos = vms_owner;
1033   return (&vms_passwd);
1034 }
1035
1036 /* Approximate localtime_r as best we can in its absence.  */
1037 struct tm *
1038 localtime_r (t, tp)
1039      const time_t *t;
1040      struct tm *tp;
1041 {
1042   struct tm *l = localtime (t);
1043   if (! l)
1044     return 0;
1045   *tp = *l;
1046   return tp;
1047 }
1048
1049 #endif  /* __CRTL_VER < 70000000 */
1050