1 /* HETUPD.C (c) Copyright Leland Lucius, 2000-2009 */
2 /* Update/Copy Hercules Emulated Tape */
3
4 /*
5 || ----------------------------------------------------------------------------
6 ||
7 || HETUPD.C (c) Copyright Leland Lucius, 2000-2009
8 || Released under terms of the Q Public License.
9 ||
10 || Copy/update Hercules Emulated Tapes while allowing various modifications
11 || like enabling/disabling compression, changing compression method/level, and
12 || internal chunk size.
13 ||
14 || ----------------------------------------------------------------------------
15 */
16
17 #include "hstdinc.h"
18
19 #include "hercules.h"
20 #include "hetlib.h"
21 #include "sllib.h"
22 #include "herc_getopt.h"
23
24 /*
25 || Local volatile data
26 */
27 static int o_chunksize = HETDFLT_CHKSIZE;
28 static int o_decompress = HETDFLT_DECOMPRESS;
29 static int o_compress = HETDFLT_COMPRESS;
30 static int o_level = HETDFLT_LEVEL;
31 static int o_method = HETDFLT_METHOD;
32 static int o_verbose = FALSE;
33 static char *o_sname = NULL;
34 static char *o_dname = NULL;
35 static int dorename = FALSE;
36 static HETB *s_hetb = NULL;
37 static HETB *d_hetb = NULL;
38 #ifdef EXTERNALGUI
39 /* Previous reported file position */
40 static off_t prevpos = 0;
41 /* Report progress every this many bytes */
42 #define PROGRESS_MASK (~0x3FFFF /* 256K */)
43 #endif /*EXTERNALGUI*/
44
45 /*
46 || Local constant data
47 */
48 static const char help[] =
49 "%s - Updates the compression of a Hercules Emulated Tape file.\n\n"
50 "Usage: %s [options] source [dest]\n\n"
51 "Options:\n"
52 " -1 compress fast\n"
53 " ...\n"
54 " -9 compress best\n"
55 #if defined( HET_BZIP2 )
56 " -b use BZLIB compression\n"
57 #endif /* defined( HET_BZIP2 ) */
58 " -c n set chunk size to \"n\"\n"
59 " -d decompress source tape\n"
60 " -h display usage summary\n"
61 " -r rechucnk\n"
62 " -s strict AWSTAPE specification (chunksize=4096,no compression)\n"
63 " -v verbose information\n"
64 " -z use ZLIB compression\n";
65
66 /*
67 || Prints usage information
68 */
69 static void
usage(char * name)70 usage( char *name )
71 {
72 printf( help, name, name );
73 }
74
75 /*
76 || Supply "Yes" or "No"
77 */
78 static const char *
yesno(int val)79 yesno( int val )
80 {
81 return( ( val ? "Yes" : "No" ) );
82 }
83
84 /*
85 || Close tapes and cleanup
86 */
87 static void
closetapes(int rc)88 closetapes( int rc )
89 {
90
91 het_close( &d_hetb );
92 het_close( &s_hetb );
93
94 if( dorename )
95 {
96 if( rc >= 0 )
97 {
98 rc = rename( o_dname, o_sname );
99 }
100 else
101 {
102 rc = remove( o_dname );
103 }
104 if( rc == -1 )
105 {
106 printf( "Error renaming files - manual checks required\n");
107 }
108 }
109
110 return;
111 }
112
113 /*
114 || Copy source to dest
115 */
116 static int
copytape(void)117 copytape( void )
118 {
119 int rc;
120 char buf[ HETMAX_BLOCKSIZE ];
121
122 while( TRUE )
123 {
124 #ifdef EXTERNALGUI
125 if( extgui )
126 {
127 /* Report progress every nnnK */
128 off_t curpos = ftell( s_hetb->fd );
129 if( ( curpos & PROGRESS_MASK ) != ( prevpos & PROGRESS_MASK ) )
130 {
131 prevpos = curpos;
132 fprintf( stderr, "IPOS=%" I64_FMT "d\n", (U64)curpos );
133 }
134 }
135 #endif /*EXTERNALGUI*/
136
137 rc = het_read( s_hetb, buf );
138 if( rc == HETE_EOT )
139 {
140 rc = 0;
141 break;
142 }
143
144 if( rc == HETE_TAPEMARK )
145 {
146 rc = het_tapemark( d_hetb );
147 if( rc < 0 )
148 {
149 printf( "Error writing tapemark - rc: %d\n", rc );
150 break;
151 }
152 continue;
153 }
154
155 if( rc < 0 )
156 {
157 printf( "het_read() returned %d\n", rc );
158 break;
159 }
160
161 rc = het_write( d_hetb, buf, rc );
162 if( rc < 0 )
163 {
164 printf( "het_write() returned %d\n", rc );
165 break;
166 }
167 }
168
169 return( rc );
170 }
171
172 /*
173 || Open HET tapes and set options
174 */
175 static int
opentapes(void)176 opentapes( void )
177 {
178 int rc;
179
180 rc = het_open( &s_hetb, o_sname, 0 );
181 if( rc < 0 )
182 {
183 goto exit;
184 }
185
186 rc = het_open( &d_hetb, o_dname, HETOPEN_CREATE );
187 if( rc < 0 )
188 {
189 goto exit;
190 }
191
192 rc = het_cntl( s_hetb, HETCNTL_SET | HETCNTL_DECOMPRESS, o_decompress );
193 if( rc < 0 )
194 {
195 goto exit;
196 }
197
198 rc = het_cntl( d_hetb, HETCNTL_SET | HETCNTL_COMPRESS, o_compress );
199 if( rc < 0 )
200 {
201 goto exit;
202 }
203
204 rc = het_cntl( d_hetb, HETCNTL_SET | HETCNTL_METHOD, o_method );
205 if( rc < 0 )
206 {
207 goto exit;
208 }
209
210 rc = het_cntl( d_hetb, HETCNTL_SET | HETCNTL_LEVEL, o_level );
211 if( rc < 0 )
212 {
213 goto exit;
214 }
215
216 rc = het_cntl( d_hetb, HETCNTL_SET | HETCNTL_CHUNKSIZE, o_chunksize );
217 if( rc < 0 )
218 {
219 goto exit;
220 }
221
222 if( o_verbose )
223 {
224 printf( "Source : %s\n",
225 o_sname );
226 printf( "Destination : %s\n",
227 o_dname );
228 printf( "Decompress source : %s\n",
229 yesno( het_cntl( s_hetb, HETCNTL_DECOMPRESS, 0 ) ) );
230 printf( "Compress dest : %s\n",
231 yesno( het_cntl( d_hetb, HETCNTL_COMPRESS, 0 ) ) );
232 printf( "Compression method : %d\n",
233 het_cntl( d_hetb, HETCNTL_METHOD, 0 ) );
234 printf( "Compression level : %d\n",
235 het_cntl( d_hetb, HETCNTL_LEVEL, 0 ) );
236 }
237
238 exit:
239
240 if( rc < 0 )
241 {
242 het_close( &d_hetb );
243 het_close( &s_hetb );
244 }
245
246 return( rc );
247 }
248
249 /*
250 || Standard main
251 */
252 int
main(int argc,char * argv[])253 main( int argc, char *argv[] )
254 {
255 char toname[ PATH_MAX ];
256 HETB *s_hetb;
257 HETB *d_hetb;
258 int rc;
259
260 INITIALIZE_UTILITY("hetupd");
261
262 s_hetb = NULL;
263 d_hetb = NULL;
264
265 /* Display the program identification message */
266 display_version (stderr, "Hercules HET copy/update program ", FALSE);
267
268 while( TRUE )
269 {
270 #if defined( HET_BZIP2 )
271 rc = getopt( argc, argv, "bc:dhrsvz0123456789" );
272 #else
273 rc = getopt( argc, argv, "c:dhrsvz0123456789" );
274 #endif /* defined( HET_BZIP2 ) */
275 if( rc == -1 )
276 {
277 break;
278 }
279
280 switch( rc )
281 {
282 case '1': case '2': case '3': case '4': /* Compression level */
283 case '5': case '6': case '7': case '8':
284 case '9':
285 o_level = ( rc - '0' );
286 break;
287
288 #if defined( HET_BZIP2 )
289 case 'b': /* Use BZLIB compression */
290 o_method = HETMETH_BZLIB;
291 o_compress = TRUE;
292 o_decompress = TRUE;
293 break;
294 #endif /* defined( HET_BZIP2 ) */
295
296 case 'c': /* Chunk size */
297 o_chunksize = atoi( optarg );
298 break;
299
300 case 'd': /* Decompress */
301 o_compress = FALSE;
302 o_decompress = TRUE;
303 break;
304
305 case 'h': /* Print usage */
306 usage( argv[ 0 ] );
307 exit( 1 );
308 break;
309
310 case 'r': /* Rechunk */
311 o_compress = FALSE;
312 o_decompress = FALSE;
313 break;
314
315 case 's': /* Strict HET spec */
316 o_chunksize = 4096;
317 o_compress = FALSE;
318 o_decompress = TRUE;
319 break;
320
321 case 'v': /* Be chatty */
322 o_verbose = TRUE;
323 break;
324
325 case 'z': /* Use ZLIB compression */
326 o_method = HETMETH_ZLIB;
327 o_compress = TRUE;
328 o_decompress = TRUE;
329 break;
330
331 default: /* Print usage */
332 usage( argv[ 0 ] );
333 exit( 1 );
334 break;
335 }
336 }
337
338 argc -= optind;
339
340 switch( argc )
341 {
342 case 1:
343 sprintf( toname, "%s.%010d", argv[ optind ], rand() );
344 o_dname = toname;
345 dorename = TRUE;
346 break;
347
348 case 2:
349 o_dname = argv[ optind + 1 ];
350 break;
351
352 default:
353 usage( argv[ 0 ] );
354 exit( 1 );
355 break;
356 }
357 o_sname = argv[ optind ] ;
358
359 rc = opentapes();
360 if( rc < 0 )
361 {
362 printf( "Error opening files - HETLIB rc: %d\n%s\n",
363 rc,
364 het_error( rc ) );
365 exit( 1 );
366 }
367
368 rc = copytape();
369 if( rc < 0 )
370 {
371 printf( "Error copying files - HETLIB rc: %d\n%s\n",
372 rc,
373 het_error( rc ) );
374 exit( 1 );
375 }
376
377 closetapes( rc );
378
379 return 0;
380 }
381