xref: /plan9/sys/src/cmd/bsplit.c (revision 4d2c0504d2bd576e9eb786d7a9d27f921b5ebd5e)
1*4d2c0504SDavid du Colombier /*
2*4d2c0504SDavid du Colombier  * bsplit - split big binaries (copy-less plan 9 version)
3*4d2c0504SDavid du Colombier  */
4*4d2c0504SDavid du Colombier 
5*4d2c0504SDavid du Colombier #include <u.h>
6*4d2c0504SDavid du Colombier #include <libc.h>
7*4d2c0504SDavid du Colombier #include <authsrv.h>		/* for ANAMELEN */
8*4d2c0504SDavid du Colombier 
9*4d2c0504SDavid du Colombier enum {
10*4d2c0504SDavid du Colombier 	Stdin,
11*4d2c0504SDavid du Colombier 	Sectsiz = 512,
12*4d2c0504SDavid du Colombier 	Bufsiz = 256*Sectsiz,
13*4d2c0504SDavid du Colombier };
14*4d2c0504SDavid du Colombier 
15*4d2c0504SDavid du Colombier /* disk address (in bytes or sectors), also type of 2nd arg. to seek */
16*4d2c0504SDavid du Colombier typedef uvlong Daddr;
17*4d2c0504SDavid du Colombier 
18*4d2c0504SDavid du Colombier #define BLEN(s)	((s)->wp - (s)->rp)
19*4d2c0504SDavid du Colombier #define BALLOC(s) ((s)->lim - (s)->base)
20*4d2c0504SDavid du Colombier 
21*4d2c0504SDavid du Colombier typedef struct {
22*4d2c0504SDavid du Colombier 	uchar*	rp;		/* first unconsumed byte */
23*4d2c0504SDavid du Colombier 	uchar*	wp;		/* first empty byte */
24*4d2c0504SDavid du Colombier 	uchar*	lim;		/* 1 past the end of the buffer */
25*4d2c0504SDavid du Colombier 	uchar*	base;		/* start of the buffer */
26*4d2c0504SDavid du Colombier } Buffer;
27*4d2c0504SDavid du Colombier 
28*4d2c0504SDavid du Colombier typedef struct {
29*4d2c0504SDavid du Colombier 	/* parameters */
30*4d2c0504SDavid du Colombier 	Daddr	maxoutsz;	/* maximum size of output file(s) */
31*4d2c0504SDavid du Colombier 
32*4d2c0504SDavid du Colombier 	Daddr	fileout;	/* bytes written to the current output file */
33*4d2c0504SDavid du Colombier 	char	*filenm;
34*4d2c0504SDavid du Colombier 	int	filesz;		/* size of filenm */
35*4d2c0504SDavid du Colombier 	char	*prefix;
36*4d2c0504SDavid du Colombier 	long	filenum;
37*4d2c0504SDavid du Colombier 	int	outf;		/* open output file */
38*4d2c0504SDavid du Colombier 
39*4d2c0504SDavid du Colombier 	Buffer	buff;
40*4d2c0504SDavid du Colombier } Copy;
41*4d2c0504SDavid du Colombier 
42*4d2c0504SDavid du Colombier /* global data */
43*4d2c0504SDavid du Colombier char *argv0;
44*4d2c0504SDavid du Colombier 
45*4d2c0504SDavid du Colombier /* private data */
46*4d2c0504SDavid du Colombier static Copy cp = { 512*1024*1024 };	/* default maximum size */
47*4d2c0504SDavid du Colombier static int debug;
48*4d2c0504SDavid du Colombier 
49*4d2c0504SDavid du Colombier static void
bufreset(Buffer * bp)50*4d2c0504SDavid du Colombier bufreset(Buffer *bp)
51*4d2c0504SDavid du Colombier {
52*4d2c0504SDavid du Colombier 	bp->rp = bp->wp = bp->base;
53*4d2c0504SDavid du Colombier }
54*4d2c0504SDavid du Colombier 
55*4d2c0504SDavid du Colombier static void
bufinit(Buffer * bp,uchar * block,unsigned size)56*4d2c0504SDavid du Colombier bufinit(Buffer *bp, uchar *block, unsigned size)
57*4d2c0504SDavid du Colombier {
58*4d2c0504SDavid du Colombier 	bp->base = block;
59*4d2c0504SDavid du Colombier 	bp->lim = bp->base + size;
60*4d2c0504SDavid du Colombier 	bufreset(bp);
61*4d2c0504SDavid du Colombier }
62*4d2c0504SDavid du Colombier 
63*4d2c0504SDavid du Colombier static int
eopen(char * file,int mode)64*4d2c0504SDavid du Colombier eopen(char *file, int mode)
65*4d2c0504SDavid du Colombier {
66*4d2c0504SDavid du Colombier 	int fd = open(file, mode);
67*4d2c0504SDavid du Colombier 
68*4d2c0504SDavid du Colombier 	if (fd < 0)
69*4d2c0504SDavid du Colombier 		sysfatal("can't open %s: %r", file);
70*4d2c0504SDavid du Colombier 	return fd;
71*4d2c0504SDavid du Colombier }
72*4d2c0504SDavid du Colombier 
73*4d2c0504SDavid du Colombier static int
ecreate(char * file,int mode)74*4d2c0504SDavid du Colombier ecreate(char *file, int mode)
75*4d2c0504SDavid du Colombier {
76*4d2c0504SDavid du Colombier 	int fd = create(file, mode, 0666);
77*4d2c0504SDavid du Colombier 
78*4d2c0504SDavid du Colombier 	if (fd < 0)
79*4d2c0504SDavid du Colombier 		sysfatal("can't create %s: %r", file);
80*4d2c0504SDavid du Colombier 	return fd;
81*4d2c0504SDavid du Colombier }
82*4d2c0504SDavid du Colombier 
83*4d2c0504SDavid du Colombier static char *
filename(Copy * cp)84*4d2c0504SDavid du Colombier filename(Copy *cp)
85*4d2c0504SDavid du Colombier {
86*4d2c0504SDavid du Colombier 	return cp->filenm;
87*4d2c0504SDavid du Colombier }
88*4d2c0504SDavid du Colombier 
89*4d2c0504SDavid du Colombier static int
opennext(Copy * cp)90*4d2c0504SDavid du Colombier opennext(Copy *cp)
91*4d2c0504SDavid du Colombier {
92*4d2c0504SDavid du Colombier 	if (cp->outf >= 0)
93*4d2c0504SDavid du Colombier 		sysfatal("opennext called with file open");
94*4d2c0504SDavid du Colombier 	snprint(cp->filenm, cp->filesz, "%s%5.5ld", cp->prefix, cp->filenum++);
95*4d2c0504SDavid du Colombier 	cp->outf = ecreate(cp->filenm, OWRITE);
96*4d2c0504SDavid du Colombier 	cp->fileout = 0;
97*4d2c0504SDavid du Colombier 	return cp->outf;
98*4d2c0504SDavid du Colombier }
99*4d2c0504SDavid du Colombier 
100*4d2c0504SDavid du Colombier static int
closeout(Copy * cp)101*4d2c0504SDavid du Colombier closeout(Copy *cp)
102*4d2c0504SDavid du Colombier {
103*4d2c0504SDavid du Colombier 	if (cp->outf >= 0) {
104*4d2c0504SDavid du Colombier 		if (close(cp->outf) < 0)
105*4d2c0504SDavid du Colombier 			sysfatal("error writing %s: %r", filename(cp));
106*4d2c0504SDavid du Colombier 		cp->outf = -1;
107*4d2c0504SDavid du Colombier 		cp->fileout = 0;
108*4d2c0504SDavid du Colombier 	}
109*4d2c0504SDavid du Colombier 	return cp->outf;
110*4d2c0504SDavid du Colombier }
111*4d2c0504SDavid du Colombier 
112*4d2c0504SDavid du Colombier /*
113*4d2c0504SDavid du Colombier  * process - process input file
114*4d2c0504SDavid du Colombier  */
115*4d2c0504SDavid du Colombier static void
process(int in,char * inname)116*4d2c0504SDavid du Colombier process(int in, char *inname)
117*4d2c0504SDavid du Colombier {
118*4d2c0504SDavid du Colombier 	int n = 1;
119*4d2c0504SDavid du Colombier 	unsigned avail, tolim, wsz;
120*4d2c0504SDavid du Colombier 	Buffer *bp = &cp.buff;
121*4d2c0504SDavid du Colombier 
122*4d2c0504SDavid du Colombier 	USED(inname);
123*4d2c0504SDavid du Colombier 	do {
124*4d2c0504SDavid du Colombier 		if (BLEN(bp) == 0) {
125*4d2c0504SDavid du Colombier 			if (bp->lim == bp->wp)
126*4d2c0504SDavid du Colombier 				bufreset(bp);
127*4d2c0504SDavid du Colombier 			n = read(in, bp->wp, bp->lim - bp->wp);
128*4d2c0504SDavid du Colombier 			if (n <= 0)
129*4d2c0504SDavid du Colombier 				break;
130*4d2c0504SDavid du Colombier 			bp->wp += n;
131*4d2c0504SDavid du Colombier 		}
132*4d2c0504SDavid du Colombier 		if (cp.outf < 0)
133*4d2c0504SDavid du Colombier 			opennext(&cp);
134*4d2c0504SDavid du Colombier 
135*4d2c0504SDavid du Colombier 		/*
136*4d2c0504SDavid du Colombier 		 * write from buffer's current point to end or enough bytes to
137*4d2c0504SDavid du Colombier 		 * reach file-size limit.
138*4d2c0504SDavid du Colombier 		 */
139*4d2c0504SDavid du Colombier 		avail = BLEN(bp);
140*4d2c0504SDavid du Colombier 		tolim = cp.maxoutsz - cp.fileout;
141*4d2c0504SDavid du Colombier 		wsz = (tolim < avail? tolim: avail);
142*4d2c0504SDavid du Colombier 
143*4d2c0504SDavid du Colombier 		/* try to write full sectors */
144*4d2c0504SDavid du Colombier 		if (tolim >= avail && n > 0 && wsz >= Sectsiz)
145*4d2c0504SDavid du Colombier 			wsz = (wsz / Sectsiz) * Sectsiz;
146*4d2c0504SDavid du Colombier 		if (write(cp.outf, bp->rp, wsz) != wsz)
147*4d2c0504SDavid du Colombier 			sysfatal("error writing %s: %r", filename(&cp));
148*4d2c0504SDavid du Colombier 		bp->rp += wsz;
149*4d2c0504SDavid du Colombier 
150*4d2c0504SDavid du Colombier 		cp.fileout += wsz;
151*4d2c0504SDavid du Colombier 		if (cp.fileout >= cp.maxoutsz)
152*4d2c0504SDavid du Colombier 			closeout(&cp);
153*4d2c0504SDavid du Colombier 	} while (n > 0 || BLEN(bp) != 0);
154*4d2c0504SDavid du Colombier }
155*4d2c0504SDavid du Colombier 
156*4d2c0504SDavid du Colombier static void
usage(void)157*4d2c0504SDavid du Colombier usage(void)
158*4d2c0504SDavid du Colombier {
159*4d2c0504SDavid du Colombier 	fprint(2, "usage: %s [-d][-p pfx][-s size] [file...]\n", argv0);
160*4d2c0504SDavid du Colombier 	exits("usage");
161*4d2c0504SDavid du Colombier }
162*4d2c0504SDavid du Colombier 
163*4d2c0504SDavid du Colombier void
main(int argc,char ** argv)164*4d2c0504SDavid du Colombier main(int argc, char **argv)
165*4d2c0504SDavid du Colombier {
166*4d2c0504SDavid du Colombier 	int i, errflg = 0;
167*4d2c0504SDavid du Colombier 	uchar block[Bufsiz];
168*4d2c0504SDavid du Colombier 
169*4d2c0504SDavid du Colombier 	cp.prefix = "bs.";
170*4d2c0504SDavid du Colombier 	ARGBEGIN {
171*4d2c0504SDavid du Colombier 	case 'd':
172*4d2c0504SDavid du Colombier 		debug++;
173*4d2c0504SDavid du Colombier 		break;
174*4d2c0504SDavid du Colombier 	case 'p':
175*4d2c0504SDavid du Colombier 		cp.prefix = EARGF(usage());
176*4d2c0504SDavid du Colombier 		break;
177*4d2c0504SDavid du Colombier 	case 's':
178*4d2c0504SDavid du Colombier 		cp.maxoutsz = atoll(EARGF(usage()));
179*4d2c0504SDavid du Colombier 		if (cp.maxoutsz < 1)
180*4d2c0504SDavid du Colombier 			errflg++;
181*4d2c0504SDavid du Colombier 		break;
182*4d2c0504SDavid du Colombier 	default:
183*4d2c0504SDavid du Colombier 		errflg++;
184*4d2c0504SDavid du Colombier 		break;
185*4d2c0504SDavid du Colombier 	} ARGEND
186*4d2c0504SDavid du Colombier 	if (errflg || argc < 0)
187*4d2c0504SDavid du Colombier 		usage();
188*4d2c0504SDavid du Colombier 
189*4d2c0504SDavid du Colombier 	bufinit(&cp.buff, block, sizeof block);
190*4d2c0504SDavid du Colombier 	cp.outf = -1;
191*4d2c0504SDavid du Colombier 	cp.filesz = strlen(cp.prefix) + 2*ANAMELEN;	/* 2* is slop */
192*4d2c0504SDavid du Colombier 	cp.filenm = malloc(cp.filesz + 1);
193*4d2c0504SDavid du Colombier 	if (cp.filenm == nil)
194*4d2c0504SDavid du Colombier 		sysfatal("no memory: %r");
195*4d2c0504SDavid du Colombier 
196*4d2c0504SDavid du Colombier 	if (argc == 0)
197*4d2c0504SDavid du Colombier 		process(Stdin, "/fd/0");
198*4d2c0504SDavid du Colombier 	else
199*4d2c0504SDavid du Colombier 		for (i = 0; i < argc; i++) {
200*4d2c0504SDavid du Colombier 			int in = eopen(argv[i], OREAD);
201*4d2c0504SDavid du Colombier 
202*4d2c0504SDavid du Colombier 			process(in, argv[i]);
203*4d2c0504SDavid du Colombier 			close(in);
204*4d2c0504SDavid du Colombier 		}
205*4d2c0504SDavid du Colombier 	closeout(&cp);
206*4d2c0504SDavid du Colombier 	exits(0);
207*4d2c0504SDavid du Colombier }
208