1/* $NetBSD: unixdev.c,v 1.3 2012/01/18 23:12:21 nonaka Exp $ */ 2/* $OpenBSD: unixdev.c,v 1.6 2007/06/16 00:26:33 deraadt Exp $ */ 3 4/* 5 * Copyright (c) 1996-1998 Michael Shalayeff 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 */ 30 31#include <sys/param.h> 32#include <sys/reboot.h> 33 34#include "boot.h" 35#include "bootinfo.h" 36#include "disk.h" 37#include "unixdev.h" 38#include "compat_linux.h" 39 40static struct btinfo_bootdisk bi_disk; 41 42int 43unixstrategy(void *devdata, int rw, daddr_t blk, size_t size, void *buf, 44 size_t *rsize) 45{ 46 off_t off; 47 int fd = (int)devdata; 48 int rc = 0; 49 50#ifdef UNIX_DEBUG 51 printf("unixstrategy: %s %d bytes @ %d\n", 52 ((rw == F_READ) ? "reading" : "writing"), (int)size, (int)blk); 53#endif 54 55 off = (off_t)blk * DEV_BSIZE; 56 if ((rc = ulseek(fd, off, SEEK_SET)) >= 0) 57 rc = (rw == F_READ) ? uread(fd, buf, size) : 58 uwrite(fd, buf, size); 59 60 if (rc >= 0) { 61 *rsize = (size_t)rc; 62 rc = 0; 63 } else 64 rc = errno; 65 return rc; 66} 67 68int 69unixopen(struct open_file *f, ...) 70{ 71 va_list ap; 72 char path[PATH_MAX]; 73 struct diskinfo *dip; 74 char *devname; 75 const char *fname; 76 u_int unit, partition; 77 int dospart; 78 79 va_start(ap, f); 80 devname = va_arg(ap, char *); 81 unit = va_arg(ap, u_int); 82 partition = va_arg(ap, u_int); 83 fname = va_arg(ap, char *); 84 va_end(ap); 85 86#ifdef UNIX_DEBUG 87 printf("%s: devname=%s, unit=%d, partition=%d, fname=%s\n", 88 __func__, devname, unit, partition, fname); 89#else 90 __USE(fname); 91#endif 92 93 f->f_devdata = NULL; 94 95 /* Find device. */ 96 dip = dkdevice(devname, unit); 97 if (dip == NULL) 98 return ENOENT; 99 100 /* Try for disklabel again (might be removable media). */ 101 if (dip->bios_info.flags & BDI_BADLABEL) { 102 const char *st = bios_getdisklabel(&dip->bios_info, 103 &dip->disklabel); 104#ifdef UNIX_DEBUG 105 if (debug && st) 106 printf("%s\n", st); 107#endif 108 if (!st) { 109 dip->bios_info.flags &= ~BDI_BADLABEL; 110 dip->bios_info.flags |= BDI_GOODLABEL; 111 } else 112 return ERDLAB; 113 } 114 115 dospart = bios_getdospart(&dip->bios_info); 116 bios_devpath(dip->bios_info.bios_number, dospart, path); 117 f->f_devdata = (void *)uopen(path, LINUX_O_RDONLY); 118 if ((int)f->f_devdata == -1) 119 return errno; 120 121 bi_disk.biosdev = dip->bios_info.bios_number; 122 bi_disk.partition = partition; 123 bi_disk.labelsector = 124 dip->disklabel.d_partitions[partition].p_offset + LABELSECTOR; 125 bi_disk.label.type = dip->disklabel.d_type; 126 memcpy(bi_disk.label.packname, dip->disklabel.d_packname, 16); 127 bi_disk.label.checksum = dip->disklabel.d_checksum; 128 BI_ADD(&bi_disk, BTINFO_BOOTDISK, sizeof(bi_disk)); 129 130 return 0; 131} 132 133int 134unixpathopen(struct open_file *f, ...) 135{ 136 va_list ap; 137 char *devname; 138 const char *fname; 139 u_int unit, partition; 140 141 va_start(ap, f); 142 devname = va_arg(ap, char *); 143 unit = va_arg(ap, u_int); 144 partition = va_arg(ap, u_int); 145 fname = va_arg(ap, char *); 146 va_end(ap); 147 148#ifdef UNIX_DEBUG 149 printf("%s: devname=%s, unit=%d, partition=%d, fname=%s\n", 150 __func__, devname, unit, partition, fname); 151#else 152 __USE(devname); __USE(partition); __USE(unit); 153#endif 154 155 if (fname == NULL || fname[0] == '\0') 156 return EINVAL; 157 158 f->f_devdata = (void *)uopen(fname, LINUX_O_RDONLY); 159 if ((int)f->f_devdata == -1) 160 return errno; 161 162 bi_del(BTINFO_BOOTDISK); 163 164 return 0; 165} 166 167int 168unixclose(struct open_file *f) 169{ 170 171#ifdef UNIX_DEBUG 172 printf("%s\n", __func__); 173#endif 174 175 return uclose((int)f->f_devdata); 176} 177 178int 179unixioctl(struct open_file *f, u_long cmd, void *data) 180{ 181 182#ifdef UNIX_DEBUG 183 printf("%s: cmd=0x%08lx\n", __func__, cmd); 184#endif 185 186 return uioctl((int)f->f_devdata, cmd, data); 187} 188 189off_t 190ulseek(int fd, off_t off, int wh) 191{ 192 extern long ulseek32(int, long, int); 193 off_t r; 194 195 /* XXX only SEEK_SET is used, so anything else can fail for now. */ 196 197 if (wh == SEEK_SET) { 198 if (ulseek32(fd, 0, SEEK_SET) != 0) 199 return -1; 200 while (off > OFFT_OFFSET_MAX) { 201 off -= OFFT_OFFSET_MAX; 202 if (ulseek32(fd, OFFT_OFFSET_MAX, SEEK_CUR) < 0 && 203 errno != LINUX_EOVERFLOW) 204 return -1; 205 } 206 r = ulseek32(fd, (long)off, SEEK_CUR); 207 if (r == -1 && errno == LINUX_EOVERFLOW) 208 r = off; 209 } else 210 r = ulseek32(fd, (long)off, wh); 211 212 return r; 213} 214