#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <asm/page.h>
#include <sys/swap.h>
#include <sys/sysmacros.h>
#include <sys/statfs.h>
#include <unistd.h>
#include <zlib.h>
#include "../isys/imount.h"
#include "../isys/isys.h"
#include "commands.h"
#include "idmap.h"
#include "ls.h"
#include "popt.h"
#include "../isys/cpio.h"
static int copyfd(int to, int from);
static int copyfd(int to, int from) {
char buf[1024];
int size;
while ((size = read(from, buf, sizeof(buf))) > 0) {
if (write(to, buf, size) != size) {
fprintf(stderr, "error writing output: %s\n", strerror(errno));
return 1;
}
}
if (size < 0) {
fprintf(stderr, "error reading input: %s\n", strerror(errno));
return 1;
}
return 0;
}
static int catFile(char * filename) {
int fd;
int rc;
fd = open(filename, O_RDONLY);
if (fd < 0) {
fprintf(stderr, "cannot open %s: %s\n", filename, strerror(errno));
return 1;
}
rc = copyfd(1, fd);
close(fd);
return rc;
}
int catCommand(int argc, char ** argv) {
char ** argptr = argv + 1;
int rc;
if (!*argptr) {
return copyfd(1, 0);
} else {
while (*argptr) {
rc = catFile(*argptr);
if (rc) return rc;
argptr++;
}
}
return 0;
}
int lsmodCommand(int argc, char ** argv) {
puts("Module: #pages: Used by:");
catFile("/proc/modules");
return 0;
}
#define MOUNT_USAGE fprintf(stderr, "usage: mount -t <fs> <device> <dir>\n" \
" (if /dev/ is left off the device name, a " \
"temporary node will be created)\n")
int mountCommand(int argc, char ** argv) {
char * dev, * dir;
char * fs, * buf;
if (argc < 2) {
return catFile("/proc/mounts");
} else if (argc == 3) {
if (strchr(argv[1], ':'))
fs = "nfs";
else
fs = "ext2";
dev = argv[1];
dir = argv[2];
} else if (argc != 5) {
MOUNT_USAGE;
return 1;
} else {
if (strcmp(argv[1], "-t")) {
MOUNT_USAGE;
return 1;
}
fs = argv[2];
dev = argv[3];
dir = argv[4];
}
if (!strncmp(dev, "/dev/", 5) && access(dev, X_OK)) {
dev += 5;
buf = alloca(strlen(dev) + 10);
sprintf(buf, "/tmp/%s", dev);
devMakeInode(dev, buf);
dev = buf;
}
if (doPwMount(dev, dir, fs, 0, 1, NULL, NULL))
return 1;
return 0;
}
int umountCommand(int argc, char ** argv) {
if (argc != 2) {
fprintf(stderr, "umount expects a single argument\n");
return 1;
}
if (umount(argv[1])) {
fprintf(stderr, "error unmounting %s: %s\n", argv[1], strerror(errno));
return 1;
}
return 0;
}
int mkdirCommand(int argc, char ** argv) {
char ** argptr = argv + 1;
if (argc < 2) {
fprintf(stderr, "umount expects one or more arguments\n");
return 1;
}
while (*argptr) {
if (mkdir(*argptr, 0755)) {
fprintf(stderr, "error creating directory %s: %s\n", *argptr,
strerror(errno));
return 1;
}
argptr++;
}
return 0;
}
int mknodCommand(int argc, char ** argv) {
int major, minor;
char * path;
int mode = 0600;
char *end;
if (argc != 5 && argc != 2) {
fprintf(stderr, "usage: mknod <path> [b|c] <major> <minor> or mknod <path>\n");
return 1;
}
path = argv[1];
if (argc == 2) {
end = path + strlen(path) - 1;
while (end > path && *end != '/') end--;
if (*end == '/') end++;
if (devMakeInode(end, path)) {
return 1;
}
return 0;
}
if (!strcmp(argv[2], "b"))
mode |= S_IFBLK;
else if (!strcmp(argv[2], "c"))
mode |= S_IFCHR;
else {
fprintf(stderr, "unknown node type %s\n", argv[2]);
return 1;
}
major = strtol(argv[3], &end, 0);
if (*end) {
fprintf(stderr, "bad major number %s\n", argv[3]);
return 1;
}
minor = strtol(argv[4], &end, 0);
if (*end) {
fprintf(stderr, "bad minor number %s\n", argv[4]);
return 1;
}
if (mknod(path, mode, makedev(major, minor))) {
fprintf(stderr, "mknod failed: %s\n", strerror(errno));
return 1;
}
return 0;
}
int lnCommand(int argc, char ** argv) {
char ** argptr = argv + 1;
int force = 0, soft = 0;
int rc;
while (*argptr && **argptr == '-') {
if (!strcmp(*argptr, "-f"))
force = 1;
else if (!strcmp(*argptr, "-s"))
soft = 1;
else if (!strcmp(*argptr, "-fs") || !strcmp(*argptr, "-sf"))
force = soft = 1;
else {
fprintf(stderr, "ln: unknown argument %s\n", *argptr);
return 1;
}
argptr++;
}
if (!*argptr || !(*argptr + 1) || *(argptr + 2)) {
fprintf(stderr, "ln requires exactly two filenames\n");
return 1;
}
if (force) unlink(*(argptr + 1));
if (soft)
rc = symlink(*argptr, *(argptr + 1));
else
rc = link(*argptr, *(argptr + 1));
if (rc) {
perror("error");
return 1;
}
return 0;
}
int rmCommand(int argc, char ** argv) {
char ** argptr = argv + 1;
if (argc < 2) {
fprintf(stderr, "rm expects one or more arguments "
"(no flags are supported");
return 1;
}
while (*argptr) {
if (unlink(*argptr)) {
fprintf(stderr, "unlink of %s failed: %s\n", *argptr,
strerror(errno));
return 1;
}
argptr++;
}
return 0;
}
int chmodCommand(int argc, char ** argv) {
char ** argptr = argv + 2;
int mode;
char * end;
if (argc < 3) {
fprintf(stderr, "usage: chmod <mode> <one or files>\n");
return 1;
}
mode = strtol(argv[1], &end, 8);
if (*end) {
fprintf(stderr, "illegal mode %s\n", argv[1]);
return 1;
}
while (*argptr) {
if (chmod(*argptr, mode)) {
fprintf(stderr, "error in chmod of %s to 0%o: %s\n", *argptr,
mode, strerror(errno));
return 1;
}
argptr++;
}
return 0;
}
#define CPIOERR_CHECK_ERRNO 0x00008000
int uncpioCommand(int argc, char ** argv) {
int rc;
char * fail;
CFD_t cfd;
if (argc != 1) {
fprintf(stderr, "uncpio reads from stdin");
return 1;
}
cfd.cpioPos = 0;
cfd.cpioIoType = cpioIoTypeGzFd;
cfd.cpioGzFd = gzdFdopen(fdDup(0), "r");
rc = cpioInstallArchive(&cfd, NULL, 0, NULL, NULL, &fail);
if (rc) {
fprintf(stderr, "cpio failed on %s: ", fail);
if (rc & CPIOERR_CHECK_ERRNO)
fprintf(stderr, "%s\n", strerror(errno));
else
fprintf(stderr, "(internal)\n");
}
return (rc != 0);
}
int dfCommand(int argc, char ** argv) {
int fd;
char * buf = alloca(2048);
char * end;
struct statfs fs;
int i;
int badjust;
if ((fd = open("/proc/mounts", O_RDONLY)) < 0) {
perror("failed to open /proc/mounts");
return 1;
}
i = read(fd, buf, 2048);
buf[i] = '\0';
printf("%-30s %-10s %-10s %-10s\n",
"Mount Point", "1k-blocks", "Used", "Available");
while (buf && *buf) {
end = strchr(buf, ' ');
if (!end) return 1;
buf = end + 1;
end = strchr(buf, ' ');
if (!end) return 1;
*end = '\0';
statfs(buf, &fs);
badjust = fs.f_bsize / 1024;
printf("%-30s %-10d %-10d %-10d\n",
buf, fs.f_blocks * badjust,
(fs.f_blocks - fs.f_bfree) * badjust,
fs.f_bfree * badjust);
buf = strchr(end + 1, '\n');
if (buf) buf++;
}
return 0;
}
int lsCommand(int argc, char ** argv) {
poptContext optCon;
int flags = 0;
int rc;
char path[1024];
struct poptOption ksOptions[] = {
{ NULL, 'l', 0, NULL, 'l' },
{ NULL, 'C', 0, NULL, 'C' },
{ NULL, 'd', 0, NULL, 'd' },
{ NULL, 'g', 0, NULL, 'g' },
{ NULL, 'n', 0, NULL, 'n' },
{ NULL, 'p', 0, NULL, 'p' },
{ NULL, 'a', 0, NULL, 'a' },
{ NULL, 'L', 0, NULL, 'L' },
{ NULL, 'f', 0, NULL, 'f' },
{ NULL, 'r', 0, NULL, 'r' },
{ NULL, 't', 0, NULL, 't' },
{ NULL, 'S', 0, NULL, 'S' },
{ NULL, 'R', 0, NULL, 'R' },
{ NULL, '\0', 0, NULL, '\0' }
};
optCon = poptGetContext(NULL, argc, argv, ksOptions, 0);
if (isatty(1)) flags |= SENDDIR_MULTICOLUMN;
while ((rc = poptGetNextOpt(optCon)) >= 0) {
switch (rc) {
case 'l':
flags |= SENDDIR_LONG; flags &= ~SENDDIR_MULTICOLUMN;
break;
case 'C':
flags |= SENDDIR_MULTICOLUMN; flags &= ~SENDDIR_LONG;
break;
case 'd': flags |= SENDDIR_SIMPLEDIRS; break;
case 'g': /* ignored */ break;
case 'n': flags |= SENDDIR_NUMIDS; break;
case 'p': case 'F': flags |= SENDDIR_FILETYPE; break;
case 'a': flags |= SENDDIR_ALL; break;
case 'L': flags |= SENDDIR_FOLLOWLINKS; break;
case 'f': flags |= SENDDIR_SORTNONE; break;
case 'r': flags |= SENDDIR_SORTREVERSE; break;
case 't': flags |= SENDDIR_SORTMTIME; break;
case 'S': flags |= SENDDIR_SORTSIZE; break;
case 'R': flags |= SENDDIR_RECURSE; break;
}
}
getcwd(path, 1000);
if (rc < -1) {
fprintf(stderr, "argument error: %s %s",
poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
poptStrerror(rc));
} else {
idInit();
argv = poptGetArgs(optCon);
if (argv) {
while (*argv) {
if (argv[0][0] == '/')
listFiles("", *argv, flags);
else
listFiles(path, *argv, flags);
argv++;
}
} else {
listFiles(path, "", flags);
}
}
return 0;
}
int gunzipCommand(int argc, char ** argv) {
gzFile f;
char buf[16384];
int i;
f = gzdopen(0, "r");
while ((i = gzread(f, buf, sizeof(buf))) > 0)
write(1, buf, i);
gzclose(f);
return 0;
}