Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / pdisk / file_media.c
blob4317126576d2147694a9f93ac70c8676fe8b62ee
1 /*
2 * file_media.c -
4 * Written by Eryk Vershen
5 */
7 /*
8 * Copyright 1997,1998 by Apple Computer, Inc.
9 * All Rights Reserved
11 * Permission to use, copy, modify, and distribute this software and
12 * its documentation for any purpose and without fee is hereby granted,
13 * provided that the above copyright notice appears in all copies and
14 * that both the copyright notice and this permission notice appear in
15 * supporting documentation.
17 * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
18 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 * FOR A PARTICULAR PURPOSE.
21 * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
22 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
23 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
24 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
25 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
28 // for printf()
29 #include <stdio.h>
30 // for malloc() & free()
31 #include <stdlib.h>
32 // for lseek(), read(), write(), close()
33 #include <unistd.h>
34 // for open()
35 #include <fcntl.h>
36 // for LONG_MAX
37 #include <limits.h>
38 // for errno
39 #include <errno.h>
41 #ifdef __linux__
42 #include <sys/ioctl.h>
43 #include <linux/fs.h>
44 #include <linux/hdreg.h>
45 #include <sys/stat.h>
46 #else
47 #ifdef __unix__
48 #include <sys/ioctl.h>
49 #include <sys/stat.h>
50 #endif
51 #endif
53 #include "file_media.h"
54 #include "errors.h"
58 * Defines
60 #ifdef __linux__
61 #define LOFF_MAX 9223372036854775807LL
62 extern __loff_t llseek __P ((int __fd, __loff_t __offset, int __whence));
63 #elif defined(__NetBSD__) || defined(__APPLE__)
64 #define loff_t off_t
65 #define llseek lseek
66 #define LOFF_MAX LLONG_MAX
67 #else
68 #define loff_t long
69 #define llseek lseek
70 #define LOFF_MAX LONG_MAX
71 #endif
75 * Types
77 typedef struct file_media *FILE_MEDIA;
79 struct file_media {
80 struct media m;
81 int fd;
82 int regular_file;
85 struct file_media_globals {
86 long exists;
87 long kind;
90 typedef struct file_media_iterator *FILE_MEDIA_ITERATOR;
92 struct file_media_iterator {
93 struct media_iterator m;
94 long style;
95 long index;
100 * Global Constants
102 int potential_block_sizes[] = {
103 1, 512, 1024, 2048,
107 enum {
108 kSCSI_Disks = 0,
109 kATA_Devices = 1,
110 kSCSI_CDs = 2,
111 kMaxStyle = 2
116 * Global Variables
118 static long file_inited = 0;
119 static struct file_media_globals file_info;
122 * Forward declarations
124 int compute_block_size(int fd);
125 void file_init(void);
126 FILE_MEDIA new_file_media(void);
127 long read_file_media(MEDIA m, long long offset, unsigned long count, void *address);
128 long write_file_media(MEDIA m, long long offset, unsigned long count, void *address);
129 long close_file_media(MEDIA m);
130 long os_reload_file_media(MEDIA m);
131 FILE_MEDIA_ITERATOR new_file_iterator(void);
132 void reset_file_iterator(MEDIA_ITERATOR m);
133 char *step_file_iterator(MEDIA_ITERATOR m);
134 void delete_file_iterator(MEDIA_ITERATOR m);
138 * Routines
140 void
141 file_init(void)
143 if (file_inited != 0) {
144 return;
146 file_inited = 1;
148 file_info.kind = allocate_media_kind();
152 FILE_MEDIA
153 new_file_media(void)
155 return (FILE_MEDIA) new_media(sizeof(struct file_media));
160 compute_block_size(int fd)
162 int size;
163 int max_size;
164 loff_t x;
165 long t;
166 int i;
167 char *buffer;
169 max_size = 0;
170 for (i = 0; ; i++) {
171 size = potential_block_sizes[i];
172 if (size == 0) {
173 break;
175 if (max_size < size) {
176 max_size = size;
180 buffer = malloc(max_size);
181 if (buffer != 0) {
182 for (i = 0; ; i++) {
183 size = potential_block_sizes[i];
184 if (size == 0) {
185 break;
187 if ((x = llseek(fd, (loff_t)0, 0)) < 0) {
188 error(errno, "Can't seek on file");
189 break;
191 if ((t = read(fd, buffer, size)) == size) {
192 free(buffer);
193 return size;
197 return 0;
201 MEDIA
202 open_file_as_media(char *file, int oflag)
204 FILE_MEDIA a;
205 int fd;
206 loff_t off;
207 #if defined(__linux__) || defined(__unix__)
208 struct stat info;
209 #endif
211 if (file_inited == 0) {
212 file_init();
215 a = 0;
216 fd = open(file, oflag);
217 if (fd >= 0) {
218 a = new_file_media();
219 if (a != 0) {
220 a->m.kind = file_info.kind;
221 a->m.grain = compute_block_size(fd);
222 off = llseek(fd, (loff_t)0, 2); /* seek to end of media */
223 #if !defined(__linux__) && !defined(__unix__)
224 if (off <= 0) {
225 off = 1; /* XXX not right? */
227 #endif
228 //printf("file size = %Ld\n", off);
229 a->m.size_in_bytes = (long long) off;
230 a->m.do_read = read_file_media;
231 a->m.do_write = write_file_media;
232 a->m.do_close = close_file_media;
233 a->m.do_os_reload = os_reload_file_media;
234 a->fd = fd;
235 a->regular_file = 0;
236 #if defined(__linux__) || defined(__unix__)
237 if (fstat(fd, &info) < 0) {
238 error(errno, "can't stat file '%s'", file);
239 } else {
240 a->regular_file = S_ISREG(info.st_mode);
242 #endif
243 } else {
244 close(fd);
247 return (MEDIA) a;
251 long
252 read_file_media(MEDIA m, long long offset, unsigned long count, void *address)
254 FILE_MEDIA a;
255 long rtn_value;
256 loff_t off;
257 int t;
259 a = (FILE_MEDIA) m;
260 rtn_value = 0;
261 if (a == 0) {
262 /* no media */
263 fprintf(stderr,"no media\n");
264 } else if (a->m.kind != file_info.kind) {
265 /* wrong kind - XXX need to error here - this is an internal problem */
266 fprintf(stderr,"wrong kind\n");
267 } else if (count <= 0 || count % a->m.grain != 0) {
268 /* can't handle size */
269 fprintf(stderr,"bad size\n");
270 } else if (offset < 0 || offset % a->m.grain != 0) {
271 /* can't handle offset */
272 fprintf(stderr,"bad offset\n");
273 } else if (offset + count > a->m.size_in_bytes && a->m.size_in_bytes != (long long) 0) {
274 /* check for offset (and offset+count) too large */
275 fprintf(stderr,"offset+count too large\n");
276 } else if (offset + count > (long long) LOFF_MAX) {
277 /* check for offset (and offset+count) too large */
278 fprintf(stderr,"offset+count too large 2\n");
279 } else {
280 /* do the read */
281 off = offset;
282 if ((off = llseek(a->fd, off, 0)) >= 0) {
283 if ((t = read(a->fd, address, count)) == (ssize_t)count) {
284 rtn_value = 1;
285 } else {
286 fprintf(stderr,"read failed\n");
288 } else {
289 fprintf(stderr,"lseek failed\n");
292 return rtn_value;
296 long
297 write_file_media(MEDIA m, long long offset, unsigned long count, void *address)
299 FILE_MEDIA a;
300 long rtn_value;
301 loff_t off;
302 int t;
304 a = (FILE_MEDIA) m;
305 rtn_value = 0;
306 if (a == 0) {
307 /* no media */
308 } else if (a->m.kind != file_info.kind) {
309 /* wrong kind - XXX need to error here - this is an internal problem */
310 } else if (count <= 0 || count % a->m.grain != 0) {
311 /* can't handle size */
312 } else if (offset < 0 || offset % a->m.grain != 0) {
313 /* can't handle offset */
314 } else if (offset + count > (long long) LOFF_MAX) {
315 /* check for offset (and offset+count) too large */
316 } else {
317 /* do the write */
318 off = offset;
319 if ((off = llseek(a->fd, off, 0)) >= 0) {
320 if ((t = write(a->fd, address, count)) == (ssize_t)count) {
321 if (off + count > a->m.size_in_bytes) {
322 a->m.size_in_bytes = off + count;
324 rtn_value = 1;
328 return rtn_value;
332 long
333 close_file_media(MEDIA m)
335 FILE_MEDIA a;
337 a = (FILE_MEDIA) m;
338 if (a == 0) {
339 return 0;
340 } else if (a->m.kind != file_info.kind) {
341 /* XXX need to error here - this is an internal problem */
342 return 0;
345 close(a->fd);
346 return 1;
350 long
351 os_reload_file_media(MEDIA m)
353 FILE_MEDIA a;
354 long rtn_value;
355 #if defined(__linux__)
356 int i;
357 int saved_errno;
358 #endif
360 a = (FILE_MEDIA) m;
361 rtn_value = 0;
362 if (a == 0) {
363 /* no media */
364 } else if (a->m.kind != file_info.kind) {
365 /* wrong kind - XXX need to error here - this is an internal problem */
366 } else if (a->regular_file) {
367 /* okay - nothing to do */
368 rtn_value = 1;
369 } else {
370 #ifdef __linux__
371 sync();
372 sleep(2);
373 if ((i = ioctl(a->fd, BLKRRPART)) != 0) {
374 saved_errno = errno;
375 } else {
376 // some kernel versions (1.2.x) seem to have trouble
377 // rereading the partition table, but if asked to do it
378 // twice, the second time works. - biro@yggdrasil.com */
379 sync();
380 sleep(2);
381 if ((i = ioctl(a->fd, BLKRRPART)) != 0) {
382 saved_errno = errno;
386 // printf("Syncing disks.\n");
387 sync();
388 sleep(4); /* for sync() */
390 if (i < 0) {
391 error(saved_errno, "Re-read of partition table failed");
392 printf("Reboot your system to ensure the "
393 "partition table is updated.\n");
395 #endif
396 rtn_value = 1;
398 return rtn_value;
402 #if !defined(__linux__) && !defined(__unix__)
403 #pragma mark -
404 #endif
407 FILE_MEDIA_ITERATOR
408 new_file_iterator(void)
410 return (FILE_MEDIA_ITERATOR) new_media_iterator(sizeof(struct file_media_iterator));
414 MEDIA_ITERATOR
415 create_file_iterator(void)
417 FILE_MEDIA_ITERATOR a;
419 if (file_inited == 0) {
420 file_init();
423 a = new_file_iterator();
424 if (a != 0) {
425 a->m.kind = file_info.kind;
426 a->m.state = kInit;
427 a->m.do_reset = reset_file_iterator;
428 a->m.do_step = step_file_iterator;
429 a->m.do_delete = delete_file_iterator;
430 a->style = 0;
431 a->index = 0;
434 return (MEDIA_ITERATOR) a;
438 void
439 reset_file_iterator(MEDIA_ITERATOR m)
441 FILE_MEDIA_ITERATOR a;
443 a = (FILE_MEDIA_ITERATOR) m;
444 if (a == 0) {
445 /* no media */
446 } else if (a->m.kind != file_info.kind) {
447 /* wrong kind - XXX need to error here - this is an internal problem */
448 } else if (a->m.state != kInit) {
449 a->m.state = kReset;
454 char *
455 step_file_iterator(MEDIA_ITERATOR m)
457 FILE_MEDIA_ITERATOR a;
458 char *result;
459 struct stat info;
460 int fd;
461 int bump;
462 int value;
464 a = (FILE_MEDIA_ITERATOR) m;
465 if (a == 0) {
466 /* no media */
467 } else if (a->m.kind != file_info.kind) {
468 /* wrong kind - XXX need to error here - this is an internal problem */
469 } else {
470 switch (a->m.state) {
471 case kInit:
472 a->m.state = kReset;
473 /* fall through to reset */
474 case kReset:
475 a->style = 0 /* first style */;
476 a->index = 0 /* first index */;
477 a->m.state = kIterating;
478 /* fall through to iterate */
479 case kIterating:
480 while (1) {
481 if (a->style > kMaxStyle) {
482 break;
484 #ifndef notdef
485 /* if old version of mklinux then skip CD drive */
486 if (a->style == kSCSI_Disks && a->index == 3) {
487 a->index += 1;
489 #endif
490 /* generate result */
491 result = (char *) malloc(20);
492 if (result != NULL) {
494 * for DR3 we should actually iterate through:
496 * /dev/sd[a...] # first missing is end of list
497 * /dev/hd[a...] # may be holes in sequence
498 * /dev/scd[0...] # first missing is end of list
500 * and stop in each group when either a stat of
501 * the name fails or if an open fails for
502 * particular reasons.
504 bump = 0;
505 value = (int) a->index;
506 switch (a->style) {
507 case kSCSI_Disks:
508 if (value < 26) {
509 snprintf(result, 20, "/dev/sd%c", 'a'+value);
510 } else if (value < 676) {
511 snprintf(result, 20, "/dev/sd%c%c",
512 'a' + value / 26,
513 'a' + value % 26);
514 } else {
515 bump = -1;
517 break;
518 case kATA_Devices:
519 if (value < 26) {
520 snprintf(result, 20, "/dev/hd%c", 'a'+value);
521 } else {
522 bump = -1;
524 break;
525 case kSCSI_CDs:
526 if (value < 10) {
527 snprintf(result, 20, "/dev/scd%c", '0'+value);
528 } else {
529 bump = -1;
531 break;
533 if (bump != 0) {
534 // already set don't even check
535 } else if (stat(result, &info) < 0) {
536 bump = 1;
537 } else if ((fd = open(result, O_RDONLY)) >= 0) {
538 close(fd);
539 #if defined(__linux__) || defined(__unix__)
540 } else if (errno == ENXIO || errno == ENODEV) {
541 if (a->style == kATA_Devices) {
542 bump = -1;
543 } else {
544 bump = 1;
546 #endif
548 if (bump) {
549 if (bump > 0) {
550 a->style += 1; /* next style */
551 a->index = 0; /* first index again */
552 } else {
553 a->index += 1; /* next index */
555 free(result);
556 continue;
560 a->index += 1; /* next index */
561 return result;
563 a->m.state = kEnd;
564 /* fall through to end */
565 case kEnd:
566 default:
567 break;
570 return 0 /* no entry */;
574 void
575 delete_file_iterator(MEDIA_ITERATOR m)
577 return;