xref: /titanic_51/usr/src/boot/lib/libstand/splitfs.c (revision 4a5d661a82b942b6538acd26209d959ce98b593a)
1*4a5d661aSToomas Soome /*
2*4a5d661aSToomas Soome  * Copyright (c) 2002 Maxim Sobolev
3*4a5d661aSToomas Soome  * All rights reserved.
4*4a5d661aSToomas Soome  *
5*4a5d661aSToomas Soome  * Redistribution and use in source and binary forms, with or without
6*4a5d661aSToomas Soome  * modification, are permitted provided that the following conditions
7*4a5d661aSToomas Soome  * are met:
8*4a5d661aSToomas Soome  * 1. Redistributions of source code must retain the above copyright
9*4a5d661aSToomas Soome  *    notice, this list of conditions and the following disclaimer.
10*4a5d661aSToomas Soome  * 2. Redistributions in binary form must reproduce the above copyright
11*4a5d661aSToomas Soome  *    notice, this list of conditions and the following disclaimer in the
12*4a5d661aSToomas Soome  *    documentation and/or other materials provided with the distribution.
13*4a5d661aSToomas Soome  *
14*4a5d661aSToomas Soome  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*4a5d661aSToomas Soome  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*4a5d661aSToomas Soome  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*4a5d661aSToomas Soome  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*4a5d661aSToomas Soome  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*4a5d661aSToomas Soome  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*4a5d661aSToomas Soome  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*4a5d661aSToomas Soome  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*4a5d661aSToomas Soome  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*4a5d661aSToomas Soome  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*4a5d661aSToomas Soome  * SUCH DAMAGE.
25*4a5d661aSToomas Soome  */
26*4a5d661aSToomas Soome 
27*4a5d661aSToomas Soome #include <sys/cdefs.h>
28*4a5d661aSToomas Soome __FBSDID("$FreeBSD$");
29*4a5d661aSToomas Soome 
30*4a5d661aSToomas Soome #include "stand.h"
31*4a5d661aSToomas Soome 
32*4a5d661aSToomas Soome #define NTRIES		(3)
33*4a5d661aSToomas Soome #define CONF_BUF	(512)
34*4a5d661aSToomas Soome #define SEEK_BUF	(512)
35*4a5d661aSToomas Soome 
36*4a5d661aSToomas Soome struct split_file
37*4a5d661aSToomas Soome {
38*4a5d661aSToomas Soome     char  **filesv;	/* Filenames */
39*4a5d661aSToomas Soome     char  **descsv;	/* Descriptions */
40*4a5d661aSToomas Soome     int	  filesc;	/* Number of parts */
41*4a5d661aSToomas Soome     int	  curfile;	/* Current file number */
42*4a5d661aSToomas Soome     int	  curfd;	/* Current file descriptor */
43*4a5d661aSToomas Soome     off_t tot_pos;	/* Offset from the beginning of the sequence */
44*4a5d661aSToomas Soome     off_t file_pos;	/* Offset from the beginning of the slice */
45*4a5d661aSToomas Soome };
46*4a5d661aSToomas Soome 
47*4a5d661aSToomas Soome static int	split_openfile(struct split_file *sf);
48*4a5d661aSToomas Soome static int	splitfs_open(const char *path, struct open_file *f);
49*4a5d661aSToomas Soome static int	splitfs_close(struct open_file *f);
50*4a5d661aSToomas Soome static int	splitfs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
51*4a5d661aSToomas Soome static off_t	splitfs_seek(struct open_file *f, off_t offset, int where);
52*4a5d661aSToomas Soome static int	splitfs_stat(struct open_file *f, struct stat *sb);
53*4a5d661aSToomas Soome 
54*4a5d661aSToomas Soome struct fs_ops splitfs_fsops = {
55*4a5d661aSToomas Soome     "split",
56*4a5d661aSToomas Soome     splitfs_open,
57*4a5d661aSToomas Soome     splitfs_close,
58*4a5d661aSToomas Soome     splitfs_read,
59*4a5d661aSToomas Soome     null_write,
60*4a5d661aSToomas Soome     splitfs_seek,
61*4a5d661aSToomas Soome     splitfs_stat,
62*4a5d661aSToomas Soome     null_readdir
63*4a5d661aSToomas Soome };
64*4a5d661aSToomas Soome 
65*4a5d661aSToomas Soome static void
66*4a5d661aSToomas Soome split_file_destroy(struct split_file *sf)
67*4a5d661aSToomas Soome {
68*4a5d661aSToomas Soome     int i;
69*4a5d661aSToomas Soome 
70*4a5d661aSToomas Soome     if (sf->filesc > 0) {
71*4a5d661aSToomas Soome 	for (i = 0; i < sf->filesc; i++) {
72*4a5d661aSToomas Soome 	    free(sf->filesv[i]);
73*4a5d661aSToomas Soome 	    free(sf->descsv[i]);
74*4a5d661aSToomas Soome 	}
75*4a5d661aSToomas Soome 	free(sf->filesv);
76*4a5d661aSToomas Soome 	free(sf->descsv);
77*4a5d661aSToomas Soome     }
78*4a5d661aSToomas Soome     free(sf);
79*4a5d661aSToomas Soome }
80*4a5d661aSToomas Soome 
81*4a5d661aSToomas Soome static int
82*4a5d661aSToomas Soome split_openfile(struct split_file *sf)
83*4a5d661aSToomas Soome {
84*4a5d661aSToomas Soome     int i;
85*4a5d661aSToomas Soome 
86*4a5d661aSToomas Soome     for (i = 0;; i++) {
87*4a5d661aSToomas Soome 	sf->curfd = open(sf->filesv[sf->curfile], O_RDONLY);
88*4a5d661aSToomas Soome 	if (sf->curfd >= 0)
89*4a5d661aSToomas Soome 	    break;
90*4a5d661aSToomas Soome 	if ((sf->curfd == -1) && (errno != ENOENT))
91*4a5d661aSToomas Soome 	    return (errno);
92*4a5d661aSToomas Soome 	if (i == NTRIES)
93*4a5d661aSToomas Soome 	    return (EIO);
94*4a5d661aSToomas Soome 	printf("\nInsert disk labelled %s and press any key...",
95*4a5d661aSToomas Soome 	    sf->descsv[sf->curfile]);
96*4a5d661aSToomas Soome 	getchar();
97*4a5d661aSToomas Soome 	putchar('\n');
98*4a5d661aSToomas Soome     }
99*4a5d661aSToomas Soome     sf->file_pos = 0;
100*4a5d661aSToomas Soome     return (0);
101*4a5d661aSToomas Soome }
102*4a5d661aSToomas Soome 
103*4a5d661aSToomas Soome static int
104*4a5d661aSToomas Soome splitfs_open(const char *fname, struct open_file *f)
105*4a5d661aSToomas Soome {
106*4a5d661aSToomas Soome     char *buf, *confname, *cp;
107*4a5d661aSToomas Soome     int	conffd;
108*4a5d661aSToomas Soome     struct split_file *sf;
109*4a5d661aSToomas Soome     struct stat sb;
110*4a5d661aSToomas Soome 
111*4a5d661aSToomas Soome     /* Have to be in "just read it" mode */
112*4a5d661aSToomas Soome     if (f->f_flags != F_READ)
113*4a5d661aSToomas Soome 	return(EPERM);
114*4a5d661aSToomas Soome 
115*4a5d661aSToomas Soome     /* If the name already ends in `.split', ignore it */
116*4a5d661aSToomas Soome     if ((cp = strrchr(fname, '.')) && (!strcmp(cp, ".split")))
117*4a5d661aSToomas Soome 	return(ENOENT);
118*4a5d661aSToomas Soome 
119*4a5d661aSToomas Soome     /* Construct new name */
120*4a5d661aSToomas Soome     confname = malloc(strlen(fname) + 7);
121*4a5d661aSToomas Soome     sprintf(confname, "%s.split", fname);
122*4a5d661aSToomas Soome 
123*4a5d661aSToomas Soome     /* Try to open the configuration file */
124*4a5d661aSToomas Soome     conffd = open(confname, O_RDONLY);
125*4a5d661aSToomas Soome     free(confname);
126*4a5d661aSToomas Soome     if (conffd == -1)
127*4a5d661aSToomas Soome 	return(ENOENT);
128*4a5d661aSToomas Soome 
129*4a5d661aSToomas Soome     if (fstat(conffd, &sb) < 0) {
130*4a5d661aSToomas Soome 	printf("splitfs_open: stat failed\n");
131*4a5d661aSToomas Soome 	close(conffd);
132*4a5d661aSToomas Soome 	return(ENOENT);
133*4a5d661aSToomas Soome     }
134*4a5d661aSToomas Soome     if (!S_ISREG(sb.st_mode)) {
135*4a5d661aSToomas Soome 	printf("splitfs_open: not a file\n");
136*4a5d661aSToomas Soome 	close(conffd);
137*4a5d661aSToomas Soome 	return(EISDIR);			/* best guess */
138*4a5d661aSToomas Soome     }
139*4a5d661aSToomas Soome 
140*4a5d661aSToomas Soome     /* Allocate a split_file structure, populate it from the config file */
141*4a5d661aSToomas Soome     sf = malloc(sizeof(struct split_file));
142*4a5d661aSToomas Soome     bzero(sf, sizeof(struct split_file));
143*4a5d661aSToomas Soome     buf = malloc(CONF_BUF);
144*4a5d661aSToomas Soome     while (fgetstr(buf, CONF_BUF, conffd) > 0) {
145*4a5d661aSToomas Soome 	cp = buf;
146*4a5d661aSToomas Soome 	while ((*cp != '\0') && (isspace(*cp) == 0))
147*4a5d661aSToomas Soome 	    cp++;
148*4a5d661aSToomas Soome 	if (*cp != '\0') {
149*4a5d661aSToomas Soome 	    *cp = '\0';
150*4a5d661aSToomas Soome 	    cp++;
151*4a5d661aSToomas Soome 	}
152*4a5d661aSToomas Soome 	while ((*cp != '\0') && (isspace(*cp) != 0))
153*4a5d661aSToomas Soome 	    cp++;
154*4a5d661aSToomas Soome 	if (*cp == '\0')
155*4a5d661aSToomas Soome 	    cp = buf;
156*4a5d661aSToomas Soome 	sf->filesc++;
157*4a5d661aSToomas Soome 	sf->filesv = realloc(sf->filesv, sizeof(*(sf->filesv)) * sf->filesc);
158*4a5d661aSToomas Soome 	sf->descsv = realloc(sf->descsv, sizeof(*(sf->descsv)) * sf->filesc);
159*4a5d661aSToomas Soome 	sf->filesv[sf->filesc - 1] = strdup(buf);
160*4a5d661aSToomas Soome 	sf->descsv[sf->filesc - 1] = strdup(cp);
161*4a5d661aSToomas Soome     }
162*4a5d661aSToomas Soome     free(buf);
163*4a5d661aSToomas Soome     close(conffd);
164*4a5d661aSToomas Soome 
165*4a5d661aSToomas Soome     if (sf->filesc == 0) {
166*4a5d661aSToomas Soome 	split_file_destroy(sf);
167*4a5d661aSToomas Soome 	return(ENOENT);
168*4a5d661aSToomas Soome     }
169*4a5d661aSToomas Soome     errno = split_openfile(sf);
170*4a5d661aSToomas Soome     if (errno != 0) {
171*4a5d661aSToomas Soome 	split_file_destroy(sf);
172*4a5d661aSToomas Soome 	return(ENOENT);
173*4a5d661aSToomas Soome     }
174*4a5d661aSToomas Soome 
175*4a5d661aSToomas Soome     /* Looks OK, we'll take it */
176*4a5d661aSToomas Soome     f->f_fsdata = sf;
177*4a5d661aSToomas Soome     return (0);
178*4a5d661aSToomas Soome }
179*4a5d661aSToomas Soome 
180*4a5d661aSToomas Soome static int
181*4a5d661aSToomas Soome splitfs_close(struct open_file *f)
182*4a5d661aSToomas Soome {
183*4a5d661aSToomas Soome     int fd;
184*4a5d661aSToomas Soome     struct split_file *sf;
185*4a5d661aSToomas Soome 
186*4a5d661aSToomas Soome     sf = (struct split_file *)f->f_fsdata;
187*4a5d661aSToomas Soome     fd = sf->curfd;
188*4a5d661aSToomas Soome     split_file_destroy(sf);
189*4a5d661aSToomas Soome     return(close(fd));
190*4a5d661aSToomas Soome }
191*4a5d661aSToomas Soome 
192*4a5d661aSToomas Soome static int
193*4a5d661aSToomas Soome splitfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
194*4a5d661aSToomas Soome {
195*4a5d661aSToomas Soome     ssize_t nread;
196*4a5d661aSToomas Soome     size_t totread;
197*4a5d661aSToomas Soome     struct split_file *sf;
198*4a5d661aSToomas Soome 
199*4a5d661aSToomas Soome     sf = (struct split_file *)f->f_fsdata;
200*4a5d661aSToomas Soome     totread = 0;
201*4a5d661aSToomas Soome     do {
202*4a5d661aSToomas Soome 	nread = read(sf->curfd, buf, size - totread);
203*4a5d661aSToomas Soome 
204*4a5d661aSToomas Soome 	/* Error? */
205*4a5d661aSToomas Soome 	if (nread == -1)
206*4a5d661aSToomas Soome 	    return (errno);
207*4a5d661aSToomas Soome 
208*4a5d661aSToomas Soome 	sf->tot_pos += nread;
209*4a5d661aSToomas Soome 	sf->file_pos += nread;
210*4a5d661aSToomas Soome 	totread += nread;
211*4a5d661aSToomas Soome 	buf = (char *)buf + nread;
212*4a5d661aSToomas Soome 
213*4a5d661aSToomas Soome 	if (totread < size) {				/* EOF */
214*4a5d661aSToomas Soome 	    if (sf->curfile == (sf->filesc - 1))	/* Last slice */
215*4a5d661aSToomas Soome 		break;
216*4a5d661aSToomas Soome 
217*4a5d661aSToomas Soome 	    /* Close previous slice */
218*4a5d661aSToomas Soome 	    if (close(sf->curfd) != 0)
219*4a5d661aSToomas Soome 		return (errno);
220*4a5d661aSToomas Soome 
221*4a5d661aSToomas Soome 	    sf->curfile++;
222*4a5d661aSToomas Soome 	    errno = split_openfile(sf);
223*4a5d661aSToomas Soome 	    if (errno)
224*4a5d661aSToomas Soome 		    return (errno);
225*4a5d661aSToomas Soome 	}
226*4a5d661aSToomas Soome     } while (totread < size);
227*4a5d661aSToomas Soome 
228*4a5d661aSToomas Soome     if (resid != NULL)
229*4a5d661aSToomas Soome 	*resid = size - totread;
230*4a5d661aSToomas Soome 
231*4a5d661aSToomas Soome     return (0);
232*4a5d661aSToomas Soome }
233*4a5d661aSToomas Soome 
234*4a5d661aSToomas Soome static off_t
235*4a5d661aSToomas Soome splitfs_seek(struct open_file *f, off_t offset, int where)
236*4a5d661aSToomas Soome {
237*4a5d661aSToomas Soome     int nread;
238*4a5d661aSToomas Soome     size_t resid;
239*4a5d661aSToomas Soome     off_t new_pos, seek_by;
240*4a5d661aSToomas Soome     struct split_file *sf;
241*4a5d661aSToomas Soome 
242*4a5d661aSToomas Soome     sf = (struct split_file *)f->f_fsdata;
243*4a5d661aSToomas Soome 
244*4a5d661aSToomas Soome     seek_by = offset;
245*4a5d661aSToomas Soome     switch (where) {
246*4a5d661aSToomas Soome     case SEEK_SET:
247*4a5d661aSToomas Soome 	seek_by -= sf->tot_pos;
248*4a5d661aSToomas Soome 	break;
249*4a5d661aSToomas Soome     case SEEK_CUR:
250*4a5d661aSToomas Soome 	break;
251*4a5d661aSToomas Soome     case SEEK_END:
252*4a5d661aSToomas Soome 	panic("splitfs_seek: SEEK_END not supported");
253*4a5d661aSToomas Soome 	break;
254*4a5d661aSToomas Soome     default:
255*4a5d661aSToomas Soome 	errno = EINVAL;
256*4a5d661aSToomas Soome 	return (-1);
257*4a5d661aSToomas Soome     }
258*4a5d661aSToomas Soome 
259*4a5d661aSToomas Soome     if (seek_by > 0) {
260*4a5d661aSToomas Soome 	/*
261*4a5d661aSToomas Soome 	 * Seek forward - implemented using splitfs_read(), because otherwise we'll be
262*4a5d661aSToomas Soome 	 * unable to detect that we have crossed slice boundary and hence
263*4a5d661aSToomas Soome 	 * unable to do a long seek crossing that boundary.
264*4a5d661aSToomas Soome 	 */
265*4a5d661aSToomas Soome 	void *tmp;
266*4a5d661aSToomas Soome 
267*4a5d661aSToomas Soome 	tmp = malloc(SEEK_BUF);
268*4a5d661aSToomas Soome 	if (tmp == NULL) {
269*4a5d661aSToomas Soome 	    errno = ENOMEM;
270*4a5d661aSToomas Soome 	    return (-1);
271*4a5d661aSToomas Soome 	}
272*4a5d661aSToomas Soome 
273*4a5d661aSToomas Soome 	nread = 0;
274*4a5d661aSToomas Soome 	for (; seek_by > 0; seek_by -= nread) {
275*4a5d661aSToomas Soome 	    resid = 0;
276*4a5d661aSToomas Soome 	    errno = splitfs_read(f, tmp, min(seek_by, SEEK_BUF), &resid);
277*4a5d661aSToomas Soome 	    nread = min(seek_by, SEEK_BUF) - resid;
278*4a5d661aSToomas Soome 	    if ((errno != 0) || (nread == 0))
279*4a5d661aSToomas Soome 		/* Error or EOF */
280*4a5d661aSToomas Soome 		break;
281*4a5d661aSToomas Soome 	}
282*4a5d661aSToomas Soome 	free(tmp);
283*4a5d661aSToomas Soome 	if (errno != 0)
284*4a5d661aSToomas Soome 	    return (-1);
285*4a5d661aSToomas Soome     }
286*4a5d661aSToomas Soome 
287*4a5d661aSToomas Soome     if (seek_by != 0) {
288*4a5d661aSToomas Soome 	/* Seek backward or seek past the boundary of the last slice */
289*4a5d661aSToomas Soome 	if (sf->file_pos + seek_by < 0)
290*4a5d661aSToomas Soome 	    panic("splitfs_seek: can't seek past the beginning of the slice");
291*4a5d661aSToomas Soome 	new_pos = lseek(sf->curfd, seek_by, SEEK_CUR);
292*4a5d661aSToomas Soome 	if (new_pos < 0) {
293*4a5d661aSToomas Soome 	    errno = EINVAL;
294*4a5d661aSToomas Soome 	    return (-1);
295*4a5d661aSToomas Soome 	}
296*4a5d661aSToomas Soome 	sf->tot_pos += new_pos - sf->file_pos;
297*4a5d661aSToomas Soome 	sf->file_pos = new_pos;
298*4a5d661aSToomas Soome     }
299*4a5d661aSToomas Soome 
300*4a5d661aSToomas Soome     return (sf->tot_pos);
301*4a5d661aSToomas Soome }
302*4a5d661aSToomas Soome 
303*4a5d661aSToomas Soome static int
304*4a5d661aSToomas Soome splitfs_stat(struct open_file *f, struct stat *sb)
305*4a5d661aSToomas Soome {
306*4a5d661aSToomas Soome     int	result;
307*4a5d661aSToomas Soome     struct split_file *sf = (struct split_file *)f->f_fsdata;
308*4a5d661aSToomas Soome 
309*4a5d661aSToomas Soome     /* stat as normal, but indicate that size is unknown */
310*4a5d661aSToomas Soome     if ((result = fstat(sf->curfd, sb)) == 0)
311*4a5d661aSToomas Soome 	sb->st_size = -1;
312*4a5d661aSToomas Soome     return (result);
313*4a5d661aSToomas Soome }
314