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 <signal.h>
#include <fcntl.h>
#include <errno.h>
-#include <sys/errno.h>
#include <sys/param.h>
#include <sys/time.h>
#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();
}
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])
|| 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)
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);
}
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_ */