view rvinterf/etmsync/fsread.c @ 988:5a6019ed7e72

pln-ppb-test: implement read-id
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 03 Dec 2023 00:04:18 +0000
parents 74d284add54d
children
line wrap: on
line source

/*
 * Commands for reading the content of a GSM device's file system
 */

#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include "etm.h"
#include "ffs.h"
#include "tmffs2.h"
#include "limits.h"
#include "ffslimits.h"
#include "localtypes.h"
#include "localstruct.h"
#include "exitcodes.h"

extern char *pathname_for_ffs_child();

void
ll_print_line(pathname, stat)
	char *pathname;
	struct stat_info *stat;
{
	char readonly;
	char rlbuf[256];

	if (stat->flags & OF_READONLY)
		readonly = 'r';
	else
		readonly = ' ';
	switch (stat->type) {
	case OT_FILE:
		printf("f%c %7u %s\n", readonly, stat->size, pathname);
		return;
	case OT_DIR:
		printf("d%c         %s\n", readonly, pathname);
		return;
	case OT_LINK:
		if (do_readlink_sancheck(pathname, rlbuf))
			strcpy(rlbuf, "<invalid>");
		printf("l%c         %s -> %s\n", readonly, pathname, rlbuf);
		return;
	default:
		printf("?%c         %s\n", readonly, pathname);
	}
}

ls_is_sane(name)
	char *name;
{
	char *cp;
	int c;

	cp = name;
	while (c = *cp++) {
		if (c < '!' || c > '~')
			return(0);
	}
	return(1);
}

do_ls_long(lsarg)
	char *lsarg;
{
	struct stat_info stat;
	u_char rdstate[4];
	char rdbuf[MAX_FN_COMPONENT+1], childpath[MAX_FULL_PATHNAME+1], *childp;
	int nument, i, rc;

	if (validate_ffs_pathname(lsarg) < 0)
		return(ERROR_USAGE);	/* err msg already printed */
	rc = do_xlstat(lsarg, &stat);
	if (rc)
		return(rc);
	if (stat.type != OT_DIR) {
		ll_print_line(lsarg, &stat);
		return(0);
	}
	rc = do_opendir(lsarg, rdstate, &nument);
	if (rc)
		return(rc);
	if (!nument) {
		printf("<empty dir>\n");
		return(0);
	}
	childp = pathname_for_ffs_child(lsarg, childpath);
	if (!childp) {
		printf("error: non-empty dir at the limit of pathname depth\n");
		return(ERROR_TARGET);
	}
	for (i = 0; i < nument; i++) {
		rc = do_readdir(rdstate, rdbuf, MAX_FN_COMPONENT+1);
		if (rc)
			return(rc);
		if (index(rdbuf, '/')) {
			printf("error: readdir result contains a slash\n");
			return(ERROR_TARGET);
		}
		if (!ls_is_sane(rdbuf)) {
		printf("error: readdir result contains non-printable chars\n");
			return(ERROR_TARGET);
		}
		strcpy(childp, rdbuf);
		rc = do_xlstat(childpath, &stat);
		if (rc) {
			printf("xlstat failed on %s\n", childpath);
			return(rc);
		}
		ll_print_line(childpath, &stat);
	}
	return(0);
}

cmd_ll(argc, argv)
	char **argv;
{
	return do_ls_long(argv[1]);
}

void
hexdump_line(offset, buf, len)
	u_char *buf;
{
	int i, c;

	printf("%02X:  ", offset);
	for (i = 0; i < 16; i++) {
		if (i < len)
			printf("%02X ", buf[i]);
		else
			fputs("   ", stdout);
		if (i == 7 || i == 15)
			putchar(' ');
	}
	for (i = 0; i < len; i++) {
		c = buf[i];
		if (c < ' ' || c > '~')
			c = '.';
		putchar(c);
	}
	putchar('\n');
}

cmd_hd(argc, argv)
	char **argv;
{
	u_char databuf[MAX_READ_DATA];
	int rc, sz, off, l;

	rc = do_file_read(argv[1], databuf, MAX_READ_DATA, &sz);
	if (rc)
		return(rc);
	printf("%d bytes read\n", sz);
	for (off = 0; off < sz; off += 16) {
		l = sz - off;
		if (l > 16)
			l = 16;
		hexdump_line(off, databuf + off, l);
	}
	return(0);
}

cpout_object(ffspath, hostpath)
	char *ffspath, *hostpath;
{
	struct stat_info stat;
	int rc;

	rc = do_xlstat(ffspath, &stat);
	if (rc)
		return(rc);
	switch (stat.type) {
	case OT_FILE:
		return cpout_file(ffspath, hostpath);
	case OT_DIR:
		return cpout_dir(ffspath, hostpath);
	case OT_LINK:
		printf("skipping FFS symlink %s\n", ffspath);
		return(0);
	default:
		printf("error: stat returned bad objtype for %s\n", ffspath);
		return(ERROR_TARGET);
	}
}

cpout_file(ffspath, hostpath)
	char *ffspath, *hostpath;
{
	int tfd;
	FILE *of;
	u_char buf[MAX_READ_DATA];
	int rc, sz;

	printf("copying %s\n", ffspath);
	rc = fd_open(ffspath, FFS_O_RDONLY, &tfd);
	if (rc)
		return(rc);
	of = fopen(hostpath, "w");
	if (!of) {
		perror(hostpath);
		fd_close(tfd);
		return(ERROR_UNIX);
	}
	for (;;) {
		rc = fd_read(tfd, buf, MAX_READ_DATA, &sz);
		if (rc) {
			fd_close(tfd);
			fclose(of);
			return(rc);
		}
		if (!sz)
			break;
		fwrite(buf, 1, sz, of);
	}
	fclose(of);
	return fd_close(tfd);
}

cpout_dir(ffspath_dir, hostpath_dir)
	char *ffspath_dir, *hostpath_dir;
{
	u_char rdstate[4];
	char rdbuf[MAX_FN_COMPONENT+1], ffspath_child[MAX_FULL_PATHNAME+1];
	char *childp;
	char hostpath_child[MAXPATHLEN];
	int nument, i, rc, childerr;

	printf("dir %s\n", ffspath_dir);
	rc = host_mkdir(hostpath_dir);
	if (rc)
		return(rc);
	rc = do_opendir(ffspath_dir, rdstate, &nument);
	if (rc)
		return(rc);
	if (!nument)
		return(0);
	childp = pathname_for_ffs_child(ffspath_dir, ffspath_child);
	if (!childp) {
		printf("error: non-empty dir at the limit of pathname depth\n");
		return(ERROR_TARGET);
	}
	childerr = 0;
	for (i = 0; i < nument; i++) {
		rc = do_readdir(rdstate, rdbuf, MAX_FN_COMPONENT+1);
		if (rc)
			return(rc);
		if (index(rdbuf, '/')) {
			printf("error: readdir result contains a slash\n");
			return(ERROR_TARGET);
		}
		if (!ls_is_sane(rdbuf)) {
		printf("error: readdir result contains non-printable chars\n");
			return(ERROR_TARGET);
		}
		strcpy(childp, rdbuf);
		if (rdbuf[0] == '.') {
			printf("skipping %s\n", ffspath_child);
			continue;
		}
		if (strlen(hostpath_dir) + strlen(rdbuf) + 2 >
		    sizeof hostpath_child) {
			fprintf(stderr,
				"error: host side pathname buffer overflow\n");
			return(ERROR_UNIX);
		}
		sprintf(hostpath_child, "%s/%s", hostpath_dir, rdbuf);
		rc = cpout_object(ffspath_child, hostpath_child);
		if (rc && rc != ERROR_TARGET)
			return(rc);
		if (rc)
			childerr = rc;
	}
	return(childerr);
}

cmd_cpout(argc, argv)
	char **argv;
{
	if (validate_ffs_pathname(argv[1]) < 0)
		return(ERROR_USAGE);	/* err msg already printed */
	return cpout_object(argv[1], argv[2]);
}

cmd_cpout_file(argc, argv)
	char **argv;
{
	return cpout_file(argv[1], argv[2]);
}