This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
-#include <sys/errno.h>
+#include <errno.h>
#include <sys/param.h>
#include <sys/time.h>
#if WITH_NetBSD_HOST /* here NetBSD as that is what we're emulating */
#include <sys/syscall.h> /* FIXME - should not be including this one */
#include <sys/sysctl.h>
+#include <sys/mount.h>
extern int getdirentries(int fd, char *buf, int nbytes, long *basep);
+
+/* NetBSD post 2.0 has the statfs system call (if COMPAT_20), but does
+ not have struct statfs. In this case don't implement fstatfs.
+ FIXME: Should implement fstatvfs. */
+#ifndef HAVE_STRUCT_STATFS
+#undef HAVE_FSTATFS
+#endif
+
#else
/* If this is not netbsd, don't allow fstatfs or getdirentries at this time */
emul_write_buffer(&t, addr, sizeof(t), processor, cia);
}
-
+#ifdef HAVE_GETTIMEOFDAY
STATIC_INLINE_EMUL_NETBSD void
write_timezone(unsigned_word addr,
struct timezone tz,
H2T(tz.tz_dsttime);
emul_write_buffer(&tz, addr, sizeof(tz), processor, cia);
}
-
+#endif
#ifdef HAVE_GETDIRENTRIES
STATIC_INLINE_EMUL_NETBSD void
nbytes -= in->d_reclen;
addr += in->d_reclen;
buf += in->d_reclen;
- zfree(out);
+ free(out);
}
}
#endif
}
#endif
+
+/* File descriptors 0, 1, and 2 should not be closed. fd_closed[]
+ tracks whether these descriptors have been closed in do_close()
+ below. */
+
+static int fd_closed[3];
+
+/* Check for some occurrences of bad file descriptors. We only check
+ whether fd 0, 1, or 2 are "closed". By "closed" we mean that these
+ descriptors aren't actually closed, but are considered to be closed
+ by this layer.
+
+ Other checks are performed by the underlying OS call. */
+
+static int
+fdbad (int fd)
+{
+ if (fd >=0 && fd <= 2 && fd_closed[fd])
+ {
+ errno = EBADF;
+ return -1;
+ }
+ return 0;
+}
+
static void
do_exit(os_emul_data *emul,
unsigned call,
status = -1;
}
#endif
- status = read (d, scratch_buffer, nbytes);
+ status = fdbad (d);
+ if (status == 0)
+ status = read (d, scratch_buffer, nbytes);
emul_write_status(processor, status, errno);
if (status > 0)
emul_write_buffer(scratch_buffer, buf, status, processor, cia);
- zfree(scratch_buffer);
+ free(scratch_buffer);
}
processor, cia);
/* write */
- status = write(d, scratch_buffer, nbytes);
+ status = fdbad (d);
+ if (status == 0)
+ status = write(d, scratch_buffer, nbytes);
+
emul_write_status(processor, status, errno);
- zfree(scratch_buffer);
+ free(scratch_buffer);
flush_stdoutput();
}
char *path = emul_read_string(path_buf, path_addr, PATH_MAX, processor, cia);
int flags = (int)cpu_registers(processor)->gpr[arg0+1];
int mode = (int)cpu_registers(processor)->gpr[arg0+2];
+ int hostflags;
int status;
if (WITH_TRACE && ppc_trace[trace_os_emul])
SYS(open);
+ /* Do some translation on 'flags' to match it to the host's version. */
+ /* These flag values were taken from the NetBSD 1.4 header files. */
+ if ((flags & 3) == 0)
+ hostflags = O_RDONLY;
+ else if ((flags & 3) == 1)
+ hostflags = O_WRONLY;
+ else
+ hostflags = O_RDWR;
+ if (flags & 0x00000008)
+ hostflags |= O_APPEND;
+ if (flags & 0x00000200)
+ hostflags |= O_CREAT;
+ if (flags & 0x00000400)
+ hostflags |= O_TRUNC;
+ if (flags & 0x00000800)
+ hostflags |= O_EXCL;
+
/* Can't combine these statements, cuz open sets errno. */
- status = open(path, flags, mode);
+ status = open(path, hostflags, mode);
emul_write_status(processor, status, errno);
}
SYS(close);
- /* Can't combine these statements, cuz close sets errno. */
- status = close(d);
+ status = fdbad (d);
+ if (status == 0)
+ {
+ /* Do not close stdin, stdout, or stderr. GDB may still need access to
+ these descriptors. */
+ if (d == 0 || d == 1 || d == 2)
+ {
+ fd_closed[d] = 1;
+ status = 0;
+ }
+ else
+ status = close(d);
+ }
+
emul_write_status(processor, status, errno);
}
unsigned_word cia)
{
int oldd = cpu_registers(processor)->gpr[arg0];
- int status = dup(oldd);
+ int status = (fdbad (oldd) < 0) ? -1 : dup(oldd);
int err = errno;
if (WITH_TRACE && ppc_trace[trace_os_emul])
natural_word how = cpu_registers(processor)->gpr[arg0];
unsigned_word set = cpu_registers(processor)->gpr[arg0+1];
unsigned_word oset = cpu_registers(processor)->gpr[arg0+2];
+#ifdef SYS_sigprocmask
SYS(sigprocmask);
+#endif
if (WITH_TRACE && ppc_trace[trace_os_emul])
printf_filtered ("%ld, 0x%ld, 0x%ld", (long)how, (long)set, (long)oset);
|| dir & IOC_OUT
|| !(dir & IOC_VOID))
error("do_ioctl() read or write of parameter not implemented\n");
- status = ioctl(d, request, NULL);
+ status = fdbad (d);
+ if (status == 0)
+ status = ioctl(d, request, NULL);
emul_write_status(processor, status, errno);
#endif
{
int oldd = cpu_registers(processor)->gpr[arg0];
int newd = cpu_registers(processor)->gpr[arg0+1];
- int status = dup2(oldd, newd);
+ int status = (fdbad (oldd) < 0) ? -1 : dup2(oldd, newd);
int err = errno;
if (WITH_TRACE && ppc_trace[trace_os_emul])
printf_filtered ("%d, %d, %d", fd, cmd, arg);
SYS(fcntl);
- status = fcntl(fd, cmd, arg);
+ status = fdbad (fd);
+ if (status == 0)
+ status = fcntl(fd, cmd, arg);
emul_write_status(processor, status, errno);
}
#endif
printf_filtered ("%d, 0x%lx", fd, (long)buf_addr);
SYS(fstatfs);
- status = fstatfs(fd, (buf_addr == 0 ? NULL : &buf));
+ status = fdbad (fd);
+ if (status == 0)
+ status = fstatfs(fd, (buf_addr == 0 ? NULL : &buf));
emul_write_status(processor, status, errno);
if (status == 0) {
if (buf_addr != 0)
char *path = emul_read_string(path_buf, path_addr, PATH_MAX, processor, cia);
struct stat buf;
int status;
+#ifdef SYS_stat
SYS(stat);
+#endif
status = stat(path, &buf);
emul_write_status(processor, status, errno);
if (status == 0)
unsigned_word stat_buf_addr = cpu_registers(processor)->gpr[arg0+1];
struct stat buf;
int status;
+#ifdef SYS_fstat
SYS(fstat);
+#endif
/* Can't combine these statements, cuz fstat sets errno. */
- status = fstat(fd, &buf);
+ status = fdbad (fd);
+ if (status == 0)
+ status = fstat(fd, &buf);
emul_write_status(processor, status, errno);
write_stat(stat_buf_addr, buf, processor, cia);
}
unsigned_word stat_buf_addr = cpu_registers(processor)->gpr[arg0+1];
struct stat buf;
int status;
+#ifdef SYS_lstat
SYS(lstat);
+#endif
/* Can't combine these statements, cuz lstat sets errno. */
status = lstat(path, &buf);
emul_write_status(processor, status, errno);
unsigned_word basep_addr = cpu_registers(processor)->gpr[arg0+3];
long basep;
int status;
+#ifdef SYS_getdirentries
SYS(getdirentries);
+#endif
if (buf_addr != 0 && nbytes >= 0)
buf = zalloc(nbytes);
else
if (status > 0)
write_direntries(buf_addr, buf, status, processor, cia);
if (buf != NULL)
- zfree(buf);
+ free(buf);
}
#endif
int whence = cpu_registers(processor)->gpr[arg0+4];
off_t status;
SYS(lseek);
- status = lseek(fildes, offset, whence);
+ status = fdbad (fildes);
+ if (status == 0)
+ status = lseek(fildes, offset, whence);
if (status == -1)
emul_write_status(processor, -1, errno);
else {
int elf_binary;
os_emul_data *bsd_data;
device *vm;
+ char *filename;
/* check that this emulation is really for us */
if (name != NULL && strcmp(name, "netbsd") != 0)
(unsigned long)(top_of_stack - stack_size));
tree_parse(vm, "./nr-bytes 0x%x", stack_size);
+ filename = tree_quote_property (bfd_get_filename(image));
tree_parse(root, "/openprom/vm/map-binary/file-name %s",
- bfd_get_filename(image));
+ filename);
+ free (filename);
/* finish the init */
tree_parse(root, "/openprom/init/register/pc 0x%lx",
emul_netbsd_init(os_emul_data *emul_data,
int nr_cpus)
{
- /* nothing yet */
+ fd_closed[0] = 0;
+ fd_closed[1] = 0;
+ fd_closed[2] = 0;
}
static void
0 /*data*/
};
-#endif _EMUL_NETBSD_C_
+#endif /* _EMUL_NETBSD_C_ */