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