te-vms.c revision 1.8 1 1.1 christos /* te-vms.c -- Utilities for VMS.
2 1.8 christos Copyright (C) 2009-2022 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.6 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.5 christos char * fullname;
119 1.5 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.5 christos fullname = concat (dirname, filename, 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.5 christos {
191 1.5 christos free (fullname);
192 1.5 christos return 1;
193 1.5 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.5 christos {
201 1.5 christos free (fullname);
202 1.5 christos return 1;
203 1.5 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.5 christos {
215 1.5 christos free (fullname);
216 1.5 christos return 1;
217 1.5 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.5 christos {
236 1.5 christos free (fullname);
237 1.5 christos return 1;
238 1.5 christos }
239 1.5 christos
240 1.1 christos if ((iosb.status & 1) != 1)
241 1.5 christos {
242 1.5 christos free (fullname);
243 1.5 christos return 1;
244 1.5 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.5 christos {
251 1.5 christos free (fullname);
252 1.5 christos return 1;
253 1.5 christos }
254 1.5 christos
255 1.1 christos if ((iosb.status & 1) != 1)
256 1.5 christos {
257 1.5 christos free (fullname);
258 1.5 christos return 1;
259 1.5 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.5 christos {
265 1.5 christos free (fullname);
266 1.5 christos return 1;
267 1.5 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.5 christos fullname = concat (dirname, filename, NULL);
282 1.1 christos
283 1.1 christos if ((stat (fullname, &buff)) != 0)
284 1.5 christos {
285 1.5 christos free (fullname);
286 1.5 christos return 1;
287 1.5 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.5 christos free (fullname);
339 1.1 christos return 0;
340 1.1 christos }
341 1.1 christos
342 1.8 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.3 christos snprintf (buff, 255 + 7, "%s;%d", filename, ver);
374 1.1 christos return buff;
375 1.1 christos }
376