1 /*
2 * Copyright 2018, University Corporation for Atmospheric Research
3 * See top level COPYRIGHT file for copying and redistribution conditions.
4 */
5 /* $Id: t_ncio.c,v 1.10 2010/05/26 11:11:26 ed Exp $ */
6
7 #if HAVE_CONFIG_H
8 #include <config.h>
9 #endif
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <ctype.h>
15 #include <assert.h>
16 #include "ncio.h"
17 #ifndef NC_NOERR
18 #define NC_NOERR 0
19 #endif
20
21
22 static void
usage(const char * av0)23 usage(const char *av0)
24 {
25 (void)fprintf(stderr,
26 "Usage: %s [options] fname\t\nOptions:\n", av0);
27 (void)fprintf(stderr,
28 "\t-v Verbose\n") ;
29 (void)fprintf(stderr,
30 "\t-w Open Read/Write, default is read only\n") ;
31 (void)fprintf(stderr,
32 "\t-c Create, clobber existing\n") ;
33 (void)fprintf(stderr,
34 "\t-n Create, error if it already exists\n") ;
35 (void)fprintf(stderr,
36 "\t-L Use locking if available\n") ;
37 (void)fprintf(stderr,
38 "\t-S Share updates (turn off caching)\n") ;
39 (void)fprintf(stderr,
40 "\t-U Delete (unlink) on close\n") ;
41 (void)fprintf(stderr,
42 "\t-o igeto Initial get offset\n") ;
43 (void)fprintf(stderr,
44 "\t-i igetsz Initial get size\n") ;
45 (void)fprintf(stderr,
46 "\t-I initialsz Initial file size for create\n") ;
47 (void)fprintf(stderr,
48 "\t-s sizehint Buffer size\n") ;
49 exit(EXIT_FAILURE);
50 }
51
52
53 static long
argscale(const char * arg,const char * tag)54 argscale(const char *arg, const char *tag)
55 {
56 long value = 0;
57 /* last character */
58 const char *cp = arg + strlen(arg) -1;
59 value = atol(arg);
60 if(isalpha(*cp))
61 {
62 switch(*cp) {
63 case 'k':
64 case 'K':
65 value *= 1024;
66 break;
67 case 'm':
68 case 'M':
69 value *= (1024*1024);
70 break;
71 default:
72 value = 0; /* trigger error below */
73 break;
74 }
75 }
76 if(value == 0)
77 {
78 fprintf(stderr,
79 "Illegal %s \"%s\", ignored\n", tag, arg);
80 }
81 return value;
82 }
83
84
85 static void
modify_ex(off_t offset,size_t extent,void * vp)86 modify_ex(off_t offset, size_t extent, void *vp)
87 {
88 unsigned char *obuf = vp;
89 const unsigned char *const end = &obuf[extent];
90 unsigned char *cp = obuf;
91
92 if(cp >= end) return;
93 *cp++ = (unsigned char)( offset >> 24);
94 if(cp >= end) return;
95 *cp++ = (unsigned char)((offset & 0x00ff0000) >> 16);
96 if(cp >= end) return;
97 *cp++ = (unsigned char)((offset & 0x0000ff00) >> 8);
98 if(cp >= end) return;
99 *cp++ = (unsigned char)( offset & 0x000000ff);
100 if(cp >= end) return;
101 *cp++ = (unsigned char)( extent >> 24);
102 if(cp >= end) return;
103 *cp++ = (unsigned char)((extent & 0x00ff0000) >> 16);
104 if(cp >= end) return;
105 *cp++ = (unsigned char)((extent & 0x0000ff00) >> 8);
106 if(cp >= end) return;
107 *cp++ = (unsigned char)( extent & 0x000000ff);
108
109 while(cp < end)
110 {
111 *cp++ = (unsigned char) (cp - obuf);
112 }
113 }
114
115
116 typedef struct riu {
117 struct riu *next;
118 struct riu *prev;
119 off_t offset;
120 size_t extent;
121 void *vp;
122 } riu;
123
124 static void
free_riu(riu * riup)125 free_riu(riu *riup)
126 {
127 if(riup == NULL)
128 return;
129 free(riup);
130 }
131
132 static riu *
new_riu(off_t offset,size_t extent,void * vp)133 new_riu(off_t offset, size_t extent, void *vp)
134 {
135 riu *riup = (riu *)malloc(sizeof(riu));
136 if(riup == NULL)
137 {
138 fprintf(stderr,
139 "new_riu: malloc failed\n");
140 exit(EXIT_FAILURE);
141 }
142 riup->next = NULL;
143 riup->prev = NULL;
144 riup->offset = offset;
145 riup->extent = extent;
146 riup->vp = vp;
147 return riup;
148 }
149
150 static riu *stack = NULL;
151
152 static void
riu_push(off_t offset,size_t extent,void * vp)153 riu_push(off_t offset, size_t extent, void *vp)
154 {
155 riu *riup = new_riu(offset, extent, vp);
156 /* assert(riup != NULL); */
157 riup->next = stack;
158 if(stack != NULL)
159 stack->prev = riup;
160 stack = riup;
161 }
162
163 static int
riu_pop(off_t offset,int modify)164 riu_pop(off_t offset, int modify)
165 {
166 riu *riup = stack;
167 while(riup != NULL)
168 {
169 if(riup->offset == offset)
170 {
171 if(modify)
172 {
173 modify_ex(riup->offset, riup->extent, riup->vp);
174 }
175 if(riup->next != NULL)
176 {
177 riup->next->prev = riup->prev;
178 }
179 if(riup == stack)
180 {
181 stack = riup->next;
182 }
183 else
184 {
185 assert(riup->prev != NULL);
186 riup->prev->next = riup->next;
187 }
188 free_riu(riup);
189 return 1;
190 }
191 riup = riup->next;
192 }
193 /* else, not found */
194 return 0;
195 }
196
main(int ac,char * av[])197 main(int ac, char *av[])
198 {
199 char *path = "";
200 ncio *nciop;
201 char linebuf[128];
202 off_t offset;
203 size_t extent;
204 void *vp;
205 int status = NC_NOERR;
206 int verbose = 0;
207 int flags = 0;
208 int create = 0;
209 off_t igeto = 0;
210 size_t igetsz = 0;
211 size_t initialsz = 0;
212 int doUnlink = 0;
213 size_t sizehint = NC_SIZEHINT_DEFAULT;
214
215 {
216 extern int optind;
217 extern int opterr;
218 extern char *optarg;
219 int ch;
220
221 opterr = 1;
222
223 while ((ch = getopt(ac, av, "vwcnLSUo:i:I:s:")) != EOF)
224 switch (ch) {
225 case 'v':
226 verbose = 1;
227 break;
228 case 'w':
229 flags |= NC_WRITE;
230 break;
231 case 'c':
232 create = 1;
233 break;
234 case 'n':
235 create = 1;
236 flags |= NC_NOCLOBBER;
237 break;
238 case 'L':
239 flags |= NC_LOCK;
240 break;
241 case 'S':
242 flags |= NC_SHARE;
243 break;
244 case 'U':
245 doUnlink = 1;
246 break;
247 case 'o':
248 igeto = argscale(optarg, "igeto");
249 break;
250 case 'i':
251 igetsz = argscale(optarg, "igetsz");
252 break;
253 case 'I':
254 initialsz = argscale(optarg, "initialsz");
255 break;
256 case 's':
257 sizehint = argscale(optarg, "sizehint");
258 break;
259 case '?':
260 usage(av[0]);
261 break;
262 }
263
264 /* last arg, the file name, is required */
265 if(ac - optind <= 0)
266 usage(av[0]) ;
267 path = av[optind];
268
269
270 }
271
272 if(!create)
273 {
274 status = ncio_open(path, flags,
275 igeto, igetsz, &sizehint,
276 &nciop, &vp);
277 if(status != NC_NOERR)
278 {
279 fprintf(stderr, "ncio_open: %s: %s\n",
280 path, strerror(status));
281 return(EXIT_FAILURE);
282 }
283 } else {
284 status = ncio_create(path, flags, initialsz,
285 igeto, igetsz, &sizehint,
286 &nciop, &vp);
287 if(status != NC_NOERR)
288 {
289 fprintf(stderr, "ncio_create: %s: %s\n",
290 path, strerror(status));
291 return(EXIT_FAILURE);
292 }
293 }
294
295 while(fgets(linebuf, sizeof(linebuf), stdin) != NULL)
296 {
297 offset = 0;
298 extent = 0;
299
300 if(*linebuf == '#')
301 continue; /* comment */
302 if(sscanf(linebuf, "rel 0x%lx", &offset) == 1
303 || sscanf(linebuf, "rel %ld", &offset) == 1)
304 {
305 if(verbose)
306 printf("- rel %8ld\n", offset);
307 if(!riu_pop(offset, 0))
308 continue;
309 status = nciop->rel(nciop, offset, 0);
310 if(status)
311 {
312 fprintf(stderr, "- rel error: %s\n",
313 strerror(status));
314 continue;
315 }
316 }
317 else if(sscanf(linebuf, "relm 0x%lx", &offset) == 1
318 || sscanf(linebuf, "relm %ld", &offset) == 1)
319 {
320 if(verbose)
321 printf("- relm %8ld\n", offset);
322 if(!riu_pop(offset, 1))
323 continue;
324 status = nciop->rel(nciop, offset, RGN_MODIFIED);
325 if(status)
326 {
327 fprintf(stderr, "- relm %8ld error: %s\n",
328 offset, strerror(status));
329 continue;
330 }
331 }
332 else if(sscanf(linebuf, "get 0x%lx %ld", &offset, &extent) == 2
333 || sscanf(linebuf, "get %ld %ld", &offset, &extent) == 2)
334 {
335 if(verbose)
336 printf("- get %10ld %8ld\n", offset, extent);
337 status = nciop->get(nciop, offset, extent, 0, &vp);
338 if(status)
339 {
340 fprintf(stderr, "- get error: %s\n",
341 strerror(status));
342 continue;
343 }
344 riu_push(offset, extent, vp);
345 }
346 else if(sscanf(linebuf, "getw 0x%lx %ld", &offset, &extent) == 2
347 || sscanf(linebuf, "getw %ld %ld", &offset, &extent) == 2)
348 {
349 if(verbose)
350 printf("- getw %10ld %8ld\n", offset, extent);
351 status = nciop->get(nciop, offset, extent, RGN_WRITE, &vp);
352 if(status)
353 {
354 fprintf(stderr, "- getw error: %s\n",
355 strerror(status));
356 continue;
357 }
358 riu_push(offset, extent, vp);
359 }
360 else if(strchr(linebuf, 'q') != NULL)
361 break;
362 else
363 printf("???\n");
364 }
365
366 status = ncio_close(nciop, doUnlink);
367 if(status != NC_NOERR)
368 {
369 fprintf(stderr, "ncio_close(%s): %s: %s\n",
370 doUnlink ? "doUnlink" : "",
371 path, strerror(status));
372 return(EXIT_FAILURE);
373 }
374
375 return(EXIT_SUCCESS);
376 }
377