Home | History | Annotate | Line # | Download | only in config
te-vms.c revision 1.1.1.8
      1      1.1  christos /* te-vms.c -- Utilities for VMS.
      2  1.1.1.8  christos    Copyright (C) 2009-2025 Free Software Foundation, Inc.
      3      1.1  christos 
      4      1.1  christos    Written by Douglas B Rupp <rupp (at) gnat.com>
      5      1.1  christos 
      6      1.1  christos    This program is free software; you can redistribute it and/or modify
      7      1.1  christos    it under the terms of the GNU General Public License as published by
      8      1.1  christos    the Free Software Foundation; either version 3 of the License, or
      9      1.1  christos    (at your option) any later version.
     10      1.1  christos 
     11      1.1  christos    This program is distributed in the hope that it will be useful,
     12      1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     13      1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14      1.1  christos    GNU General Public License for more details.
     15      1.1  christos 
     16      1.1  christos    You should have received a copy of the GNU General Public License
     17      1.1  christos    along with this program; if not, write to the Free Software
     18      1.1  christos    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
     19      1.1  christos 
     20      1.1  christos #include "as.h"
     21      1.1  christos #include "te-vms.h"
     22      1.1  christos 
     23  1.1.1.4  christos /* The purpose of the two alternate versions below is to have one that
     24      1.1  christos    works for native VMS and one that works on an NFS mounted filesystem
     25      1.1  christos    (Unix Server/VMS client).  The main issue being to generate the special
     26      1.1  christos    VMS file timestamps for the debug info.  */
     27      1.1  christos 
     28      1.1  christos #ifdef VMS
     29      1.1  christos #define __NEW_STARLET 1
     30      1.1  christos #include <vms/starlet.h>
     31      1.1  christos #include <vms/rms.h>
     32      1.1  christos #include <vms/atrdef.h>
     33      1.1  christos #include <vms/fibdef.h>
     34      1.1  christos #include <vms/stsdef.h>
     35      1.1  christos #include <vms/iodef.h>
     36      1.1  christos #include <vms/fatdef.h>
     37      1.1  christos #include <errno.h>
     38      1.1  christos #include <vms/descrip.h>
     39      1.1  christos #include <string.h>
     40      1.1  christos #include <unixlib.h>
     41      1.1  christos 
     42      1.1  christos #define MAXPATH 256
     43      1.1  christos 
     44      1.1  christos /* Descrip.h doesn't have everything...  */
     45      1.1  christos typedef struct fibdef * __fibdef_ptr32 __attribute__ (( mode (SI) ));
     46      1.1  christos 
     47      1.1  christos struct dsc$descriptor_fib
     48      1.1  christos {
     49      1.1  christos   unsigned int   fib$l_len;
     50      1.1  christos   __fibdef_ptr32 fib$l_addr;
     51      1.1  christos };
     52      1.1  christos 
     53      1.1  christos /* I/O Status Block.  */
     54      1.1  christos struct IOSB
     55      1.1  christos {
     56      1.1  christos   unsigned short status, count;
     57      1.1  christos   unsigned int devdep;
     58      1.1  christos };
     59      1.1  christos 
     60      1.1  christos static char *tryfile;
     61      1.1  christos 
     62      1.1  christos /* Variable length string.  */
     63      1.1  christos struct vstring
     64      1.1  christos {
     65      1.1  christos   short length;
     66      1.1  christos   char string[NAM$C_MAXRSS+1];
     67      1.1  christos };
     68      1.1  christos 
     69      1.1  christos static char filename_buff [MAXPATH];
     70      1.1  christos static char vms_filespec [MAXPATH];
     71      1.1  christos 
     72      1.1  christos /* Callback function for filespec style conversion.  */
     73      1.1  christos 
     74      1.1  christos static int
     75      1.1  christos translate_unix (char *name, int type ATTRIBUTE_UNUSED)
     76      1.1  christos {
     77      1.1  christos   strncpy (filename_buff, name, MAXPATH);
     78      1.1  christos   filename_buff [MAXPATH - 1] = (char) 0;
     79      1.1  christos   return 0;
     80      1.1  christos }
     81      1.1  christos 
     82      1.1  christos /* Wrapper for DECC function that converts a Unix filespec
     83      1.1  christos    to VMS style filespec.  */
     84      1.1  christos 
     85      1.1  christos static char *
     86      1.1  christos to_vms_file_spec (char *filespec)
     87      1.1  christos {
     88      1.1  christos   strncpy (vms_filespec, "", MAXPATH);
     89      1.1  christos   decc$to_vms (filespec, translate_unix, 1, 1);
     90      1.1  christos   strncpy (vms_filespec, filename_buff, MAXPATH);
     91      1.1  christos 
     92      1.1  christos   vms_filespec [MAXPATH - 1] = (char) 0;
     93      1.1  christos 
     94      1.1  christos   return vms_filespec;
     95      1.1  christos }
     96      1.1  christos 
     97      1.1  christos #else /* not VMS */
     98      1.1  christos 
     99      1.1  christos #define _BSD_SOURCE 1
    100      1.1  christos #include <sys/stat.h>
    101      1.1  christos #include <time.h>
    102      1.1  christos 
    103      1.1  christos #define VMS_EPOCH_OFFSET        35067168000000000LL
    104      1.1  christos #define VMS_GRANULARITY_FACTOR  10000000
    105      1.1  christos 
    106      1.1  christos #endif /* VMS */
    107      1.1  christos 
    108      1.1  christos /* Return VMS file date, size, format, version given a name.  */
    109      1.1  christos 
    110      1.1  christos static int
    111      1.1  christos vms_file_stats_name (const char *dirname,
    112      1.1  christos                      const char *filename,
    113      1.1  christos 		     long long *cdt,
    114      1.1  christos 		     long *siz,
    115      1.1  christos 		     char *rfo,
    116      1.1  christos 		     int *ver)
    117      1.1  christos {
    118  1.1.1.3  christos   char * fullname;
    119  1.1.1.3  christos 
    120      1.1  christos #ifdef VMS
    121      1.1  christos   struct FAB fab;
    122      1.1  christos   struct NAM nam;
    123      1.1  christos 
    124      1.1  christos   unsigned long long create;
    125      1.1  christos   FAT recattr;
    126      1.1  christos   char ascnamebuff [256];
    127      1.1  christos 
    128      1.1  christos   ATRDEF atrlst[]
    129      1.1  christos     = {
    130      1.1  christos       { ATR$S_CREDATE,  ATR$C_CREDATE,  &create },
    131      1.1  christos       { ATR$S_RECATTR,  ATR$C_RECATTR,  &recattr },
    132      1.1  christos       { ATR$S_ASCNAME,  ATR$C_ASCNAME,  &ascnamebuff },
    133      1.1  christos       { 0, 0, 0}
    134      1.1  christos     };
    135      1.1  christos 
    136      1.1  christos   FIBDEF fib;
    137      1.1  christos   struct dsc$descriptor_fib fibdsc = {sizeof (fib), (void *) &fib};
    138      1.1  christos 
    139      1.1  christos   struct IOSB iosb;
    140      1.1  christos 
    141      1.1  christos   long status;
    142      1.1  christos   unsigned short chan;
    143      1.1  christos 
    144      1.1  christos   struct vstring file;
    145      1.1  christos   struct dsc$descriptor_s filedsc
    146      1.1  christos     = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) file.string};
    147      1.1  christos   struct vstring device;
    148      1.1  christos   struct dsc$descriptor_s devicedsc
    149      1.1  christos     = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) device.string};
    150      1.1  christos   struct vstring result;
    151      1.1  christos   struct dsc$descriptor_s resultdsc
    152      1.1  christos     = {NAM$C_MAXRSS, DSC$K_DTYPE_VT, DSC$K_CLASS_VS, (void *) result.string};
    153      1.1  christos 
    154      1.1  christos   if (strcmp (filename, "<internal>") == 0
    155      1.1  christos       || strcmp (filename, "<built-in>") == 0)
    156      1.1  christos     {
    157      1.1  christos       if (cdt)
    158      1.1  christos 	*cdt = 0;
    159      1.1  christos 
    160      1.1  christos       if (siz)
    161      1.1  christos 	*siz = 0;
    162      1.1  christos 
    163      1.1  christos       if (rfo)
    164      1.1  christos 	*rfo = 0;
    165      1.1  christos 
    166      1.1  christos       if (ver)
    167      1.1  christos         *ver = 0;
    168      1.1  christos 
    169      1.1  christos       return 0;
    170      1.1  christos     }
    171      1.1  christos 
    172  1.1.1.8  christos   fullname = concat (dirname, filename, (const char *) NULL);
    173      1.1  christos   tryfile = to_vms_file_spec (fullname);
    174      1.1  christos 
    175      1.1  christos   /* Allocate and initialize a FAB and NAM structures.  */
    176      1.1  christos   fab = cc$rms_fab;
    177      1.1  christos   nam = cc$rms_nam;
    178      1.1  christos 
    179      1.1  christos   nam.nam$l_esa = file.string;
    180      1.1  christos   nam.nam$b_ess = NAM$C_MAXRSS;
    181      1.1  christos   nam.nam$l_rsa = result.string;
    182      1.1  christos   nam.nam$b_rss = NAM$C_MAXRSS;
    183      1.1  christos   fab.fab$l_fna = tryfile;
    184      1.1  christos   fab.fab$b_fns = strlen (tryfile);
    185      1.1  christos   fab.fab$l_nam = &nam;
    186      1.1  christos 
    187      1.1  christos   /* Validate filespec syntax and device existence.  */
    188      1.1  christos   status = SYS$PARSE (&fab, 0, 0);
    189      1.1  christos   if ((status & 1) != 1)
    190  1.1.1.3  christos     {
    191  1.1.1.3  christos       free (fullname);
    192  1.1.1.3  christos       return 1;
    193  1.1.1.3  christos     }
    194      1.1  christos 
    195      1.1  christos   file.string[nam.nam$b_esl] = 0;
    196      1.1  christos 
    197      1.1  christos   /* Find matching filespec.  */
    198      1.1  christos   status = SYS$SEARCH (&fab, 0, 0);
    199      1.1  christos   if ((status & 1) != 1)
    200  1.1.1.3  christos     {
    201  1.1.1.3  christos       free (fullname);
    202  1.1.1.3  christos       return 1;
    203  1.1.1.3  christos     }
    204      1.1  christos 
    205      1.1  christos   file.string[nam.nam$b_esl] = 0;
    206      1.1  christos   result.string[result.length=nam.nam$b_rsl] = 0;
    207      1.1  christos 
    208      1.1  christos   /* Get the device name and assign an IO channel.  */
    209      1.1  christos   strncpy (device.string, nam.nam$l_dev, nam.nam$b_dev);
    210      1.1  christos   devicedsc.dsc$w_length  = nam.nam$b_dev;
    211      1.1  christos   chan = 0;
    212      1.1  christos   status = SYS$ASSIGN (&devicedsc, &chan, 0, 0, 0);
    213      1.1  christos   if ((status & 1) != 1)
    214  1.1.1.3  christos     {
    215  1.1.1.3  christos       free (fullname);
    216  1.1.1.3  christos       return 1;
    217  1.1.1.3  christos     }
    218      1.1  christos 
    219      1.1  christos   /* Initialize the FIB and fill in the directory id field.  */
    220      1.1  christos   memset (&fib, 0, sizeof (fib));
    221      1.1  christos   fib.fib$w_did[0]  = nam.nam$w_did[0];
    222      1.1  christos   fib.fib$w_did[1]  = nam.nam$w_did[1];
    223      1.1  christos   fib.fib$w_did[2]  = nam.nam$w_did[2];
    224      1.1  christos   fib.fib$l_acctl = 0;
    225      1.1  christos   fib.fib$l_wcc = 0;
    226      1.1  christos   strcpy (file.string, (strrchr (result.string, ']') + 1));
    227      1.1  christos   filedsc.dsc$w_length = strlen (file.string);
    228      1.1  christos   result.string[result.length = 0] = 0;
    229      1.1  christos 
    230      1.1  christos   /* Open and close the file to fill in the attributes.  */
    231      1.1  christos   status
    232      1.1  christos     = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
    233      1.1  christos 		&fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
    234      1.1  christos   if ((status & 1) != 1)
    235  1.1.1.3  christos     {
    236  1.1.1.3  christos       free (fullname);
    237  1.1.1.3  christos       return 1;
    238  1.1.1.3  christos     }
    239  1.1.1.3  christos 
    240      1.1  christos   if ((iosb.status & 1) != 1)
    241  1.1.1.3  christos     {
    242  1.1.1.3  christos       free (fullname);
    243  1.1.1.3  christos       return 1;
    244  1.1.1.3  christos     }
    245      1.1  christos 
    246      1.1  christos   result.string[result.length] = 0;
    247      1.1  christos   status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0, &fibdsc, 0, 0, 0,
    248      1.1  christos 		     &atrlst, 0);
    249      1.1  christos   if ((status & 1) != 1)
    250  1.1.1.3  christos     {
    251  1.1.1.3  christos       free (fullname);
    252  1.1.1.3  christos       return 1;
    253  1.1.1.3  christos     }
    254  1.1.1.3  christos 
    255      1.1  christos   if ((iosb.status & 1) != 1)
    256  1.1.1.3  christos     {
    257  1.1.1.3  christos       free (fullname);
    258  1.1.1.3  christos       return 1;
    259  1.1.1.3  christos     }
    260      1.1  christos 
    261      1.1  christos   /* Deassign the channel and exit.  */
    262      1.1  christos   status = SYS$DASSGN (chan);
    263      1.1  christos   if ((status & 1) != 1)
    264  1.1.1.3  christos     {
    265  1.1.1.3  christos       free (fullname);
    266  1.1.1.3  christos       return 1;
    267  1.1.1.3  christos     }
    268      1.1  christos 
    269      1.1  christos   if (cdt) *cdt = create;
    270      1.1  christos   if (siz) *siz = (512 * 65536 * recattr.fat$w_efblkh) +
    271      1.1  christos                   (512 * (recattr.fat$w_efblkl - 1)) +
    272      1.1  christos                   recattr.fat$w_ffbyte;
    273      1.1  christos   if (rfo) *rfo = recattr.fat$v_rtype;
    274      1.1  christos   if (ver) *ver = strtol (strrchr (ascnamebuff, ';') + 1, 0, 10);
    275      1.1  christos #else /* not VMS */
    276      1.1  christos 
    277      1.1  christos   struct stat buff;
    278      1.1  christos   struct tm *ts;
    279      1.1  christos   long long gmtoff, secs, nsecs;
    280      1.1  christos 
    281  1.1.1.8  christos   fullname = concat (dirname, filename, (const char *) NULL);
    282      1.1  christos 
    283      1.1  christos   if ((stat (fullname, &buff)) != 0)
    284  1.1.1.3  christos     {
    285  1.1.1.3  christos       free (fullname);
    286  1.1.1.3  christos       return 1;
    287  1.1.1.3  christos     }
    288      1.1  christos 
    289      1.1  christos   if (cdt)
    290      1.1  christos     {
    291      1.1  christos       ts = localtime (& buff.st_mtime);
    292      1.1  christos 
    293      1.1  christos #ifdef HAVE_TM_GMTOFF
    294      1.1  christos 	gmtoff = ts->tm_gmtoff;
    295      1.1  christos #else
    296      1.1  christos 	{
    297      1.1  christos 	  extern long timezone;
    298      1.1  christos 
    299      1.1  christos 	  if (ts->tm_isdst == 1)
    300      1.1  christos 	    gmtoff = - (timezone - 3600);
    301      1.1  christos 	  else
    302      1.1  christos 	    gmtoff = - timezone;
    303      1.1  christos 	}
    304      1.1  christos #endif
    305      1.1  christos 
    306      1.1  christos #ifdef HAVE_ST_MTIM_TV_SEC
    307      1.1  christos       secs = buff.st_mtim.tv_sec;
    308      1.1  christos #else
    309      1.1  christos       secs = buff.st_mtime;
    310      1.1  christos #endif
    311      1.1  christos 
    312      1.1  christos #ifdef HAVE_ST_MTIM_TV_NSEC
    313      1.1  christos       nsecs = buff.st_mtim.tv_nsec;
    314      1.1  christos #else
    315      1.1  christos       nsecs = 0;
    316      1.1  christos #endif
    317      1.1  christos 
    318      1.1  christos       /* VMS timestamps are stored in local time to 100 nsec accuracy, but by
    319      1.1  christos 	 experiment I found timestamps truncated to (at least) microseconds
    320      1.1  christos 	 on an NFS mounted filesystem, hence the adjustment below. DBR. */
    321      1.1  christos       *cdt = ((secs + gmtoff) * VMS_GRANULARITY_FACTOR)
    322      1.1  christos 	+ (nsecs / 1000 * 10) + VMS_EPOCH_OFFSET;
    323      1.1  christos     }
    324      1.1  christos 
    325      1.1  christos   if (siz)
    326      1.1  christos     *siz = buff.st_size;
    327      1.1  christos 
    328      1.1  christos   if (rfo)
    329      1.1  christos     *rfo = 2; /* Stream LF format.  */
    330      1.1  christos 
    331      1.1  christos   /* Returning a file version of 0 is never correct for debug info, version 1
    332      1.1  christos      will be correct if file editing is done only on the Unix side.  If editing
    333      1.1  christos      is done on the VMS side, then its TBD.  */
    334      1.1  christos   if (ver)
    335      1.1  christos     *ver = 1;
    336      1.1  christos #endif /* VMS */
    337      1.1  christos 
    338  1.1.1.3  christos   free (fullname);
    339      1.1  christos   return 0;
    340      1.1  christos }
    341      1.1  christos 
    342  1.1.1.6  christos uint64_t
    343      1.1  christos vms_dwarf2_file_time_name (const char *filename, const char *dirname)
    344      1.1  christos {
    345      1.1  christos   long long cdt;
    346      1.1  christos 
    347      1.1  christos   if (vms_file_stats_name (dirname, filename, &cdt, 0, 0, 0) == 0)
    348      1.1  christos     return cdt;
    349      1.1  christos   else
    350      1.1  christos     return 0;
    351      1.1  christos }
    352      1.1  christos 
    353      1.1  christos long
    354      1.1  christos vms_dwarf2_file_size_name (const char *filename, const char *dirname)
    355      1.1  christos {
    356      1.1  christos   long siz;
    357      1.1  christos 
    358      1.1  christos   if (vms_file_stats_name (dirname, filename, 0, &siz, 0, 0) == 0)
    359      1.1  christos     return siz;
    360      1.1  christos   else
    361      1.1  christos     return 0;
    362      1.1  christos }
    363      1.1  christos 
    364      1.1  christos /* VMS debugger needs the filename with version appended.  */
    365      1.1  christos /* Longest filename on VMS is 255 characters. Largest version is 32768.  */
    366      1.1  christos char *
    367      1.1  christos vms_dwarf2_file_name (const char *filename, const char *dirname)
    368      1.1  christos {
    369      1.1  christos   int ver;
    370      1.1  christos   static char buff [255 + 7];
    371      1.1  christos 
    372      1.1  christos   vms_file_stats_name (dirname, filename, 0, 0, 0, &ver);
    373  1.1.1.2  christos   snprintf (buff, 255 + 7, "%s;%d", filename, ver);
    374      1.1  christos   return buff;
    375      1.1  christos }
    376