/**************************************************************************** * net/net_procfs.c * * Copyright (C) 2015 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * 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 NuttX 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 COPYRIGHT HOLDERS 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 * COPYRIGHT OWNER 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. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_FS_PROCFS) /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ /* Determines the size of an intermediate buffer that must be large enough * to handle the longest line generated by this logic. */ #define NET_LINELEN 64 /**************************************************************************** * Private Types ****************************************************************************/ /* This enumeration identifies all of the thread attributes that can be * accessed via the procfs file system. */ /* This structure describes one open "file" */ struct netprocfs_file_s { struct procfs_file_s base; /* Base open file structure */ uint8_t lineno; /* Line number */ uint8_t linesize; /* Number of valid characters in line[] */ uint8_t offset; /* Offset to first valid character in line[] */ char line[NET_LINELEN]; /* Pre-allocated buffer for formatted lines */ }; /* Level 1 is the directory of attributes */ struct netprocfs_level1_s { struct procfs_dir_priv_s base; /* Base directory private data */ }; /* Line generating function type */ typedef int (*linegen_t)(FAR struct netprocfs_file_s *netfile); /**************************************************************************** * Private Function Prototypes ****************************************************************************/ /* Line generating functions */ #ifdef CONFIG_NET_STATISTICS static int netprocfs_header(FAR struct netprocfs_file_s *netfile); static int netprocfs_received(FAR struct netprocfs_file_s *netfile); static int netprocfs_dropped(FAR struct netprocfs_file_s *netfile); #ifdef CONFIG_NET_IPv4 static int netprocfs_ipv4_dropped(FAR struct netprocfs_file_s *netfile); #endif /* CONFIG_NET_IPv4 */ #ifdef CONFIG_NET_IPv6 static int netprocfs_ipv6_dropped(FAR struct netprocfs_file_s *netfile); #endif /* CONFIG_NET_IPv4 */ static int netprocfs_checksum(FAR struct netprocfs_file_s *netfile); #ifdef CONFIG_NET_TCP static int netprocfs_tcp_dropped_1(FAR struct netprocfs_file_s *netfile); static int netprocfs_tcp_dropped_2(FAR struct netprocfs_file_s *netfile); #endif /* CONFIG_NET_TCP */ static int netprocfs_prototype(FAR struct netprocfs_file_s *netfile); static int netprocfs_sent(FAR struct netprocfs_file_s *netfile); #ifdef CONFIG_NET_TCP static int netprocfs_retransmissions(FAR struct netprocfs_file_s *netfile); #endif /* CONFIG_NET_TCP */ #endif /* CONFIG_NET_STATISTICS */ /* File system methods */ static int netprocfs_open(FAR struct file *filep, FAR const char *relpath, int oflags, mode_t mode); static int netprocfs_close(FAR struct file *filep); static ssize_t netprocfs_read(FAR struct file *filep, FAR char *buffer, size_t buflen); static int netprocfs_dup(FAR const struct file *oldp, FAR struct file *newp); static int netprocfs_opendir(FAR const char *relpath, FAR struct fs_dirent_s *dir); static int netprocfs_closedir(FAR struct fs_dirent_s *dir); static int netprocfs_readdir(FAR struct fs_dirent_s *dir); static int netprocfs_rewinddir(FAR struct fs_dirent_s *dir); static int netprocfs_stat(FAR const char *relpath, FAR struct stat *buf); /**************************************************************************** * Private Data ****************************************************************************/ /* Line generating functions */ #ifdef CONFIG_NET_STATISTICS static const linegen_t g_linegen[] = { netprocfs_header, netprocfs_received, netprocfs_dropped, #ifdef CONFIG_NET_IPv4 netprocfs_ipv4_dropped, #endif /* CONFIG_NET_IPv4 */ #ifdef CONFIG_NET_IPv6 netprocfs_ipv6_dropped, #endif /* CONFIG_NET_IPv4 */ netprocfs_checksum, #ifdef CONFIG_NET_TCP netprocfs_tcp_dropped_1, netprocfs_tcp_dropped_2, #endif /* CONFIG_NET_TCP */ netprocfs_prototype, netprocfs_sent #ifdef CONFIG_NET_TCP , netprocfs_retransmissions #endif /* CONFIG_NET_TCP */ }; #define NSTAT_LINES (sizeof(g_linegen) / sizeof(linegen_t)) #endif /* CONFIG_NET_STATISTICS */ /**************************************************************************** * Public Data ****************************************************************************/ /* See include/nutts/fs/procfs.h * We use the old-fashioned kind of initializers so that this will compile * with any compiler. */ const struct procfs_operations net_procfsoperations = { netprocfs_open, /* open */ netprocfs_close, /* close */ netprocfs_read, /* read */ NULL, /* write */ netprocfs_dup, /* dup */ netprocfs_opendir, /* opendir */ netprocfs_closedir, /* closedir */ netprocfs_readdir, /* readdir */ netprocfs_rewinddir, /* rewinddir */ netprocfs_stat /* stat */ }; /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * Name: netprocfs_header ****************************************************************************/ #ifdef CONFIG_NET_STATISTICS static int netprocfs_header(FAR struct netprocfs_file_s *netfile) { int len = 0; len += snprintf(&netfile->line[len], NET_LINELEN - len, " "); #ifdef CONFIG_NET_IPv4 len += snprintf(&netfile->line[len], NET_LINELEN - len, " IPv4"); #endif #ifdef CONFIG_NET_IPv6 len += snprintf(&netfile->line[len], NET_LINELEN - len, " IPv6"); #endif #ifdef CONFIG_NET_TCP len += snprintf(&netfile->line[len], NET_LINELEN - len, " TCP"); #endif #ifdef CONFIG_NET_UDP len += snprintf(&netfile->line[len], NET_LINELEN - len, " UDP"); #endif #ifdef CONFIG_NET_ICMP len += snprintf(&netfile->line[len], NET_LINELEN - len, " ICMP"); #endif #ifdef CONFIG_NET_ICMPv6 len += snprintf(&netfile->line[len], NET_LINELEN - len, " ICMPv6"); #endif len += snprintf(&netfile->line[len], NET_LINELEN - len, "\n"); return len; } #endif /* CONFIG_NET_STATISTICS */ /**************************************************************************** * Name: netprocfs_received ****************************************************************************/ #ifdef CONFIG_NET_STATISTICS static int netprocfs_received(FAR struct netprocfs_file_s *netfile) { int len = 0; len += snprintf(&netfile->line[len], NET_LINELEN - len, "Received "); #ifdef CONFIG_NET_IPv4 len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", g_netstats.ipv4.recv); #endif #ifdef CONFIG_NET_IPv6 len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", g_netstats.ipv6.recv); #endif #ifdef CONFIG_NET_TCP len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", g_netstats.tcp.recv); #endif #ifdef CONFIG_NET_UDP len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", g_netstats.udp.recv); #endif #ifdef CONFIG_NET_ICMP len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", g_netstats.icmp.recv); #endif #ifdef CONFIG_NET_ICMPv6 len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", g_netstats.icmpv6.recv); #endif len += snprintf(&netfile->line[len], NET_LINELEN - len, "\n"); return len; } #endif /* CONFIG_NET_STATISTICS */ /**************************************************************************** * Name: netprocfs_dropped ****************************************************************************/ #ifdef CONFIG_NET_STATISTICS static int netprocfs_dropped(FAR struct netprocfs_file_s *netfile) { int len = 0; len += snprintf(&netfile->line[len], NET_LINELEN - len, "Dropped "); #ifdef CONFIG_NET_IPv4 len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", g_netstats.ipv4.drop); #endif #ifdef CONFIG_NET_IPv6 len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", g_netstats.ipv6.drop); #endif #ifdef CONFIG_NET_TCP len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", g_netstats.tcp.drop); #endif #ifdef CONFIG_NET_UDP len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", g_netstats.udp.drop); #endif #ifdef CONFIG_NET_ICMP len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", g_netstats.icmp.drop); #endif #ifdef CONFIG_NET_ICMPv6 len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", g_netstats.icmpv6.drop); #endif len += snprintf(&netfile->line[len], NET_LINELEN - len, "\n"); return len; } #endif /* CONFIG_NET_STATISTICS */ /**************************************************************************** * Name: netprocfs_ipv4_dropped ****************************************************************************/ #if defined(CONFIG_NET_STATISTICS) && defined(CONFIG_NET_IPv4) static int netprocfs_ipv4_dropped(FAR struct netprocfs_file_s *netfile) { return snprintf(netfile->line, NET_LINELEN, " IPv4 VHL: %04x Frg: %04x\n", g_netstats.ipv4.vhlerr, g_netstats.ipv4.fragerr); } #endif /* CONFIG_NET_STATISTICS && CONFIG_NET_IPv4 */ /**************************************************************************** * Name: netprocfs_ipv6_dropped ****************************************************************************/ #if defined(CONFIG_NET_STATISTICS) && defined(CONFIG_NET_IPv6) static int netprocfs_ipv6_dropped(FAR struct netprocfs_file_s *netfile) { return snprintf(netfile->line, NET_LINELEN, " IPv6 VHL: %04x\n", g_netstats.ipv6.vhlerr); } #endif /* CONFIG_NET_STATISTICS && CONFIG_NET_IPv6 */ /**************************************************************************** * Name: netprocfs_checksum ****************************************************************************/ #ifdef CONFIG_NET_STATISTICS static int netprocfs_checksum(FAR struct netprocfs_file_s *netfile) { int len = 0; len += snprintf(&netfile->line[len], NET_LINELEN - len, " Checksum "); #ifdef CONFIG_NET_IPv4 len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", g_netstats.ipv4.chkerr); #endif #ifdef CONFIG_NET_IPv6 len += snprintf(&netfile->line[len], NET_LINELEN - len, " ----"); #endif #ifdef CONFIG_NET_TCP len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", g_netstats.tcp.chkerr); #endif #ifdef CONFIG_NET_UDP len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", g_netstats.udp.chkerr); #endif #ifdef CONFIG_NET_ICMP len += snprintf(&netfile->line[len], NET_LINELEN - len, " ----"); #endif #ifdef CONFIG_NET_ICMPv6 len += snprintf(&netfile->line[len], NET_LINELEN - len, " ----"); #endif len += snprintf(&netfile->line[len], NET_LINELEN - len, "\n"); return len; } #endif /* CONFIG_NET_STATISTICS */ /**************************************************************************** * Name: netprocfs_tcp_dropped_1 ****************************************************************************/ #if defined(CONFIG_NET_STATISTICS) && defined(CONFIG_NET_TCP) static int netprocfs_tcp_dropped_1(FAR struct netprocfs_file_s *netfile) { return snprintf(netfile->line, NET_LINELEN, " TCP ACK: %04x SYN: %04x\n", g_netstats.tcp.ackerr, g_netstats.tcp.syndrop); } #endif /* CONFIG_NET_STATISTICS && CONFIG_NET_TCP */ /**************************************************************************** * Name: netprocfs_tcp_dropped_2 ****************************************************************************/ #if defined(CONFIG_NET_STATISTICS) && defined(CONFIG_NET_TCP) static int netprocfs_tcp_dropped_2(FAR struct netprocfs_file_s *netfile) { return snprintf(netfile->line, NET_LINELEN, " RST: %04x %04x\n", g_netstats.tcp.rst, g_netstats.tcp.synrst); } #endif /* CONFIG_NET_STATISTICS && CONFIG_NET_TCP */ /**************************************************************************** * Name: netprocfs_prototype ****************************************************************************/ #ifdef CONFIG_NET_STATISTICS static int netprocfs_prototype(FAR struct netprocfs_file_s *netfile) { int len = 0; len += snprintf(&netfile->line[len], NET_LINELEN - len, " Type "); #ifdef CONFIG_NET_IPv4 len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", g_netstats.ipv4.protoerr); #endif #ifdef CONFIG_NET_IPv6 len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", g_netstats.ipv6.protoerr); #endif #ifdef CONFIG_NET_TCP len += snprintf(&netfile->line[len], NET_LINELEN - len, " ----"); #endif #ifdef CONFIG_NET_UDP len += snprintf(&netfile->line[len], NET_LINELEN - len, " ----"); #endif #ifdef CONFIG_NET_ICMP len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", g_netstats.icmp.typeerr); #endif #ifdef CONFIG_NET_ICMPv6 len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", g_netstats.icmpv6.typeerr); #endif len += snprintf(&netfile->line[len], NET_LINELEN - len, "\n"); return len; } #endif /* CONFIG_NET_STATISTICS */ /**************************************************************************** * Name: netprocfs_sent ****************************************************************************/ #ifdef CONFIG_NET_STATISTICS static int netprocfs_sent(FAR struct netprocfs_file_s *netfile) { int len = 0; len += snprintf(&netfile->line[len], NET_LINELEN - len, "Sent "); #ifdef CONFIG_NET_IPv4 len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", g_netstats.ipv4.sent); #endif #ifdef CONFIG_NET_IPv6 len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", g_netstats.ipv6.sent); #endif #ifdef CONFIG_NET_TCP len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", g_netstats.tcp.sent); #endif #ifdef CONFIG_NET_UDP len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", g_netstats.udp.sent); #endif #ifdef CONFIG_NET_ICMP len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", g_netstats.icmp.sent); #endif #ifdef CONFIG_NET_ICMPv6 len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", g_netstats.icmpv6.sent); #endif len += snprintf(&netfile->line[len], NET_LINELEN - len, "\n"); return len; } #endif /* CONFIG_NET_STATISTICS */ /**************************************************************************** * Name: netprocfs_retransmissions ****************************************************************************/ #if defined(CONFIG_NET_STATISTICS) && defined(CONFIG_NET_TCP) static int netprocfs_retransmissions(FAR struct netprocfs_file_s *netfile) { int len = 0; len += snprintf(&netfile->line[len], NET_LINELEN - len, " Rexmit "); #ifdef CONFIG_NET_IPv4 len += snprintf(&netfile->line[len], NET_LINELEN - len, " ----"); #endif #ifdef CONFIG_NET_IPv6 len += snprintf(&netfile->line[len], NET_LINELEN - len, " ----"); #endif len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", g_netstats.tcp.rexmit); #ifdef CONFIG_NET_UDP len += snprintf(&netfile->line[len], NET_LINELEN - len, " ----"); #endif #ifdef CONFIG_NET_ICMP len += snprintf(&netfile->line[len], NET_LINELEN - len, " ----"); #endif #ifdef CONFIG_NET_ICMPv6 len += snprintf(&netfile->line[len], NET_LINELEN - len, " ----"); #endif len += snprintf(&netfile->line[len], NET_LINELEN - len, "\n"); return len; } #endif /* CONFIG_NET_STATISTICS && CONFIG_NET_TCP */ /**************************************************************************** * Name: netprocfs_open ****************************************************************************/ static int netprocfs_open(FAR struct file *filep, FAR const char *relpath, int oflags, mode_t mode) { FAR struct netprocfs_file_s *priv; fvdbg("Open '%s'\n", relpath); /* PROCFS is read-only. Any attempt to open with any kind of write * access is not permitted. * * REVISIT: Write-able proc files could be quite useful. */ if (((oflags & O_WRONLY) != 0 || (oflags & O_RDONLY) == 0) && (net_procfsoperations.write == NULL)) { fdbg("ERROR: Only O_RDONLY supported\n"); return -EACCES; } /* "net/stat" is the only acceptable value for the relpath */ if (strcmp(relpath, "net/stat") != 0) { fdbg("ERROR: relpath is '%s'\n", relpath); return -ENOENT; } /* Allocate a container to hold the task and attribute selection */ priv = (FAR struct netprocfs_file_s *)kmm_zalloc(sizeof(struct netprocfs_file_s)); if (!priv) { fdbg("ERROR: Failed to allocate file attributes\n"); return -ENOMEM; } /* Save the index as the open-specific state in filep->f_priv */ filep->f_priv = (FAR void *)priv; return OK; } /**************************************************************************** * Name: netprocfs_close ****************************************************************************/ static int netprocfs_close(FAR struct file *filep) { FAR struct netprocfs_file_s *priv; /* Recover our private data from the struct file instance */ priv = (FAR struct netprocfs_file_s *)filep->f_priv; DEBUGASSERT(priv); /* Release the file attributes structure */ kmm_free(priv); filep->f_priv = NULL; return OK; } /**************************************************************************** * Name: netprocfs_read ****************************************************************************/ static ssize_t netprocfs_read(FAR struct file *filep, FAR char *buffer, size_t buflen) { #ifdef CONFIG_NET_STATISTICS FAR struct netprocfs_file_s *priv; size_t xfrsize; ssize_t nreturned; fvdbg("buffer=%p buflen=%d\n", buffer, (int)buflen); /* Recover our private data from the struct file instance */ priv = (FAR struct netprocfs_file_s *)filep->f_priv; DEBUGASSERT(priv); /* Is there line data already buffered? */ nreturned = 0; if (priv->linesize > 0) { /* Yes, how much can we transfer now? */ xfrsize = priv->linesize; if (xfrsize > buflen) { xfrsize = buflen; } /* Transfer the data to the user buffer */ memcpy(buffer, &priv->line[priv->offset], xfrsize); /* Update pointers, sizes, and offsets */ buffer += xfrsize; buflen -= xfrsize; priv->linesize -= xfrsize; priv->offset += xfrsize; nreturned = xfrsize; } /* Loop until the user buffer is full or until all of the network * statistics have been transferred. At this point we know that * either: * * 1. The user buffer is full, and/or * 2. All of the current line data has been transferred. */ while (buflen > 0 && priv->lineno < NSTAT_LINES) { int len; /* Read the next line into the working buffer */ len = g_linegen[priv->lineno](priv); /* Update line-related information */ priv->lineno++; priv->linesize = len; priv->offset = 0; /* Transfer data to the user buffer */ xfrsize = priv->linesize; if (xfrsize > buflen) { xfrsize = buflen; } memcpy(buffer, &priv->line[priv->offset], xfrsize); /* Update pointers, sizes, and offsets */ buffer += xfrsize; buflen -= xfrsize; priv->linesize -= xfrsize; priv->offset += xfrsize; nreturned += xfrsize; } /* Update the file offset */ if (nreturned > 0) { filep->f_pos += nreturned; } return nreturned; #else return 0; #endif } /**************************************************************************** * Name: netprocfs_dup * * Description: * Duplicate open file data in the new file structure. * ****************************************************************************/ static int netprocfs_dup(FAR const struct file *oldp, FAR struct file *newp) { FAR struct netprocfs_file_s *oldpriv; FAR struct netprocfs_file_s *newpriv; fvdbg("Dup %p->%p\n", oldp, newp); /* Recover our private data from the old struct file instance */ oldpriv = (FAR struct netprocfs_file_s *)oldp->f_priv; DEBUGASSERT(oldpriv); /* Allocate a new container to hold the task and attribute selection */ newpriv = (FAR struct netprocfs_file_s *)kmm_zalloc(sizeof(struct netprocfs_file_s)); if (!newpriv) { fdbg("ERROR: Failed to allocate file attributes\n"); return -ENOMEM; } /* The copy the file attribtes from the old attributes to the new */ memcpy(newpriv, oldpriv, sizeof(struct netprocfs_file_s)); /* Save the new attributes in the new file structure */ newp->f_priv = (FAR void *)newpriv; return OK; } /**************************************************************************** * Name: netprocfs_opendir * * Description: * Open a directory for read access * ****************************************************************************/ static int netprocfs_opendir(FAR const char *relpath, FAR struct fs_dirent_s *dir) { FAR struct netprocfs_level1_s *level1; fvdbg("relpath: \"%s\"\n", relpath ? relpath : "NULL"); DEBUGASSERT(relpath && dir && !dir->u.procfs); /* The path refers to the 1st level sbdirectory. Allocate the level1 * dirent structure. */ level1 = (FAR struct netprocfs_level1_s *) kmm_zalloc(sizeof(struct netprocfs_level1_s)); if (!level1) { fdbg("ERROR: Failed to allocate the level1 directory structure\n"); return -ENOMEM; } /* Initialze base structure components */ level1->base.level = 1; level1->base.nentries = 1; level1->base.index = 0; dir->u.procfs = (FAR void *) level1; return OK; } /**************************************************************************** * Name: netprocfs_closedir * * Description: Close the directory listing * ****************************************************************************/ static int netprocfs_closedir(FAR struct fs_dirent_s *dir) { FAR struct netprocfs_level1_s *priv; DEBUGASSERT(dir && dir->u.procfs); priv = dir->u.procfs; if (priv) { kmm_free(priv); } dir->u.procfs = NULL; return OK; } /**************************************************************************** * Name: netprocfs_readdir * * Description: Read the next directory entry * ****************************************************************************/ static int netprocfs_readdir(FAR struct fs_dirent_s *dir) { FAR struct netprocfs_level1_s *level1; int index; int ret; DEBUGASSERT(dir && dir->u.procfs); level1 = dir->u.procfs; /* Have we reached the end of the directory */ index = level1->base.index; if (index >= level1->base.nentries) { /* We signal the end of the directory by returning the special * error -ENOENT */ fvdbg("Entry %d: End of directory\n", index); ret = -ENOENT; } /* Currently only one element in the directory */ else { DEBUGASSERT(level1->base.level == 1); DEBUGASSERT(level1->base.index <= 1); /* Copy the one supported directory entry */ dir->fd_dir.d_type = DTYPE_FILE; strncpy(dir->fd_dir.d_name, "stat", NAME_MAX + 1); /* Set up the next directory entry offset. NOTE that we could use the * standard f_pos instead of our own private index. */ level1->base.index = index + 1; ret = OK; } return ret; } /**************************************************************************** * Name: netprocfs_rewindir * * Description: Reset directory read to the first entry * ****************************************************************************/ static int netprocfs_rewinddir(FAR struct fs_dirent_s *dir) { FAR struct netprocfs_level1_s *priv; DEBUGASSERT(dir && dir->u.procfs); priv = dir->u.procfs; priv->base.index = 0; return OK; } /**************************************************************************** * Name: netprocfs_stat * * Description: Return information about a file or directory * ****************************************************************************/ static int netprocfs_stat(FAR const char *relpath, FAR struct stat *buf) { /* "net" and "net/stat" are the only acceptable values for the relpath */ if (strcmp(relpath, "net") == 0) { buf->st_mode = S_IFDIR | S_IROTH | S_IRGRP | S_IRUSR; } else if (strcmp(relpath, "net/stat") == 0) { buf->st_mode = S_IFREG | S_IROTH | S_IRGRP | S_IRUSR; } else { fdbg("ERROR: relpath is '%s'\n", relpath); return -ENOENT; } /* File/directory size, access block size */ buf->st_size = 0; buf->st_blksize = 512; buf->st_blocks = 0; return OK; } /**************************************************************************** * Public Functions ****************************************************************************/ #endif /* !CONFIG_DISABLE_MOUNTPOINT && CONFIG_FS_PROCFS */