xref: /plan9/sys/src/cmd/venti/srv/part.c (revision f9e1cf08d3be51592e03e639fc848a68dc31a55e)
1368c31abSDavid du Colombier #include "stdinc.h"
2368c31abSDavid du Colombier #include <ctype.h>
3368c31abSDavid du Colombier #include "dat.h"
4368c31abSDavid du Colombier #include "fns.h"
5368c31abSDavid du Colombier 
6368c31abSDavid du Colombier u32int	maxblocksize;
7368c31abSDavid du Colombier int	readonly;
8368c31abSDavid du Colombier 
9368c31abSDavid du Colombier static int
strtoullsuf(char * p,char ** pp,int rad,u64int * u)10368c31abSDavid du Colombier strtoullsuf(char *p, char **pp, int rad, u64int *u)
11368c31abSDavid du Colombier {
12368c31abSDavid du Colombier 	u64int v;
13368c31abSDavid du Colombier 
14368c31abSDavid du Colombier 	if(!isdigit((uchar)*p))
15368c31abSDavid du Colombier 		return -1;
16368c31abSDavid du Colombier 	v = strtoull(p, &p, rad);
17368c31abSDavid du Colombier 	switch(*p){
18368c31abSDavid du Colombier 	case 'k':
19368c31abSDavid du Colombier 	case 'K':
20368c31abSDavid du Colombier 		v *= 1024;
21368c31abSDavid du Colombier 		p++;
22368c31abSDavid du Colombier 		break;
23368c31abSDavid du Colombier 	case 'm':
24368c31abSDavid du Colombier 	case 'M':
25368c31abSDavid du Colombier 		v *= 1024*1024;
26368c31abSDavid du Colombier 		p++;
27368c31abSDavid du Colombier 		break;
28368c31abSDavid du Colombier 	case 'g':
29368c31abSDavid du Colombier 	case 'G':
30368c31abSDavid du Colombier 		v *= 1024*1024*1024;
31368c31abSDavid du Colombier 		p++;
32368c31abSDavid du Colombier 		break;
33368c31abSDavid du Colombier 	case 't':
34368c31abSDavid du Colombier 	case 'T':
35368c31abSDavid du Colombier 		v *= 1024*1024;
36368c31abSDavid du Colombier 		v *= 1024*1024;
37368c31abSDavid du Colombier 		p++;
38368c31abSDavid du Colombier 		break;
39368c31abSDavid du Colombier 	}
40368c31abSDavid du Colombier 	*pp = p;
41368c31abSDavid du Colombier 	*u = v;
42368c31abSDavid du Colombier 	return 0;
43368c31abSDavid du Colombier }
44368c31abSDavid du Colombier 
45368c31abSDavid du Colombier static int
parsepart(char * name,char ** file,u64int * lo,u64int * hi)46368c31abSDavid du Colombier parsepart(char *name, char **file, u64int *lo, u64int *hi)
47368c31abSDavid du Colombier {
48368c31abSDavid du Colombier 	char *p;
49368c31abSDavid du Colombier 
50368c31abSDavid du Colombier 	*file = estrdup(name);
51368c31abSDavid du Colombier 	if((p = strrchr(*file, ':')) == nil){
52368c31abSDavid du Colombier 		*lo = 0;
53368c31abSDavid du Colombier 		*hi = 0;
54368c31abSDavid du Colombier 		return 0;
55368c31abSDavid du Colombier 	}
56368c31abSDavid du Colombier 	*p++ = 0;
57368c31abSDavid du Colombier 	if(*p == '-')
58368c31abSDavid du Colombier 		*lo = 0;
59368c31abSDavid du Colombier 	else{
60368c31abSDavid du Colombier 		if(strtoullsuf(p, &p, 0, lo) < 0){
61368c31abSDavid du Colombier 			free(*file);
62368c31abSDavid du Colombier 			return -1;
63368c31abSDavid du Colombier 		}
64368c31abSDavid du Colombier 	}
65368c31abSDavid du Colombier 	if(*p == '-')
66368c31abSDavid du Colombier 		p++;
67368c31abSDavid du Colombier 	if(*p == 0){
68368c31abSDavid du Colombier 		*hi = 0;
69368c31abSDavid du Colombier 		return 0;
70368c31abSDavid du Colombier 	}
71368c31abSDavid du Colombier 	if(strtoullsuf(p, &p, 0, hi) < 0 || *p != 0){
72368c31abSDavid du Colombier 		free(*file);
73368c31abSDavid du Colombier 		return -1;
74368c31abSDavid du Colombier 	}
75368c31abSDavid du Colombier 	return 0;
76368c31abSDavid du Colombier }
77368c31abSDavid du Colombier 
78368c31abSDavid du Colombier Part*
initpart(char * name,int mode)79368c31abSDavid du Colombier initpart(char *name, int mode)
80368c31abSDavid du Colombier {
81368c31abSDavid du Colombier 	Part *part;
82368c31abSDavid du Colombier 	Dir *dir;
83368c31abSDavid du Colombier 	char *file;
84368c31abSDavid du Colombier 	u64int lo, hi;
85368c31abSDavid du Colombier 
86368c31abSDavid du Colombier 	if(parsepart(name, &file, &lo, &hi) < 0)
87368c31abSDavid du Colombier 		return nil;
88368c31abSDavid du Colombier 	trace(TraceDisk, "initpart %s file %s lo 0x%llx hi 0x%llx", name, file, lo, hi);
89368c31abSDavid du Colombier 	part = MKZ(Part);
90368c31abSDavid du Colombier 	part->name = estrdup(name);
91368c31abSDavid du Colombier 	part->filename = estrdup(file);
92368c31abSDavid du Colombier 	if(readonly){
93368c31abSDavid du Colombier 		mode &= ~(OREAD|OWRITE|ORDWR);
94368c31abSDavid du Colombier 		mode |= OREAD;
95368c31abSDavid du Colombier 	}
96368c31abSDavid du Colombier 	part->fd = open(file, mode);
97368c31abSDavid du Colombier 	if(part->fd < 0){
98368c31abSDavid du Colombier 		if((mode&(OREAD|OWRITE|ORDWR)) == ORDWR)
99368c31abSDavid du Colombier 			part->fd = open(file, (mode&~ORDWR)|OREAD);
100368c31abSDavid du Colombier 		if(part->fd < 0){
101368c31abSDavid du Colombier 			freepart(part);
102368c31abSDavid du Colombier 			fprint(2, "can't open partition='%s': %r\n", file);
103368c31abSDavid du Colombier 			seterr(EOk, "can't open partition='%s': %r", file);
104368c31abSDavid du Colombier 			fprint(2, "%r\n");
105368c31abSDavid du Colombier 			free(file);
106368c31abSDavid du Colombier 			return nil;
107368c31abSDavid du Colombier 		}
108368c31abSDavid du Colombier 		fprint(2, "warning: %s opened for reading only\n", name);
109368c31abSDavid du Colombier 	}
110368c31abSDavid du Colombier 	part->offset = lo;
111368c31abSDavid du Colombier 	dir = dirfstat(part->fd);
112368c31abSDavid du Colombier 	if(dir == nil){
113368c31abSDavid du Colombier 		freepart(part);
114368c31abSDavid du Colombier 		seterr(EOk, "can't stat partition='%s': %r", file);
115368c31abSDavid du Colombier 		free(file);
116368c31abSDavid du Colombier 		return nil;
117368c31abSDavid du Colombier 	}
118368c31abSDavid du Colombier 	if(dir->length == 0){
119368c31abSDavid du Colombier 		free(dir);
120368c31abSDavid du Colombier 		freepart(part);
121368c31abSDavid du Colombier 		seterr(EOk, "can't determine size of partition %s", file);
122368c31abSDavid du Colombier 		free(file);
123368c31abSDavid du Colombier 		return nil;
124368c31abSDavid du Colombier 	}
125368c31abSDavid du Colombier 	if(dir->length < hi || dir->length < lo){
126368c31abSDavid du Colombier 		freepart(part);
127368c31abSDavid du Colombier 		seterr(EOk, "partition '%s': bounds out of range (max %lld)", name, dir->length);
128368c31abSDavid du Colombier 		free(dir);
129368c31abSDavid du Colombier 		free(file);
130368c31abSDavid du Colombier 		return nil;
131368c31abSDavid du Colombier 	}
132368c31abSDavid du Colombier 	if(hi == 0)
133368c31abSDavid du Colombier 		hi = dir->length;
134368c31abSDavid du Colombier 	part->size = hi - part->offset;
135368c31abSDavid du Colombier 	free(dir);
136368c31abSDavid du Colombier 	return part;
137368c31abSDavid du Colombier }
138368c31abSDavid du Colombier 
139368c31abSDavid du Colombier int
flushpart(Part * part)140368c31abSDavid du Colombier flushpart(Part *part)
141368c31abSDavid du Colombier {
142368c31abSDavid du Colombier 	USED(part);
143368c31abSDavid du Colombier 	return 0;
144368c31abSDavid du Colombier }
145368c31abSDavid du Colombier 
146368c31abSDavid du Colombier void
freepart(Part * part)147368c31abSDavid du Colombier freepart(Part *part)
148368c31abSDavid du Colombier {
149368c31abSDavid du Colombier 	if(part == nil)
150368c31abSDavid du Colombier 		return;
151368c31abSDavid du Colombier 	if(part->fd >= 0)
152368c31abSDavid du Colombier 		close(part->fd);
153368c31abSDavid du Colombier 	free(part->name);
154368c31abSDavid du Colombier 	free(part);
155368c31abSDavid du Colombier }
156368c31abSDavid du Colombier 
157368c31abSDavid du Colombier void
partblocksize(Part * part,u32int blocksize)158368c31abSDavid du Colombier partblocksize(Part *part, u32int blocksize)
159368c31abSDavid du Colombier {
160368c31abSDavid du Colombier 	if(part->blocksize)
161368c31abSDavid du Colombier 		sysfatal("resetting partition=%s's block size", part->name);
162368c31abSDavid du Colombier 	part->blocksize = blocksize;
163368c31abSDavid du Colombier 	if(blocksize > maxblocksize)
164368c31abSDavid du Colombier 		maxblocksize = blocksize;
165368c31abSDavid du Colombier }
166368c31abSDavid du Colombier 
167368c31abSDavid du Colombier enum {
168368c31abSDavid du Colombier 	Maxxfer = 64*1024,	/* for NCR SCSI controllers; was 128K */
169368c31abSDavid du Colombier };
170368c31abSDavid du Colombier 
171*f9e1cf08SDavid du Colombier static int reopen(Part*);
172368c31abSDavid du Colombier 
173368c31abSDavid du Colombier int
rwpart(Part * part,int isread,u64int offset0,u8int * buf0,u32int count0)174*f9e1cf08SDavid du Colombier rwpart(Part *part, int isread, u64int offset0, u8int *buf0, u32int count0)
175368c31abSDavid du Colombier {
176*f9e1cf08SDavid du Colombier 	u32int count, opsize;
177368c31abSDavid du Colombier 	int n;
178*f9e1cf08SDavid du Colombier 	u8int *buf;
179*f9e1cf08SDavid du Colombier 	u64int offset;
180368c31abSDavid du Colombier 
181368c31abSDavid du Colombier 	trace(TraceDisk, "%s %s %ud at 0x%llx",
182*f9e1cf08SDavid du Colombier 		isread ? "read" : "write", part->name, count0, offset0);
183*f9e1cf08SDavid du Colombier 	if(offset0 >= part->size || offset0+count0 > part->size){
184368c31abSDavid du Colombier 		seterr(EStrange, "out of bounds %s offset 0x%llux count %ud to partition %s size 0x%llux",
185*f9e1cf08SDavid du Colombier 			isread ? "read" : "write", offset0, count0, part->name,
186368c31abSDavid du Colombier 			part->size);
187368c31abSDavid du Colombier 		return -1;
188368c31abSDavid du Colombier 	}
189368c31abSDavid du Colombier 
190*f9e1cf08SDavid du Colombier 	buf = buf0;
191*f9e1cf08SDavid du Colombier 	count = count0;
192*f9e1cf08SDavid du Colombier 	offset = offset0;
193*f9e1cf08SDavid du Colombier 	while(count > 0){
194*f9e1cf08SDavid du Colombier 		opsize = count;
195*f9e1cf08SDavid du Colombier 		if(opsize > Maxxfer)
196*f9e1cf08SDavid du Colombier 			opsize = Maxxfer;
197*f9e1cf08SDavid du Colombier 		if(isread)
198*f9e1cf08SDavid du Colombier 			n = pread(part->fd, buf, opsize, offset);
199*f9e1cf08SDavid du Colombier 		else
200*f9e1cf08SDavid du Colombier 			n = pwrite(part->fd, buf, opsize, offset);
201*f9e1cf08SDavid du Colombier 		if(n <= 0){
202*f9e1cf08SDavid du Colombier 			seterr(EAdmin, "%s %s offset 0x%llux count %ud buf %p returned %d: %r",
203*f9e1cf08SDavid du Colombier 				isread ? "read" : "write", part->filename, offset, opsize, buf, n);
204*f9e1cf08SDavid du Colombier 			return -1;
205*f9e1cf08SDavid du Colombier 		}
206*f9e1cf08SDavid du Colombier 		offset += n;
207*f9e1cf08SDavid du Colombier 		count -= n;
208*f9e1cf08SDavid du Colombier 		buf += n;
209*f9e1cf08SDavid du Colombier 	}
210368c31abSDavid du Colombier 
211*f9e1cf08SDavid du Colombier 	return count0;
212368c31abSDavid du Colombier }
213368c31abSDavid du Colombier 
214368c31abSDavid du Colombier int
readpart(Part * part,u64int offset,u8int * buf,u32int count)215368c31abSDavid du Colombier readpart(Part *part, u64int offset, u8int *buf, u32int count)
216368c31abSDavid du Colombier {
217368c31abSDavid du Colombier 	return rwpart(part, 1, offset, buf, count);
218368c31abSDavid du Colombier }
219368c31abSDavid du Colombier 
220368c31abSDavid du Colombier int
writepart(Part * part,u64int offset,u8int * buf,u32int count)221368c31abSDavid du Colombier writepart(Part *part, u64int offset, u8int *buf, u32int count)
222368c31abSDavid du Colombier {
223368c31abSDavid du Colombier 	return rwpart(part, 0, offset, buf, count);
224368c31abSDavid du Colombier }
225368c31abSDavid du Colombier 
226368c31abSDavid du Colombier ZBlock*
readfile(char * name)227368c31abSDavid du Colombier readfile(char *name)
228368c31abSDavid du Colombier {
229368c31abSDavid du Colombier 	Part *p;
230368c31abSDavid du Colombier 	ZBlock *b;
231368c31abSDavid du Colombier 
232368c31abSDavid du Colombier 	p = initpart(name, OREAD);
233368c31abSDavid du Colombier 	if(p == nil)
234368c31abSDavid du Colombier 		return nil;
235368c31abSDavid du Colombier 	b = alloczblock(p->size, 0, p->blocksize);
236368c31abSDavid du Colombier 	if(b == nil){
237368c31abSDavid du Colombier 		seterr(EOk, "can't alloc %s: %r", name);
238368c31abSDavid du Colombier 		freepart(p);
239368c31abSDavid du Colombier 		return nil;
240368c31abSDavid du Colombier 	}
241368c31abSDavid du Colombier 	if(readpart(p, 0, b->data, p->size) < 0){
242368c31abSDavid du Colombier 		seterr(EOk, "can't read %s: %r", name);
243368c31abSDavid du Colombier 		freepart(p);
244368c31abSDavid du Colombier 		freezblock(b);
245368c31abSDavid du Colombier 		return nil;
246368c31abSDavid du Colombier 	}
247368c31abSDavid du Colombier 	freepart(p);
248368c31abSDavid du Colombier 	return b;
249368c31abSDavid du Colombier }
250