1 /*
2 Copyright (C) 2015-2021, Dirk Krause
3 SPDX-License-Identifier: BSD-3-Clause
4 */
5 
6 /*
7 	WARNING: This file was generated by the dkct program (see
8 	http://dktools.sourceforge.net/ for details).
9 	Changes you make here will be lost if dkct is run again!
10 	You should modify the original source and run dkct on it.
11 	Original source: dk-blks.ctr
12 */
13 
14 
15 /**	@file	dk-blks.c	The dk-blks program.
16 	the help_text array below shows details.
17 */
18 
19 
20 
21 #include "dk4conf.h"
22 
23 #include <stdio.h>
24 #if DK4_HAVE_STDLIB_H
25 #ifndef STDLIB_H_INCLUDED
26 #include <stdlib.h>
27 #define	STDLIB_H_INCLUDED 1
28 #endif
29 #endif
30 
31 #if DK4_HAVE_IO_H
32 #ifndef IO_H_INCLUDED
33 #include <io.h>
34 #define IO_H_INCLUDED 1
35 #endif
36 #endif
37 
38 #if DK4_HAVE_UNISTD_H
39 #ifndef UNISTD_H_INCLUDED
40 #include <unistd.h>
41 #define	UNISTD_H_INCLUDED 1
42 #endif
43 #endif
44 
45 #if DK4_HAVE_PROCESS_H
46 #ifndef PROCESS_H_INCLUDED
47 #include <process.h>
48 #define	PROCESS_H_INCLUDED 1
49 #endif
50 #endif
51 
52 #if DK4_HAVE_SYS_TYPES_H
53 #ifndef SYS_TYPES_H_INCLUDED
54 #include <sys/types.h>
55 #define SYS_TYPES_H_INCLUDED 1
56 #endif
57 #endif
58 
59 #if DK4_HAVE_SIGNAL_H
60 #ifndef SIGNAL_H_INCLUDED
61 #include <signal.h>
62 #define SIGNAL_H_INCLUDED 1
63 #endif
64 #endif
65 
66 #if DK4_HAVE_ERRNO_H
67 #ifndef ERRNO_H_INCLUDED
68 #include <errno.h>
69 #define	ERRNO_H_INCLUDED 1
70 #endif
71 #endif
72 
73 #if DK4_HAVE_FCNTL_H
74 #ifndef FCNTL_H_INCLUDED
75 #include <fcntl.h>
76 #define FCNTL_H_INCLUDED 1
77 #endif
78 #endif
79 
80 #if DK4_HAVE_STRING_H
81 #ifndef STRING_H_INCLUDED
82 #include <string.h>
83 #define	STRING_H_INCLUDED 1
84 #endif
85 #endif
86 
87 #include <libdk4base/dk4types.h>
88 #include <libdk4base/dk4const.h>
89 #include <libdk4base/dk4vers.h>
90 #include <libdk4app/dk4app.h>
91 #include <libdk4app/dk4aopt.h>
92 #include <libdk4base/dk4mem.h>
93 #include <libdk4app/dk4mema.h>
94 #include <libdk4base/dk4memrs.h>
95 #include <libdk4base/dk4numco.h>
96 #include <libdk4app/dk4fdrde.h>
97 #include <libdk4app/dk4fdwre.h>
98 #include <libdk4base/dk4unused.h>
99 
100 #ifndef	DK4WMAIN_H_INCLUDED
101 #include <libdk4base/dk4wmain.h>
102 #endif
103 
104 
105 
106 
107 
108 
109 #ifndef DK_BLKS_DEFAULT_BLOCK_SIZE
110 /**	Default suitable for hard disks.
111 */
112 #define	DK_BLKS_DEFAULT_BLOCK_SIZE	4096
113 #endif
114 
115 
116 
117 /**	Default help text, shown if help text file is not found.
118 */
119 static const dkChar * const	help_text[] = {
120 dkT(""),
121 dkT("Create sequence of fixed size blocks."),
122 dkT(""),
123 dkT("dk-blks [<options>]"),
124 dkT(""),
125 dkT("Options:"),
126 dkT("-b <size>\tBlock size, positive integer number."),
127 dkT("\t\tYou can append `k', `m', `g', or `t' for multiples of 1024"),
128 dkT("\t\tor powers of it (i.e. 4k = 4096 bytes, 1m = 1048576 bytes...)."),
129 dkT(""),
130 dkT("--help\t\tShow this short help text."),
131 dkT("--manual\t*** SHOW FULL MANUAL. ***"),
132 dkT("--version\tShow version information."),
133 dkT("--license\tShow license information."),
134 dkT(""),
135 dkT("http://sourceforge.net/p/dktools/wiki/dk-blks/"),
136 dkT(""),
137 NULL
138 
139 };
140 
141 
142 /**	License conditions.
143 */
144 static const dkChar * const	license_text[] = {
145 dkT("This software uses code from the following projects, either directly or as"),
146 dkT("a library:"),
147 dkT(""),
148 dkT("dktools\t\tDirk Krause's tools and libraries."),
149 dkT("\t\tSee http://sourceforge.net/p/dktools/wiki/Home/"),
150 dkT("\t\tfor more information."),
151 #if DK4_HAVE_ZLIB_H
152 dkT(""),
153 dkT("zlib\t\tData compression library."),
154 dkT("\t\tSee http://www.zlib.net/ for more information."),
155 #endif
156 #if DK4_HAVE_BZLIB_H
157 dkT(""),
158 dkT("bzip2\t\tData compression program and library."),
159 dkT("\t\tSee http://www.bzip.org/ for more information."),
160 #endif
161 dkT(""),
162 dkT("All the licenses below apply to the program."),
163 dkT("Licenses for used libraries are shown as found on my Scientific Linux 6.x"),
164 dkT("computer in the /usr/share/doc directory on 2015-04-01. Check the project"),
165 dkT("homepages of the used libraries for additional information and/or updated"),
166 dkT("license terms."),
167 dkT(""),
168 dkT(""),
169 dkT("DK tools and libraries license"),
170 dkT("=============================="),
171 dkT("Copyright (c) 2015-2016, Dirk Krause"),
172 dkT("All rights reserved."),
173 dkT(""),
174 dkT("Redistribution and use in source and binary forms, with or without"),
175 dkT("modification, are permitted provided that the following conditions are met:"),
176 dkT(""),
177 dkT("1. Redistributions of source code must retain the above copyright notice,"),
178 dkT("   this list of conditions and the following disclaimer."),
179 dkT("2. Redistributions in binary form must reproduce the above copyright"),
180 dkT("   notice, this list of conditions and the following disclaimer in the"),
181 dkT("   documentation and/or other materials provided with the distribution."),
182 dkT("3. Neither the name of the copyright holder nor the names of its"),
183 dkT("   contributors may be used to endorse or promote products derived from"),
184 dkT("   this software without specific prior written permission."),
185 dkT(""),
186 dkT("THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS"),
187 dkT("``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT"),
188 dkT("LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR"),
189 dkT("A PARTICULAR PURPOSE ARE DISCLAIMED."),
190 dkT("IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY"),
191 dkT("DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES"),
192 dkT("(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR"),
193 dkT("SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER"),
194 dkT("CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT"),
195 dkT("LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY"),
196 dkT("OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF"),
197 dkT("SUCH DAMAGE."),
198 dkT(""),
199 #if DK4_HAVE_ZLIB_H
200 dkT(""),
201 dkT(""),
202 dkT("Zlib license"),
203 dkT("============"),
204 dkT("(C) 1995-2004 Jean-loup Gailly and Mark Adler"),
205 dkT(""),
206 dkT("This software is provided 'as-is', without any express or implied"),
207 dkT("warranty.  In no event will the authors be held liable for any damages"),
208 dkT("arising from the use of this software."),
209 dkT(""),
210 dkT("Permission is granted to anyone to use this software for any purpose,"),
211 dkT("including commercial applications, and to alter it and redistribute it"),
212 dkT("freely, subject to the following restrictions:"),
213 dkT(""),
214 dkT("1. The origin of this software must not be misrepresented; you must not"),
215 dkT("   claim that you wrote the original software. If you use this software"),
216 dkT("   in a product, an acknowledgment in the product documentation would be"),
217 dkT("   appreciated but is not required."),
218 dkT("2. Altered source versions must be plainly marked as such, and must not be"),
219 dkT("   misrepresented as being the original software."),
220 dkT("3. This notice may not be removed or altered from any source distribution."),
221 dkT(""),
222 dkT("Jean-loup Gailly        Mark Adler"),
223 dkT("jloup@gzip.org          madler@alumni.caltech.edu"),
224 #endif
225 #if DK4_HAVE_BZLIB_H
226 dkT(""),
227 dkT(""),
228 dkT("Bzip2 and libbzip2 library license"),
229 dkT("=================================="),
230 dkT("This program, \"bzip2\", the associated library \"libbzip2\", and all"),
231 dkT("documentation, are copyright (C) 1996-2007 Julian R Seward.  All"),
232 dkT("rights reserved."),
233 dkT(""),
234 dkT("Redistribution and use in source and binary forms, with or without"),
235 dkT("modification, are permitted provided that the following conditions"),
236 dkT("are met:"),
237 dkT(""),
238 dkT("1. Redistributions of source code must retain the above copyright"),
239 dkT("   notice, this list of conditions and the following disclaimer."),
240 dkT(""),
241 dkT("2. The origin of this software must not be misrepresented; you must "),
242 dkT("   not claim that you wrote the original software.  If you use this "),
243 dkT("   software in a product, an acknowledgment in the product "),
244 dkT("   documentation would be appreciated but is not required."),
245 dkT(""),
246 dkT("3. Altered source versions must be plainly marked as such, and must"),
247 dkT("   not be misrepresented as being the original software."),
248 dkT(""),
249 dkT("4. The name of the author may not be used to endorse or promote "),
250 dkT("   products derived from this software without specific prior written "),
251 dkT("   permission."),
252 dkT(""),
253 dkT("THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS"),
254 dkT("OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED"),
255 dkT("WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE"),
256 dkT("ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY"),
257 dkT("DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL"),
258 dkT("DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE"),
259 dkT("GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS"),
260 dkT("INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,"),
261 dkT("WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING"),
262 dkT("NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS"),
263 dkT("SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."),
264 dkT(""),
265 dkT("Julian Seward, jseward@bzip.org"),
266 dkT("bzip2/libbzip2 version 1.0.5 of 10 December 2007"),
267 #endif
268 dkT(""),
269 NULL
270 
271 };
272 
273 
274 
275 /**	Options used by program.
276 */
277 static const dk4_option_specification_t options[] = {
278   { dkT('b'), dkT("block-size"), DK4_OPT_ARG_SIZE }
279 };
280 
281 /**	Number of elements in options array.
282 */
283 static const size_t sz_options =
284 sizeof(options)/sizeof(dk4_option_specification_t);
285 
286 
287 
288 /**	Keywords used by the program, not localized.
289 */
290 static const dkChar * const	kwnl[] = {
291 /* 0 */
292 dkT("dktools"),
293 
294 /* 1 */
295 dkT("dk-blks.txt"),
296 
297 /* 2 */
298 dkT("dk-blks.str"),
299 
300 /* 3 */
301 dkT("stdin"),
302 
303 /* 4 */
304 dkT("stdout"),
305 
306 NULL
307 
308 };
309 
310 
311 
312 /**	Constant texts used by the program, replaced by localized texts
313 	if available.
314 */
315 static const dkChar * const	kw_def[] = {
316 /* 0 */
317 dkT("Write operation partially failed!"),
318 
319 /* 1 */
320 dkT("Failed to cleanup buffer!"),
321 
322 /* 2 */
323 dkT("Block size too large!"),
324 
325 /* 3 */
326 dkT("Block size must not be 0!"),
327 
328 /* 4 */
329 dkT("Failed to set up signal handlers!"),
330 
331 /* 5 */
332 dkT("Failed to restore signal handlers!"),
333 
334 /* 6 */
335 dkT("Signal SIGPIPE received, write operation failed!"),
336 
337 /* 7 */
338 dkT("Signal SIGINT received, program aborted!"),
339 
340 /* 8 */
341 dkT("Unexpected command line argument \""),
342 
343 /* 9 */
344 dkT("\" ignored!"),
345 
346 NULL
347 
348 };
349 
350 
351 
352 /**	Message texts, localized texts are used if available.
353 */
354 static const dkChar * const	*dk_blks_msg	= kw_def;
355 
356 
357 
358 /**	Number of elements in dk_blks_msg array.
359 */
360 static size_t	sz_msg =
361 sizeof(kw_def)/sizeof(DK4_PCDKCHAR) - 1;
362 
363 
364 
365 /**	Exit status code.
366 */
367 static int	exval = EXIT_FAILURE;
368 
369 
370 
371 /**	Application structure.
372 */
373 static dk4_app_t *app = NULL;
374 
375 
376 
377 /**	Input buffer for buffer sizes up to DK_BLKS_DEFAULT_BLOCK_SIZE.
378 */
379 static char default_input_buffer[DK_BLKS_DEFAULT_BLOCK_SIZE];
380 
381 
382 
383 /**	Output buffer for buffer sizes up to DK_BLKS_DEFAULT_BLOCK_SIZE.
384 */
385 static char default_output_buffer[sizeof(default_input_buffer)];
386 
387 
388 
389 #ifdef RW_MAX
390 #undef RW_MAX
391 #endif
392 
393 #if DK4_ON_WINDOWS
394 /**	Maximum number of bytes for read or write operation.
395 */
396 #define	RW_MAX	(INT_MAX)
397 #else
398 /**	Maximum number of bytes for read or write operation.
399 */
400 #define	RW_MAX	((SIZE_MAX) / 2U)
401 #endif
402 
403 
404 
405 #ifdef SIGPIPE
406 /**	Indicator: SIGPIPE signal received.
407 */
408 static
409 DK4_VOLATILE
410 dk4_sig_atomic_t	sig_had_pipe	=	0;
411 #endif
412 
413 /**	Indicator: SIGINT signal received.
414 */
415 static
416 DK4_VOLATILE
417 dk4_sig_atomic_t	sig_had_int	=	0;
418 
419 /**	Indicator: SIGTERM signal received.
420 */
421 static
422 DK4_VOLATILE
423 dk4_sig_atomic_t	sig_had_term	=	0;
424 
425 static
426 DK4_VOLATILE
427 dk4_sig_atomic_t *
sig_pass_pointer(DK4_VOLATILE dk4_sig_atomic_t * ptr)428 sig_pass_pointer(DK4_VOLATILE dk4_sig_atomic_t *ptr)
429 {
430   return ptr;
431 }
432 
433 #ifdef SIGPIPE
434 /**	Handler for SIGPIPE signal.
435 	@param	signo	Signal number (always SIGPIPE, ignored).
436 */
437 static
438 void
sig_handler_pipe(int DK4_ARG_UNUSED (signo))439 sig_handler_pipe(int DK4_ARG_UNUSED(signo) )
440 {
441   DK4_UNUSED_ARG(signo)
442   *sig_pass_pointer(&sig_had_pipe) = 1;
443 }
444 #endif
445 
446 /**	Handler for SIGINT signal.
447 	@param	signo	Signal number (always SIGINT, ignored).
448 */
449 static
450 void
sig_handler_int(int DK4_ARG_UNUSED (signo))451 sig_handler_int(int DK4_ARG_UNUSED(signo) )
452 {
453   DK4_UNUSED_ARG(signo)
454   *sig_pass_pointer(&sig_had_int) = 1;
455 }
456 
457 /**	Handler for SIGTERM signal.
458 	@param	signo	Signal number (always SIGTERM, ignored).
459 */
460 static
461 void
sig_handler_term(int DK4_ARG_UNUSED (signo))462 sig_handler_term(int DK4_ARG_UNUSED(signo) )
463 {
464   DK4_UNUSED_ARG(signo)
465   *sig_pass_pointer(&sig_had_term) = 1;
466 }
467 
468 /**	Read value from volatile atomic type.
469 	This function is necessary as some compilers mis-optimize
470 	direct access to volatile variables (at least if you believe
471 	one of the coding standards).
472 	@param	ap	Pointer to volatile atomic variable.
473 	@return	Contents of the variable.
474 */
475 static
476 dk4_sig_atomic_t
sig_read_atomic(DK4_VOLATILE dk4_sig_atomic_t * ap)477 sig_read_atomic(DK4_VOLATILE dk4_sig_atomic_t *ap)
478 {
479   return (*ap);
480 }
481 
482 /**	Check whether we can continue or if a signal was received.
483 	@param	check_pipe	Flag: Check for occured SIGPIPE signal too.
484 	@return	1 if the program can continue, 0 if a signal was received.
485 */
486 static
487 int
sig_can_continue(int check_pipe)488 sig_can_continue(
489 #ifdef SIGPIPE
490 int check_pipe
491 #else
492 int DK4_ARG_UNUSED(check_pipe)
493 #endif
494 )
495 {
496   int		back = 1;
497 #ifndef SIGPIPE
498   DK4_UNUSED_ARG(check_pipe)
499 #else
500   if (0 != check_pipe) {
501     if (0 != sig_read_atomic(&sig_had_pipe)) { back = 0; }
502   }
503 #endif
504   if (0 != sig_read_atomic(&sig_had_int )) { back = 0; }
505   if (0 != sig_read_atomic(&sig_had_term)) { back = 0; }
506   return back;
507 }
508 
509 
510 
511 static
512 void
dk_blks_transfer(char * ib,char * ob,size_t bs)513 dk_blks_transfer(char *ib, char *ob, size_t bs)
514 {
515   int			cc	= 1;	/* Flag: Can continue */
516   size_t		irdb	= 0;	/* Bytes in input buffer */
517   size_t		iused	= 0;	/* Input bytes used */
518   size_t		oused	= 0;	/* Output bytes used */
519   size_t		iavail;		/* Input bytes available */
520   size_t		oavail;		/* Output bytes available */
521   size_t		bcp;		/* Bytes to copy */
522 #if DK4_ON_WINDOWS
523   int			rdres;		/* Number of bytes read */
524   int			wrres;		/* Number of bytes written */
525 #else
526   ssize_t		rdres;		/* Number of bytes read */
527   ssize_t		wrres;		/* Number of bytes written */
528 #endif
529   dk4_sig_atomic_t	shp;		/* Had pipe */
530 
531   /*	Process input
532   */
533   exval = EXIT_SUCCESS;
534   do {
535     if (1 == sig_can_continue(0)) {
536       errno = 0;
537 #if DK4_ON_WINDOWS
538       rdres = _read(0, ib, (unsigned)bs);
539 #else
540       rdres = read(0, ib, bs);
541 #endif
542       if (0 < rdres) {
543         irdb = (size_t)rdres;
544         iused = 0;
545         while(iused < irdb) {
546           /* Find number of bytes we can add to output buffer */
547           iavail = irdb - iused;
548 	  oavail = bs - oused;
549 	  if (iavail < oavail) {
550 	    bcp = iavail;
551 	  } else {
552 	    bcp = oavail;
553 	  }
554 	  /* Add bytes to output buffer */
555 	  DK4_MEMCPY(&(ob[oused]), &(ib[iused]), bcp);
556 	  /* Increased number of used bytes for both input and output */
557 	  oused += bcp;
558 	  iused += bcp;
559 	  /* Flush output buffer when full */
560 	  if (oused >= bs) {
561 #ifdef SIGPIPE
562 	    shp = sig_read_atomic(&sig_had_pipe);
563 #else
564 	    shp = 0;
565 #endif
566 	    if (0 == shp) {
567 	      errno = 0;
568 #if DK4_ON_WINDOWS
569 	      wrres = _write(1, ob, (unsigned)bs);
570 #else
571 	      wrres = write(1, ob, bs);
572 #endif
573 	      if (0 <= wrres) {
574 	        if (((size_t)wrres) < bs) {
575 	          /* ERROR: Not all bytes written */
576 	          dk4app_log_1(app, dk_blks_msg, sz_msg, DK4_LL_ERROR, 0);
577 	          exval = EXIT_FAILURE;
578 	          cc = -1;
579 	        }
580 	      } else {
581 	        /* ERROR Write attempt failed */
582 	        dk4fd_write_error_msg(app, kwnl[4], errno);
583 	        exval = EXIT_FAILURE;
584 	        cc = -1;
585 	      }
586 	    }
587 	    oused = 0;
588 	  }
589         }
590       } else {
591         if (0 == rdres) {
592           cc = 0;
593         } else {
594           /* ERROR: Read operation failed */
595 	  dk4fd_read_error_msg(app, kwnl[3], errno);
596 	  cc = 0;
597 	  exval = EXIT_FAILURE;
598         }
599       }
600 #if DK4_ON_WINDOWS
601       if (_eof(0)) {
602         cc = 0;
603       }
604 #endif
605     } else {
606       cc = -1;
607     }
608   } while (1 == cc);
609 
610   /*	Flush output buffer */
611   if (0 == cc) {
612     if (0 < oused) {
613 #ifdef SIGPIPE
614       shp = sig_read_atomic(&sig_had_pipe);
615 #else
616       shp = 0;
617 #endif
618       if (0 == shp) {
619         errno = 0;
620 #if DK4_ON_WINDOWS
621         wrres = _write(1, ob, (unsigned)oused);
622 #else
623         wrres = write(1, ob, oused);
624 #endif
625         if (0 <= wrres) {
626           if (((size_t)wrres) < oused) {
627 	    /* ERROR: Not all bytes written */
628 	    dk4app_log_1(app, dk_blks_msg, sz_msg, DK4_LL_ERROR, 0);
629 	    exval = EXIT_FAILURE;
630 	  }
631         } else {
632           /* ERROR: Write attempt failed */
633 	  dk4fd_write_error_msg(app, kwnl[4], errno);
634 	  exval = EXIT_FAILURE;
635         }
636       }
637     }
638   }
639 
640   /*	Finally zero-fill used buffers.
641   */
642   if (0 == dk4mem_reset_secure(ib, bs, NULL)) {
643     /* ERROR: Secure memory reset failed */
644     dk4app_log_1(app, dk_blks_msg, sz_msg, DK4_LL_ERROR, 1);
645     exval = EXIT_FAILURE;
646   }
647   if (0 == dk4mem_reset_secure(ob, bs, NULL)) {
648     /* ERROR: Secure memory reset failed */
649     dk4app_log_1(app, dk_blks_msg, sz_msg, DK4_LL_ERROR, 1);
650     exval = EXIT_FAILURE;
651   }
652 
653 
654 }
655 
656 
657 
658 static
659 void
dk_blks_with_buffers(char * ib,char * ob,size_t bs)660 dk_blks_with_buffers(char *ib, char *ob, size_t bs)
661 {
662 #if DK4_ON_WINDOWS
663   int oldinmode = 0;
664   int oldoutmode = 0;
665 #endif
666   if ((dk4_um_t)RW_MAX >= (dk4_um_t)bs) {
667 #if DK4_ON_WINDOWS
668     oldinmode  = _setmode(0, _O_BINARY);
669     oldoutmode = _setmode(1, _O_BINARY);
670 #endif
671     dk_blks_transfer(ib, ob, bs);
672 #if DK4_ON_WINDOWS
673     _setmode(1, oldoutmode);
674     _setmode(0, oldinmode);
675 #endif
676   } else {
677     /* ERROR: Block size too large */
678     dk4app_log_1(app, dk_blks_msg, sz_msg, DK4_LL_ERROR, 2);
679   }
680 }
681 
682 
683 
684 /**	Run normally.
685 */
686 static
687 void
dk_blks_normal_run(void)688 dk_blks_normal_run(void)
689 {
690   char		*myib;
691   char		*myob;
692   size_t	 mybs	= DK_BLKS_DEFAULT_BLOCK_SIZE;
693   int		 res	= 0;
694 
695   if (0 != dk4app_opt_is_set_short(app, dkT('b'), NULL)) {
696     res = dk4app_opt_get_size_short(&mybs, app, dkT('b'), NULL);
697     if (0 == res) {
698       mybs = DK_BLKS_DEFAULT_BLOCK_SIZE;
699     }
700   }
701   if ((0 < mybs) && (mybs <= DK_BLKS_DEFAULT_BLOCK_SIZE)) {
702     dk_blks_with_buffers(
703       default_input_buffer,
704       default_output_buffer,
705       mybs
706     );
707   } else {
708     if (0 < mybs) {
709       myib = (char *)dk4mem_calloc_app(1, mybs, app);
710       if (NULL != myib) {
711         myob = (char *)dk4mem_calloc_app(1, mybs, app);
712         if (NULL != myob) {
713           dk_blks_with_buffers(myib, myob, mybs);
714           dk4mem_free(myob);
715         }
716         dk4mem_free(myib);
717       }
718     } else {
719       /* ERROR: Illegal block size */
720       dk4app_log_1(app, dk_blks_msg, sz_msg, DK4_LL_ERROR, 3);
721     }
722   }
723 
724 }
725 
726 
727 
728 #if	DK4_HAVE_SIGACTION
729 /**	Set signal handlers and run.
730 */
731 static
732 void
run_with_signals(void)733 run_with_signals(void)
734 {
735 #ifdef SIGPIPE
736   struct sigaction opipe;
737 #endif
738   struct sigaction oint;
739   struct sigaction oterm;
740 #ifdef SIGPIPE
741   struct sigaction npipe;
742 #endif
743   struct sigaction nint;
744   struct sigaction nterm;
745   int	 success = 0;
746 
747 #ifdef SIGPIPE
748   /*	Set up signal handling for SIGPIPE.
749   */
750   DK4_MEMRES(&npipe, sizeof(npipe));
751   npipe.sa_handler = sig_handler_pipe;
752   npipe.sa_flags = 0;
753   if (0 != sigemptyset(&npipe.sa_mask)) {
754     /* ERROR: Failed to set up masked signal set for SIGPIPE */
755     dk4app_log_1(app, dk_blks_msg, sz_msg, DK4_LL_ERROR, 4);
756     goto finished;
757   }
758   if (0 != sigaddset(&npipe.sa_mask, SIGPIPE)) {
759     /* ERROR: Failed to set up masked signal set for SIGPIPE */
760     dk4app_log_1(app, dk_blks_msg, sz_msg, DK4_LL_ERROR, 4);
761     goto finished;
762   }
763   if (0 != sigaction(SIGPIPE, &npipe, &opipe)) {
764     /* ERROR: Failed to set up signal handler for SIGPIPE */
765     dk4app_log_1(app, dk_blks_msg, sz_msg, DK4_LL_ERROR, 4);
766     goto finished;
767   }
768 #endif
769 
770   /*	Set up signal handling for SIGINT.
771   */
772   DK4_MEMRES(&nint, sizeof(nint));
773   nint.sa_handler = sig_handler_int;
774   nint.sa_flags = 0;
775   if (0 != sigemptyset(&nint.sa_mask)) {
776     /* ERROR: Failed to set up masked signal set for SIGINT */
777     dk4app_log_1(app, dk_blks_msg, sz_msg, DK4_LL_ERROR, 4);
778     goto restore_old_pipe;
779   }
780   if (0 != sigaddset(&nint.sa_mask, SIGINT)) {
781     /* ERROR: Failed to set up masked signal set for SIGINT */
782     dk4app_log_1(app, dk_blks_msg, sz_msg, DK4_LL_ERROR, 4);
783     goto restore_old_pipe;
784   }
785   if (0 != sigaction(SIGINT, &nint, &oint)) {
786     /* ERROR: Failed to set up signal handler for SIGINT */
787     dk4app_log_1(app, dk_blks_msg, sz_msg, DK4_LL_ERROR, 4);
788     goto restore_old_pipe;
789   }
790 
791   /*	Set up signal handling for SIGTERM
792   */
793   DK4_MEMRES(&nterm, sizeof(nterm));
794   nterm.sa_handler = sig_handler_term;
795   nterm.sa_flags = 0;
796   if (0 != sigemptyset(&nterm.sa_mask)) {
797     /* ERROR: Failed to set up masked signal set for SIGTERM */
798     dk4app_log_1(app, dk_blks_msg, sz_msg, DK4_LL_ERROR, 4);
799     goto restore_old_int;
800   }
801   if (0 != sigaddset(&nterm.sa_mask, SIGTERM)) {
802     /* ERROR: Failed to set up masked signal set for SIGTERM */
803     dk4app_log_1(app, dk_blks_msg, sz_msg, DK4_LL_ERROR, 4);
804     goto restore_old_int;
805   }
806   if (0 != sigaction(SIGTERM, &nterm, &oterm)) {
807     /* ERROR: Failed to set up signal handler for SIGTERM */
808     dk4app_log_1(app, dk_blks_msg, sz_msg, DK4_LL_ERROR, 4);
809     goto restore_old_int;
810   }
811 
812   success = 1;
813   dk_blks_normal_run();
814 
815   /*	Restore signal handling for SIGTERM.
816   */
817   if (0 != sigaction(SIGTERM, &oterm, NULL)) {
818     /* ERROR: Failed to restore old SIGTERM settings */
819     dk4app_log_1(app, dk_blks_msg, sz_msg, DK4_LL_ERROR, 5);
820     success = 0;
821   }
822 
823   /*	Restore signal handling for SIGINT.
824   */
825   restore_old_int:
826   if (0 != sigaction(SIGINT, &oint, NULL)) {
827     /* ERROR: Failed to restore old SIGPIPE settings */
828     dk4app_log_1(app, dk_blks_msg, sz_msg, DK4_LL_ERROR, 5);
829     success = 0;
830   }
831 
832 #ifdef SIGPIPE
833   /*	Restore signal handling for SIGPIPE.
834   */
835   restore_old_pipe:
836   if (0 != sigaction(SIGPIPE, &opipe, NULL)) {
837     /* ERROR: Failed to restore old SIGPIPE settings */
838     dk4app_log_1(app, dk_blks_msg, sz_msg, DK4_LL_ERROR, 5);
839     success = 0;
840   }
841 #endif
842 
843   /*	Set exit status code if error occured.
844   */
845   finished:
846   if (0 == success) { exval = EXIT_FAILURE; }
847 }
848 #else
849 #if	DK4_HAVE_SIGSET
850 /**	Set signal handlers and run.
851 */
852 static
853 void
run_with_signals(void)854 run_with_signals(void)
855 {
856 #ifdef SIGPIPE
857   dk4_sig_handler_t	*oldpipe = NULL;
858 #endif
859   dk4_sig_handler_t	*oldint  = NULL;
860   dk4_sig_handler_t	*oldterm = NULL;
861 
862 #ifdef SIGPIPE
863   oldpipe = sigset(SIGPIPE, sig_handler_pipe);
864 #endif
865   oldint  = sigset(SIGINT,  sig_handler_int);
866   oldterm = sigset(SIGTERM, sig_handler_term);
867   dk_blks_normal_run();
868   sigset(SIGTERM, oldterm);
869   sigset(SIGINT,  oldint);
870 #ifdef SIGPIPE
871   sigset(SIGPIPE, oldpipe);
872 #endif
873 }
874 #else
875 #if	DK4_HAVE_SIGNAL
876 /**	Set signal handlers and run.
877 */
878 static
879 void
run_with_signals(void)880 run_with_signals(void)
881 {
882 #ifdef SIGPIPE
883   dk4_sig_handler_t	*oldpipe = NULL;
884 #endif
885   dk4_sig_handler_t	*oldint  = NULL;
886   dk4_sig_handler_t	*oldterm = NULL;
887 
888 #ifdef SIGPIPE
889   oldpipe = signal(SIGPIPE, sig_handler_pipe);
890 #endif
891   oldint  = signal(SIGINT,  sig_handler_int);
892   oldterm = signal(SIGTERM, sig_handler_term);
893   dk_blks_normal_run();
894   signal(SIGTERM, oldterm);
895   signal(SIGINT,  oldint);
896 #ifdef SIGPIPE
897   signal(SIGPIPE, oldpipe);
898 #endif
899 }
900 #else
901 /**	Set signal handlers and run.
902 */
903 static
904 void
run_with_signals(void)905 run_with_signals(void)
906 {
907   dk_blks_normal_run();
908 }
909 #endif
910 #endif
911 #endif
912 
913 
914 /**	Main function.
915 	@param	argc	Number of command line arguments.
916 	@param	argv	Command line arguments array.
917 	@return	0 on success, all other values indicate errors.
918 */
919 #if DK4_CHAR_SIZE > 1
wmain(int argc,wchar_t * argv[])920 int wmain(int argc, wchar_t *argv[])
921 #else
922 int main(int argc, char *argv[])
923 #endif
924 {
925   dkChar const	*xargv;
926   int		 xargc;
927   int		 i;
928 
929 
930   app = dk4app_open_cmd(
931     argc, argv, options, sz_options, kwnl[0], DKT_VERSION_DK,
932     kwnl[1], help_text, license_text
933   );
934   if (NULL != app) {
935     sz_msg =	  dk4app_string_table_size(kw_def);
936     dk_blks_msg = dk4app_string_table(app, kwnl[2], kw_def);
937     if (0 != dk4app_can_run_normally(app)) {
938       run_with_signals();
939       xargc = dk4app_get_argc(app);
940       if (0 < xargc) {
941         for (i = 0; i < xargc; i++) {
942 	  xargv = dk4app_get_argv(app, i);
943 	  if (NULL != xargv) {
944 	    dk4app_log_3(app, dk_blks_msg, sz_msg, DK4_LL_ERROR, 8, 9, xargv);
945 	    exval = EXIT_FAILURE;
946 	  }
947 	}
948       }
949 #ifdef SIGPIPE
950       if (0 != sig_read_atomic(&sig_had_pipe)) {
951 	dk4app_log_1(app, dk_blks_msg, sz_msg, DK4_LL_ERROR, 6);
952 	exval = EXIT_FAILURE;
953       }
954 #endif
955       if (0 != sig_read_atomic(&sig_had_int)) {
956         dk4app_log_1(app, dk_blks_msg, sz_msg, DK4_LL_ERROR, 7);
957 	exval = EXIT_FAILURE;
958       }
959     } else {
960       if (0 != dk4app_help_version_license(app)) {
961         exval = EXIT_SUCCESS;
962       }
963     }
964     dk4app_close(app); app = NULL;
965   } else {
966   }
967 
968 
969   exit(exval); return exval;
970 }
971 
972