Hello,

I patched the sparc64 bootloader to allow users to manually specify
network config and where to load the kernel from via openfirmware
parameters instead of always requiring rarp/bootparams/bootp.

This enables remote bootstrapping of semi-recent sun boxes (like
the T1000) on networks where you are unable to set up the required
daemons. With this patch, the only thing required to bootstrap a
server with blank disks is access to the remote management port,
any tftp server to serve ofwboot.net, and any nfs server to serve
the kernel.

I'm not the first one to want to be able to do this, and I tried
to make it behave as users expect: http://marc.info/?t=137129897800005

Historically it made sense for ofwboot to assume the user already
has the relevant daemons on the network because they were required
to get ofwboot loaded in the first place, but at some point sun's
firmware allowed people to specify network config and a tftp
server/file to load. So, for newer machines all the daemons are an
artificial requirement imposed only by OpenBSD's ofwboot.

If someone happens to have a variety of sun hardware laying around,
I'm particularly interested in the format and availability of the
/options/network-boot-arguments ofw property across different
firmware versions. I expect only newer boxes to have it at all;
older ones still require rarp & friends to load ofwboot in the first
place, so these changes shouldn't affect them.

I know you guys are busy with all the other stuff you're trying to
fit in before 5.5, but if someone does find some time to test this
and/or give some feedback it'd be much appreciated.

This patch also includes various style(9), alphabetizing, and
whitespace changes which are unrelated to the netbooting logic. I
could put them in a separate diff if it helps.

Index: share/man/man8/man8.sparc64/boot_sparc64.8
===================================================================
RCS file: /cvs/src/share/man/man8/man8.sparc64/boot_sparc64.8,v
retrieving revision 1.13
diff -u -p -r1.13 boot_sparc64.8
--- share/man/man8/man8.sparc64/boot_sparc64.8  3 Jan 2010 16:43:46 -0000       
1.13
+++ share/man/man8/man8.sparc64/boot_sparc64.8  11 Feb 2014 00:39:13 -0000
@@ -105,6 +105,26 @@ as soon as the kernel console has been i
 Boot the system single-user.
 The system will be booted multi-user unless this option is specified.
 .El
+.Ss Specifying netboot configuration
+An alternative to setting up all the daemons described in
+.Xr diskless 8
+is to manually specify your configuration via
+.Tn Open Firmware
+parameters.
+To make this work, set the
+.Va host-ip ,
+.Va router-ip ,
+and
+.Va subnet-mask
+fields in the
+.Va network-boot-arguments
+parameter, and use an NFS URL of form
+.Pp
+.Dl nfs://1.2.3.4//var/nfs/bsd.rd -options
+.Pp
+as the
+.Va boot-file
+parameter.
 .Ss Accessing the PROM during runtime
 If the
 .Xr sysctl 8
@@ -144,8 +164,9 @@ secondary bootstrap (usually also instal
 network bootstrap
 .El
 .Sh SEE ALSO
-.Xr ddb 4 ,
 .Xr boot_config 8 ,
+.Xr ddb 4 ,
+.Xr diskless 8 ,
 .Xr halt 8 ,
 .Xr init 8 ,
 .Xr installboot 8 ,
Index: sys/arch/sparc64/stand/libsa/Makefile
===================================================================
RCS file: /cvs/src/sys/arch/sparc64/stand/libsa/Makefile,v
retrieving revision 1.9
diff -u -p -r1.9 Makefile
--- sys/arch/sparc64/stand/libsa/Makefile       1 Jan 2013 18:49:33 -0000       
1.9
+++ sys/arch/sparc64/stand/libsa/Makefile       11 Feb 2014 00:39:13 -0000
@@ -16,8 +16,9 @@ CFLAGS= ${CEXTRAFLAGS} ${AFLAGS} -O2 -D_
 CPPFLAGS+= -D__INTERNAL_LIBSA_CREAD
 
 # stand routines
-SRCS=  alloc.c exit.c getfile.c gets.c globals.c \
-       memcmp.c memcpy.c memset.c printf.c snprintf.c strerror.c strncpy.c
+SRCS=  alloc.c exit.c getfile.c gets.c globals.c memcmp.c memcpy.c memset.c \
+       printf.c snprintf.c strchr.c strerror.c strncmp strncpy.c strrchr.c \
+       strsep.c
 
 # io routines
 SRCS+= close.c closeall.c dev.c disklabel.c dkcksum.c fstat.c ioctl.c lseek.c \
Index: sys/arch/sparc64/stand/ofwboot/Makefile
===================================================================
RCS file: /cvs/src/sys/arch/sparc64/stand/ofwboot/Makefile,v
retrieving revision 1.18
diff -u -p -r1.18 Makefile
--- sys/arch/sparc64/stand/ofwboot/Makefile     30 Aug 2012 19:29:14 -0000      
1.18
+++ sys/arch/sparc64/stand/ofwboot/Makefile     11 Feb 2014 00:39:13 -0000
@@ -18,14 +18,14 @@ SRCS=               srt0.s Locore.c alloc.c boot.c el
                ofdev.c vers.c
 
 .PATH:         ${S}/lib/libkern/arch/sparc64 ${S}/lib/libkern
-SRCS+=         strlcpy.c strcmp.c strlcat.c strlen.c
+SRCS+=         strcmp.c strlcat.c strlcpy.c strlen.c
 
 CWARNFLAGS+=   -Wno-main
 AFLAGS+=       -Wa,-Av9a
 AFLAGS+=       -x assembler-with-cpp -D_LOCORE -D__ELF__ -fno-pie
 CFLAGS+=       ${COPTS} -fno-pie
 CPPFLAGS+=     -D_STANDALONE -DSUN4U -nostdinc
-#CPPFLAGS+=    -DNETIF_DEBUG 
+#CPPFLAGS+=    -DNETIF_DEBUG
 
 BINMODE=       444
 
Index: sys/arch/sparc64/stand/ofwboot/boot.c
===================================================================
RCS file: /cvs/src/sys/arch/sparc64/stand/ofwboot/boot.c,v
retrieving revision 1.20
diff -u -p -r1.20 boot.c
--- sys/arch/sparc64/stand/ofwboot/boot.c       28 Dec 2013 21:00:21 -0000      
1.20
+++ sys/arch/sparc64/stand/ofwboot/boot.c       11 Feb 2014 00:39:13 -0000
@@ -40,7 +40,7 @@
  * First try for the boot code
  *
  * Input syntax is:
- *     [promdev[{:|,}partition]]/[filename] [flags]
+ *     [promdev[{:|,}partition]]/[[nfs://ip/path/]filename] [flags]
  */
 
 #define ELFSIZE 64
@@ -93,7 +93,7 @@ prom2boot(char *dev)
        char *cp, *lp = 0;
        int handle;
        char devtype[16];
-       
+
        for (cp = dev; *cp; cp++)
                if (*cp == ':')
                        lp = cp;
@@ -127,10 +127,10 @@ parseargs(char *str, int *howtop)
                while (*cp == ' ')
                        ++cp;
        }
-       *str = 0;
-       switch(*cp) {
+       *str = '\0';
+       switch (*cp) {
        default:
-               printf ("boot options string <%s> must start with -\n", cp);
+               printf("boot options string <%s> must start with -\n", cp);
                return -1;
        case 0:
                return 0;
@@ -188,7 +188,7 @@ chain(u_int64_t pentry, char *args, void
        bcopy(&machine_tag, args + l, sizeof(machine_tag));
        l += sizeof(machine_tag);
 
-       /* 
+       /*
         * Since we don't need the boot string (we can get it from /chosen)
         * we won't pass it in.  Just pass in esym and magic #
         */
@@ -296,7 +296,7 @@ main()
        int i, fd;
        char **bootlp;
        char *just_bootline[2];
-       
+
        printf(">> OpenBSD BOOT %s\n", version);
 
        /*
@@ -353,13 +353,17 @@ main()
                                _rtt();
                        }
                }
+               /*
+                * Need to find a better way to bootstrap entropy when
+                * netbooting.
+                */
                if (loadrandom(BOOTRANDOM, rnddata, sizeof(rnddata)))
                        printf("open %s: %s\n", opened_name, strerror(errno));
                if ((fd = open(bootline, 0)) < 0) {
                        printf("open %s: %s\n", opened_name, strerror(errno));
                        continue;
                }
-#ifdef __notyet__
+#ifdef __notyet__
                OF_setprop(chosen, "bootpath", opened_name, strlen(opened_name) 
+ 1);
                cp = bootline;
 #else
@@ -378,7 +382,7 @@ main()
                        *--cp = 0;
                else
                        *++cp = 0;
-#ifdef __notyet__
+#ifdef __notyet__
                OF_setprop(chosen, "bootargs", bootline, strlen(bootline) + 1);
 #endif
                /* XXX void, for now */
Index: sys/arch/sparc64/stand/ofwboot/net.c
===================================================================
RCS file: /cvs/src/sys/arch/sparc64/stand/ofwboot/net.c,v
retrieving revision 1.5
diff -u -p -r1.5 net.c
--- sys/arch/sparc64/stand/ofwboot/net.c        3 Sep 2009 16:49:13 -0000       
1.5
+++ sys/arch/sparc64/stand/ofwboot/net.c        11 Feb 2014 00:39:13 -0000
@@ -41,9 +41,18 @@
  *
  * At open time, this does:
  *
- * find interface      - netif_open()
- * BOOTP               - bootp()
- * RPC/mountd          - nfs_mount()
+ * find interface
+ *  - netif_open()
+ * if no NFS config is manually specified:
+ *    use BOOTPARAMS
+ *     - rarp_getipaddress()
+ *     - bp_whoami()
+ *     - bp_getfile()
+ * if BOOTPARAMS failed:
+ *    use BOOTP
+ *     - bootp()
+ * RPC/mountd
+ *  - nfs_mount()
  *
  * The root file handle from mountd is saved in a global
  * for use by the NFS open code (NFS/lookup).
@@ -64,6 +73,7 @@
 
 #include "ofdev.h"
 
+static int net_mountroot_manual(void);
 static int net_mountroot_bootparams(void);
 static int net_mountroot_bootp(void);
 
@@ -72,6 +82,75 @@ char rootpath[FNAME_SIZE];
 static int netdev_sock = -1;
 static int open_count;
 
+#ifdef NETBOOT
+int manual_nfs_url = 0;
+/*
+ * Extracts NFS information from a URL-formatted filename, if present.
+ * Upon return, *url contains the /mount/path/file to be opened on the NFS
+ * server. Returns EFTYPE if *url is not a URL, and EINVAL if it looks like a
+ * URL but is malformed.
+ */
+int
+extract_nfs_opts(const char **url)
+{
+       char ipbuf[16], *end;
+       const char *next;
+       n_long ip;
+
+       manual_nfs_url = 0;
+
+       next = *url;
+
+       if (strncmp(next, "nfs://", strlen("nfs://")) != 0)
+               return EFTYPE;
+       next += strlen("nfs://");
+
+       /*
+        * Get the ip. Using a temporary buffer because inet_addr() fails on
+        * trailing chars, and we can't modify **url.
+        */
+       strlcpy(ipbuf, next, sizeof(ipbuf));
+       end = strchr(ipbuf, '/');
+       if (end)
+               *end = '\0';
+       ip = inet_addr(ipbuf);
+
+       if (ip == htonl(INADDR_NONE))
+               return EINVAL;
+
+       next = strchr(next, '/');
+       if (next == NULL)
+               return EINVAL;
+       next++;
+
+       if (strchr(next, '/') == NULL)
+               return EINVAL;
+
+       /*
+        * At this point we know it's a complete URL, so we can overwrite
+        * whatever's stored.
+        */
+       manual_nfs_url = 1;
+
+       /* ip */
+       rootip.s_addr = ip;
+
+       /* path */
+       strlcpy(rootpath, next, FNAME_SIZE);
+       end = strrchr(rootpath, '/');
+       if (end == NULL) /* NOTREACHED */
+               return EINVAL;
+       *end = '\0';
+       next = end + 1;
+
+       /* file */
+       strlcpy(bootfile, next, FNAME_SIZE);
+       *url = next;
+
+       return 0;
+}
+#endif
+
 /*
  * Called by devopen after it sets f->f_dev to our devsw entry.
  * This opens the low-level device and sets f->f_devdata.
@@ -80,7 +159,7 @@ int
 net_open(struct of_dev *op)
 {
        int error = 0;
-       
+
        /*
         * On first open, do netif open, mount, etc.
         */
@@ -116,6 +195,139 @@ net_close(struct of_dev *op)
 }
 
 int
+net_mountroot_manual(void)
+{
+       struct iodesc *io;
+       n_long converted, smask, nmask;
+       int dev;
+       char buf[512], *key, *value, *next;
+
+       if ((dev = OF_finddevice("/options")) == -1) {
+               printf("no OpenFirmware /options device\n");
+               return (ENOENT);
+       }
+       if (OF_getprop(dev, "network-boot-arguments", buf, sizeof(buf)) < 0) {
+               printf("/options has no network-boot-arguments property\n");
+               return (ENOENT);
+       }
+
+       myip.s_addr = 0;
+       gateip.s_addr = 0;
+       smask = 0;
+       hostname[0] = '\0';
+
+       /* Extract config from network-boot-arguments. */
+
+       for (next = buf; (key = strsep(&next, ",")) != NULL; ) {
+               if (key[0] == '\0') {
+                       printf("Empty entry in network-boot-arguments\n");
+                       continue;
+               }
+
+               value = key;
+               strsep(&value, "=");
+
+               if (value == NULL) {
+                       printf("Key without value in network-boot-arguments: "
+                           "%s\n", key);
+                       continue;
+               }
+
+               if (strcmp(key, "host-ip") == 0) {
+                       DNPRINTF(BOOT_D_OFNET, "host-ip: %s\n", value);
+                       converted = inet_addr(value);
+                       if (converted == htonl(INADDR_NONE)) {
+                               printf("warning: invalid host-ip: %s\n", value);
+                               continue;
+                       }
+                       if (myip.s_addr)
+                               printf("warning: duplicate host-ip\n");
+                       myip.s_addr = converted;
+               } else if (strcmp(key, "router-ip") == 0) {
+                       DNPRINTF(BOOT_D_OFNET, "router-ip: %s\n", value);
+                       converted = inet_addr(value);
+                       if (converted == htonl(INADDR_NONE)) {
+                               printf("warning: invalid router-ip: %s\n",
+                                   value);
+                               continue;
+                       }
+                       if (gateip.s_addr)
+                               printf("warning: duplicate router-ip\n");
+                       gateip.s_addr = converted;
+               } else if (strcmp(key, "subnet-mask") == 0) {
+                       DNPRINTF(BOOT_D_OFNET, "subnet-mask: %s\n", value);
+                       converted = inet_addr(value);
+                       if (converted == htonl(INADDR_NONE)) {
+                               printf("warning: invalid subnet-mask: %s\n",
+                                   value);
+                               continue;
+                       }
+                       if (smask)
+                               printf("warning: duplicate subnet-mask\n");
+                       smask = converted;
+               } else if (strcmp(key, "hostname") == 0) {
+                       DNPRINTF(BOOT_D_OFNET, "hostname: %s\n", value);
+                       strlcpy(hostname, value, FNAME_SIZE);
+               }
+       }
+
+       /* Validate config and inform user of possible issues. */
+
+       if (myip.s_addr == 0) {
+               printf("error: no valid host-ip\n");
+               return (EINVAL);
+       }
+
+       if (IN_CLASSA(myip.s_addr))
+               nmask = IN_CLASSA_NET;
+       else if (IN_CLASSB(myip.s_addr))
+               nmask = IN_CLASSB_NET;
+       else
+               nmask = IN_CLASSC_NET;
+
+       if ((nmask & smask) != nmask) {
+               printf("warning: bad subnet-mask: %s\n", intoa(smask));
+               smask = 0;
+       }
+
+       if (smask)
+               netmask = smask;
+       else {
+               printf("warning: defaulting to default netmask: %s\n",
+                   intoa(nmask));
+               netmask = nmask;
+       }
+
+       if (!SAMENET(myip, gateip, netmask))
+               printf("warning: router-ip is on different network\n");
+
+       if (!SAMENET(myip, rootip, netmask) && gateip.s_addr == 0)
+               printf("warning: router-ip required but none specified\n");
+
+       io = socktodesc(netdev_sock);
+       io->myip = myip;
+
+       if (debug) {
+               printf("Using manual config:\n");
+               printf("\tip: %s\n", inet_ntoa(myip));
+               printf("\tgateway: %s\n",
+                   gateip.s_addr ? inet_ntoa(gateip) : "(none)");
+               printf("\tnetmask: %s\n", intoa(netmask));
+               printf("\thostname: %s\n",
+                   hostname[0] != '\0' ? hostname : "(none)");
+               printf("\tnfs server: %s\n", inet_ntoa(rootip));
+               printf("\tnfs path: %s\n", rootpath);
+               printf("\tnfs file: %s\n", bootfile);
+       } else {
+               printf("ip: %s, ", inet_ntoa(myip));
+               printf("gateway: %s, ", inet_ntoa(gateip));
+               printf("netmask: %s\n", intoa(netmask));
+       }
+
+       return (0);
+}
+
+int
 net_mountroot_bootparams(void)
 {
        /* Get our IP address.  (rarp.c) */
@@ -144,7 +356,7 @@ net_mountroot_bootp(void)
        bootp(netdev_sock);
 
        if (myip.s_addr == 0)
-               return(ENOENT);
+               return (ENOENT);
 
        printf("Using BOOTP protocol: ");
        printf("ip address: %s", inet_ntoa(myip));
@@ -165,24 +377,39 @@ net_mountroot(void)
 {
        int error;
 
-#ifdef DEBUG
-       printf("net_mountroot\n");
-#endif
-
        /*
         * Get info for NFS boot: our IP address, our hostname,
         * server IP address, and our root path on the server.
-        * There are two ways to do this:  The old, Sun way,
-        * and the more modern, BOOTP way. (RFC951, RFC1048)
+        * There are three ways to do this:
+        *  - Manually specifying the information.
+        *  - The old Sun way. (bootparams)
+        *  - The more modern, BOOTP way. (RFC951, RFC1048)
         */
 
-       /* Historically, we've used BOOTPARAMS, so try that first */
-       error = net_mountroot_bootparams();
-       if (error != 0)
-               /* Next, try BOOTP */
-               error = net_mountroot_bootp();
-       if (error != 0)
-               return (error);
+#ifdef NETBOOT
+       if (manual_nfs_url) {
+               DNPRINTF(BOOT_D_OFNET, "net_mountroot: trying manual\n");
+               error = net_mountroot_manual();
+
+               if (error != 0) {
+                       printf("manual boot failed\n");
+                       return (error);
+               }
+       } else {
+#endif
+               /* Historically, we've used BOOTPARAMS, so try that first */
+               DNPRINTF(BOOT_D_OFNET, "net_mountroot: trying bootparams\n");
+               error = net_mountroot_bootparams();
+               if (error != 0) {
+                       /* Next, try BOOTP */
+                       DNPRINTF(BOOT_D_OFNET, "net_mountroot: trying bootp\n");
+                       error = net_mountroot_bootp();
+               }
+               if (error != 0)
+                       return (error);
+#ifdef NETBOOT
+       }
+#endif
 
        printf("root addr=%s path=%s\n", inet_ntoa(rootip), rootpath);
 
Index: sys/arch/sparc64/stand/ofwboot/ofdev.c
===================================================================
RCS file: /cvs/src/sys/arch/sparc64/stand/ofwboot/ofdev.c,v
retrieving revision 1.20
diff -u -p -r1.20 ofdev.c
--- sys/arch/sparc64/stand/ofwboot/ofdev.c      5 Nov 2013 00:51:58 -0000       
1.20
+++ sys/arch/sparc64/stand/ofwboot/ofdev.c      11 Feb 2014 00:39:13 -0000
@@ -468,6 +468,12 @@ devopen(struct open_file *of, const char
        if (of->f_flags != F_READ)
                return EPERM;
        DNPRINTF(BOOT_D_OFDEV, "devopen: you want %s\n", name);
+#ifdef NETBOOT
+       if (extract_nfs_opts(&name) == EINVAL) {
+               printf("malformed URL: %s\n", name);
+               return EINVAL;
+       }
+#endif
        strlcpy(fname, name, sizeof fname);
        cp = filename(fname, &partition);
        if (cp) {
Index: sys/arch/sparc64/stand/ofwboot/ofdev.h
===================================================================
RCS file: /cvs/src/sys/arch/sparc64/stand/ofwboot/ofdev.h,v
retrieving revision 1.4
diff -u -p -r1.4 ofdev.h
--- sys/arch/sparc64/stand/ofwboot/ofdev.h      4 Nov 2009 12:03:57 -0000       
1.4
+++ sys/arch/sparc64/stand/ofwboot/ofdev.h      11 Feb 2014 00:39:13 -0000
@@ -62,4 +62,8 @@ struct of_dev {
 extern char opened_name[];
 extern int floppyboot;
 
+#ifdef NETBOOT
+int extract_nfs_opts(const char **);
+#endif
+
 #endif
Index: sys/arch/sparc64/stand/ofwboot/vers.c
===================================================================
RCS file: /cvs/src/sys/arch/sparc64/stand/ofwboot/vers.c,v
retrieving revision 1.7
diff -u -p -r1.7 vers.c
--- sys/arch/sparc64/stand/ofwboot/vers.c       28 Dec 2013 21:00:21 -0000      
1.7
+++ sys/arch/sparc64/stand/ofwboot/vers.c       11 Feb 2014 00:39:13 -0000
@@ -1 +1 @@
-const char version[] = "1.6";
+const char version[] = "1.7";
Index: sys/lib/libsa/Makefile
===================================================================
RCS file: /cvs/src/sys/lib/libsa/Makefile,v
retrieving revision 1.24
diff -u -p -r1.24 Makefile
--- sys/lib/libsa/Makefile      1 Jan 2013 18:49:33 -0000       1.24
+++ sys/lib/libsa/Makefile      11 Feb 2014 00:39:13 -0000
@@ -24,9 +24,9 @@ CPPFLAGS+= -D__INTERNAL_LIBSA_CREAD
 .endif
 
 # stand routines
-SRCS+= alloc.c memcpy.c exit.c getfile.c gets.c globals.c \
-       printf.c snprintf.c strerror.c strcmp.c memset.c memcmp.c \
-       strncpy.c strncmp.c strchr.c
+SRCS+= alloc.c exit.c getfile.c gets.c globals.c memcmp.c memcpy.c \
+       memset.c printf.c snprintf.c strchr.c strcmp.c strerror.c \
+       strncmp.c strncpy.c strrchr.c strsep.c
 
 # math from libkern
 SRCS+= divdi3.c qdivrem.c
Index: sys/lib/libsa/net.h
===================================================================
RCS file: /cvs/src/sys/lib/libsa/net.h,v
retrieving revision 1.7
diff -u -p -r1.7 net.h
--- sys/lib/libsa/net.h 11 Aug 2003 06:23:09 -0000      1.7
+++ sys/lib/libsa/net.h 11 Feb 2014 00:39:13 -0000
@@ -98,10 +98,8 @@ int  rarp_getipaddress(int);
 n_long ip_convertaddr(char *);
 
 /* Link functions: */
-ssize_t sendether(struct iodesc *d, void *pkt, size_t len,
-           u_char *dea, int etype);
-ssize_t readether(struct iodesc *d, void *pkt, size_t len,
-           time_t tleft, u_int16_t *etype);
+ssize_t sendether(struct iodesc *, void *, size_t, u_char *, int);
+ssize_t readether(struct iodesc *, void *, size_t, time_t, u_int16_t *);
 
 ssize_t        sendudp(struct iodesc *, void *, size_t);
 ssize_t        readudp(struct iodesc *, void *, size_t, time_t);
Index: sys/lib/libsa/nfs.h
===================================================================
RCS file: /cvs/src/sys/lib/libsa/nfs.h,v
retrieving revision 1.7
diff -u -p -r1.7 nfs.h
--- sys/lib/libsa/nfs.h 2 Jun 2003 23:28:09 -0000       1.7
+++ sys/lib/libsa/nfs.h 11 Feb 2014 00:39:13 -0000
@@ -30,13 +30,11 @@
  * SUCH DAMAGE.
  */
 
-int    nfs_open(char *path, struct open_file *f);
-int    nfs_close(struct open_file *f);
-int    nfs_read(struct open_file *f, void *buf,
-                       size_t size, size_t *resid);
-int    nfs_write(struct open_file *f, void *buf,
-                       size_t size, size_t *resid);
-off_t  nfs_seek(struct open_file *f, off_t offset, int where);
-int    nfs_stat(struct open_file *f, struct stat *sb);
+int    nfs_open(char *, struct open_file *);
+int    nfs_close(struct open_file *);
+int    nfs_read(struct open_file *, void *, size_t, size_t *);
+int    nfs_write(struct open_file *, void *, size_t, size_t *);
+off_t  nfs_seek(struct open_file *, off_t, int);
+int    nfs_stat(struct open_file *, struct stat *);
 int    nfs_mount(int, struct in_addr, char *);
-int    nfs_readdir(struct open_file *f, char *name);
+int    nfs_readdir(struct open_file *, char *);
Index: sys/lib/libsa/stand.h
===================================================================
RCS file: /cvs/src/sys/lib/libsa/stand.h,v
retrieving revision 1.56
diff -u -p -r1.56 stand.h
--- sys/lib/libsa/stand.h       28 Dec 2013 02:51:07 -0000      1.56
+++ sys/lib/libsa/stand.h       11 Feb 2014 00:39:13 -0000
@@ -147,13 +147,15 @@ __dead void       _rtt(void) __attribute__((no
 void   explicit_bzero(void *, size_t);
 void   *memcpy(void *, const void *, size_t);
 int    memcmp(const void *, const void *, size_t);
-char   *strncpy(char *, const char *, size_t);
-int    strncmp(const char *, const char *, size_t);
+char   *strchr(const char *, int);
 int    strcmp(const char *, const char *);
 size_t strlen(const char *);
+int    strncmp(const char *, const char *, size_t);
+char   *strncpy(char *, const char *, size_t);
+char   *strrchr(const char *, int);
+char   *strsep(char **, const char *);
 long   strtol(const char *, char **, int);
 long long      strtoll(const char *, char **, int);
-char   *strchr(const char *, int);
 void   *memset(void *, int, size_t);
 void   exit(void);
 int    open(const char *, int);
Index: sys/lib/libsa/strrchr.c
===================================================================
RCS file: sys/lib/libsa/strrchr.c
diff -N sys/lib/libsa/strrchr.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ sys/lib/libsa/strrchr.c     11 Feb 2014 00:39:13 -0000
@@ -0,0 +1,45 @@
+/*     $OpenBSD: rindex.c,v 1.6 2005/08/08 08:05:37 espie Exp $ */
+/*
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "stand.h"
+
+char *
+strrchr(const char *p, int ch)
+{
+       char *save;
+
+       for (save = NULL;; ++p) {
+               if (*p == ch)
+                       save = (char *)p;
+               if (!*p)
+                       return(save);
+       }
+       /* NOTREACHED */
+}
Index: sys/lib/libsa/strsep.c
===================================================================
RCS file: sys/lib/libsa/strsep.c
diff -N sys/lib/libsa/strsep.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ sys/lib/libsa/strsep.c      11 Feb 2014 00:39:13 -0000
@@ -0,0 +1,70 @@
+/*     $OpenBSD: strsep.c,v 1.6 2005/08/08 08:05:37 espie Exp $        */
+
+/*-
+ * Copyright (c) 1990, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "stand.h"
+
+/*
+ * Get next token from string *stringp, where tokens are possibly-empty
+ * strings separated by characters from delim.
+ *
+ * Writes NULs into the string at *stringp to end tokens.
+ * delim need not remain constant from call to call.
+ * On return, *stringp points past the last NUL written (if there might
+ * be further tokens), or is NULL (if there are definitely no more tokens).
+ *
+ * If *stringp is NULL, strsep returns NULL.
+ */
+char *
+strsep(char **stringp, const char *delim)
+{
+       char *s;
+       const char *spanp;
+       int c, sc;
+       char *tok;
+
+       if ((s = *stringp) == NULL)
+               return (NULL);
+       for (tok = s;;) {
+               c = *s++;
+               spanp = delim;
+               do {
+                       if ((sc = *spanp++) == c) {
+                               if (c == 0)
+                                       s = NULL;
+                               else
+                                       s[-1] = 0;
+                               *stringp = s;
+                               return (tok);
+                       }
+               } while (sc != 0);
+       }
+       /* NOTREACHED */
+}

Reply via email to