Home | History | Annotate | Line # | Download | only in config
te-vms.c revision 1.1.1.2
      1      1.1  christos /* te-vms.c -- Utilities for VMS.
      2  1.1.1.2  christos    Copyright (C) 2009-2015 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  christos /* The purspose 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  christos   char fullname[strlen (dirname) + strlen (filename) + 1];
    119      1.1  christos #ifdef VMS
    120      1.1  christos   struct FAB fab;
    121      1.1  christos   struct NAM nam;
    122      1.1  christos 
    123      1.1  christos   unsigned long long create;
    124      1.1  christos   FAT recattr;
    125      1.1  christos   char ascnamebuff [256];
    126      1.1  christos 
    127      1.1  christos   ATRDEF atrlst[]
    128      1.1  christos     = {
    129      1.1  christos       { ATR$S_CREDATE,  ATR$C_CREDATE,  &create },
    130      1.1  christos       { ATR$S_RECATTR,  ATR$C_RECATTR,  &recattr },
    131      1.1  christos       { ATR$S_ASCNAME,  ATR$C_ASCNAME,  &ascnamebuff },
    132      1.1  christos       { 0, 0, 0}
    133      1.1  christos     };
    134      1.1  christos 
    135      1.1  christos   FIBDEF fib;
    136      1.1  christos   struct dsc$descriptor_fib fibdsc = {sizeof (fib), (void *) &fib};
    137      1.1  christos 
    138      1.1  christos   struct IOSB iosb;
    139      1.1  christos 
    140      1.1  christos   long status;
    141      1.1  christos   unsigned short chan;
    142      1.1  christos 
    143      1.1  christos   struct vstring file;
    144      1.1  christos   struct dsc$descriptor_s filedsc
    145      1.1  christos     = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) file.string};
    146      1.1  christos   struct vstring device;
    147      1.1  christos   struct dsc$descriptor_s devicedsc
    148      1.1  christos     = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) device.string};
    149      1.1  christos   struct vstring result;
    150      1.1  christos   struct dsc$descriptor_s resultdsc
    151      1.1  christos     = {NAM$C_MAXRSS, DSC$K_DTYPE_VT, DSC$K_CLASS_VS, (void *) result.string};
    152      1.1  christos 
    153      1.1  christos   if (strcmp (filename, "<internal>") == 0
    154      1.1  christos       || strcmp (filename, "<built-in>") == 0)
    155      1.1  christos     {
    156      1.1  christos       if (cdt)
    157      1.1  christos 	*cdt = 0;
    158      1.1  christos 
    159      1.1  christos       if (siz)
    160      1.1  christos 	*siz = 0;
    161      1.1  christos 
    162      1.1  christos       if (rfo)
    163      1.1  christos 	*rfo = 0;
    164      1.1  christos 
    165      1.1  christos       if (ver)
    166      1.1  christos         *ver = 0;
    167      1.1  christos 
    168      1.1  christos       return 0;
    169      1.1  christos     }
    170      1.1  christos 
    171      1.1  christos   strcpy (fullname, dirname);
    172      1.1  christos   strcat (fullname, filename);
    173      1.1  christos 
    174      1.1  christos   tryfile = to_vms_file_spec (fullname);
    175      1.1  christos 
    176      1.1  christos   /* Allocate and initialize a FAB and NAM structures.  */
    177      1.1  christos   fab = cc$rms_fab;
    178      1.1  christos   nam = cc$rms_nam;
    179      1.1  christos 
    180      1.1  christos   nam.nam$l_esa = file.string;
    181      1.1  christos   nam.nam$b_ess = NAM$C_MAXRSS;
    182      1.1  christos   nam.nam$l_rsa = result.string;
    183      1.1  christos   nam.nam$b_rss = NAM$C_MAXRSS;
    184      1.1  christos   fab.fab$l_fna = tryfile;
    185      1.1  christos   fab.fab$b_fns = strlen (tryfile);
    186      1.1  christos   fab.fab$l_nam = &nam;
    187      1.1  christos 
    188      1.1  christos   /* Validate filespec syntax and device existence.  */
    189      1.1  christos   status = SYS$PARSE (&fab, 0, 0);
    190      1.1  christos   if ((status & 1) != 1)
    191      1.1  christos     return 1;
    192      1.1  christos 
    193      1.1  christos   file.string[nam.nam$b_esl] = 0;
    194      1.1  christos 
    195      1.1  christos   /* Find matching filespec.  */
    196      1.1  christos   status = SYS$SEARCH (&fab, 0, 0);
    197      1.1  christos   if ((status & 1) != 1)
    198      1.1  christos     return 1;
    199      1.1  christos 
    200      1.1  christos   file.string[nam.nam$b_esl] = 0;
    201      1.1  christos   result.string[result.length=nam.nam$b_rsl] = 0;
    202      1.1  christos 
    203      1.1  christos   /* Get the device name and assign an IO channel.  */
    204      1.1  christos   strncpy (device.string, nam.nam$l_dev, nam.nam$b_dev);
    205      1.1  christos   devicedsc.dsc$w_length  = nam.nam$b_dev;
    206      1.1  christos   chan = 0;
    207      1.1  christos   status = SYS$ASSIGN (&devicedsc, &chan, 0, 0, 0);
    208      1.1  christos   if ((status & 1) != 1)
    209      1.1  christos     return 1;
    210      1.1  christos 
    211      1.1  christos   /* Initialize the FIB and fill in the directory id field.  */
    212      1.1  christos   memset (&fib, 0, sizeof (fib));
    213      1.1  christos   fib.fib$w_did[0]  = nam.nam$w_did[0];
    214      1.1  christos   fib.fib$w_did[1]  = nam.nam$w_did[1];
    215      1.1  christos   fib.fib$w_did[2]  = nam.nam$w_did[2];
    216      1.1  christos   fib.fib$l_acctl = 0;
    217      1.1  christos   fib.fib$l_wcc = 0;
    218      1.1  christos   strcpy (file.string, (strrchr (result.string, ']') + 1));
    219      1.1  christos   filedsc.dsc$w_length = strlen (file.string);
    220      1.1  christos   result.string[result.length = 0] = 0;
    221      1.1  christos 
    222      1.1  christos   /* Open and close the file to fill in the attributes.  */
    223      1.1  christos   status
    224      1.1  christos     = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
    225      1.1  christos 		&fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
    226      1.1  christos   if ((status & 1) != 1)
    227      1.1  christos     return 1;
    228      1.1  christos   if ((iosb.status & 1) != 1)
    229      1.1  christos     return 1;
    230      1.1  christos 
    231      1.1  christos   result.string[result.length] = 0;
    232      1.1  christos   status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0, &fibdsc, 0, 0, 0,
    233      1.1  christos 		     &atrlst, 0);
    234      1.1  christos   if ((status & 1) != 1)
    235      1.1  christos     return 1;
    236      1.1  christos   if ((iosb.status & 1) != 1)
    237      1.1  christos     return 1;
    238      1.1  christos 
    239      1.1  christos   /* Deassign the channel and exit.  */
    240      1.1  christos   status = SYS$DASSGN (chan);
    241      1.1  christos   if ((status & 1) != 1)
    242      1.1  christos     return 1;
    243      1.1  christos 
    244      1.1  christos   if (cdt) *cdt = create;
    245      1.1  christos   if (siz) *siz = (512 * 65536 * recattr.fat$w_efblkh) +
    246      1.1  christos                   (512 * (recattr.fat$w_efblkl - 1)) +
    247      1.1  christos                   recattr.fat$w_ffbyte;
    248      1.1  christos   if (rfo) *rfo = recattr.fat$v_rtype;
    249      1.1  christos   if (ver) *ver = strtol (strrchr (ascnamebuff, ';') + 1, 0, 10);
    250      1.1  christos #else /* not VMS */
    251      1.1  christos 
    252      1.1  christos   struct stat buff;
    253      1.1  christos   struct tm *ts;
    254      1.1  christos   long long gmtoff, secs, nsecs;
    255      1.1  christos 
    256      1.1  christos   strcpy (fullname, dirname);
    257      1.1  christos   strcat (fullname, filename);
    258      1.1  christos 
    259      1.1  christos   if ((stat (fullname, &buff)) != 0)
    260      1.1  christos      return 1;
    261      1.1  christos 
    262      1.1  christos   if (cdt)
    263      1.1  christos     {
    264      1.1  christos       ts = localtime (& buff.st_mtime);
    265      1.1  christos 
    266      1.1  christos #ifdef HAVE_TM_GMTOFF
    267      1.1  christos 	gmtoff = ts->tm_gmtoff;
    268      1.1  christos #else
    269      1.1  christos 	{
    270      1.1  christos 	  extern long timezone;
    271      1.1  christos 
    272      1.1  christos 	  if (ts->tm_isdst == 1)
    273      1.1  christos 	    gmtoff = - (timezone - 3600);
    274      1.1  christos 	  else
    275      1.1  christos 	    gmtoff = - timezone;
    276      1.1  christos 	}
    277      1.1  christos #endif
    278      1.1  christos 
    279      1.1  christos #ifdef HAVE_ST_MTIM_TV_SEC
    280      1.1  christos       secs = buff.st_mtim.tv_sec;
    281      1.1  christos #else
    282      1.1  christos       secs = buff.st_mtime;
    283      1.1  christos #endif
    284      1.1  christos 
    285      1.1  christos #ifdef HAVE_ST_MTIM_TV_NSEC
    286      1.1  christos       nsecs = buff.st_mtim.tv_nsec;
    287      1.1  christos #else
    288      1.1  christos       nsecs = 0;
    289      1.1  christos #endif
    290      1.1  christos 
    291      1.1  christos       /* VMS timestamps are stored in local time to 100 nsec accuracy, but by
    292      1.1  christos 	 experiment I found timestamps truncated to (at least) microseconds
    293      1.1  christos 	 on an NFS mounted filesystem, hence the adjustment below. DBR. */
    294      1.1  christos       *cdt = ((secs + gmtoff) * VMS_GRANULARITY_FACTOR)
    295      1.1  christos 	+ (nsecs / 1000 * 10) + VMS_EPOCH_OFFSET;
    296      1.1  christos     }
    297      1.1  christos 
    298      1.1  christos   if (siz)
    299      1.1  christos     *siz = buff.st_size;
    300      1.1  christos 
    301      1.1  christos   if (rfo)
    302      1.1  christos     *rfo = 2; /* Stream LF format.  */
    303      1.1  christos 
    304      1.1  christos   /* Returning a file version of 0 is never correct for debug info, version 1
    305      1.1  christos      will be correct if file editing is done only on the Unix side.  If editing
    306      1.1  christos      is done on the VMS side, then its TBD.  */
    307      1.1  christos   if (ver)
    308      1.1  christos     *ver = 1;
    309      1.1  christos #endif /* VMS */
    310      1.1  christos 
    311      1.1  christos   return 0;
    312      1.1  christos }
    313      1.1  christos 
    314      1.1  christos bfd_uint64_t
    315      1.1  christos vms_dwarf2_file_time_name (const char *filename, const char *dirname)
    316      1.1  christos {
    317      1.1  christos   long long cdt;
    318      1.1  christos 
    319      1.1  christos   if (vms_file_stats_name (dirname, filename, &cdt, 0, 0, 0) == 0)
    320      1.1  christos     return cdt;
    321      1.1  christos   else
    322      1.1  christos     return 0;
    323      1.1  christos }
    324      1.1  christos 
    325      1.1  christos long
    326      1.1  christos vms_dwarf2_file_size_name (const char *filename, const char *dirname)
    327      1.1  christos {
    328      1.1  christos   long siz;
    329      1.1  christos 
    330      1.1  christos   if (vms_file_stats_name (dirname, filename, 0, &siz, 0, 0) == 0)
    331      1.1  christos     return siz;
    332      1.1  christos   else
    333      1.1  christos     return 0;
    334      1.1  christos }
    335      1.1  christos 
    336      1.1  christos /* VMS debugger needs the filename with version appended.  */
    337      1.1  christos /* Longest filename on VMS is 255 characters. Largest version is 32768.  */
    338      1.1  christos char *
    339      1.1  christos vms_dwarf2_file_name (const char *filename, const char *dirname)
    340      1.1  christos {
    341      1.1  christos   int ver;
    342      1.1  christos   static char buff [255 + 7];
    343      1.1  christos 
    344      1.1  christos   vms_file_stats_name (dirname, filename, 0, 0, 0, &ver);
    345  1.1.1.2  christos   snprintf (buff, 255 + 7, "%s;%d", filename, ver);
    346      1.1  christos   return buff;
    347      1.1  christos }
    348