1 |
#! /bin/sh |
2 |
# This is a shell archive. Remove anything before this line, then unpack |
3 |
# it by saving it into a file and typing "sh file". To overwrite existing |
4 |
# files, type "sh file -c". You can also feed this as standard input via |
5 |
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you |
6 |
# will see the following message at the end: |
7 |
# "End of shell archive." |
8 |
# Contents: README buffer.man Makefile buffer.c sem.c sem.h COPYING |
9 |
# Wrapped by lmjm@toucan.doc.ic.ac.uk on Tue Jul 29 11:24:59 1997 |
10 |
PATH=/bin:/usr/bin:/usr/ucb ; export PATH |
11 |
if test -f 'README' -a "${1}" != "-c" ; then |
12 |
echo shar: Will not clobber existing file \"'README'\" |
13 |
else |
14 |
echo shar: Extracting \"'README'\" \(2208 characters\) |
15 |
sed "s/^X//" >'README' <<'END_OF_FILE' |
16 |
XThis is a program designed to speed up writing tapes on remote tape |
17 |
Xdrives. Requirements are shared memory and locks which normally |
18 |
Xmeans that these are supported in your kernel. |
19 |
X |
20 |
XBuffer has been tested under SunOS 4.0.*, SunOS 4.1.*, Solarix, HP-UX 7.0, |
21 |
Xand Gould UTX 2.1A (sv universe). |
22 |
X |
23 |
XThe program splits itself into two processes. The first process reads |
24 |
X(and reblocks) from stdin into a shared memory buffer. The second |
25 |
Xwrites from the shared memory buffer to stdout. Doing it this way |
26 |
Xmeans that the writing side effectly sits in a tight write loop and |
27 |
Xdoesn't have to wait for input. Similarly for the input side. It is |
28 |
Xthis waiting that slows down other reblocking processes, like dd. |
29 |
X |
30 |
XI run an archive and need to write large chunks out to tape regularly |
31 |
Xwith an ethernet in the way. Using 'buffer' in a command like: |
32 |
X |
33 |
X tar cvf - stuff | rsh somebox buffer -o /dev/rst8 |
34 |
X |
35 |
Xis a factor of 5 faster than the best alternative, gnu tar with its |
36 |
Xremote tape option: |
37 |
X |
38 |
X tar cvf somebox:/dev/rst8 stuff |
39 |
X |
40 |
XWe have been using buffer here at Imperial for a couple of years now |
41 |
Xfor writing tar tapes and the main system dumps. |
42 |
X |
43 |
XThanks to Kevin Twidle <kpt@doc.ic.ac.uk> for the -p and -B code. |
44 |
XThanks to Bard Isley <brad@slammer.atl.ga.us> for fixes to the |
45 |
X read loop/SIGCHLD handling. |
46 |
XThanks to PerSteinar.Iversen@fi.uib.no for the DEC Alpha patches. |
47 |
XThanks to kargard@ampex.com (Erik L. Kargard) for the AMPEX enhancements. |
48 |
X |
49 |
XINSTALLATION: |
50 |
X Check that your kernel supports shared memory and semaphores. |
51 |
X A quick way to check is to build buffer and run it. |
52 |
X If it says "couldn't create shared memory segment" you probably |
53 |
X need to reconfigure and rebuild your kernel. |
54 |
X |
55 |
X To install edit the Makefile and tailor the variables to |
56 |
X your local systems. Then type make. |
57 |
X |
58 |
XDISCLAIMER: |
59 |
X This package is under the GNU GENERAL PUBLIC LICENSE! |
60 |
X In addtion under NO circumstances can I, or Imperial College, |
61 |
X be held liable for any event caused by the running or storing |
62 |
X of this program or its documentation. |
63 |
X |
64 |
XLee McLoughlin. Phone: +44 171 594 8388 |
65 |
XIC-Parc, William Penney Lab, Fax: +44 171 594 8449 |
66 |
XImperial College, London, SW7 2BZ, UK Email: L.McLoughlin@doc.ic.ac.uk |
67 |
END_OF_FILE |
68 |
if test 2208 -ne `wc -c <'README'`; then |
69 |
echo shar: \"'README'\" unpacked with wrong size! |
70 |
fi |
71 |
# end of 'README' |
72 |
fi |
73 |
if test -f 'buffer.man' -a "${1}" != "-c" ; then |
74 |
echo shar: Will not clobber existing file \"'buffer.man'\" |
75 |
else |
76 |
echo shar: Extracting \"'buffer.man'\" \(5087 characters\) |
77 |
sed "s/^X//" >'buffer.man' <<'END_OF_FILE' |
78 |
X.\" Buffer. Very fast reblocking filter speedy writing of tapes. |
79 |
X.\" Copyright (C) 1990,1991 Lee McLoughlin |
80 |
X.\" |
81 |
X.\" This program is free software; you can redistribute it and/or modify |
82 |
X.\" it under the terms of the GNU General Public License as published by |
83 |
X.\" the Free Software Foundation; either version 1, or (at your option) |
84 |
X.\" any later version. |
85 |
X.\" |
86 |
X.\" This program is distributed in the hope that it will be useful, |
87 |
X.\" but WITHOUT ANY WARRANTY; without even the implied warranty of |
88 |
X.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
89 |
X.\" GNU General Public License for more details. |
90 |
X.\" |
91 |
X.\" You should have received a copy of the GNU General Public License |
92 |
X.\" along with this program; if not, write to the Free Software |
93 |
X.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
94 |
X.\" |
95 |
X.\" Lee McLoughlin. |
96 |
X.\" Dept of Computing, Imperial College, |
97 |
X.\" 180 Queens Gate, London, SW7 2BZ, UK. |
98 |
X.\" |
99 |
X.\" Email: L.McLoughlin@doc.ic.ac.uk |
100 |
X.TH BUFFER 1 "14 May 1990" |
101 |
X.SH NAME |
102 |
Xbuffer \- very fast reblocking program |
103 |
X.SH SYNTAX |
104 |
X.B buffer |
105 |
X[\fB\-S size\fP] [\fB\-b blocks\fP] [\fB\-s size\fP] [\fB\-m size\fP] |
106 |
X[\fB\-p percentage\fP] [\fB\-u microseconds\fP] [\fB-B\fR] [\fB-t\fR] |
107 |
X[\fB-Z\fR] [\fB-i filename\fR] [\fB-o filename\fR] |
108 |
X.SH OPTIONS |
109 |
X.TP 5 |
110 |
X.B \-i filename |
111 |
XUse the given file as the input file. The default is stdin. |
112 |
X.TP |
113 |
X.B \-o filename |
114 |
XUse the given file as the output file. The default is stdout. |
115 |
X.TP |
116 |
X.B \-S size |
117 |
XAfter every chunk this size has been writen print out how much been writen so far. |
118 |
XBy default this is not set. |
119 |
X.TP |
120 |
X.B \-s size |
121 |
XSize in bytes of each block. The default blocksize is 10k to match |
122 |
Xthe normal output of the |
123 |
X.I tar(1) |
124 |
Xprogram. |
125 |
X.TP |
126 |
X.B \-z size |
127 |
XCombines the |
128 |
X.B \-S |
129 |
Xand |
130 |
X.B \-s |
131 |
Xflags. |
132 |
X.TP |
133 |
X.B \-b blocks |
134 |
XNumber of blocks to allocate to shared memory circular buffer. |
135 |
XDefaults to the number required to fill up the shared memory requested. |
136 |
X.TP |
137 |
X.B \-m size |
138 |
XMaximum size of the shared memory chunk to allocate for the circular |
139 |
Xqueue. Defaults to one megabyte. |
140 |
X.TP |
141 |
X.B \-p percentage |
142 |
XOnly start a write when the given percentage of the internal queue is |
143 |
Xfull. A percentage around 75 often proves best. Defaults to zero. |
144 |
X.TP |
145 |
X.B \-u microseconds |
146 |
XAfter every write pause for this many microseconds. Defaults to zero. |
147 |
X(Suprisingly a small sleep, 100 usecs, after each write can greatly enhance |
148 |
Xthroughput on some drives.) |
149 |
X.TP |
150 |
X.B \-B |
151 |
XForce each block writen to be padded out to the blocksize. This is needed by some tape |
152 |
Xand cartridge drives. Defaults to unpadded. This only affects the |
153 |
Xlast block writen. |
154 |
X.TP |
155 |
X.B \-t |
156 |
XOn exiting print to stderr a brief message showing the total number of |
157 |
Xbytes written. |
158 |
X.TP |
159 |
X.B \-Z |
160 |
XIf reading/writing directly to a character device (like a tape drive) |
161 |
Xthen after each gigabyte perform an lseek to the start of the file. |
162 |
XUse this flag with extreme care. If can only be used on devices where |
163 |
Xan lseek does not rewind the tape but does reset the kernels position |
164 |
Xflags. It is used to allow more than 2 gigabytes to be written. |
165 |
X.PP |
166 |
XSizes are a number with an optional trailing character. A 'b' |
167 |
Xmultiplies the size by 512, a 'k' by 1024 and an 'm' by a meg. |
168 |
X.SH DESCRIPTION |
169 |
X.I Buffer |
170 |
Xreads from standard input reblocking to the given blocksize and writes |
171 |
Xeach block to standard output. |
172 |
X.PP |
173 |
XInternally |
174 |
X.I buffer |
175 |
Xis a pair of processes communicating via a large circular queue held |
176 |
Xin shared memory. The reader process only has to block when the queue |
177 |
Xis full and the writer process when the queue is empty. |
178 |
X.I Buffer |
179 |
Xis designed to try and keep the writer side continuously busy so that |
180 |
Xit can stream when writing to tape drives. When used to write tapes |
181 |
Xwith an intervening network |
182 |
X.I buffer |
183 |
Xcan result in a considerable increase in throughput. |
184 |
X.PP |
185 |
XThe default settings for |
186 |
X.I buffer |
187 |
Xare normally good enough. If you are a heavy tape user then it is |
188 |
Xworth your while trying out various different combinations of options. |
189 |
XIn particular running a |
190 |
X.I buffer |
191 |
Xat both ends of the pipe can provide a substantial increase (see last |
192 |
Xexample below). |
193 |
X.SH EXAMPLES |
194 |
X.br |
195 |
X$ \fBbuffer < /etc/termcap > /dev/rst8\fP |
196 |
X.br |
197 |
X.sp |
198 |
X$ \fBtar cf - . | rsh somehost 'buffer > /dev/rst8'\fP |
199 |
X.br |
200 |
X.sp |
201 |
X$ \fBdump fu - | rsh somehost 'buffer -s 16k > /dev/nrst8'\fP |
202 |
X.br |
203 |
X$ \fBtar cf - . | buffer | |
204 |
X.br |
205 |
X\ \ \ rsh somehost 'buffer -S 500K -p 75 > /dev/rst0'\fP |
206 |
X.SH BUGS |
207 |
XInternally, for printing purposes, buffer counts in terms of the |
208 |
Xnumber of kilobytes output. If the blocksize you use is not a whole |
209 |
Xnumber of kilobytes then the numbers printed will be inaccurate. |
210 |
X |
211 |
X.SH THANKS |
212 |
XThanks to Kevin Twidle <kpt@doc.ic.ac.uk> for a lot of early |
213 |
Xsuggestions and patches to make it work with non-tar/dump tapes to |
214 |
Xexabyte drives. |
215 |
X |
216 |
XThanks to Andi Karrer <karrer@bernina.ethz.ch>, Rumi Zahir |
217 |
X<rumi@iis.ethz.ch> and Christoph Wicki <wicki@iis.ethz.ch> for patches |
218 |
Xto make buffer work when trying to write single tape files of greater |
219 |
Xthan 2 gigabytes. |
220 |
X |
221 |
X.SH COPYRIGHT |
222 |
X.if n Copyright (C) 1990, 1991 by Lee McLoughlin. |
223 |
X.if t Copyright \(co 1990, 1991 by Lee McLoughlin. |
224 |
X.SH SEE ALSO |
225 |
Xdd(1), tar(1), rsh(1) |
226 |
END_OF_FILE |
227 |
if test 5087 -ne `wc -c <'buffer.man'`; then |
228 |
echo shar: \"'buffer.man'\" unpacked with wrong size! |
229 |
fi |
230 |
# end of 'buffer.man' |
231 |
fi |
232 |
if test -f 'Makefile' -a "${1}" != "-c" ; then |
233 |
echo shar: Will not clobber existing file \"'Makefile'\" |
234 |
else |
235 |
echo shar: Extracting \"'Makefile'\" \(1121 characters\) |
236 |
sed "s/^X//" >'Makefile' <<'END_OF_FILE' |
237 |
X# Make the buffer program |
238 |
X |
239 |
X# You might need to add the following to CGFLAGS: |
240 |
X# |
241 |
X# Add -DSYS5 for A System 5 (USG) version of Unix |
242 |
X# You should also add -DSYS5 for Ultrix, AIX, and Solaris. |
243 |
X# Add -DDEF_SHMEM=n if you can only have n bytes of shared memory |
244 |
X# (eg: -DDEF_SHMEM=524288 if you can only have half a meg.) |
245 |
X# Add -DAMPEX to change the default settings suitable for the high capacity |
246 |
X# Ampex drives, such as the DST 310. |
247 |
X |
248 |
XCC=gcc |
249 |
XCFLAGS=-Wall |
250 |
X |
251 |
X# Where to install buffer and its manual pages |
252 |
XINSTBIN=/usr/local/bin |
253 |
XINSTMAN=/usr/man/manl |
254 |
X# The manual page section (normally l or 1) |
255 |
XS=l |
256 |
X |
257 |
XRM=/bin/rm |
258 |
XALL=README buffer.man Makefile buffer.c sem.c sem.h COPYING |
259 |
X |
260 |
Xall: buffer |
261 |
X |
262 |
Xbuffer: buffer.o sem.o |
263 |
X $(CC) -o buffer $(CFLAGS) buffer.o sem.o |
264 |
X |
265 |
Xclean: |
266 |
X $(RM) -f *.o core buffer .merrs |
267 |
X |
268 |
Xinstall: buffer |
269 |
X rm -f $(INSTBIN)/buffer |
270 |
X cp buffer $(INSTBIN)/buffer |
271 |
X chmod 111 $(INSTBIN)/buffer |
272 |
X rm -f $(INSTMAN)/buffer.$S |
273 |
X cp buffer.man $(INSTMAN)/buffer.$S |
274 |
X chmod 444 $(INSTMAN)/buffer.$S |
275 |
X |
276 |
Xbuffer.tar: $(ALL) |
277 |
X $(RM) -f buffer.tar |
278 |
X tar cvf buffer.tar $(ALL) |
279 |
X |
280 |
Xbuffer.shar: $(ALL) |
281 |
X $(RM) -f buffer.shar |
282 |
X shar $(ALL) > buffer.shar |
283 |
END_OF_FILE |
284 |
if test 1121 -ne `wc -c <'Makefile'`; then |
285 |
echo shar: \"'Makefile'\" unpacked with wrong size! |
286 |
fi |
287 |
# end of 'Makefile' |
288 |
fi |
289 |
if test -f 'buffer.c' -a "${1}" != "-c" ; then |
290 |
echo shar: Will not clobber existing file \"'buffer.c'\" |
291 |
else |
292 |
echo shar: Extracting \"'buffer.c'\" \(21928 characters\) |
293 |
sed "s/^X//" >'buffer.c' <<'END_OF_FILE' |
294 |
X/* |
295 |
X Buffer. Very fast reblocking filter speedy writing of tapes. |
296 |
X Copyright (C) 1990,1991 Lee McLoughlin |
297 |
X |
298 |
X This program is free software; you can redistribute it and/or modify |
299 |
X it under the terms of the GNU General Public License as published by |
300 |
X the Free Software Foundation; either version 1, or (at your option) |
301 |
X any later version. |
302 |
X |
303 |
X This program is distributed in the hope that it will be useful, |
304 |
X but WITHOUT ANY WARRANTY; without even the implied warranty of |
305 |
X MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
306 |
X GNU General Public License for more details. |
307 |
X |
308 |
X You should have received a copy of the GNU General Public License |
309 |
X along with this program; if not, write to the Free Software |
310 |
X Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
311 |
X |
312 |
X Lee McLoughlin. |
313 |
X Dept of Computing, Imperial College, |
314 |
X 180 Queens Gate, London, SW7 2BZ, UK. |
315 |
X |
316 |
X Email: L.McLoughlin@doc.ic.ac.uk |
317 |
X*/ |
318 |
X |
319 |
X/* This is a reblocking process, designed to try and read from stdin |
320 |
X * and write to stdout - but to always try and keep the writing side |
321 |
X * busy. It is meant to try and stream tape writes. |
322 |
X * |
323 |
X * This program runs in two parts. The reader and the writer. They |
324 |
X * communicate using shared memory with semaphores locking the access. |
325 |
X * The shared memory implements a circular list of blocks of data. |
326 |
X * |
327 |
X * L.McLoughlin, Imperial College, 1990 |
328 |
X * |
329 |
X * $Log: buffer.c,v $ |
330 |
X * Revision 1.19 1995/08/24 17:46:28 lmjm |
331 |
X * Be more careful abour EINTR errors |
332 |
X * Ingnore child processes dying. |
333 |
X * |
334 |
X * Revision 1.18 1993/08/25 19:07:31 lmjm |
335 |
X * Added Brad Isleys patchs to read/sigchld handling. |
336 |
X * |
337 |
X * Revision 1.17 1993/06/04 10:26:39 lmjm |
338 |
X * Cleaned up error reporting. |
339 |
X * Spot when the child terminating is not mine but inherited from via exec. |
340 |
X * Use only one semaphore group. |
341 |
X * Print out why writer died on error. |
342 |
X * |
343 |
X * Revision 1.16 1993/05/28 10:47:32 lmjm |
344 |
X * Debug shutdown sequence. |
345 |
X * |
346 |
X * Revision 1.15 1992/11/23 23:32:58 lmjm |
347 |
X * Oops! This should be outside the ifdef |
348 |
X * |
349 |
X * Revision 1.14 1992/11/23 23:29:58 lmjm |
350 |
X * allow MAX_BLOCKSIZE and DEF_SHMEM to be configured |
351 |
X * |
352 |
X * Revision 1.13 1992/11/23 23:22:29 lmjm |
353 |
X * Printf's use %lu where appropriate. |
354 |
X * |
355 |
X * Revision 1.12 1992/11/23 23:17:55 lmjm |
356 |
X * Got rid of floats and use Kbyte counters instead. |
357 |
X * |
358 |
X * Revision 1.11 1992/11/03 23:11:51 lmjm |
359 |
X * Forgot Andi Karrer on the patch list. |
360 |
X * |
361 |
X * Revision 1.10 1992/11/03 22:58:41 lmjm |
362 |
X * Cleaned up the debugging prints. |
363 |
X * |
364 |
X * Revision 1.9 1992/11/03 22:53:00 lmjm |
365 |
X * Corrected stdin, stout and showevery use. |
366 |
X * |
367 |
X * Revision 1.8 1992/11/03 22:41:34 lmjm |
368 |
X * Added 2Gig patches from: |
369 |
X * Andi Karrer <karrer@bernina.ethz.ch> |
370 |
X * Rumi Zahir <rumi@iis.ethz.ch> |
371 |
X * Christoph Wicki <wicki@iis.ethz.ch> |
372 |
X * |
373 |
X * Revision 1.7 1992/07/23 20:42:03 lmjm |
374 |
X * Added 't' option to print total writen at end. |
375 |
X * |
376 |
X * Revision 1.6 1992/04/07 19:57:30 lmjm |
377 |
X * Added Kevins -B and -p options. |
378 |
X * Turn off buffering to make -S output appear ok. |
379 |
X * Added GPL. |
380 |
X * |
381 |
X * Revision 1.5 90/07/22 18:46:38 lmjm |
382 |
X * Added system 5 support. |
383 |
X * |
384 |
X * Revision 1.4 90/07/22 18:29:48 lmjm |
385 |
X * Updated arg handling to be more consistent. |
386 |
X * Make sofar printing size an option. |
387 |
X * |
388 |
X * Revision 1.3 90/05/15 23:27:46 lmjm |
389 |
X * Added -S option (show how much has been writen). |
390 |
X * Added -m option to specify how much shared memory to grab. |
391 |
X * Now tries to fill this with blocks. |
392 |
X * reader waits for writer to terminate and then frees the shared mem and sems. |
393 |
X * |
394 |
X * Revision 1.2 90/01/20 21:37:59 lmjm |
395 |
X * Reset default number of blocks and blocksize for best thruput of |
396 |
X * standard tar 10K Allow. |
397 |
X * blocks number of blocks to be changed. |
398 |
X * Don't need a hole in the circular queue since the semaphores prevent block |
399 |
X * clash. |
400 |
X * |
401 |
X * Revision 1.1 90/01/17 11:30:23 lmjm |
402 |
X * Initial revision |
403 |
X * |
404 |
X */ |
405 |
X#include <unistd.h> |
406 |
X#include <stdio.h> |
407 |
X#include <signal.h> |
408 |
X#include <fcntl.h> |
409 |
X#include <errno.h> |
410 |
X#include <sys/types.h> |
411 |
X#include <sys/stat.h> |
412 |
X#include <sys/ipc.h> |
413 |
X#include <sys/shm.h> |
414 |
X#include <sys/sem.h> |
415 |
X#include <sys/wait.h> |
416 |
X#include "sem.h" |
417 |
X |
418 |
X#ifndef lint |
419 |
Xstatic char *rcsid = "$Header: /a/swan/home/swan/staff/csg/lmjm/src/buffer/RCS/buffer.c,v 1.19 1995/08/24 17:46:28 lmjm Exp lmjm $"; |
420 |
X#endif |
421 |
X |
422 |
X#ifndef __alpha |
423 |
Xextern char *shmat(); |
424 |
X#endif /* __alpha */ |
425 |
X |
426 |
X/* General macros */ |
427 |
X#define TRUE 1 |
428 |
X#define FALSE 0 |
429 |
X#define K *1024 |
430 |
X#define M *1024*1024 |
431 |
X |
432 |
X/* Some forward declarations */ |
433 |
Xvoid byee(); |
434 |
Xvoid start_reader_and_writer(); |
435 |
Xvoid parse_args(); |
436 |
Xvoid set_handlers(); |
437 |
Xvoid buffer_allocate(); |
438 |
Xvoid report_proc(); |
439 |
Xint do_size(); |
440 |
Xvoid get_buffer(); |
441 |
Xvoid reader(); |
442 |
Xvoid writer(); |
443 |
Xvoid writer_end(); |
444 |
Xvoid wait_for_writer_end(); |
445 |
Xvoid get_next_free_block(); |
446 |
Xvoid test_writer(); |
447 |
Xint fill_block(); |
448 |
Xvoid get_next_filled_block(); |
449 |
Xint data_to_write(); |
450 |
Xvoid write_blocks_to_stdout(); |
451 |
Xvoid write_block_to_stdout(); |
452 |
Xvoid pr_out(); |
453 |
Xvoid end_writer(); |
454 |
X |
455 |
X/* When showing print a note every this many bytes writen */ |
456 |
Xint showevery = 0; |
457 |
X#define PRINT_EVERY 10 K |
458 |
X |
459 |
X/* Pause after every write */ |
460 |
Xunsigned write_pause; |
461 |
X |
462 |
X/* This is the inter-process buffer - it implements a circular list |
463 |
X * of blocks. */ |
464 |
X |
465 |
X#ifdef AMPEX |
466 |
X#define MAX_BLOCKSIZE (4 M) |
467 |
X#define DEF_BLOCKSIZE MAX_BLOCKSIZE |
468 |
X#define DEF_SHMEM (32 M) |
469 |
X#endif |
470 |
X |
471 |
X |
472 |
X#ifndef MAX_BLOCKSIZE |
473 |
X#define MAX_BLOCKSIZE (512 K) |
474 |
X#endif |
475 |
X#ifndef DEF_BLOCKSIZE |
476 |
X#define DEF_BLOCKSIZE (10 K) |
477 |
X#endif |
478 |
X |
479 |
Xint blocksize = DEF_BLOCKSIZE; |
480 |
X |
481 |
X/* Which process... in error reports*/ |
482 |
Xchar *proc_string = "buffer"; |
483 |
X |
484 |
X/* Numbers of blocks in the queue. |
485 |
X */ |
486 |
X#define MAX_BLOCKS 2048 |
487 |
Xint blocks = 1; |
488 |
X/* Circular increment of a buffer index */ |
489 |
X#define INC(i) (((i)+1) == blocks ? 0 : ((i)+1)) |
490 |
X |
491 |
X/* Max amount of shared memory you can allocate - can't see a way to look |
492 |
X * this up. |
493 |
X */ |
494 |
X#ifndef DEF_SHMEM |
495 |
X#define DEF_SHMEM (1 K K) |
496 |
X#endif |
497 |
Xint max_shmem = DEF_SHMEM; |
498 |
X |
499 |
X/* Just a flag to show unfilled */ |
500 |
X#define NONE (-1) |
501 |
X |
502 |
X/* the shared memory id of the buffer */ |
503 |
Xint buffer_id = NONE; |
504 |
Xstruct block { |
505 |
X int bytes; |
506 |
X char *data; |
507 |
X} *curr_block; |
508 |
X |
509 |
X#define NO_BUFFER ((struct buffer *)-1) |
510 |
Xstruct buffer { |
511 |
X /* Id of the semaphore group */ |
512 |
X int semid; |
513 |
X |
514 |
X /* writer will hang trying to lock this till reader fills in a block */ |
515 |
X int blocks_used_lock; |
516 |
X /* reader will hang trying to lock this till writer empties a block */ |
517 |
X int blocks_free_lock; |
518 |
X |
519 |
X int next_block_in; |
520 |
X int next_block_out; |
521 |
X |
522 |
X struct block block[ MAX_BLOCKS ]; |
523 |
X |
524 |
X /* These actual space for the blocks is here - the array extends |
525 |
X * pass 1 */ |
526 |
X char data_space[ 1 ]; |
527 |
X} *pbuffer = NO_BUFFER; |
528 |
Xint buffer_size; |
529 |
X |
530 |
Xint fdin = 0; |
531 |
Xint fdout = 1; |
532 |
Xint in_ISCHR = 0; |
533 |
Xint out_ISCHR = 0; |
534 |
Xint padblock = FALSE; |
535 |
Xint writer_pid = 0; |
536 |
Xint reader_pid = 0; |
537 |
Xint free_shm = 1; |
538 |
Xint percent = 0; |
539 |
Xint debug = 0; |
540 |
Xint Zflag = 0; |
541 |
Xint writer_status = 0; |
542 |
Xchar *progname = "buffer"; |
543 |
X |
544 |
Xchar print_total = 0; |
545 |
X/* Number of K output */ |
546 |
Xunsigned long outk = 0; |
547 |
X |
548 |
Xint |
549 |
Xmain( argc, argv ) |
550 |
X int argc; |
551 |
X char **argv; |
552 |
X{ |
553 |
X parse_args( argc, argv ); |
554 |
X |
555 |
X set_handlers(); |
556 |
X |
557 |
X buffer_allocate(); |
558 |
X |
559 |
X start_reader_and_writer(); |
560 |
X |
561 |
X byee( 0 ); |
562 |
X |
563 |
X /* NOTREACHED */ |
564 |
X exit( 0 ); |
565 |
X} |
566 |
X |
567 |
Xvoid |
568 |
Xparse_args( argc, argv ) |
569 |
X int argc; |
570 |
X char **argv; |
571 |
X{ |
572 |
X int c; |
573 |
X int iflag = 0; |
574 |
X int oflag = 0; |
575 |
X int zflag = 0; |
576 |
X extern char *optarg; |
577 |
X char blocks_given = FALSE; |
578 |
X struct stat buf; |
579 |
X |
580 |
X |
581 |
X while( (c = getopt( argc, argv, "BS:Zdm:s:b:p:u:ti:o:z:" )) != -1 ){ |
582 |
X switch( c ){ |
583 |
X case 't': /* Print to stderr the total no of bytes writen */ |
584 |
X print_total++; |
585 |
X break; |
586 |
X case 'u': /* pause after write for given microseconds */ |
587 |
X write_pause = atoi( optarg ); |
588 |
X break; |
589 |
X case 'B': /* Pad last block */ |
590 |
X padblock = TRUE; |
591 |
X break; |
592 |
X case 'Z': /* Zero by lseek on the tape device */ |
593 |
X Zflag = TRUE; |
594 |
X break; |
595 |
X case 'i': /* Input file */ |
596 |
X iflag++; |
597 |
X if( iflag > 1 ){ |
598 |
X report_proc(); |
599 |
X fprintf( stderr, "-i given twice\n" ); |
600 |
X byee( -1 ); |
601 |
X } |
602 |
X if( (fdin = open( optarg, O_RDONLY )) < 0 ){ |
603 |
X report_proc(); |
604 |
X perror( "cannot open input file" ); |
605 |
X fprintf( stderr, "filename: %s\n", optarg ); |
606 |
X byee ( -1 ); |
607 |
X } |
608 |
X break; |
609 |
X case 'o': /* Output file */ |
610 |
X oflag++; |
611 |
X if( oflag > 1 ){ |
612 |
X report_proc(); |
613 |
X fprintf( stderr, "-o given twice\n" ); |
614 |
X byee( -1 ); |
615 |
X } |
616 |
X if( (fdout = open( optarg, O_WRONLY | O_CREAT | O_TRUNC, 0666 )) < 0 ){ |
617 |
X report_proc(); |
618 |
X perror( "cannot open output file" ); |
619 |
X fprintf( stderr, "filename: %s\n", optarg ); |
620 |
X byee ( -1 ); |
621 |
X } |
622 |
X break; |
623 |
X case 'S': |
624 |
X /* Show every once in a while how much is printed */ |
625 |
X showevery = do_size( optarg ); |
626 |
X if( showevery <= 0 ) |
627 |
X showevery = PRINT_EVERY; |
628 |
X break; |
629 |
X case 'd': /* debug */ |
630 |
X debug++; |
631 |
X if( debug == 1 ){ |
632 |
X setbuf( stdout, NULL ); |
633 |
X setbuf( stderr, NULL ); |
634 |
X fprintf( stderr, "debugging turned on\n" ); |
635 |
X } |
636 |
X break; |
637 |
X case 'm': |
638 |
X /* Max size of shared memory lump */ |
639 |
X max_shmem = do_size( optarg ); |
640 |
X |
641 |
X if( max_shmem < (sizeof( struct buffer ) + (blocksize * blocks)) ){ |
642 |
X fprintf( stderr, "max_shmem %d too low\n", max_shmem ); |
643 |
X byee( -1 ); |
644 |
X } |
645 |
X break; |
646 |
X case 'b': |
647 |
X /* Number of blocks */ |
648 |
X blocks_given = TRUE; |
649 |
X blocks = atoi( optarg ); |
650 |
X if( (blocks <= 0) || (MAX_BLOCKS < blocks) ){ |
651 |
X fprintf( stderr, "blocks %d out of range\n", blocks ); |
652 |
X byee( -1 ); |
653 |
X } |
654 |
X break; |
655 |
X case 'p': /* percent to wait before dumping */ |
656 |
X percent = atoi( optarg ); |
657 |
X |
658 |
X if( (percent < 0) || (100 < percent) ){ |
659 |
X fprintf( stderr, "percent %d out of range\n", percent ); |
660 |
X byee( -1 ); |
661 |
X } |
662 |
X if( debug ) |
663 |
X fprintf( stderr, "percent set to %d\n", percent ); |
664 |
X break; |
665 |
X case 'z': |
666 |
X zflag++; |
667 |
X /* FALL THRU */ |
668 |
X case 's': /* Size of a block */ |
669 |
X blocksize = do_size( optarg ); |
670 |
X |
671 |
X if( (blocksize <= 0) || (MAX_BLOCKSIZE < blocksize) ){ |
672 |
X fprintf( stderr, "blocksize %d out of range\n", blocksize ); |
673 |
X byee( -1 ); |
674 |
X } |
675 |
X break; |
676 |
X default: |
677 |
X fprintf( stderr, "Usage: %s [-B] [-t] [-S size] [-m memsize] [-b blocks] [-p percent] [-s blocksize] [-u pause] [-i infile] [-o outfile] [-z size]\n", |
678 |
X progname ); |
679 |
X fprintf( stderr, "-B = blocked device - pad out last block\n" ); |
680 |
X fprintf( stderr, "-t = show total amount writen at end\n" ); |
681 |
X fprintf( stderr, "-S size = show amount writen every size bytes\n" ); |
682 |
X fprintf( stderr, "-m size = size of shared mem chunk to grab\n" ); |
683 |
X fprintf( stderr, "-b num = number of blocks in queue\n" ); |
684 |
X fprintf( stderr, "-p percent = don't start writing until percent blocks filled\n" ); |
685 |
X fprintf( stderr, "-s size = size of a block\n" ); |
686 |
X fprintf( stderr, "-u usecs = microseconds to sleep after each write\n" ); |
687 |
X fprintf( stderr, "-i infile = file to read from\n" ); |
688 |
X fprintf( stderr, "-o outfile = file to write to\n" ); |
689 |
X fprintf( stderr, "-z size = combined -S/-s flag\n" ); |
690 |
X byee( -1 ); |
691 |
X } |
692 |
X } |
693 |
X |
694 |
X if (zflag) showevery = blocksize; |
695 |
X |
696 |
X /* If -b was not given try and work out the max buffer size */ |
697 |
X if( !blocks_given ){ |
698 |
X blocks = (max_shmem - sizeof( struct buffer )) / blocksize; |
699 |
X if( blocks <= 0 ){ |
700 |
X fprintf( stderr, "Cannot handle blocks that big, aborting!\n" ); |
701 |
X byee( -1 ); |
702 |
X } |
703 |
X if( MAX_BLOCKS < blocks ){ |
704 |
X fprintf( stderr, "Cannot handle that many blocks, aborting!\n" ); |
705 |
X byee( -1 ); |
706 |
X } |
707 |
X } |
708 |
X |
709 |
X /* check if fdin or fdout are character special files */ |
710 |
X if( fstat( fdin, &buf ) != 0 ){ |
711 |
X report_proc(); |
712 |
X perror( "can't stat input file" ); |
713 |
X byee( -1 ); |
714 |
X } |
715 |
X in_ISCHR = S_ISCHR( buf.st_mode ); |
716 |
X if( fstat( fdout, &buf ) != 0 ){ |
717 |
X report_proc(); |
718 |
X perror( "can't stat output file" ); |
719 |
X byee( -1 ); |
720 |
X } |
721 |
X out_ISCHR = S_ISCHR( buf.st_mode ); |
722 |
X} |
723 |
X |
724 |
X/* The interrupt handler */ |
725 |
Xvoid |
726 |
Xshutdown() |
727 |
X{ |
728 |
X static int shutting; |
729 |
X if( shutting ){ |
730 |
X if( debug ) |
731 |
X fprintf( stderr, "%s: ALREADY SHUTTING!\n", proc_string ); |
732 |
X return; |
733 |
X } |
734 |
X shutting = 1; |
735 |
X if( debug ) |
736 |
X fprintf( stderr, "%s: shutdown on signal\n", proc_string ); |
737 |
X |
738 |
X byee( -1 ); |
739 |
X} |
740 |
X |
741 |
X/* Shutdown because the child has ended */ |
742 |
Xvoid |
743 |
Xchild_shutdown() |
744 |
X{ |
745 |
X /* Find out which child has died. (They may not be my |
746 |
X * children if buffer was exec'd on top of something that had |
747 |
X * childred.) |
748 |
X */ |
749 |
X int deadpid; |
750 |
X |
751 |
X while( (deadpid = waitpid( -1, &writer_status, WNOHANG )) && |
752 |
X deadpid != -1 && deadpid != 0 ){ |
753 |
X if( debug > 2 ) |
754 |
X fprintf( stderr, "child_shutdown %d: 0x%04x\n", deadpid, writer_status ); |
755 |
X if( deadpid == writer_pid ){ |
756 |
X if( debug > 2 ) |
757 |
X fprintf( stderr, "writer has ended\n" ); |
758 |
X writer_pid = 0; |
759 |
X byee( 0 ); |
760 |
X } |
761 |
X } |
762 |
X} |
763 |
X |
764 |
Xvoid |
765 |
Xset_handlers() |
766 |
X{ |
767 |
X if( debug ) |
768 |
X fprintf( stderr, "%s: setting handlers\n", proc_string ); |
769 |
X |
770 |
X signal( SIGHUP, shutdown ); |
771 |
X signal( SIGINT, shutdown ); |
772 |
X signal( SIGQUIT, shutdown ); |
773 |
X signal( SIGTERM, shutdown ); |
774 |
X#ifdef SIGCHLD |
775 |
X signal( SIGCHLD, child_shutdown ); |
776 |
X#else |
777 |
X#ifdef SIGCLD |
778 |
X signal( SIGCLD, child_shutdown ); |
779 |
X#endif |
780 |
X#endif |
781 |
X} |
782 |
X |
783 |
Xvoid |
784 |
Xbuffer_allocate() |
785 |
X{ |
786 |
X /* Allow for the data space */ |
787 |
X buffer_size = sizeof( struct buffer ) + |
788 |
X ((blocks * blocksize) - sizeof( char )); |
789 |
X |
790 |
X /* Create the space for the buffer */ |
791 |
X buffer_id = shmget( IPC_PRIVATE, |
792 |
X buffer_size, |
793 |
X IPC_CREAT|S_IREAD|S_IWRITE ); |
794 |
X if( buffer_id < 0 ){ |
795 |
X report_proc(); |
796 |
X perror( "couldn't create shared memory segment" ); |
797 |
X byee( -1 ); |
798 |
X } |
799 |
X |
800 |
X get_buffer(); |
801 |
X |
802 |
X if( debug ) |
803 |
X fprintf( stderr, "%s pbuffer is 0x%08x, buffer_size is %d [%d x %d]\n", |
804 |
X proc_string, |
805 |
X (char *)pbuffer, buffer_size, blocks, blocksize ); |
806 |
X |
807 |
X#ifdef SYS5 |
808 |
X memset( (char *)pbuffer, '\0', buffer_size ); |
809 |
X#else |
810 |
X bzero( (char *)pbuffer, buffer_size ); |
811 |
X#endif |
812 |
X pbuffer->semid = -1; |
813 |
X pbuffer->blocks_used_lock = -1; |
814 |
X pbuffer->blocks_free_lock = -1; |
815 |
X |
816 |
X pbuffer->semid = new_sems( 2 ); /* Get a read and a write sem */ |
817 |
X pbuffer->blocks_used_lock = 0; |
818 |
X /* Start it off locked - it is unlocked when a buffer gets filled in */ |
819 |
X lock( pbuffer->semid, pbuffer->blocks_used_lock ); |
820 |
X |
821 |
X pbuffer->blocks_free_lock = 1; |
822 |
X /* start this off so lock() can be called on it for each block |
823 |
X * till all the blocks are used up */ |
824 |
X sem_set( pbuffer->semid, pbuffer->blocks_free_lock, blocks - 1 ); |
825 |
X |
826 |
X /* Detattach the shared memory so the fork doesnt do anything odd */ |
827 |
X shmdt( (char *)pbuffer ); |
828 |
X pbuffer = NO_BUFFER; |
829 |
X} |
830 |
X |
831 |
Xvoid |
832 |
Xbuffer_remove() |
833 |
X{ |
834 |
X static char removing = FALSE; |
835 |
X |
836 |
X /* Avoid accidental recursion */ |
837 |
X if( removing ) |
838 |
X return; |
839 |
X removing = TRUE; |
840 |
X |
841 |
X /* Buffer not yet created */ |
842 |
X if( buffer_id == NONE ) |
843 |
X return; |
844 |
X |
845 |
X /* There should be a buffer so this must be after its detached it |
846 |
X * but before the fork picks it up */ |
847 |
X if( pbuffer == NO_BUFFER ) |
848 |
X get_buffer(); |
849 |
X |
850 |
X if( debug ) |
851 |
X fprintf( stderr, "%s: removing semaphores and buffer\n", proc_string ); |
852 |
X remove_sems( pbuffer->semid ); |
853 |
X |
854 |
X if( shmctl( buffer_id, IPC_RMID, (struct shmid_ds *)0 ) == -1 ){ |
855 |
X report_proc(); |
856 |
X perror( "failed to remove shared memory buffer" ); |
857 |
X } |
858 |
X} |
859 |
X |
860 |
Xvoid |
861 |
Xget_buffer() |
862 |
X{ |
863 |
X int b; |
864 |
X |
865 |
X /* Grab the buffer space */ |
866 |
X pbuffer = (struct buffer *)shmat( buffer_id, (char *)0, 0 ); |
867 |
X if( pbuffer == NO_BUFFER ){ |
868 |
X report_proc(); |
869 |
X perror( "failed to attach shared memory" ); |
870 |
X byee( -1 ); |
871 |
X } |
872 |
X |
873 |
X /* Setup the data space pointers */ |
874 |
X for( b = 0; b < blocks; b++ ) |
875 |
X pbuffer->block[ b ].data = |
876 |
X &pbuffer->data_space[ b * blocksize ]; |
877 |
X |
878 |
X} |
879 |
X |
880 |
Xvoid |
881 |
Xstart_reader_and_writer() |
882 |
X{ |
883 |
X fflush( stdout ); |
884 |
X fflush( stderr ); |
885 |
X |
886 |
X if( (writer_pid = fork()) == -1 ){ |
887 |
X report_proc(); |
888 |
X perror( "unable to fork" ); |
889 |
X byee( -1 ); |
890 |
X } |
891 |
X else if( writer_pid == 0 ){ |
892 |
X free_shm = 0; |
893 |
X proc_string = "buffer (writer)"; |
894 |
X reader_pid = getppid(); |
895 |
X |
896 |
X /* Never trust fork() to propogate signals - reset them */ |
897 |
X set_handlers(); |
898 |
X |
899 |
X writer(); |
900 |
X } |
901 |
X else { |
902 |
X proc_string = "buffer (reader)"; |
903 |
X reader(); |
904 |
X |
905 |
X wait_for_writer_end(); |
906 |
X } |
907 |
X} |
908 |
X |
909 |
X/* Read from stdin into the buffer */ |
910 |
Xvoid |
911 |
Xreader() |
912 |
X{ |
913 |
X if( debug ) |
914 |
X fprintf( stderr, "R: Entering reader\n" ); |
915 |
X |
916 |
X get_buffer(); |
917 |
X |
918 |
X while( 1 ){ |
919 |
X get_next_free_block(); |
920 |
X if( ! fill_block() ) |
921 |
X break; |
922 |
X } |
923 |
X |
924 |
X if( debug ) |
925 |
X fprintf( stderr, "R: Exiting reader\n" ); |
926 |
X} |
927 |
X |
928 |
Xvoid |
929 |
Xget_next_free_block() |
930 |
X{ |
931 |
X test_writer(); |
932 |
X |
933 |
X /* Maybe wait till there is room in the buffer */ |
934 |
X lock( pbuffer->semid, pbuffer->blocks_free_lock ); |
935 |
X |
936 |
X curr_block = &pbuffer->block[ pbuffer->next_block_in ]; |
937 |
X |
938 |
X pbuffer->next_block_in = INC( pbuffer->next_block_in ); |
939 |
X} |
940 |
X |
941 |
Xint |
942 |
Xfill_block() |
943 |
X{ |
944 |
X int bytes; |
945 |
X char *start; |
946 |
X int toread; |
947 |
X static char eof_reached = 0; |
948 |
X |
949 |
X if( eof_reached ){ |
950 |
X curr_block->bytes = 0; |
951 |
X unlock( pbuffer->semid, pbuffer->blocks_used_lock ); |
952 |
X return 0; |
953 |
X } |
954 |
X |
955 |
X start = curr_block->data; |
956 |
X toread = blocksize; |
957 |
X |
958 |
X /* Fill the block with input. This reblocks the input. */ |
959 |
X while( toread != 0 ){ |
960 |
X bytes = read( fdin, start, toread ); |
961 |
X if( bytes <= 0 ){ |
962 |
X /* catch interrupted system calls for death |
963 |
X * of children in pipeline */ |
964 |
X if( bytes < 0 && errno == EINTR ) |
965 |
X continue; |
966 |
X break; |
967 |
X } |
968 |
X start += bytes; |
969 |
X toread -= bytes; |
970 |
X } |
971 |
X |
972 |
X if( bytes == 0 ) |
973 |
X eof_reached = 1; |
974 |
X |
975 |
X if( bytes < 0 ){ |
976 |
X report_proc(); |
977 |
X perror( "failed to read input" ); |
978 |
X byee( -1 ); |
979 |
X } |
980 |
X |
981 |
X /* number of bytes available. Zero will be taken as eof */ |
982 |
X if( !padblock || toread == blocksize ) |
983 |
X curr_block->bytes = blocksize - toread; |
984 |
X else { |
985 |
X if( toread ) bzero( start, toread ); |
986 |
X curr_block->bytes = blocksize; |
987 |
X } |
988 |
X |
989 |
X if( debug > 1 ) |
990 |
X fprintf( stderr, "R: got %d bytes\n", curr_block->bytes ); |
991 |
X |
992 |
X unlock( pbuffer->semid, pbuffer->blocks_used_lock ); |
993 |
X |
994 |
X return curr_block->bytes; |
995 |
X} |
996 |
X |
997 |
X/* Write the buffer to stdout */ |
998 |
Xvoid |
999 |
Xwriter() |
1000 |
X{ |
1001 |
X int filled = 0; |
1002 |
X int maxfilled = (blocks * percent) / 100; |
1003 |
X int first_block; |
1004 |
X |
1005 |
X if( debug ) |
1006 |
X fprintf( stderr, "\tW: Entering writer\n blocks = %d\n maxfilled = %d\n", |
1007 |
X blocks, |
1008 |
X maxfilled ); |
1009 |
X |
1010 |
X get_buffer(); |
1011 |
X |
1012 |
X while( 1 ){ |
1013 |
X if( !filled ) |
1014 |
X first_block = pbuffer->next_block_out; |
1015 |
X get_next_filled_block(); |
1016 |
X if( !data_to_write() ) |
1017 |
X break; |
1018 |
X |
1019 |
X filled++; |
1020 |
X if( debug > 1 ) |
1021 |
X fprintf( stderr, "W: filled = %d\n", filled ); |
1022 |
X if( filled >= maxfilled ){ |
1023 |
X if( debug > 1 ) |
1024 |
X fprintf( stderr, "W: writing\n" ); |
1025 |
X write_blocks_to_stdout( filled, first_block ); |
1026 |
X filled = 0; |
1027 |
X } |
1028 |
X } |
1029 |
X |
1030 |
X write_blocks_to_stdout( filled, first_block ); |
1031 |
X |
1032 |
X if( showevery ){ |
1033 |
X pr_out(); |
1034 |
X fprintf( stderr, "\n" ); |
1035 |
X } |
1036 |
X |
1037 |
X if( print_total ){ |
1038 |
X fprintf( stderr, "Kilobytes Out %lu\n", outk ); |
1039 |
X } |
1040 |
X |
1041 |
X if( debug ) |
1042 |
X fprintf( stderr, "\tW: Exiting writer\n" ); |
1043 |
X} |
1044 |
X |
1045 |
Xvoid |
1046 |
Xget_next_filled_block() |
1047 |
X{ |
1048 |
X /* Hang till some data is available */ |
1049 |
X lock( pbuffer->semid, pbuffer->blocks_used_lock ); |
1050 |
X |
1051 |
X curr_block = &pbuffer->block[ pbuffer->next_block_out ]; |
1052 |
X |
1053 |
X pbuffer->next_block_out = INC( pbuffer->next_block_out ); |
1054 |
X} |
1055 |
X |
1056 |
Xint |
1057 |
Xdata_to_write() |
1058 |
X{ |
1059 |
X return curr_block->bytes; |
1060 |
X} |
1061 |
X |
1062 |
Xvoid |
1063 |
Xwrite_blocks_to_stdout( filled, first_block ) |
1064 |
X int filled; |
1065 |
X int first_block; |
1066 |
X{ |
1067 |
X pbuffer->next_block_out = first_block; |
1068 |
X |
1069 |
X while( filled-- ){ |
1070 |
X curr_block = &pbuffer->block[ pbuffer->next_block_out ]; |
1071 |
X pbuffer->next_block_out = INC( pbuffer->next_block_out ); |
1072 |
X write_block_to_stdout(); |
1073 |
X } |
1074 |
X} |
1075 |
X |
1076 |
Xvoid |
1077 |
Xwrite_block_to_stdout() |
1078 |
X{ |
1079 |
X static unsigned long out = 0; |
1080 |
X static unsigned long last_gb = 0; |
1081 |
X static unsigned long next_k = 0; |
1082 |
X int written; |
1083 |
X |
1084 |
X if( next_k == 0 && showevery ){ |
1085 |
X if( debug > 3 ) |
1086 |
X fprintf( stderr, "W: next_k = %lu showevery = %d\n", next_k, showevery ); |
1087 |
X showevery = showevery / 1024; |
1088 |
X next_k = showevery; |
1089 |
X } |
1090 |
X |
1091 |
X if( (written = write( fdout, curr_block->data, curr_block->bytes )) != curr_block->bytes ){ |
1092 |
X report_proc(); |
1093 |
X perror( "write of data failed" ); |
1094 |
X fprintf( stderr, "bytes to write=%d, bytes written=%d, total written %10luK\n", curr_block->bytes, written, outk ); |
1095 |
X byee( -1 ); |
1096 |
X } |
1097 |
X |
1098 |
X if( write_pause ){ |
1099 |
X usleep( write_pause ); |
1100 |
X } |
1101 |
X |
1102 |
X out = curr_block->bytes / 1024; |
1103 |
X outk += out; |
1104 |
X last_gb += out; |
1105 |
X |
1106 |
X /* |
1107 |
X * on character special devices (tapes), do an lseek() every 1 Gb, |
1108 |
X * to overcome the 2Gb limit. This resets the file offset to |
1109 |
X * zero, but -- at least on exabyte SCSI drives -- does not perform |
1110 |
X * any actual action on the tape. |
1111 |
X */ |
1112 |
X if( Zflag && last_gb >= 1 K K ){ |
1113 |
X last_gb = 0; |
1114 |
X if( in_ISCHR ) |
1115 |
X (void) lseek( fdin, 0, SEEK_SET); |
1116 |
X if( out_ISCHR ) |
1117 |
X (void) lseek( fdout, 0, SEEK_SET); |
1118 |
X } |
1119 |
X if( showevery ){ |
1120 |
X if( debug > 3 ) |
1121 |
X fprintf( stderr, "W: outk = %lu, next_k = %lu\n", |
1122 |
X outk, next_k ); |
1123 |
X if( outk >= next_k ){ |
1124 |
X pr_out(); |
1125 |
X next_k += showevery; |
1126 |
X } |
1127 |
X } |
1128 |
X |
1129 |
X unlock( pbuffer->semid, pbuffer->blocks_free_lock ); |
1130 |
X} |
1131 |
X |
1132 |
X |
1133 |
Xvoid |
1134 |
Xbyee( exit_val ) |
1135 |
X int exit_val; |
1136 |
X{ |
1137 |
X if( writer_pid != 0 ){ |
1138 |
X if( exit_val != 0 ){ |
1139 |
X /* I am shutting down due to an error. |
1140 |
X * Shut the writer down or else it will try to access |
1141 |
X * the freed up locks */ |
1142 |
X end_writer(); |
1143 |
X } |
1144 |
X wait_for_writer_end(); |
1145 |
X } |
1146 |
X |
1147 |
X if( free_shm ){ |
1148 |
X buffer_remove(); |
1149 |
X } |
1150 |
X |
1151 |
X#ifdef SIGCHLD |
1152 |
X signal( SIGCHLD, SIG_IGN ); |
1153 |
X#else |
1154 |
X#ifdef SIGCLD |
1155 |
X signal( SIGCLD, SIG_IGN ); |
1156 |
X#endif |
1157 |
X#endif |
1158 |
X |
1159 |
X /* If the child died or was killed show this in the exit value */ |
1160 |
X if( writer_status ){ |
1161 |
X if( WEXITSTATUS( writer_status ) || WIFSIGNALED( writer_status ) ){ |
1162 |
X if( debug ) |
1163 |
X fprintf( stderr, "writer died badly: 0x%04x\n", writer_status ); |
1164 |
X exit( -2 ); |
1165 |
X } |
1166 |
X } |
1167 |
X |
1168 |
X exit( exit_val ); |
1169 |
X} |
1170 |
X |
1171 |
X/* Kill off the writer */ |
1172 |
Xvoid |
1173 |
Xend_writer() |
1174 |
X{ |
1175 |
X if( writer_pid ) |
1176 |
X kill( writer_pid, SIGHUP ); |
1177 |
X} |
1178 |
X |
1179 |
Xvoid |
1180 |
Xwait_for_writer_end() |
1181 |
X{ |
1182 |
X int deadpid; |
1183 |
X |
1184 |
X /* Now wait for the writer to finish */ |
1185 |
X while( writer_pid && ((deadpid = wait( &writer_status )) != writer_pid) && |
1186 |
X deadpid != -1 ) |
1187 |
X ; |
1188 |
X} |
1189 |
X |
1190 |
Xvoid |
1191 |
Xtest_writer() |
1192 |
X{ |
1193 |
X /* Has the writer gone unexpectedly? */ |
1194 |
X if( writer_pid == 0 ){ |
1195 |
X fprintf( stderr, "writer has died unexpectedly\n" ); |
1196 |
X byee( -1 ); |
1197 |
X } |
1198 |
X} |
1199 |
X |
1200 |
X/* Given a string of <num>[<suff>] returns a num |
1201 |
X * suff = |
1202 |
X * m/M for 1meg |
1203 |
X * k/K for 1k |
1204 |
X * b/B for 512 |
1205 |
X */ |
1206 |
Xint |
1207 |
Xdo_size( arg ) |
1208 |
X char *arg; |
1209 |
X{ |
1210 |
X char format[ 20 ]; |
1211 |
X int ret; |
1212 |
X |
1213 |
X *format = '\0'; |
1214 |
X sscanf( arg, "%d%s", &ret, format ); |
1215 |
X |
1216 |
X switch( *format ){ |
1217 |
X case 'm': |
1218 |
X case 'M': |
1219 |
X ret = ret K K; |
1220 |
X break; |
1221 |
X case 'k': |
1222 |
X case 'K': |
1223 |
X ret = ret K; |
1224 |
X break; |
1225 |
X case 'b': |
1226 |
X case 'B': |
1227 |
X ret *= 512; |
1228 |
X break; |
1229 |
X } |
1230 |
X |
1231 |
X return ret; |
1232 |
X} |
1233 |
X |
1234 |
Xvoid |
1235 |
Xpr_out() |
1236 |
X{ |
1237 |
X fprintf( stderr, " %10luK\r", outk ); |
1238 |
X} |
1239 |
X |
1240 |
X#ifdef SYS5 |
1241 |
X#include <sys/time.h> |
1242 |
X |
1243 |
X#ifndef __alpha |
1244 |
Xbzero( b, l ) |
1245 |
X char *b; |
1246 |
X unsigned l; |
1247 |
X{ |
1248 |
X memset( b, '\0', l ); |
1249 |
X} |
1250 |
X#endif /* __alpha */ |
1251 |
X |
1252 |
Xusleep_back() |
1253 |
X{ |
1254 |
X} |
1255 |
X |
1256 |
Xvoid |
1257 |
Xusleep( u ) |
1258 |
X unsigned u; |
1259 |
X{ |
1260 |
X struct itimerval old, t; |
1261 |
X signal( SIGALRM, usleep_back ); |
1262 |
X t.it_interval.tv_sec = 0; |
1263 |
X t.it_interval.tv_usec = 0; |
1264 |
X t.it_value.tv_sec = u / 1000000; |
1265 |
X t.it_value.tv_usec = u % 1000000; |
1266 |
X setitimer( ITIMER_REAL, &t, &old ); |
1267 |
X pause(); |
1268 |
X setitimer( ITIMER_REAL, &old, NULL ); |
1269 |
X} |
1270 |
X#endif |
1271 |
X |
1272 |
X/* Called before error reports */ |
1273 |
Xvoid |
1274 |
Xreport_proc() |
1275 |
X{ |
1276 |
X fprintf( stderr, "%s: ", proc_string ); |
1277 |
X} |
1278 |
END_OF_FILE |
1279 |
if test 21928 -ne `wc -c <'buffer.c'`; then |
1280 |
echo shar: \"'buffer.c'\" unpacked with wrong size! |
1281 |
fi |
1282 |
# end of 'buffer.c' |
1283 |
fi |
1284 |
if test -f 'sem.c' -a "${1}" != "-c" ; then |
1285 |
echo shar: Will not clobber existing file \"'sem.c'\" |
1286 |
else |
1287 |
echo shar: Extracting \"'sem.c'\" \(3087 characters\) |
1288 |
sed "s/^X//" >'sem.c' <<'END_OF_FILE' |
1289 |
X/* |
1290 |
X Buffer. Very fast reblocking filter speedy writing of tapes. |
1291 |
X Copyright (C) 1990,1991 Lee McLoughlin |
1292 |
X |
1293 |
X This program is free software; you can redistribute it and/or modify |
1294 |
X it under the terms of the GNU General Public License as published by |
1295 |
X the Free Software Foundation; either version 1, or (at your option) |
1296 |
X any later version. |
1297 |
X |
1298 |
X This program is distributed in the hope that it will be useful, |
1299 |
X but WITHOUT ANY WARRANTY; without even the implied warranty of |
1300 |
X MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1301 |
X GNU General Public License for more details. |
1302 |
X |
1303 |
X You should have received a copy of the GNU General Public License |
1304 |
X along with this program; if not, write to the Free Software |
1305 |
X Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
1306 |
X |
1307 |
X Lee McLoughlin. |
1308 |
X Dept of Computing, Imperial College, |
1309 |
X 180 Queens Gate, London, SW7 2BZ, UK. |
1310 |
X |
1311 |
X Email: L.McLoughlin@doc.ic.ac.uk |
1312 |
X*/ |
1313 |
X |
1314 |
X/* This is a simple module to provide an easier to understand interface to |
1315 |
X * semaphores */ |
1316 |
X |
1317 |
X#include <stdio.h> |
1318 |
X#include <sys/types.h> |
1319 |
X#include <sys/stat.h> |
1320 |
X#include <sys/ipc.h> |
1321 |
X#include <sys/sem.h> |
1322 |
X#include <errno.h> |
1323 |
X#include "sem.h" |
1324 |
X |
1325 |
X#if defined(SYS5) || defined(ultrix) || defined(_AIX) |
1326 |
Xunion semun { |
1327 |
X int val; |
1328 |
X struct semid_ds *buf; |
1329 |
X ushort *array; |
1330 |
X}; |
1331 |
X#endif |
1332 |
X |
1333 |
X/* IMPORTS */ |
1334 |
X |
1335 |
X/* Used to print error messages */ |
1336 |
Xextern void report_proc(); |
1337 |
X |
1338 |
X/* Used to end the program - on error */ |
1339 |
Xextern void byee(); |
1340 |
X |
1341 |
X |
1342 |
X |
1343 |
X/* Set a semaphore to a particular value - meant to be used before |
1344 |
X * first lock/unlock */ |
1345 |
Xvoid |
1346 |
Xsem_set( sem_id, semn, val ) |
1347 |
X int sem_id; |
1348 |
X int semn; |
1349 |
X int val; |
1350 |
X{ |
1351 |
X union semun arg; |
1352 |
X extern int errno; |
1353 |
X |
1354 |
X arg.val = val; |
1355 |
X |
1356 |
X errno = 0; |
1357 |
X semctl( sem_id, semn, SETVAL, arg ); |
1358 |
X if( errno != 0 ){ |
1359 |
X report_proc(); |
1360 |
X perror( "internal error, sem_set" ); |
1361 |
X byee( -1 ); |
1362 |
X } |
1363 |
X} |
1364 |
X |
1365 |
Xint |
1366 |
Xnew_sems( nsems ) |
1367 |
X int nsems; |
1368 |
X{ |
1369 |
X int sem; |
1370 |
X int i; |
1371 |
X |
1372 |
X sem = semget( IPC_PRIVATE, nsems, IPC_CREAT|S_IREAD|S_IWRITE ); |
1373 |
X if( sem < 0 ){ |
1374 |
X report_proc(); |
1375 |
X perror( "internal error, couldn't create semaphore" ); |
1376 |
X byee( -1 ); |
1377 |
X } |
1378 |
X |
1379 |
X for( i = 0; i < nsems; i++ ){ |
1380 |
X sem_set( sem, i, 1 ); |
1381 |
X } |
1382 |
X |
1383 |
X return sem; |
1384 |
X} |
1385 |
X |
1386 |
Xstatic |
1387 |
Xdo_sem( sem_id, pbuf, err ) |
1388 |
X int sem_id; |
1389 |
X struct sembuf *pbuf; |
1390 |
X char *err; |
1391 |
X{ |
1392 |
X /* This just keeps us going in case of EINTR */ |
1393 |
X while( 1 ){ |
1394 |
X if( semop( sem_id, pbuf, 1 ) == -1 ){ |
1395 |
X if( errno == EINTR ){ |
1396 |
X continue; |
1397 |
X } |
1398 |
X report_proc(); |
1399 |
X fprintf( stderr, "internal error pid %d, lock id %d\n", |
1400 |
X getpid(), sem_id ); |
1401 |
X perror( err ); |
1402 |
X byee( -1 ); |
1403 |
X } |
1404 |
X return; |
1405 |
X } |
1406 |
X} |
1407 |
X |
1408 |
Xvoid |
1409 |
Xlock( sem_id, semn ) |
1410 |
X int sem_id; |
1411 |
X int semn; |
1412 |
X{ |
1413 |
X struct sembuf sembuf; |
1414 |
X |
1415 |
X sembuf.sem_num = semn; |
1416 |
X sembuf.sem_op = -1; |
1417 |
X sembuf.sem_flg = 0; |
1418 |
X |
1419 |
X do_sem( sem_id, &sembuf, "lock error" ); |
1420 |
X} |
1421 |
X |
1422 |
Xvoid |
1423 |
Xunlock( sem_id, semn ) |
1424 |
X int sem_id; |
1425 |
X int semn; |
1426 |
X{ |
1427 |
X struct sembuf sembuf; |
1428 |
X |
1429 |
X sembuf.sem_num = semn; |
1430 |
X sembuf.sem_op = 1; |
1431 |
X sembuf.sem_flg = 0; |
1432 |
X |
1433 |
X do_sem( sem_id, &sembuf, "unlock error" ); |
1434 |
X} |
1435 |
X |
1436 |
Xvoid |
1437 |
Xremove_sems( sem_id ) |
1438 |
X int sem_id; |
1439 |
X{ |
1440 |
X if( sem_id == -1 ) |
1441 |
X return; |
1442 |
X |
1443 |
X if( semctl( sem_id, 0, IPC_RMID, NULL ) == -1 ){ |
1444 |
X report_proc(); |
1445 |
X perror( "internal error, failed to remove semaphore" ); |
1446 |
X } |
1447 |
X} |
1448 |
END_OF_FILE |
1449 |
if test 3087 -ne `wc -c <'sem.c'`; then |
1450 |
echo shar: \"'sem.c'\" unpacked with wrong size! |
1451 |
fi |
1452 |
# end of 'sem.c' |
1453 |
fi |
1454 |
if test -f 'sem.h' -a "${1}" != "-c" ; then |
1455 |
echo shar: Will not clobber existing file \"'sem.h'\" |
1456 |
else |
1457 |
echo shar: Extracting \"'sem.h'\" \(1189 characters\) |
1458 |
sed "s/^X//" >'sem.h' <<'END_OF_FILE' |
1459 |
X/* |
1460 |
X Buffer. Very fast reblocking filter speedy writing of tapes. |
1461 |
X Copyright (C) 1990,1991 Lee McLoughlin |
1462 |
X |
1463 |
X This program is free software; you can redistribute it and/or modify |
1464 |
X it under the terms of the GNU General Public License as published by |
1465 |
X the Free Software Foundation; either version 1, or (at your option) |
1466 |
X any later version. |
1467 |
X |
1468 |
X This program is distributed in the hope that it will be useful, |
1469 |
X but WITHOUT ANY WARRANTY; without even the implied warranty of |
1470 |
X MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1471 |
X GNU General Public License for more details. |
1472 |
X |
1473 |
X You should have received a copy of the GNU General Public License |
1474 |
X along with this program; if not, write to the Free Software |
1475 |
X Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
1476 |
X |
1477 |
X Lee McLoughlin. |
1478 |
X Dept of Computing, Imperial College, |
1479 |
X 180 Queens Gate, London, SW7 2BZ, UK. |
1480 |
X |
1481 |
X Email: L.McLoughlin@doc.ic.ac.uk |
1482 |
X*/ |
1483 |
X |
1484 |
X/* This is a simple module to provide an easier to understand interface to |
1485 |
X * semaphores */ |
1486 |
X |
1487 |
X/* Allocate new semaphores */ |
1488 |
Xint new_sems(); |
1489 |
X |
1490 |
X/* Perform actions on semaphores */ |
1491 |
Xvoid sem_set(); |
1492 |
Xvoid lock(); |
1493 |
Xvoid unlock(); |
1494 |
Xvoid remove_sems(); |
1495 |
END_OF_FILE |
1496 |
if test 1189 -ne `wc -c <'sem.h'`; then |
1497 |
echo shar: \"'sem.h'\" unpacked with wrong size! |
1498 |
fi |
1499 |
# end of 'sem.h' |
1500 |
fi |
1501 |
if test -f 'COPYING' -a "${1}" != "-c" ; then |
1502 |
echo shar: Will not clobber existing file \"'COPYING'\" |
1503 |
else |
1504 |
echo shar: Extracting \"'COPYING'\" \(17982 characters\) |
1505 |
sed "s/^X//" >'COPYING' <<'END_OF_FILE' |
1506 |
X GNU GENERAL PUBLIC LICENSE |
1507 |
X Version 2, June 1991 |
1508 |
X |
1509 |
X Copyright (C) 1989, 1991 Free Software Foundation, Inc. |
1510 |
X 675 Mass Ave, Cambridge, MA 02139, USA |
1511 |
X Everyone is permitted to copy and distribute verbatim copies |
1512 |
X of this license document, but changing it is not allowed. |
1513 |
X |
1514 |
X Preamble |
1515 |
X |
1516 |
X The licenses for most software are designed to take away your |
1517 |
Xfreedom to share and change it. By contrast, the GNU General Public |
1518 |
XLicense is intended to guarantee your freedom to share and change free |
1519 |
Xsoftware--to make sure the software is free for all its users. This |
1520 |
XGeneral Public License applies to most of the Free Software |
1521 |
XFoundation's software and to any other program whose authors commit to |
1522 |
Xusing it. (Some other Free Software Foundation software is covered by |
1523 |
Xthe GNU Library General Public License instead.) You can apply it to |
1524 |
Xyour programs, too. |
1525 |
X |
1526 |
X When we speak of free software, we are referring to freedom, not |
1527 |
Xprice. Our General Public Licenses are designed to make sure that you |
1528 |
Xhave the freedom to distribute copies of free software (and charge for |
1529 |
Xthis service if you wish), that you receive source code or can get it |
1530 |
Xif you want it, that you can change the software or use pieces of it |
1531 |
Xin new free programs; and that you know you can do these things. |
1532 |
X |
1533 |
X To protect your rights, we need to make restrictions that forbid |
1534 |
Xanyone to deny you these rights or to ask you to surrender the rights. |
1535 |
XThese restrictions translate to certain responsibilities for you if you |
1536 |
Xdistribute copies of the software, or if you modify it. |
1537 |
X |
1538 |
X For example, if you distribute copies of such a program, whether |
1539 |
Xgratis or for a fee, you must give the recipients all the rights that |
1540 |
Xyou have. You must make sure that they, too, receive or can get the |
1541 |
Xsource code. And you must show them these terms so they know their |
1542 |
Xrights. |
1543 |
X |
1544 |
X We protect your rights with two steps: (1) copyright the software, and |
1545 |
X(2) offer you this license which gives you legal permission to copy, |
1546 |
Xdistribute and/or modify the software. |
1547 |
X |
1548 |
X Also, for each author's protection and ours, we want to make certain |
1549 |
Xthat everyone understands that there is no warranty for this free |
1550 |
Xsoftware. If the software is modified by someone else and passed on, we |
1551 |
Xwant its recipients to know that what they have is not the original, so |
1552 |
Xthat any problems introduced by others will not reflect on the original |
1553 |
Xauthors' reputations. |
1554 |
X |
1555 |
X Finally, any free program is threatened constantly by software |
1556 |
Xpatents. We wish to avoid the danger that redistributors of a free |
1557 |
Xprogram will individually obtain patent licenses, in effect making the |
1558 |
Xprogram proprietary. To prevent this, we have made it clear that any |
1559 |
Xpatent must be licensed for everyone's free use or not licensed at all. |
1560 |
X |
1561 |
X The precise terms and conditions for copying, distribution and |
1562 |
Xmodification follow. |
1563 |
X |
1564 |
X GNU GENERAL PUBLIC LICENSE |
1565 |
X TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION |
1566 |
X |
1567 |
X 0. This License applies to any program or other work which contains |
1568 |
Xa notice placed by the copyright holder saying it may be distributed |
1569 |
Xunder the terms of this General Public License. The "Program", below, |
1570 |
Xrefers to any such program or work, and a "work based on the Program" |
1571 |
Xmeans either the Program or any derivative work under copyright law: |
1572 |
Xthat is to say, a work containing the Program or a portion of it, |
1573 |
Xeither verbatim or with modifications and/or translated into another |
1574 |
Xlanguage. (Hereinafter, translation is included without limitation in |
1575 |
Xthe term "modification".) Each licensee is addressed as "you". |
1576 |
X |
1577 |
XActivities other than copying, distribution and modification are not |
1578 |
Xcovered by this License; they are outside its scope. The act of |
1579 |
Xrunning the Program is not restricted, and the output from the Program |
1580 |
Xis covered only if its contents constitute a work based on the |
1581 |
XProgram (independent of having been made by running the Program). |
1582 |
XWhether that is true depends on what the Program does. |
1583 |
X |
1584 |
X 1. You may copy and distribute verbatim copies of the Program's |
1585 |
Xsource code as you receive it, in any medium, provided that you |
1586 |
Xconspicuously and appropriately publish on each copy an appropriate |
1587 |
Xcopyright notice and disclaimer of warranty; keep intact all the |
1588 |
Xnotices that refer to this License and to the absence of any warranty; |
1589 |
Xand give any other recipients of the Program a copy of this License |
1590 |
Xalong with the Program. |
1591 |
X |
1592 |
XYou may charge a fee for the physical act of transferring a copy, and |
1593 |
Xyou may at your option offer warranty protection in exchange for a fee. |
1594 |
X |
1595 |
X 2. You may modify your copy or copies of the Program or any portion |
1596 |
Xof it, thus forming a work based on the Program, and copy and |
1597 |
Xdistribute such modifications or work under the terms of Section 1 |
1598 |
Xabove, provided that you also meet all of these conditions: |
1599 |
X |
1600 |
X a) You must cause the modified files to carry prominent notices |
1601 |
X stating that you changed the files and the date of any change. |
1602 |
X |
1603 |
X b) You must cause any work that you distribute or publish, that in |
1604 |
X whole or in part contains or is derived from the Program or any |
1605 |
X part thereof, to be licensed as a whole at no charge to all third |
1606 |
X parties under the terms of this License. |
1607 |
X |
1608 |
X c) If the modified program normally reads commands interactively |
1609 |
X when run, you must cause it, when started running for such |
1610 |
X interactive use in the most ordinary way, to print or display an |
1611 |
X announcement including an appropriate copyright notice and a |
1612 |
X notice that there is no warranty (or else, saying that you provide |
1613 |
X a warranty) and that users may redistribute the program under |
1614 |
X these conditions, and telling the user how to view a copy of this |
1615 |
X License. (Exception: if the Program itself is interactive but |
1616 |
X does not normally print such an announcement, your work based on |
1617 |
X the Program is not required to print an announcement.) |
1618 |
X |
1619 |
XThese requirements apply to the modified work as a whole. If |
1620 |
Xidentifiable sections of that work are not derived from the Program, |
1621 |
Xand can be reasonably considered independent and separate works in |
1622 |
Xthemselves, then this License, and its terms, do not apply to those |
1623 |
Xsections when you distribute them as separate works. But when you |
1624 |
Xdistribute the same sections as part of a whole which is a work based |
1625 |
Xon the Program, the distribution of the whole must be on the terms of |
1626 |
Xthis License, whose permissions for other licensees extend to the |
1627 |
Xentire whole, and thus to each and every part regardless of who wrote it. |
1628 |
X |
1629 |
XThus, it is not the intent of this section to claim rights or contest |
1630 |
Xyour rights to work written entirely by you; rather, the intent is to |
1631 |
Xexercise the right to control the distribution of derivative or |
1632 |
Xcollective works based on the Program. |
1633 |
X |
1634 |
XIn addition, mere aggregation of another work not based on the Program |
1635 |
Xwith the Program (or with a work based on the Program) on a volume of |
1636 |
Xa storage or distribution medium does not bring the other work under |
1637 |
Xthe scope of this License. |
1638 |
X |
1639 |
X 3. You may copy and distribute the Program (or a work based on it, |
1640 |
Xunder Section 2) in object code or executable form under the terms of |
1641 |
XSections 1 and 2 above provided that you also do one of the following: |
1642 |
X |
1643 |
X a) Accompany it with the complete corresponding machine-readable |
1644 |
X source code, which must be distributed under the terms of Sections |
1645 |
X 1 and 2 above on a medium customarily used for software interchange; or, |
1646 |
X |
1647 |
X b) Accompany it with a written offer, valid for at least three |
1648 |
X years, to give any third party, for a charge no more than your |
1649 |
X cost of physically performing source distribution, a complete |
1650 |
X machine-readable copy of the corresponding source code, to be |
1651 |
X distributed under the terms of Sections 1 and 2 above on a medium |
1652 |
X customarily used for software interchange; or, |
1653 |
X |
1654 |
X c) Accompany it with the information you received as to the offer |
1655 |
X to distribute corresponding source code. (This alternative is |
1656 |
X allowed only for noncommercial distribution and only if you |
1657 |
X received the program in object code or executable form with such |
1658 |
X an offer, in accord with Subsection b above.) |
1659 |
X |
1660 |
XThe source code for a work means the preferred form of the work for |
1661 |
Xmaking modifications to it. For an executable work, complete source |
1662 |
Xcode means all the source code for all modules it contains, plus any |
1663 |
Xassociated interface definition files, plus the scripts used to |
1664 |
Xcontrol compilation and installation of the executable. However, as a |
1665 |
Xspecial exception, the source code distributed need not include |
1666 |
Xanything that is normally distributed (in either source or binary |
1667 |
Xform) with the major components (compiler, kernel, and so on) of the |
1668 |
Xoperating system on which the executable runs, unless that component |
1669 |
Xitself accompanies the executable. |
1670 |
X |
1671 |
XIf distribution of executable or object code is made by offering |
1672 |
Xaccess to copy from a designated place, then offering equivalent |
1673 |
Xaccess to copy the source code from the same place counts as |
1674 |
Xdistribution of the source code, even though third parties are not |
1675 |
Xcompelled to copy the source along with the object code. |
1676 |
X |
1677 |
X 4. You may not copy, modify, sublicense, or distribute the Program |
1678 |
Xexcept as expressly provided under this License. Any attempt |
1679 |
Xotherwise to copy, modify, sublicense or distribute the Program is |
1680 |
Xvoid, and will automatically terminate your rights under this License. |
1681 |
XHowever, parties who have received copies, or rights, from you under |
1682 |
Xthis License will not have their licenses terminated so long as such |
1683 |
Xparties remain in full compliance. |
1684 |
X |
1685 |
X 5. You are not required to accept this License, since you have not |
1686 |
Xsigned it. However, nothing else grants you permission to modify or |
1687 |
Xdistribute the Program or its derivative works. These actions are |
1688 |
Xprohibited by law if you do not accept this License. Therefore, by |
1689 |
Xmodifying or distributing the Program (or any work based on the |
1690 |
XProgram), you indicate your acceptance of this License to do so, and |
1691 |
Xall its terms and conditions for copying, distributing or modifying |
1692 |
Xthe Program or works based on it. |
1693 |
X |
1694 |
X 6. Each time you redistribute the Program (or any work based on the |
1695 |
XProgram), the recipient automatically receives a license from the |
1696 |
Xoriginal licensor to copy, distribute or modify the Program subject to |
1697 |
Xthese terms and conditions. You may not impose any further |
1698 |
Xrestrictions on the recipients' exercise of the rights granted herein. |
1699 |
XYou are not responsible for enforcing compliance by third parties to |
1700 |
Xthis License. |
1701 |
X |
1702 |
X 7. If, as a consequence of a court judgment or allegation of patent |
1703 |
Xinfringement or for any other reason (not limited to patent issues), |
1704 |
Xconditions are imposed on you (whether by court order, agreement or |
1705 |
Xotherwise) that contradict the conditions of this License, they do not |
1706 |
Xexcuse you from the conditions of this License. If you cannot |
1707 |
Xdistribute so as to satisfy simultaneously your obligations under this |
1708 |
XLicense and any other pertinent obligations, then as a consequence you |
1709 |
Xmay not distribute the Program at all. For example, if a patent |
1710 |
Xlicense would not permit royalty-free redistribution of the Program by |
1711 |
Xall those who receive copies directly or indirectly through you, then |
1712 |
Xthe only way you could satisfy both it and this License would be to |
1713 |
Xrefrain entirely from distribution of the Program. |
1714 |
X |
1715 |
XIf any portion of this section is held invalid or unenforceable under |
1716 |
Xany particular circumstance, the balance of the section is intended to |
1717 |
Xapply and the section as a whole is intended to apply in other |
1718 |
Xcircumstances. |
1719 |
X |
1720 |
XIt is not the purpose of this section to induce you to infringe any |
1721 |
Xpatents or other property right claims or to contest validity of any |
1722 |
Xsuch claims; this section has the sole purpose of protecting the |
1723 |
Xintegrity of the free software distribution system, which is |
1724 |
Ximplemented by public license practices. Many people have made |
1725 |
Xgenerous contributions to the wide range of software distributed |
1726 |
Xthrough that system in reliance on consistent application of that |
1727 |
Xsystem; it is up to the author/donor to decide if he or she is willing |
1728 |
Xto distribute software through any other system and a licensee cannot |
1729 |
Ximpose that choice. |
1730 |
X |
1731 |
XThis section is intended to make thoroughly clear what is believed to |
1732 |
Xbe a consequence of the rest of this License. |
1733 |
X |
1734 |
X 8. If the distribution and/or use of the Program is restricted in |
1735 |
Xcertain countries either by patents or by copyrighted interfaces, the |
1736 |
Xoriginal copyright holder who places the Program under this License |
1737 |
Xmay add an explicit geographical distribution limitation excluding |
1738 |
Xthose countries, so that distribution is permitted only in or among |
1739 |
Xcountries not thus excluded. In such case, this License incorporates |
1740 |
Xthe limitation as if written in the body of this License. |
1741 |
X |
1742 |
X 9. The Free Software Foundation may publish revised and/or new versions |
1743 |
Xof the General Public License from time to time. Such new versions will |
1744 |
Xbe similar in spirit to the present version, but may differ in detail to |
1745 |
Xaddress new problems or concerns. |
1746 |
X |
1747 |
XEach version is given a distinguishing version number. If the Program |
1748 |
Xspecifies a version number of this License which applies to it and "any |
1749 |
Xlater version", you have the option of following the terms and conditions |
1750 |
Xeither of that version or of any later version published by the Free |
1751 |
XSoftware Foundation. If the Program does not specify a version number of |
1752 |
Xthis License, you may choose any version ever published by the Free Software |
1753 |
XFoundation. |
1754 |
X |
1755 |
X 10. If you wish to incorporate parts of the Program into other free |
1756 |
Xprograms whose distribution conditions are different, write to the author |
1757 |
Xto ask for permission. For software which is copyrighted by the Free |
1758 |
XSoftware Foundation, write to the Free Software Foundation; we sometimes |
1759 |
Xmake exceptions for this. Our decision will be guided by the two goals |
1760 |
Xof preserving the free status of all derivatives of our free software and |
1761 |
Xof promoting the sharing and reuse of software generally. |
1762 |
X |
1763 |
X NO WARRANTY |
1764 |
X |
1765 |
X 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY |
1766 |
XFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN |
1767 |
XOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES |
1768 |
XPROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED |
1769 |
XOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
1770 |
XMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS |
1771 |
XTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE |
1772 |
XPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, |
1773 |
XREPAIR OR CORRECTION. |
1774 |
X |
1775 |
X 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING |
1776 |
XWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR |
1777 |
XREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, |
1778 |
XINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING |
1779 |
XOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED |
1780 |
XTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY |
1781 |
XYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER |
1782 |
XPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE |
1783 |
XPOSSIBILITY OF SUCH DAMAGES. |
1784 |
X |
1785 |
X END OF TERMS AND CONDITIONS |
1786 |
X |
1787 |
X Appendix: How to Apply These Terms to Your New Programs |
1788 |
X |
1789 |
X If you develop a new program, and you want it to be of the greatest |
1790 |
Xpossible use to the public, the best way to achieve this is to make it |
1791 |
Xfree software which everyone can redistribute and change under these terms. |
1792 |
X |
1793 |
X To do so, attach the following notices to the program. It is safest |
1794 |
Xto attach them to the start of each source file to most effectively |
1795 |
Xconvey the exclusion of warranty; and each file should have at least |
1796 |
Xthe "copyright" line and a pointer to where the full notice is found. |
1797 |
X |
1798 |
X <one line to give the program's name and a brief idea of what it does.> |
1799 |
X Copyright (C) 19yy <name of author> |
1800 |
X |
1801 |
X This program is free software; you can redistribute it and/or modify |
1802 |
X it under the terms of the GNU General Public License as published by |
1803 |
X the Free Software Foundation; either version 2 of the License, or |
1804 |
X (at your option) any later version. |
1805 |
X |
1806 |
X This program is distributed in the hope that it will be useful, |
1807 |
X but WITHOUT ANY WARRANTY; without even the implied warranty of |
1808 |
X MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1809 |
X GNU General Public License for more details. |
1810 |
X |
1811 |
X You should have received a copy of the GNU General Public License |
1812 |
X along with this program; if not, write to the Free Software |
1813 |
X Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
1814 |
X |
1815 |
XAlso add information on how to contact you by electronic and paper mail. |
1816 |
X |
1817 |
XIf the program is interactive, make it output a short notice like this |
1818 |
Xwhen it starts in an interactive mode: |
1819 |
X |
1820 |
X Gnomovision version 69, Copyright (C) 19yy name of author |
1821 |
X Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. |
1822 |
X This is free software, and you are welcome to redistribute it |
1823 |
X under certain conditions; type `show c' for details. |
1824 |
X |
1825 |
XThe hypothetical commands `show w' and `show c' should show the appropriate |
1826 |
Xparts of the General Public License. Of course, the commands you use may |
1827 |
Xbe called something other than `show w' and `show c'; they could even be |
1828 |
Xmouse-clicks or menu items--whatever suits your program. |
1829 |
X |
1830 |
XYou should also get your employer (if you work as a programmer) or your |
1831 |
Xschool, if any, to sign a "copyright disclaimer" for the program, if |
1832 |
Xnecessary. Here is a sample; alter the names: |
1833 |
X |
1834 |
X Yoyodyne, Inc., hereby disclaims all copyright interest in the program |
1835 |
X `Gnomovision' (which makes passes at compilers) written by James Hacker. |
1836 |
X |
1837 |
X <signature of Ty Coon>, 1 April 1989 |
1838 |
X Ty Coon, President of Vice |
1839 |
X |
1840 |
XThis General Public License does not permit incorporating your program into |
1841 |
Xproprietary programs. If your program is a subroutine library, you may |
1842 |
Xconsider it more useful to permit linking proprietary applications with the |
1843 |
Xlibrary. If this is what you want to do, use the GNU Library General |
1844 |
XPublic License instead of this License. |
1845 |
END_OF_FILE |
1846 |
if test 17982 -ne `wc -c <'COPYING'`; then |
1847 |
echo shar: \"'COPYING'\" unpacked with wrong size! |
1848 |
fi |
1849 |
# end of 'COPYING' |
1850 |
fi |
1851 |
echo shar: End of shell archive. |
1852 |
exit 0 |