Beispiel #1
0
static int ls_recursive(const char *dirpath, struct dirent *entryp, void *pvarg)
{
	int ret = OK;

	/*
	 * Is this entry a directory (and not one of the special
	 * directories, . and ..)?
	 */

	if (DIRENT_ISDIRECTORY(entryp->d_type) && !ls_specialdir(entryp->d_name)) {
		/* Yes.. */

		char *newpath;
		newpath = get_dirpath(dirpath, entryp->d_name);

		/* List the directory contents */

		FSCMD_OUTPUT("%s:\n", newpath);

		/* Traverse the directory */

		ret = foreach_direntry("ls", newpath, ls_handler, pvarg);
		if (ret == 0) {
			/*
			 * Then recurse to list each directory
			 * within the directory
			 */

			ret = foreach_direntry("ls", newpath, ls_recursive, pvarg);
		}
		fscmd_free(newpath);
	}

	return ret;
}
Beispiel #2
0
static int ls_recursive(FAR struct nsh_vtbl_s *vtbl, const char *dirpath,
                        struct dirent *entryp, void *pvarg)
{
  int ret = OK;

  /* Is this entry a directory (and not one of the special directories, . and ..)? */

  if (DIRENT_ISDIRECTORY(entryp->d_type) && !ls_specialdir(entryp->d_name))
    {
      /* Yes.. */

      char *newpath;
      newpath = nsh_getdirpath(dirpath, entryp->d_name);

      /* List the directory contents */

      nsh_output(vtbl, "%s:\n", newpath);

      /* Traverse the directory  */

      ret = foreach_direntry(vtbl, "ls", newpath, ls_handler, pvarg);
      if (ret == 0)
        {
          /* Then recurse to list each directory within the directory */

          ret = foreach_direntry(vtbl, "ls", newpath, ls_recursive, pvarg);
          free(newpath);
        }
    }
  return ret;
}
Beispiel #3
0
static int read_pid_entry(FAR const char *dirpath, FAR struct dirent *entryp, FAR void *pvarg)
{
	/* This function is for showing all file entries of /proc/[pid] */
	int ret;
	int i;
	char filepath[PROC_FILEPATH_LEN];

	if (!DIRENT_ISDIRECTORY(entryp->d_type)) {
		/* Not a directory... skip this entry */
		return OK;
	}

	for (i = 0; i < NAME_MAX && entryp->d_name[i] != '\0'; i++) {
		if (!isdigit(entryp->d_name[i])) {
			/* Name contains something other than a numeric character */
			return OK;
		}
	}

	printf("[TASK %s] \n", entryp->d_name);

	for (i = 0; i < sizeof(g_proc_pid_entries) / sizeof(g_proc_pid_entries[0]); i++) {
		/* Read values from entries of /proc/[pid] */
		snprintf(filepath, PROC_FILEPATH_LEN, "%s/%s/%s", PROC_MOUNTPOINT, entryp->d_name, g_proc_pid_entries[i]);
		ret = readfile(filepath);
		if (ret < 0) {
			printf("Failed to read %s\n", filepath);
			return ERROR;
		}
	}
	printf("----------------------------------\n");

	return OK;
}
Beispiel #4
0
/* Read all files in the directory */
static int read_dir_entries(const char *dirpath)
{
	int fd;
	int ret;
	DIR *dirp;
	ssize_t nread;
	struct dirent *entryp;
	char path[PROC_FILEPATH_LEN];
	char buf[PROC_BUFFER_LEN];

	dirp = opendir(dirpath);
	if (!dirp) {
		printf("Failed to open directory %s\n", dirpath);
		return ERROR;
	}

	while ((entryp = readdir(dirp)) != NULL) {
		snprintf(path, PROC_FILEPATH_LEN, "%s/%s", dirpath, entryp->d_name);
		if (!DIRENT_ISDIRECTORY(entryp->d_type)) {
			/* If this entry is a file, open and read it. */
			printf("%s: \n", path);
			fd = open(path, O_RDONLY);
			if (fd < 0) {
				printf("Failed to open file %s\n", path);
				goto error;
			}
			nread = 0;
			do {
				nread = read(fd, buf, PROC_BUFFER_LEN - 1);
				if (nread < 0) {
					/* Read error */
					printf("Failed to read : %d\n", errno);
					goto error_with_fd;
				}
				buf[nread] = '\0';
				printf("%s", buf);
			} while (nread == PROC_BUFFER_LEN - 1);
			printf("\n");
			close(fd);
		} else {
			ret = read_dir_entries(path);
			if (ret != OK) {
				goto error;
			}
		}
	}
	closedir(dirp);

	return OK;
error_with_fd:
	close(fd);
error:
	closedir(dirp);

	return ERROR;
}
static void show_directories(const char *path, int indent)
{
    DIR *dirp;
    struct dirent *direntry;
    int i;

    dirp = opendir(path);
    if ( !dirp )
    {
        printf("show_directories: ERROR opendir(\"%s\") failed with errno=%d\n",
               path, errno);
        g_nerrors++;
        return;
    }

    for (direntry = readdir(dirp); direntry; direntry = readdir(dirp))
    {
        for (i = 0; i < 2*indent; i++)
        {
            putchar(' ');
        }
        if (DIRENT_ISDIRECTORY(direntry->d_type))
        {
            char *subdir;
            printf("%s/\n", direntry->d_name);
            sprintf(g_namebuffer, "%s/%s", path, direntry->d_name);
            subdir = strdup(g_namebuffer);
            show_directories( subdir, indent + 1);
            free(subdir);
        }
        else
        {
            printf("%s\n", direntry->d_name);
        }
    }

    closedir(dirp);
}
Beispiel #6
0
static int read_proc_entry(FAR const char *dirpath, FAR struct dirent *entryp, FAR void *pvarg)
{
	/* This function is for showing all file entries of /proc like uptime, version */
	int ret;
	char filepath[PROC_FILEPATH_LEN];

	if (DIRENT_ISDIRECTORY(entryp->d_type)) {
		/* Is a directory... skip this entry */
		return OK;
	}

	snprintf(filepath, PROC_FILEPATH_LEN, "%s/%s", PROC_MOUNTPOINT, entryp->d_name);

	printf("%s : ", entryp->d_name);

	ret = readfile(filepath);
	if (ret < 0) {
		printf("Failed to read %s\n", filepath);
		return ERROR;
	}
	printf("----------------------------------------\n");

	return OK;
}
Beispiel #7
0
static int ls_handler(FAR struct nsh_vtbl_s *vtbl, const char *dirpath, struct dirent *entryp, void *pvarg)
{
  unsigned int lsflags = (unsigned int)pvarg;
  int ret;

  /* Check if any options will require that we stat the file */

  if ((lsflags & (LSFLAGS_SIZE|LSFLAGS_LONG)) != 0)
    {
      struct stat buf;
      char *fullpath = nsh_getdirpath(dirpath, entryp->d_name);

      /* Yes, stat the file */

      ret = stat(fullpath, &buf);
      free(fullpath);
      if (ret != 0)
        {
          nsh_output(vtbl, g_fmtcmdfailed, "ls", "stat", NSH_ERRNO);
          return ERROR;
        }

      if ((lsflags & LSFLAGS_LONG) != 0)
        {
          char details[] = "----------";
          if (S_ISDIR(buf.st_mode))
            {
              details[0]='d';
            }
          else if (S_ISCHR(buf.st_mode))
            {
              details[0]='c';
            }
          else if (S_ISBLK(buf.st_mode))
            {
              details[0]='b';
            }

          if ((buf.st_mode & S_IRUSR) != 0)
            {
              details[1]='r';
            }

          if ((buf.st_mode & S_IWUSR) != 0)
            {
              details[2]='w';
            }

          if ((buf.st_mode & S_IXUSR) != 0)
            {
              details[3]='x';
            }

          if ((buf.st_mode & S_IRGRP) != 0)
            {
              details[4]='r';
            }

          if ((buf.st_mode & S_IWGRP) != 0)
            {
              details[5]='w';
            }

          if ((buf.st_mode & S_IXGRP) != 0)
            {
              details[6]='x';
            }

          if ((buf.st_mode & S_IROTH) != 0)
            {
              details[7]='r';
            }

          if ((buf.st_mode & S_IWOTH) != 0)
            {
              details[8]='w';
            }

          if ((buf.st_mode & S_IXOTH) != 0)
            {
              details[9]='x';
            }

          nsh_output(vtbl, " %s", details);
        }

      if ((lsflags & LSFLAGS_SIZE) != 0)
        {
          nsh_output(vtbl, "%8d", buf.st_size);
        }
    }

  /* then provide the filename that is common to normal and verbose output */

#ifdef CONFIG_NSH_FULLPATH
  nsh_output(vtbl, " %s/%s", arg, entryp->d_name);
#else
  nsh_output(vtbl, " %s", entryp->d_name);
#endif

  if (DIRENT_ISDIRECTORY(entryp->d_type) && !ls_specialdir(entryp->d_name))
    {
      nsh_output(vtbl, "/\n");
    }
  else
    {
      nsh_output(vtbl, "\n");
    }
  return OK;
}
Beispiel #8
0
void UavcanServers::unpackFwFromROMFS(const char* sd_path, const char* romfs_path) {
	/*
	Copy the ROMFS firmware directory to the appropriate location on SD, without
	overriding any firmware the user has already loaded there.

	The SD firmware directory structure is along the lines of:

		/fs/microsd/fw
		-	/c
			-	/nodename-v1-1.0.25d0137d.bin		cache file (copy of /fs/microsd/fw/org.pixhawk.nodename-v1/1.1/nodename-v1-1.0.25d0137d.bin)
			-	/othernode-v3-1.6.25d0137d.bin		cache file (copy of /fs/microsd/fw/com.example.othernode-v3/1.6/othernode-v3-1.6.25d0137d.bin)
		-	/org.pixhawk.nodename-v1				device directory for org.pixhawk.nodename-v1
		-	-	/1.0								version directory for hardware 1.0
		-	-	/1.1								version directory for hardware 1.1
		-	-	-	/nodename-v1-1.0.25d0137d.bin	firmware file for org.pixhawk.nodename-v1 nodes, hardware version 1.1
		-	/com.example.othernode-v3				device directory for com.example.othernode-v3
		-	-	/1.0								version directory for hardawre 1.0
		-	-	-	/othernode-v3-1.6.25d0137d.bin	firmware file for com.example.othernode-v3, hardware version 1.6

	The ROMFS directory structure is the same, but located at /etc/uavcan/fw
	Files located there are prefixed with _ to identify them a comming from the rom
	file system.

	We iterate over all device directories in the ROMFS base directory, and create
	corresponding device directories on the SD card if they don't already exist.

	In each device directory, we iterate over each version directory and create a
	corresponding version directory on the SD card if it doesn't already exist.

	In each version directory, we remove any files with a name starting with "_"
	in the corresponding directory on the SD card that don't match the bundled firmware
	filename; if the directory is empty after that process, we copy the bundled firmware.

	todo:This code would benefit from the use of strcat.

	*/
	const size_t maxlen = UAVCAN_MAX_PATH_LENGTH;
	const size_t sd_path_len = strlen(sd_path);
	const size_t romfs_path_len = strlen(romfs_path);
	struct stat sb;
	int rv;
	char dstpath[maxlen + 1];
	char srcpath[maxlen + 1];

	DIR* const romfs_dir = opendir(romfs_path);
	if (!romfs_dir) {
		return;
	}

	memcpy(dstpath, sd_path, sd_path_len + 1);
	memcpy(srcpath, romfs_path, romfs_path_len + 1);

	// Iterate over all device directories in ROMFS
	struct dirent* dev_dirent = NULL;
	while ((dev_dirent = readdir(romfs_dir)) != NULL) {
		// Skip if not a directory
		if (!DIRENT_ISDIRECTORY(dev_dirent->d_type)) {
			continue;
		}

		// Make sure the path fits
		size_t dev_dirname_len = strlen(dev_dirent->d_name);
		size_t srcpath_dev_len = romfs_path_len + 1 + dev_dirname_len;
		if (srcpath_dev_len > maxlen) {
			warnx("dev: srcpath '%s/%s' too long", romfs_path, dev_dirent->d_name);
			continue;
		}
		size_t dstpath_dev_len = sd_path_len + 1 + dev_dirname_len;
		if (dstpath_dev_len > maxlen) {
			warnx("dev: dstpath '%s/%s' too long", sd_path, dev_dirent->d_name);
			continue;
		}

		// Create the device name directory on the SD card if it doesn't already exist
		dstpath[sd_path_len] = '/';
		memcpy(&dstpath[sd_path_len + 1], dev_dirent->d_name, dev_dirname_len + 1);

		if (stat(dstpath, &sb) != 0 || !S_ISDIR(sb.st_mode)) {
			rv = mkdir(dstpath, S_IRWXU | S_IRWXG | S_IRWXO);
			if (rv != 0) {
				warnx("dev: couldn't create '%s'", dstpath);
				continue;
			}
		}

		// Set up the source path
		srcpath[romfs_path_len] = '/';
		memcpy(&srcpath[romfs_path_len + 1], dev_dirent->d_name, dev_dirname_len + 1);

		DIR* const dev_dir = opendir(srcpath);
		if (!dev_dir) {
			warnx("dev: couldn't open '%s'", srcpath);
			continue;
		}

		// Iterate over all version directories in the current ROMFS device directory
		struct dirent* ver_dirent = NULL;
		while ((ver_dirent = readdir(dev_dir)) != NULL) {
			// Skip if not a directory
			if (!DIRENT_ISDIRECTORY(ver_dirent->d_type)) {
				continue;
			}

			// Make sure the path fits
			size_t ver_dirname_len = strlen(ver_dirent->d_name);
			size_t srcpath_ver_len = srcpath_dev_len + 1 + ver_dirname_len;
			if (srcpath_ver_len > maxlen) {
				warnx("ver: srcpath '%s/%s' too long", srcpath, ver_dirent->d_name);
				continue;
			}
			size_t dstpath_ver_len = dstpath_dev_len + 1 + ver_dirname_len;
			if (dstpath_ver_len > maxlen) {
				warnx("ver: dstpath '%s/%s' too long", dstpath, ver_dirent->d_name);
				continue;
			}

			// Create the device version directory on the SD card if it doesn't already exist
			dstpath[dstpath_dev_len] = '/';
			memcpy(&dstpath[dstpath_dev_len + 1], ver_dirent->d_name, ver_dirname_len + 1);

			if (stat(dstpath, &sb) != 0 || !S_ISDIR(sb.st_mode)) {
				rv = mkdir(dstpath, S_IRWXU | S_IRWXG | S_IRWXO);
				if (rv != 0) {
					warnx("ver: couldn't create '%s'", dstpath);
					continue;
				}
			}

			// Set up the source path
			srcpath[srcpath_dev_len] = '/';
			memcpy(&srcpath[srcpath_dev_len + 1], ver_dirent->d_name, ver_dirname_len + 1);

			// Find the name of the bundled firmware file, or move on to the
			// next directory if there's no file here.
			DIR* const src_ver_dir = opendir(srcpath);
			if (!src_ver_dir) {
				warnx("ver: couldn't open '%s'", srcpath);
				continue;
			}

			struct dirent* src_fw_dirent = NULL;
			while ((src_fw_dirent = readdir(src_ver_dir)) != NULL &&
					!DIRENT_ISFILE(src_fw_dirent->d_type));

			if (!src_fw_dirent) {
				(void)closedir(src_ver_dir);
				continue;
			}

			size_t fw_len = strlen(src_fw_dirent->d_name);

			bool copy_fw = true;

			// Clear out any romfs_ files in the version directory on the SD card
			DIR* const dst_ver_dir = opendir(dstpath);
			if (!dst_ver_dir) {
				warnx("unlink: couldn't open '%s'", dstpath);
			} else {
				struct dirent* fw_dirent = NULL;
				while ((fw_dirent = readdir(dst_ver_dir)) != NULL) {
					// Skip if not a file
					if (!DIRENT_ISFILE(fw_dirent->d_type)) {
						continue;
					}

					if (!memcmp(&fw_dirent->d_name, src_fw_dirent->d_name, fw_len)) {
						/*
						 * Exact match between SD card filename and ROMFS filename; must be the same version
						 * so don't bother deleting and rewriting it.
						 */
						copy_fw = false;
					} else if (!memcmp(fw_dirent->d_name, UAVCAN_ROMFS_FW_PREFIX, sizeof(UAVCAN_ROMFS_FW_PREFIX) - 1)) {
						size_t dst_fw_len = strlen(fw_dirent->d_name);
						size_t dstpath_fw_len = dstpath_ver_len + dst_fw_len;
						if (dstpath_fw_len > maxlen) {
							// sizeof(prefix) includes trailing NUL, cancelling out the +1 for the path separator
							warnx("unlink: path '%s/%s' too long", dstpath, fw_dirent->d_name);
						} else {
							// File name starts with "_", delete it.
							dstpath[dstpath_ver_len] = '/';
							memcpy(&dstpath[dstpath_ver_len + 1], fw_dirent->d_name, dst_fw_len + 1);
							unlink(dstpath);
							warnx("unlink: removed '%s'", dstpath);
						}
					} else {
						// User file, don't copy firmware
						copy_fw = false;
					}
				}
				(void)closedir(dst_ver_dir);
			}

			// If we need to, copy the file from ROMFS to the SD card
			if (copy_fw) {
				size_t srcpath_fw_len = srcpath_ver_len + 1 + fw_len;
				size_t dstpath_fw_len = dstpath_ver_len + fw_len;

				if (srcpath_fw_len > maxlen) {
					warnx("copy: srcpath '%s/%s' too long", srcpath, src_fw_dirent->d_name);
				} else if (dstpath_fw_len > maxlen) {
					warnx("copy: dstpath '%s/%s' too long", dstpath, src_fw_dirent->d_name);
				} else {
					// All OK, make the paths and copy the file
					srcpath[srcpath_ver_len] = '/';
					memcpy(&srcpath[srcpath_ver_len + 1], src_fw_dirent->d_name, fw_len + 1);

					dstpath[dstpath_ver_len] = '/';
					memcpy(&dstpath[dstpath_ver_len +1], src_fw_dirent->d_name, fw_len + 1);

					rv = copyFw(dstpath, srcpath);
					if (rv != 0) {
						warnx("copy: '%s' -> '%s' failed: %d", srcpath, dstpath, rv);
					} else {
						warnx("copy: '%s' -> '%s' succeeded", srcpath, dstpath);
					}
				}
			}

			(void)closedir(src_ver_dir);
		}

		(void)closedir(dev_dir);
	}

	(void)closedir(romfs_dir);
}
static int proc_opendir(FAR const char *relpath, FAR struct fs_dirent_s *dir)
{
  FAR struct proc_dir_s *procdir;
  FAR const struct proc_node_s *node;
  FAR struct tcb_s *tcb;
  irqstate_t flags;
  unsigned long tmp;
  FAR char *ptr;
  pid_t pid;

  fvdbg("relpath: \"%s\"\n", relpath ? relpath : "NULL");
  DEBUGASSERT(relpath && dir && !dir->u.procfs);

  /* The relative must be either:
   *
   *  (1) "<pid>" - The sub-directory of task/thread attributes, or
   *  (2) The name of a directory node under <pid>
   */

  /* Otherwise, the relative path should be a valid task/thread ID */

  ptr = NULL;
  tmp = strtoul(relpath, &ptr, 10);

  if (!ptr || (*ptr != '\0' && *ptr != '/'))
    {
      /* strtoul failed or there is something in the path after the pid */

      fdbg("ERROR: Invalid path \"%s\"\n", relpath);
      return -ENOENT;
   }

  /* A valid PID would be in the range of 0-32767 (0 is reserved for the
   * IDLE thread).
   */

  if (tmp >= 32768)
    {
      fdbg("ERROR: Invalid PID %ld\n", tmp);
      return -ENOENT;
    }

  /* Now verify that a task with this task/thread ID exists */

  pid = (pid_t)tmp;

  flags = irqsave();
  tcb = sched_gettcb(pid);
  irqrestore(flags);

  if (!tcb)
    {
      fdbg("ERROR: PID %d is not valid\n", (int)pid);
      return -ENOENT;
    }

  /* Allocate the directory structure.  Note that the index and procentry
   * pointer are implicitly nullified by kmm_zalloc().  Only the remaining,
   * non-zero entries will need be initialized.
   */

  procdir = (FAR struct proc_dir_s *)kmm_zalloc(sizeof(struct proc_dir_s));
  if (!procdir)
    {
      fdbg("ERROR: Failed to allocate the directory structure\n");
      return -ENOMEM;
    }

  /* Was the <pid> the final element of the path? */

  if (*ptr != '\0' && strcmp(ptr, "/") != 0)
    {
      /* There is something in the path after the pid.  Skip over the path
       * segment delimiter and see if we can identify the node of interest.
       */

      ptr++;
      node = proc_findnode(ptr);
      if (!node)
        {
          fdbg("ERROR: Invalid path \"%s\"\n", relpath);
          kmm_free(procdir);
          return -ENOENT;
        }

      /* The node must be a directory, not a file */

      if (!DIRENT_ISDIRECTORY(node->dtype))
        {
          fdbg("ERROR: Path \"%s\" is not a directory\n", relpath);
          kmm_free(procdir);
          return -ENOTDIR;
        }

      /* This is a second level directory */

      procdir->base.level    = 2;
      procdir->base.nentries = PROC_NGROUPNODES;
      procdir->node          = node;
    }
  else
    {
      /* Use the special level0 node */

      procdir->base.level    = 1;
      procdir->base.nentries = PROC_NLEVEL0NODES;
      procdir->node          = &g_level0node;
    }

   procdir->pid  = pid;
   dir->u.procfs = (FAR void *)procdir;
   return OK;
}
static void readdirectories(const char *path, struct node_s *entry)
{
  DIR *dirp;
  struct node_s *node;
  struct dirent *direntry;
  char *fullpath;

  printf("Traversing directory: %s\n", path);
  dirp = opendir(path);
  if (!dirp)
    {
      printf("  ERROR opendir(\"%s\") failed: %d\n", path, errno);
      g_nerrors++;
      return;
    }

  for (direntry = readdir(dirp); direntry; direntry = readdir(dirp))
    {
      if (strcmp(direntry->d_name, ".") == 0 || strcmp(direntry->d_name, "..") == 0)
        {
           printf("  Skipping %s\n", direntry->d_name);
           continue;
        }

      node = findindirectory(entry, direntry->d_name);
      if (!node)
        {
          printf("  ERROR: No node found for %s\n", direntry->d_name);
          g_nerrors++;
          continue;
        }

      /* Get the full path to the entry */

      sprintf(g_scratchbuffer, "%s/%s", path, direntry->d_name);
      fullpath = strdup(g_scratchbuffer);

      if (DIRENT_ISDIRECTORY(direntry->d_type))
        {
          printf("  DIRECTORY: %s/\n", fullpath);
          if (!node->directory)
            {
              printf("  -- ERROR: Expected type directory\n");
              g_nerrors++;
            }
          else
            {
              checkattributes(fullpath, node->mode, 0);
              readdirectories(fullpath, node->u.child);
              printf("Continuing directory: %s\n", path);
            }
        }
      else
        {
          printf("  FILE: %s/\n", fullpath);
          if (node->directory)
            {
              printf("  -- ERROR: Expected type file\n");
              g_nerrors++;
            }
          else
            {
              checkattributes(fullpath, node->mode, node->size);
              checkfile(fullpath, node);
            }
        }
      free(fullpath);
    }

  closedir(dirp);
}
Beispiel #11
0
static int ls_handler(FAR const char *dirpath, FAR struct dirent *entryp, FAR void *pvarg)
{
	unsigned int lsflags = (unsigned int)pvarg;
	int ret;

	/* Check if any options will require that we stat the file */

	if ((lsflags & (LSFLAGS_SIZE | LSFLAGS_LONG)) != 0) {
		struct stat buf;

		/* stat the file */

		if (entryp != NULL) {
			char *fullpath = get_dirpath(dirpath, entryp->d_name);
			ret = stat(fullpath, &buf);
			fscmd_free(fullpath);
		} else {
			/*
			 * A NULL entryp signifies that we are
			 * running ls on a single file
			 */
			ret = stat(dirpath, &buf);
		}

		if (ret != 0) {
			FSCMD_OUTPUT(CMD_FAILED, "ls", "stat");

			return ERROR;
		}

		if ((lsflags & LSFLAGS_LONG) != 0) {
			char details[] = "----------";
			if (S_ISDIR(buf.st_mode)) {
				details[0] = 'd';
			} else if (S_ISCHR(buf.st_mode)) {
				details[0] = 'c';
			} else if (S_ISBLK(buf.st_mode)) {
				details[0] = 'b';
			} else if (!S_ISREG(buf.st_mode)) {
				details[0] = '?';
			}

			if ((buf.st_mode & S_IRUSR) != 0) {
				details[1] = 'r';
			}

			if ((buf.st_mode & S_IWUSR) != 0) {
				details[2] = 'w';
			}

			if ((buf.st_mode & S_IXUSR) != 0) {
				details[3] = 'x';
			}

			if ((buf.st_mode & S_IRGRP) != 0) {
				details[4] = 'r';
			}

			if ((buf.st_mode & S_IWGRP) != 0) {
				details[5] = 'w';
			}

			if ((buf.st_mode & S_IXGRP) != 0) {
				details[6] = 'x';
			}

			if ((buf.st_mode & S_IROTH) != 0) {
				details[7] = 'r';
			}

			if ((buf.st_mode & S_IWOTH) != 0) {
				details[8] = 'w';
			}

			if ((buf.st_mode & S_IXOTH) != 0) {
				details[9] = 'x';
			}

			FSCMD_OUTPUT(" %s", details);
		}

		if ((lsflags & LSFLAGS_SIZE) != 0) {
			FSCMD_OUTPUT("%8d", buf.st_size);
		}
	}

	/*
	 * Then provide the filename that is common
	 * to normal and verbose output
	 */

	if (entryp != NULL) {
		FSCMD_OUTPUT(" %s", entryp->d_name);

		if (DIRENT_ISDIRECTORY(entryp->d_type) && !ls_specialdir(entryp->d_name)) {
			FSCMD_OUTPUT("/\n");
		} else {
			FSCMD_OUTPUT("\n");
		}
	} else {
		/* A single file */
		FSCMD_OUTPUT(" %s\n", dirpath);
	}

	return OK;
}