1 1.1 christos /* te-vms.c -- Utilities for VMS. 2 1.1.1.9 christos Copyright (C) 2009-2026 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