Index: stand/libsa/close.c =================================================================== --- stand/libsa/close.c +++ stand/libsa/close.c @@ -68,23 +68,42 @@ int close(int fd) { - struct open_file *f = &files[fd]; + struct open_file *f, *last; int err1 = 0, err2 = 0; - if ((unsigned)fd >= SOPEN_MAX || f->f_flags == 0) { + TAILQ_FOREACH(f, &files, f_link) { + if (f->f_id == fd) + break; + } + + if (f == NULL) { errno = EBADF; return (-1); } free(f->f_rabuf); f->f_rabuf = NULL; - if (!(f->f_flags & F_RAW) && f->f_ops) - err1 = (f->f_ops->fo_close)(f); - if (!(f->f_flags & F_NODEV) && f->f_dev) - err2 = (f->f_dev->dv_close)(f); - if (f->f_devdata != NULL) - devclose(f); - f->f_flags = 0; + if (f->f_flags != 0) { + if (!(f->f_flags & F_RAW) && f->f_ops) + err1 = (f->f_ops->fo_close)(f); + if (!(f->f_flags & F_NODEV) && f->f_dev) + err2 = (f->f_dev->dv_close)(f); + if (f->f_devdata != NULL) + devclose(f); + f->f_flags = 0; + } else { + /* Attempt to close already closed file. */ + err1 = EBADF; + } + + /* free unused entries from tail. */ + TAILQ_FOREACH_REVERSE_SAFE(last, &files, file_list, f_link, f) { + if (last->f_flags != 0) + break; + TAILQ_REMOVE(&files, last, f_link); + free(last); + } + if (err1) { errno = err1; return (-1); Index: stand/libsa/closeall.c =================================================================== --- stand/libsa/closeall.c +++ stand/libsa/closeall.c @@ -66,11 +66,17 @@ #include "stand.h" void -closeall() +closeall(void) { - int i; + struct open_file *f; - for (i = 0; i < SOPEN_MAX; i++) - if (files[i].f_flags != 0) - (void)close(i); + /* + * Pick up last entry and close it, this will also trigger + * the removal of this entry, and we end up with empty list. + */ + while ((f = TAILQ_LAST(&files, file_list)) != NULL) { + (void) close(f->f_id); + } + /* reset errno from close() */ + errno = 0; } Index: stand/libsa/fstat.c =================================================================== --- stand/libsa/fstat.c +++ stand/libsa/fstat.c @@ -37,13 +37,16 @@ #include "stand.h" int -fstat(fd, sb) - int fd; - struct stat *sb; +fstat(int fd, struct stat *sb) { - struct open_file *f = &files[fd]; + struct open_file *f; - if ((unsigned)fd >= SOPEN_MAX || f->f_flags == 0) { + TAILQ_FOREACH(f, &files, f_link) { + if (f->f_id == fd) + break; + } + + if (f == NULL || f->f_flags == 0) { errno = EBADF; return (-1); } Index: stand/libsa/ioctl.c =================================================================== --- stand/libsa/ioctl.c +++ stand/libsa/ioctl.c @@ -66,14 +66,16 @@ #include "stand.h" int -ioctl(fd, cmd, arg) - int fd; - u_long cmd; - char *arg; +ioctl(int fd, u_long cmd, char *arg) { - struct open_file *f = &files[fd]; + struct open_file *f; - if ((unsigned)fd >= SOPEN_MAX || f->f_flags == 0) { + TAILQ_FOREACH(f, &files, f_link) { + if (f->f_id == fd) + break; + } + + if (f == NULL || f->f_flags == 0) { errno = EBADF; return (-1); } Index: stand/libsa/iodesc.h =================================================================== --- stand/libsa/iodesc.h +++ stand/libsa/iodesc.h @@ -47,6 +47,8 @@ u_long xid; /* transaction identification */ u_char myea[6]; /* my ethernet address */ struct netif *io_netif; + int io_id; /* descriptor id */ + TAILQ_ENTRY(iodesc) io_link; /* next entry in list */ }; #endif /* __SYS_LIBNETBOOT_IODESC_H */ Index: stand/libsa/lseek.c =================================================================== --- stand/libsa/lseek.c +++ stand/libsa/lseek.c @@ -32,30 +32,30 @@ * SUCH DAMAGE. * * @(#)lseek.c 8.1 (Berkeley) 6/11/93 - * + * * * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University * All Rights Reserved. * * Author: Alessandro Forin - * + * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. - * + * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * + * * Carnegie Mellon requests users of this software to return to - * + * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 - * + * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ @@ -68,74 +68,80 @@ off_t lseek(int fd, off_t offset, int where) { - off_t bufpos, filepos, target; - struct open_file *f = &files[fd]; + off_t bufpos, filepos, target; + struct open_file *f; - if ((unsigned)fd >= SOPEN_MAX || f->f_flags == 0) { - errno = EBADF; - return (-1); - } + TAILQ_FOREACH(f, &files, f_link) { + if (f->f_id == fd) + break; + } - if (f->f_flags & F_RAW) { - /* - * On RAW devices, update internal offset. - */ - switch (where) { - case SEEK_SET: - f->f_offset = offset; - break; - case SEEK_CUR: - f->f_offset += offset; - break; - default: - errno = EOFFSET; - return (-1); + if (f == NULL || f->f_flags == 0) { + errno = EBADF; + return (-1); } - return (f->f_offset); - } - /* - * If there is some unconsumed data in the readahead buffer and it - * contains the desired offset, simply adjust the buffer offset and - * length. We don't bother with SEEK_END here, since the code to - * handle it would fail in the same cases where the non-readahead - * code fails (namely, for streams which cannot seek backward and whose - * size isn't known in advance). - */ - if (f->f_ralen != 0 && where != SEEK_END) { - if ((filepos = (f->f_ops->fo_seek)(f, (off_t)0, SEEK_CUR)) == -1) - return (-1); - bufpos = filepos - f->f_ralen; - switch (where) { - case SEEK_SET: - target = offset; - break; - case SEEK_CUR: - target = bufpos + offset; - break; - default: - errno = EINVAL; - return (-1); + if (f->f_flags & F_RAW) { + /* + * On RAW devices, update internal offset. + */ + switch (where) { + case SEEK_SET: + f->f_offset = offset; + break; + case SEEK_CUR: + f->f_offset += offset; + break; + default: + errno = EOFFSET; + return (-1); + } + return (f->f_offset); } - if (bufpos <= target && target < filepos) { - f->f_raoffset += target - bufpos; - f->f_ralen -= target - bufpos; - return (target); + + /* + * If there is some unconsumed data in the readahead buffer and it + * contains the desired offset, simply adjust the buffer offset and + * length. We don't bother with SEEK_END here, since the code to + * handle it would fail in the same cases where the non-readahead + * code fails (namely, for streams which cannot seek backward and whose + * size isn't known in advance). + */ + if (f->f_ralen != 0 && where != SEEK_END) { + filepos = (f->f_ops->fo_seek)(f, 0, SEEK_CUR); + if (filepos == -1) + return (-1); + bufpos = filepos - f->f_ralen; + switch (where) { + case SEEK_SET: + target = offset; + break; + case SEEK_CUR: + target = bufpos + offset; + break; + default: + errno = EINVAL; + return (-1); + } + if (bufpos <= target && target < filepos) { + f->f_raoffset += target - bufpos; + f->f_ralen -= target - bufpos; + return (target); + } } - } - /* - * If this is a relative seek, we need to correct the offset for - * bytes that we have already read but the caller doesn't know - * about. - */ - if (where == SEEK_CUR) - offset -= f->f_ralen; + /* + * If this is a relative seek, we need to correct the offset for + * bytes that we have already read but the caller doesn't know + * about. + */ + if (where == SEEK_CUR) + offset -= f->f_ralen; - /* - * Invalidate the readahead buffer. - */ - f->f_ralen = 0; + /* + * Invalidate the readahead buffer. + */ + f->f_ralen = 0; - return (f->f_ops->fo_seek)(f, offset, where); + return (f->f_ops->fo_seek)(f, offset, where); } Index: stand/libsa/net.h =================================================================== --- stand/libsa/net.h +++ stand/libsa/net.h @@ -97,8 +97,6 @@ extern int debug; /* defined in the machdep sources */ -extern struct iodesc sockets[SOPEN_MAX]; - /* ARP/RevARP functions: */ u_char *arpwhohas(struct iodesc *, struct in_addr); void arp_reply(struct iodesc *, void *); Index: stand/libsa/netif.c =================================================================== --- stand/libsa/netif.c +++ stand/libsa/netif.c @@ -47,7 +47,9 @@ #include "net.h" #include "netif.h" -struct iodesc sockets[SOPEN_MAX]; +typedef TAILQ_HEAD(socket_list, iodesc) socket_list_t; +static socket_list_t sockets; + #ifdef NETIF_DEBUG int netif_debug = 0; #endif @@ -264,29 +266,45 @@ struct iodesc * socktodesc(int sock) { - if (sock >= SOPEN_MAX) { + struct iodesc *desc; + + TAILQ_FOREACH(desc, &sockets, io_link) { + if (desc->io_id == sock) + break; + } + + if (desc == NULL) { errno = EBADF; return (NULL); } - return (&sockets[sock]); + return (desc); } int netif_open(void *machdep_hint) { - int fd; struct iodesc *s; struct netif *nif; /* find a free socket */ - for (fd = 0, s = sockets; fd < SOPEN_MAX; fd++, s++) - if (s->io_netif == (struct netif *)0) - goto fnd; - errno = EMFILE; - return (-1); - -fnd: - bzero(s, sizeof(*s)); + TAILQ_FOREACH(s, &sockets, io_link) { + if (s->io_netif == NULL) + break; + } + + if (s == NULL) { + struct iodesc *last; + + s = calloc(1, sizeof (*s)); + if (s == NULL) + return (-1); + + last = TAILQ_LAST(&sockets, socket_list); + if (last != NULL) + s->io_id = last->io_id + 1; + TAILQ_INSERT_TAIL(&sockets, s, io_link); + } + netif_init(); nif = netif_select(machdep_hint); if (!nif) @@ -299,18 +317,46 @@ } netif_attach(nif, s, machdep_hint); - return (fd); + return (s->io_id); } int netif_close(int sock) { - if (sock >= SOPEN_MAX) { - errno = EBADF; + struct iodesc *s, *last; + int err; + + TAILQ_FOREACH(s, &sockets, io_link) { + if (s->io_id == sock) + break; + } + + err = 0; + if (s == NULL) { + err = EBADF; + return (-1); + } + netif_detach(s->io_netif); + bzero(&s->destip, sizeof (s->destip)); + bzero(&s->myip, sizeof (s->myip)); + s->destport = 0; + s->myport = 0; + s->xid = 0; + bzero(s->myea, sizeof (s->myea)); + s->io_netif = NULL; + + /* free unused entries from tail. */ + TAILQ_FOREACH_REVERSE_SAFE(last, &sockets, socket_list, io_link, s) { + if (last->io_netif != NULL) + break; + TAILQ_REMOVE(&sockets, last, io_link); + free(last); + } + + if (err) { + errno = err; return (-1); } - netif_detach(sockets[sock].io_netif); - sockets[sock].io_netif = (struct netif *)0; return (0); } Index: stand/libsa/open.c =================================================================== --- stand/libsa/open.c +++ stand/libsa/open.c @@ -67,17 +67,39 @@ struct fs_ops *exclusive_file_system; -struct open_file files[SOPEN_MAX]; +/* + * Open file list. We only add tail and remove tail. + * Mark closed file, if it is last in queue, remove it to release the memory. + */ +file_list_t files = TAILQ_HEAD_INITIALIZER(files); static int -o_gethandle(void) +o_gethandle(struct open_file **ptr) { - int fd; + struct open_file *f, *last; + + /* Pick up unused entry */ + TAILQ_FOREACH(f, &files, f_link) { + if (f->f_flags == 0) { + *ptr = f; + return (f->f_id); + } + } - for (fd = 0; fd < SOPEN_MAX; fd++) - if (files[fd].f_flags == 0) - return (fd); - return (-1); + /* Add new entry */ + f = calloc(1, sizeof (*f)); + if (f == NULL) + return (-1); + + last = TAILQ_LAST(&files, file_list); + if (last == NULL) + f->f_id = 0; + else + f->f_id = last->f_id + 1; + TAILQ_INSERT_TAIL(&files, f, f_link); + + *ptr = f; + return (f->f_id); } static void @@ -98,12 +120,11 @@ TSENTER(); - if ((fd = o_gethandle()) == -1) { + if ((fd = o_gethandle(&f)) == -1) { errno = EMFILE; return (-1); } - f = &files[fd]; f->f_flags = mode + 1; f->f_dev = NULL; f->f_ops = NULL; Index: stand/libsa/read.c =================================================================== --- stand/libsa/read.c +++ stand/libsa/read.c @@ -69,12 +69,17 @@ ssize_t read(int fd, void *dest, size_t bcount) { - struct open_file *f = &files[fd]; + struct open_file *f; size_t resid; TSENTER(); - if ((unsigned)fd >= SOPEN_MAX || !(f->f_flags & F_READ)) { + TAILQ_FOREACH(f, &files, f_link) { + if (f->f_id == fd) + break; + } + + if (f == NULL || !(f->f_flags & F_READ)) { errno = EBADF; return (-1); } Index: stand/libsa/readdir.c =================================================================== --- stand/libsa/readdir.c +++ stand/libsa/readdir.c @@ -34,9 +34,14 @@ readdirfd(int fd) { static struct dirent dir; /* XXX not thread safe */ - struct open_file *f = &files[fd]; + struct open_file *f; - if ((unsigned)fd >= SOPEN_MAX || !(f->f_flags & F_READ)) { + TAILQ_FOREACH(f, &files, f_link) { + if (f->f_id == fd) + break; + } + + if (f == NULL || !(f->f_flags & F_READ)) { errno = EBADF; return (NULL); } Index: stand/libsa/stand.h =================================================================== --- stand/libsa/stand.h +++ stand/libsa/stand.h @@ -65,6 +65,7 @@ #include #include #include +#include /* this header intentionally exports NULL from */ #include @@ -182,11 +183,13 @@ char *f_rabuf; /* readahead buffer pointer */ size_t f_ralen; /* valid data in readahead buffer */ off_t f_raoffset; /* consumer offset in readahead buffer */ + int f_id; /* file number */ + TAILQ_ENTRY(open_file) f_link; /* next entry */ #define SOPEN_RASIZE 512 }; -#define SOPEN_MAX 64 -extern struct open_file files[]; +typedef TAILQ_HEAD(file_list, open_file) file_list_t; +extern file_list_t files; /* f_flags values */ #define F_READ 0x0001 /* file opened for reading */ Index: stand/libsa/write.c =================================================================== --- stand/libsa/write.c +++ stand/libsa/write.c @@ -69,10 +69,15 @@ ssize_t write(int fd, const void *dest, size_t bcount) { - struct open_file *f = &files[fd]; + struct open_file *f; size_t resid; - if ((unsigned)fd >= SOPEN_MAX || !(f->f_flags & F_WRITE)) { + TAILQ_FOREACH(f, &files, f_link) { + if (f->f_id == fd) + break; + } + + if (f == NULL || !(f->f_flags & F_WRITE)) { errno = EBADF; return (-1); }