diff --git a/TODO b/TODO index 23d360bcf7..1b8f3dbd8f 100644 --- a/TODO +++ b/TODO @@ -2097,6 +2097,11 @@ o Build system $ make apps_distclean + One solution to this might be to making the special target + .PRECIOUS depend on apps/libapps.a. Then if make receives a + signal, it will not delete apps/libapps.a. This would have to + be done in all Makefiles. + Status Open Priority: Medium-High. It is a rare event that control-C happens at just the point in time. However, when it does occur the resulting code may diff --git a/fs/procfs/Kconfig b/fs/procfs/Kconfig index b218c405b9..de8cb8c44a 100644 --- a/fs/procfs/Kconfig +++ b/fs/procfs/Kconfig @@ -63,6 +63,11 @@ config FS_PROCFS_EXCLUDE_NET depends on NET default n +config FS_PROC_EXCLUDE_ROUTE + bool "Exclude routing table" + depends on !FS_PROCFS_EXCLUDE_NET && NET_ROUTE + default n + config FS_PROCFS_EXCLUDE_MTD bool "Exclude mtd" depends on MTD diff --git a/fs/procfs/fs_procfs.c b/fs/procfs/fs_procfs.c index 0be299c395..95cc8f0e93 100644 --- a/fs/procfs/fs_procfs.c +++ b/fs/procfs/fs_procfs.c @@ -87,6 +87,7 @@ extern const struct procfs_operations uptime_operations; */ extern const struct procfs_operations net_procfsoperations; +extern const struct procfs_operations net_procfs_routeoperations; extern const struct procfs_operations mtd_procfsoperations; extern const struct procfs_operations part_procfsoperations; extern const struct procfs_operations smartfs_procfsoperations; @@ -112,42 +113,46 @@ static const struct procfs_entry_s g_procfs_entries[] = #endif { #ifndef CONFIG_FS_PROCFS_EXCLUDE_PROCESS - { "[0-9]*/**", &proc_operations }, - { "[0-9]*", &proc_operations }, + { "[0-9]*/**", &proc_operations, PROCFS_UNKOWN_TYPE }, + { "[0-9]*", &proc_operations, PROCFS_DIR_TYPE }, #endif #if defined(CONFIG_SCHED_CPULOAD) && !defined(CONFIG_FS_PROCFS_EXCLUDE_CPULOAD) - { "cpuload", &cpuload_operations }, + { "cpuload", &cpuload_operations, PROCFS_FILE_TYPE }, #endif #if defined(CONFIG_MM_KERNEL_HEAP) && !defined(CONFIG_FS_PROCFS_EXCLUDE_KMM) - { "kmm", &kmm_operations }, + { "kmm", &kmm_operations, PROCFS_FILE_TYPE }, #endif #if defined(CONFIG_MODULE) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE) - { "modules", &module_operations }, + { "modules", &module_operations, PROCFS_DIR_TYPE }, #endif #if defined(CONFIG_FS_SMARTFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_SMARTFS) -//{ "fs/smartfs", &smartfs_procfsoperations }, - { "fs/smartfs**", &smartfs_procfsoperations }, +//{ "fs/smartfs", &smartfs_procfsoperations, PROCFS_DIR_TYPE }, + { "fs/smartfs**", &smartfs_procfsoperations, PROCFS_UNKOWN_TYPE }, #endif #if defined(CONFIG_NET) && !defined(CONFIG_FS_PROCFS_EXCLUDE_NET) - { "net", &net_procfsoperations }, - { "net/**", &net_procfsoperations }, + { "net", &net_procfsoperations, PROCFS_DIR_TYPE }, +#if defined(CONFIG_NET_ROUTE) && !defined(CONFIG_FS_PROCFS_EXCLUDE_ROUTE) + { "net/route", &net_procfs_routeoperations, PROCFS_DIR_TYPE }, + { "net/route/**", &net_procfs_routeoperations, PROCFS_UNKOWN_TYPE }, +#endif + { "net/**", &net_procfsoperations, PROCFS_UNKOWN_TYPE }, #endif #if defined(CONFIG_MTD) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MTD) - { "mtd", &mtd_procfsoperations }, + { "mtd", &mtd_procfsoperations, PROCFS_FILE_TYPE }, #endif #if defined(CONFIG_MTD_PARTITION) && !defined(CONFIG_FS_PROCFS_EXCLUDE_PARTITIONS) - { "partitions", &part_procfsoperations }, + { "partitions", &part_procfsoperations, PROCFS_DIR_TYPE }, #endif #if !defined(CONFIG_FS_PROCFS_EXCLUDE_UPTIME) - { "uptime", &uptime_operations }, + { "uptime", &uptime_operations, PROCFS_FILE_TYPE }, #endif }; @@ -348,6 +353,7 @@ static int procfs_open(FAR struct file *filep, FAR const char *relpath, ((struct procfs_file_s *) filep->f_priv)->procfsentry = &g_procfs_entries[x]; + break; } } } @@ -673,6 +679,7 @@ static int procfs_closedir(FAR struct inode *mountpt, static int procfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir) { + FAR const struct procfs_entry_s *entry = NULL; FAR struct procfs_dir_priv_s *priv; FAR struct procfs_level0_s *level0; FAR struct tcb_s *tcb; @@ -705,7 +712,9 @@ static int procfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir) while (index < priv->nentries + g_procfs_entrycount) { - name = g_procfs_entries[index - priv->nentries].pathpattern; + entry = &g_procfs_entries[index - priv->nentries]; + name = entry->pathpattern; + while (*name != '/' && *name != '\0') { if (*name == '*' || *name == '[' || *name == '?') @@ -772,7 +781,7 @@ static int procfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir) strncpy(dir->fd_dir.d_name, name, level0->lastlen); dir->fd_dir.d_name[level0->lastlen] = '\0'; - if (name[level0->lastlen] == '/') + if (entry->type == PROCFS_DIR_TYPE) { dir->fd_dir.d_type = DTYPE_DIRECTORY; } diff --git a/include/nuttx/fs/procfs.h b/include/nuttx/fs/procfs.h index f11046735e..550f087e5b 100644 --- a/include/nuttx/fs/procfs.h +++ b/include/nuttx/fs/procfs.h @@ -93,6 +93,15 @@ struct procfs_operations /* Procfs handler prototypes ************************************************/ +/* These are the types of entries that may appear in the procfs: */ + +enum procfs_entry_e +{ + PROCFS_UNKOWN_TYPE = 0, /* Unknown type */ + PROCFS_FILE_TYPE, /* File type */ + PROCFS_DIR_TYPE, /* Directory type */ +}; + /* This is a procfs entry that each handler should provide to supply * specific operations for file and directory handling. */ @@ -101,6 +110,7 @@ struct procfs_entry_s { FAR const char *pathpattern; FAR const struct procfs_operations *ops; + uint8_t type; }; /* Specifies the common elements for an open file in the procfs diff --git a/net/procfs/Make.defs b/net/procfs/Make.defs index 90cef533d2..543a90cc1e 100644 --- a/net/procfs/Make.defs +++ b/net/procfs/Make.defs @@ -47,6 +47,12 @@ ifeq ($(CONFIG_NET_STATISTICS),y) NET_CSRCS += net_statistics.c endif +# Routing table + +ifeq ($(CONFIG_NET_ROUTE),y) + NET_CSRCS += net_procfs_route.c +endif + # Include packet socket build support DEPPATH += --dep-path procfs diff --git a/net/procfs/net_procfs.c b/net/procfs/net_procfs.c index 80e30a9a0d..c31438ae84 100644 --- a/net/procfs/net_procfs.c +++ b/net/procfs/net_procfs.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include "netdev/netdev.h" @@ -64,6 +65,26 @@ #if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_FS_PROCFS) && \ !defined(CONFIG_FS_PROCFS_EXCLUDE_NET) +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Directory entry indices */ + +#if defined(CONFIG_NET_STATISTICS) && defined(CONFIG_NET_ROUTE) +# define STAT_INDEX 0 +# define ROUTE_INDEX 1 +# define DEV_INDEX 2 +#elif defined(CONFIG_NET_STATISTICS) +# define STAT_INDEX 0 +# define DEV_INDEX 1 +#elif defined(CONFIG_NET_ROUTE) +# define ROUTE_INDEX 0 +# define DEV_INDEX 1 +#else +# define DEV_INDEX 0 +#endif + /**************************************************************************** * Private Function Prototypes ****************************************************************************/ @@ -112,6 +133,8 @@ const struct procfs_operations net_procfsoperations = netprocfs_stat /* stat */ }; +extern const struct procfs_operations net_procfs_routeoperations; + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -125,6 +148,7 @@ static int netprocfs_open(FAR struct file *filep, FAR const char *relpath, { FAR struct netprocfs_file_s *priv; FAR struct net_driver_s *dev; + enum netprocfs_entry_e entry; finfo("Open '%s'\n", relpath); @@ -141,18 +165,29 @@ static int netprocfs_open(FAR struct file *filep, FAR const char *relpath, return -EACCES; } +#ifdef CONFIG_NET_STATISTICS /* "net/stat" is an acceptable value for the relpath only if network layer * statistics are enabled. */ -#ifdef CONFIG_NET_STATISTICS if (strcmp(relpath, "net/stat") == 0) { - /* A NULL network device reference is a clue that we are processing - * the network statistics file. - */ + entry = NETPROCFS_SUBDIR_STAT; + dev = NULL; + } + else +#endif - dev = NULL; +#ifdef CONFIG_NET_ROUTE + /* "net/route" is an acceptable value for the relpath only if routing + * table support is initialized. + */ + + if (match("net/route/**", relpath)) + { + /* Use the /net/route directory */ + + return net_procfs_routeoperations.open(filep, relpath, oflags, mode); } else #endif @@ -180,11 +215,14 @@ static int netprocfs_open(FAR struct file *filep, FAR const char *relpath, ferr("ERROR: relpath is '%s'\n", relpath); return -ENOENT; } + + entry = NETPROCFS_SUBDIR_DEV; } /* Allocate the open file structure */ - priv = (FAR struct netprocfs_file_s *)kmm_zalloc(sizeof(struct netprocfs_file_s)); + priv = (FAR struct netprocfs_file_s *) + kmm_zalloc(sizeof(struct netprocfs_file_s)); if (!priv) { ferr("ERROR: Failed to allocate file attributes\n"); @@ -193,7 +231,8 @@ static int netprocfs_open(FAR struct file *filep, FAR const char *relpath, /* Initialize the open-file structure */ - priv->dev = dev; + priv->dev = dev; + priv->entry = entry; /* Save the open file structure as the open-specific state in * filep->f_priv. @@ -240,24 +279,33 @@ static ssize_t netprocfs_read(FAR struct file *filep, FAR char *buffer, priv = (FAR struct netprocfs_file_s *)filep->f_priv; DEBUGASSERT(priv); -#ifdef CONFIG_NET_STATISTICS - /* A NULL device structure reference is the key that we are showing the - * network statistics. - */ + /* Read according to the sub-directory */ - if (priv->dev == NULL) + switch (priv->entry) { - /* Show the network layer statistics */ + case NETPROCFS_SUBDIR_DEV: + /* Show device-specific statistics */ - nreturned = netprocfs_read_netstats(priv, buffer, buflen); - } - else + nreturned = netprocfs_read_devstats(priv, buffer, buflen); + break; + +#ifdef CONFIG_NET_STATISTICS + case NETPROCFS_SUBDIR_STAT: + /* Show the network layer statistics */ + + nreturned = netprocfs_read_netstats(priv, buffer, buflen); + break; #endif - { - /* Otherwise, we are showing device-specific statistics */ - nreturned = netprocfs_read_devstats(priv, buffer, buflen); - } +#ifdef CONFIG_NET_ROUTE + case NETPROCFS_SUBDIR_ROUTE: + nerr("ERROR: Cannot read from directory net/route\n"); +#endif + + default: + nerr("ERROR: Invalid entry for reading: %u\n", priv->entry); + nreturned = -EINVAL; + } /* Update the file offset */ @@ -321,13 +369,56 @@ static int netprocfs_opendir(FAR const char *relpath, { FAR struct netprocfs_level1_s *level1; int ndevs; + int ret; finfo("relpath: \"%s\"\n", relpath ? relpath : "NULL"); DEBUGASSERT(relpath && dir && !dir->u.procfs); - /* "net" is the only value of relpath that is a directory */ + /* "net" and "net/route" are the only values of relpath that are + * directories. + */ - if (strcmp(relpath, "net") != 0) +#ifdef CONFIG_NET_ROUTE + if (match("net/route", relpath) || match("net/route/**", relpath)) + { + /* Use the /net/route directory */ + + return net_procfs_routeoperations.opendir(relpath, dir); + } +#endif + + /* Assume that path refers to the 1st level subdirectory. Allocate the + * level1 the dirent structure before checking. + */ + + level1 = (FAR struct netprocfs_level1_s *) + kmm_zalloc(sizeof(struct netprocfs_level1_s)); + + if (level1 == NULL) + { + ferr("ERROR: Failed to allocate the level1 directory structure\n"); + return -ENOMEM; + } + + level1->base.level = 1; + + if (strcmp(relpath, "net") == 0) + { + /* Count the number of network devices */ + + ndevs = netdev_count(); + + /* Initialze base structure components */ + + level1->base.nentries = ndevs; +#ifdef CONFIG_NET_STATISTICS + level1->base.nentries++; +#endif +#ifdef CONFIG_NET_ROUTE + level1->base.nentries++; +#endif + } + else { /* REVISIT: We really need to check if the relpath refers to a network * device. In that case, we need to return -ENOTDIR. Otherwise, we @@ -335,38 +426,16 @@ static int netprocfs_opendir(FAR const char *relpath, */ ferr("ERROR: Bad relpath: %s\n", relpath); - return -ENOTDIR; + ret = -ENOTDIR; + goto errout_with_alloc; } - /* 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) - { - ferr("ERROR: Failed to allocate the level1 directory structure\n"); - return -ENOMEM; - } - - /* Count the number of network devices */ - - ndevs = netdev_count(); - - /* Initialze base structure components */ - - level1->base.level = 1; -#ifdef CONFIG_NET_STATISTICS - level1->base.nentries = ndevs + 1; -#else - level1->base.nentries = ndevs; -#endif - level1->base.index = 0; - - dir->u.procfs = (FAR void *) level1; + dir->u.procfs = (FAR void *)level1; return OK; + +errout_with_alloc: + kmm_free(level1); + return ret; } /**************************************************************************** @@ -404,63 +473,86 @@ static int netprocfs_readdir(FAR struct fs_dirent_s *dir) FAR struct netprocfs_level1_s *level1; FAR struct net_driver_s *dev; int index; + int ret; DEBUGASSERT(dir && dir->u.procfs); level1 = dir->u.procfs; - DEBUGASSERT(level1->base.level == 1); + DEBUGASSERT(level1->base.level > 0); - /* Have we reached the end of the directory */ - - index = level1->base.index; - DEBUGASSERT(index <= level1->base.nentries); - - if (index >= level1->base.nentries) - { - /* We signal the end of the directory by returning the special - * error -ENOENT. - */ - - finfo("Entry %d: End of directory\n", index); - return -ENOENT; - } - -#ifdef CONFIG_NET_STATISTICS - else if (index == 0) - { - /* Copy the network statistics directory entry */ - - dir->fd_dir.d_type = DTYPE_FILE; - strncpy(dir->fd_dir.d_name, "stat", NAME_MAX + 1); - } - else -#endif - { - int devndx = index; - -#ifdef CONFIG_NET_STATISTICS - /* Subtract one to account for index == 0 which is used for network - * status. - */ - - devndx--; -#endif - - /* Find the device corresponding to this device index */ - - dev = netdev_findbyindex(devndx); - - /* Copy the device statistics file entry */ - - dir->fd_dir.d_type = DTYPE_FILE; - strncpy(dir->fd_dir.d_name, dev->d_ifname, 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. + /* Are we searching this directory? Or is it just an intermediate on the + * way to a sub-directory? */ - level1->base.index = index + 1; - return OK; + if (level1->base.level == 1) + { + /* This directory.. Have we reached the end of the directory? */ + + index = level1->base.index; + DEBUGASSERT(index <= level1->base.nentries); + + if (index >= level1->base.nentries) + { + /* We signal the end of the directory by returning the special + * error -ENOENT. + */ + + finfo("Entry %d: End of directory\n", index); + return -ENOENT; + } + +#ifdef CONFIG_NET_STATISTICS + else if (index == STAT_INDEX) + { + /* Copy the network statistics directory entry */ + + dir->fd_dir.d_type = DTYPE_FILE; + strncpy(dir->fd_dir.d_name, "stat", NAME_MAX + 1); + } + else +#endif +#ifdef CONFIG_NET_ROUTE + if (index == ROUTE_INDEX) + { + /* Copy the network statistics directory entry */ + + dir->fd_dir.d_type = DTYPE_DIRECTORY; + strncpy(dir->fd_dir.d_name, "route", NAME_MAX + 1); + } + else +#endif + { + int devndx = index - DEV_INDEX; + + /* Find the device corresponding to this device index */ + + dev = netdev_findbyindex(devndx); + + /* Copy the device statistics file entry */ + + dir->fd_dir.d_type = DTYPE_FILE; + strncpy(dir->fd_dir.d_name, dev->d_ifname, 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; + } + else + { + /* We are performing a directory search of one of the subdirectories + * and we must let the handler perform the read. + */ + + DEBUGASSERT(level1->base.procfsentry != NULL && + level1->base.procfsentry->ops->readdir != NULL); + + ret = level1->base.procfsentry->ops->readdir(dir); + } + + return ret; } /**************************************************************************** @@ -505,6 +597,15 @@ static int netprocfs_stat(FAR const char *relpath, FAR struct stat *buf) buf->st_mode = S_IFREG | S_IROTH | S_IRGRP | S_IRUSR; } else +#endif +#ifdef CONFIG_NET_ROUTE + /* Check for network statistics "net/stat" */ + + if (strcmp(relpath, "net/route") == 0) + { + buf->st_mode = S_IFDIR | S_IROTH | S_IRGRP | S_IRUSR; + } + else #endif { FAR struct net_driver_s *dev; diff --git a/net/procfs/net_statistics.c b/net/procfs/net_statistics.c index df35f4a165..0ceac8ecfb 100644 --- a/net/procfs/net_statistics.c +++ b/net/procfs/net_statistics.c @@ -82,7 +82,7 @@ static int netprocfs_retransmissions(FAR struct netprocfs_file_s *netfile); /* Line generating functions */ -static const linegen_t g_linegen[] = +static const linegen_t g_stat_linegen[] = { netprocfs_header, netprocfs_received, @@ -111,7 +111,7 @@ static const linegen_t g_linegen[] = #endif /* CONFIG_NET_TCP */ }; -#define NSTAT_LINES (sizeof(g_linegen) / sizeof(linegen_t)) +#define NSTAT_LINES (sizeof(g_stat_linegen) / sizeof(linegen_t)) /**************************************************************************** * Private Functions @@ -456,7 +456,7 @@ static int netprocfs_retransmissions(FAR struct netprocfs_file_s *netfile) ssize_t netprocfs_read_netstats(FAR struct netprocfs_file_s *priv, FAR char *buffer, size_t buflen) { - return netprocfs_read_linegen(priv, buffer, buflen, g_linegen, NSTAT_LINES); + return netprocfs_read_linegen(priv, buffer, buflen, g_stat_linegen, NSTAT_LINES); } #endif /* !CONFIG_DISABLE_MOUNTPOINT && CONFIG_FS_PROCFS && diff --git a/net/procfs/netdev_statistics.c b/net/procfs/netdev_statistics.c index d657f4fff6..74323d1dc1 100644 --- a/net/procfs/netdev_statistics.c +++ b/net/procfs/netdev_statistics.c @@ -84,7 +84,7 @@ static int netprocfs_errors(FAR struct netprocfs_file_s *netfile); /* Line generating functions */ -static const linegen_t g_linegen[] = +static const linegen_t g_netstat_linegen[] = { netprocfs_linklayer #ifdef CONFIG_NET_IPv4 @@ -105,7 +105,7 @@ static const linegen_t g_linegen[] = #endif /* CONFIG_NETDEV_STATISTICS */ }; -#define NSTAT_LINES (sizeof(g_linegen) / sizeof(linegen_t)) +#define NSTAT_LINES (sizeof(g_netstat_linegen) / sizeof(linegen_t)) /**************************************************************************** * Private Functions @@ -554,7 +554,8 @@ static int netprocfs_errors(FAR struct netprocfs_file_s *netfile) ssize_t netprocfs_read_devstats(FAR struct netprocfs_file_s *priv, FAR char *buffer, size_t buflen) { - return netprocfs_read_linegen(priv, buffer, buflen, g_linegen, NSTAT_LINES); + return netprocfs_read_linegen(priv, buffer, buflen, g_netstat_linegen, + NSTAT_LINES); } #endif /* !CONFIG_DISABLE_MOUNTPOINT && CONFIG_FS_PROCFS && diff --git a/net/procfs/procfs.h b/net/procfs/procfs.h index 9b0d7bfd49..3b80fbbe5a 100644 --- a/net/procfs/procfs.h +++ b/net/procfs/procfs.h @@ -50,6 +50,10 @@ * Pre-processor Definitions ****************************************************************************/ +#ifdef CONFIG_FS_PROCFS_EXCLUDE_ROUTE +# undef CONFIG_NET_ROUTE +#endif + /* Determines the size of an intermediate buffer that must be large enough * to handle the longest line generated by this logic. */ @@ -60,6 +64,19 @@ * Public Type Definitions ****************************************************************************/ +/* Describes the /net directory entries */ + +enum netprocfs_entry_e +{ + NETPROCFS_SUBDIR_DEV = 0 /* Multiple instances, e.g. /proc/net/eth0 */ +#ifdef CONFIG_NET_STATISTICS + , NETPROCFS_SUBDIR_STAT /* /proc/net/stat */ +#endif +#ifdef CONFIG_NET_ROUTE + , NETPROCFS_SUBDIR_ROUTE /* /proc/net/route */ +#endif +}; + /* This structure describes one open "file" */ struct net_driver_s; /* Forward reference */ @@ -70,6 +87,7 @@ struct netprocfs_file_s uint8_t lineno; /* Line number */ uint8_t linesize; /* Number of valid characters in line[] */ uint8_t offset; /* Offset to first valid character in line[] */ + uint8_t entry; /* See enum netprocfs_entry_e */ char line[NET_LINELEN]; /* Pre-allocated buffer for formatted lines */ }; @@ -148,6 +166,29 @@ ssize_t netprocfs_read_netstats(FAR struct netprocfs_file_s *priv, FAR char *buffer, size_t buflen); #endif +/**************************************************************************** + * Name: netprocfs_read_routes + * + * Description: + * Read and format routing table entries. + * + * Input Parameters: + * priv - A reference to the network procfs file structure + * buffer - The user-provided buffer into which network status will be + * returned. + * bulen - The size in bytes of the user provided buffer. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on failure. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_ROUTE +ssize_t netprocfs_read_routes(FAR struct netprocfs_file_s *priv, + FAR char *buffer, size_t buflen); +#endif + /**************************************************************************** * Name: netprocfs_read_devstats *