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