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