diff options
author | Erik Troan <ewt@redhat.com> | 1999-08-07 16:16:29 +0000 |
---|---|---|
committer | Erik Troan <ewt@redhat.com> | 1999-08-07 16:16:29 +0000 |
commit | a7d5886e5420bd7b12ac7203ada5886330354de2 (patch) | |
tree | 24d6535f9d8d846a8cbf1b0b96f4615fd69200c6 /collage | |
parent | bf6e9064b9f5ce40b78e61a40f9b24b48a962e37 (diff) | |
download | anaconda-a7d5886e5420bd7b12ac7203ada5886330354de2.tar.gz anaconda-a7d5886e5420bd7b12ac7203ada5886330354de2.tar.xz anaconda-a7d5886e5420bd7b12ac7203ada5886330354de2.zip |
*** empty log message ***
Diffstat (limited to 'collage')
-rw-r--r-- | collage/Makefile | 7 | ||||
-rw-r--r-- | collage/collage.c | 44 | ||||
-rw-r--r-- | collage/commands.c | 386 | ||||
-rw-r--r-- | collage/commands.h | 16 | ||||
-rw-r--r-- | collage/idmap.c | 146 | ||||
-rw-r--r-- | collage/idmap.h | 7 | ||||
-rw-r--r-- | collage/ls.c | 499 | ||||
-rw-r--r-- | collage/ls.h | 20 | ||||
-rwxr-xr-x | collage/mkcollagelinks | 6 |
9 files changed, 1131 insertions, 0 deletions
diff --git a/collage/Makefile b/collage/Makefile new file mode 100644 index 000000000..d1224990c --- /dev/null +++ b/collage/Makefile @@ -0,0 +1,7 @@ +CFLAGS = -Wall -g +LDFLAGS = -g +LOADLIBES = -L../isys -lpopt -lz -lisys -lresolv -lrpm + +all: collage + +collage: collage.o commands.o idmap.o ls.o diff --git a/collage/collage.c b/collage/collage.c new file mode 100644 index 000000000..ddc4ae28e --- /dev/null +++ b/collage/collage.c @@ -0,0 +1,44 @@ +#include <stdio.h> +#include <string.h> + +#include "commands.h" + +struct commandTableEntry { + char * name; + int (*fn)(int argc, char ** argv); +}; + +struct commandTableEntry commandTable[] = { + { "umount", umountCommand }, + { "mount", mountCommand }, + { "mkdir", mkdirCommand }, + { "mknod", mknodCommand }, + { "cat", catCommand }, + { "ls", lsCommand }, + { "ln", lnCommand }, + { "rm", rmCommand }, + { "chmod", chmodCommand }, + { "lsmod", lsmodCommand }, + { "uncpio", uncpioCommand }, + { NULL, NULL } +}; + +int main (int argc, char ** argv) { + int len = strlen(argv[0]); + struct commandTableEntry * cmd; + + for (cmd = commandTable; cmd->name; cmd++) { + if (!strcmp(argv[0] + len - strlen(cmd->name), cmd->name)) + break; + } + + if (cmd->name) + return cmd->fn(argc, argv); + + printf("collage may be run as:\n"); + for (cmd = commandTable; cmd->name; cmd++) + printf("\t%s\n", cmd->name); + + return 1; +} + diff --git a/collage/commands.c b/collage/commands.c new file mode 100644 index 000000000..5dde54a64 --- /dev/null +++ b/collage/commands.c @@ -0,0 +1,386 @@ +#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 <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" + +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; + + 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; + + 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 (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; +} + +int uncpioCommand(int argc, char ** argv) { + int rc; + char * fail; + + if (argc != 1) { + fprintf(stderr, "uncpio reads from stdin"); + return 1; + } + + rc = cpioInstallArchive(gzdopen(0, "r"), NULL, 0, NULL, NULL, &fail); + return (rc != 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; +} diff --git a/collage/commands.h b/collage/commands.h new file mode 100644 index 000000000..0b9172b0e --- /dev/null +++ b/collage/commands.h @@ -0,0 +1,16 @@ +#ifndef H_MOUNT +#define H_MOUNT + +int catCommand(int argc, char ** argv); +int chmodCommand(int argc, char ** argv); +int lsmodCommand(int argc, char ** argv); +int mkdirCommand(int argc, char ** argv); +int mknodCommand(int argc, char ** argv); +int mountCommand(int argc, char ** argv); +int rmCommand(int argc, char ** argv); +int lnCommand(int argc, char ** argv); +int lsCommand(int argc, char ** argv); +int umountCommand(int argc, char ** argv); +int uncpioCommand(int argc, char ** argv); + +#endif diff --git a/collage/idmap.c b/collage/idmap.c new file mode 100644 index 000000000..bede4457b --- /dev/null +++ b/collage/idmap.c @@ -0,0 +1,146 @@ +#include <grp.h> +#include <pwd.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#include "idmap.h" + +struct idMap_s { + struct idElement * byId; + int numEntries; +}; + +typedef struct idMap_s * idMap; + +struct idElement { + long int id; + char * name; +}; + +typedef void * (*iterFn)(void); +typedef int (*infoFn)(void * item, struct idElement * el); + +static idMap uidMap = NULL; +static idMap gidMap = NULL; + +static int idCmp(const void * a, const void * b) { + const struct idElement * one = a; + const struct idElement * two = b; + + if (one->id < two->id) + return -1; + else if (one->id > two->id) + return 1; + + return 0; +} + +static idMap readmap(iterFn fn, infoFn info) { + idMap map; + int alloced; + void * res; + struct idElement * newEntries; + + map = malloc(sizeof(*map)); + if (!map) { + return NULL; + } + + alloced = 5; + map->byId = malloc(sizeof(*map->byId) * alloced); + if (!map->byId) { + free(map); + return NULL; + } + map->numEntries = 0; + + while ((res = fn())) { + if (map->numEntries == alloced) { + alloced += 5; + newEntries = realloc(map->byId, + sizeof(*map->byId) * alloced); + if (!newEntries) { + /* FIXME: this doesn't free the id names */ + free(map->byId); + free(map); + return NULL; + } + + map->byId = newEntries; + } + + if (info(res, map->byId + map->numEntries++)) { + /* FIXME: this doesn't free the id names */ + free(map->byId); + free(map); + return NULL; + } + } + + map->byId = realloc(map->byId, + sizeof(*map->byId) * map->numEntries); + + qsort(map->byId, map->numEntries, sizeof(*map->byId), idCmp); + + return map; +} + +static int pwInfo(struct passwd * pw, struct idElement * el) { + el->id = pw->pw_uid; + el->name = strdup(pw->pw_name); + + return el->name == NULL; +} + +static int grInfo(struct group * gr, struct idElement * el) { + el->id = gr->gr_gid; + el->name = strdup(gr->gr_name); + + return el->name == NULL; +} + +idMap readUIDmap(void) { + idMap result; + + result = readmap((void *) getpwent, (void *) pwInfo); + endpwent(); + + return result; +} + +idMap readGIDmap(void) { + idMap result; + + result = readmap((void *) getgrent, (void *) grInfo); + endgrent(); + + return result; +} + +char * idSearchByUid(long int id) { + struct idElement el = { id, NULL }; + struct idElement * match; + + match = bsearch(&el, uidMap->byId, uidMap->numEntries, + sizeof(*uidMap->byId), idCmp); + + if (match) return match->name; else return NULL; +} + +char * idSearchByGid(long int id) { + struct idElement el = { id, NULL }; + struct idElement * match; + + match = bsearch(&el, gidMap->byId, gidMap->numEntries, + sizeof(*gidMap->byId), idCmp); + + if (match) return match->name; else return NULL; +} + +int idInit(void) { + if (!(uidMap = readUIDmap())) return 1; + if (!(gidMap = readGIDmap())) return 1; + + return 0; +} diff --git a/collage/idmap.h b/collage/idmap.h new file mode 100644 index 000000000..45e9f9d8b --- /dev/null +++ b/collage/idmap.h @@ -0,0 +1,7 @@ +#ifndef H_IDMAP + +char * idSearchByUid(long int id); +char * idSearchByGid(long int id); +int idInit(void); + +#endif diff --git a/collage/ls.c b/collage/ls.c new file mode 100644 index 000000000..ae827cd51 --- /dev/null +++ b/collage/ls.c @@ -0,0 +1,499 @@ +#include <errno.h> +#include <dirent.h> +#include <fcntl.h> +#include <glob.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/sysmacros.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> + +#include "idmap.h" +#include "ls.h" + +struct fileInfo { + char * name; + struct stat sb; +}; + +static void permsString(int mode, char * perms); +static int statFile(char * dir, char * fn, int flags, struct stat * sbp); +static int implicitListFile(int sock, char * path, + char * fn, struct stat * sbp, int flags); +static int nameCmp(const void * a, const void * b); +static int sizeCmp(const void * a, const void * b); +static int mtimeCmp(const void * a, const void * b); +static void multicolumnListing(int sock, struct fileInfo * files, + int filesCount, int flags); +static int sendDirContents(int sock, char * path, + char * fn, int flags); + +static void permsString(int mode, char * perms) { + strcpy(perms, "----------"); + + if (mode & S_ISVTX) perms[9] = 't'; + + if (mode & S_IRUSR) perms[1] = 'r'; + if (mode & S_IWUSR) perms[2] = 'w'; + if (mode & S_IXUSR) perms[3] = 'x'; + + if (mode & S_IRGRP) perms[4] = 'r'; + if (mode & S_IWGRP) perms[5] = 'w'; + if (mode & S_IXGRP) perms[6] = 'x'; + + if (mode & S_IROTH) perms[7] = 'r'; + if (mode & S_IWOTH) perms[8] = 'w'; + if (mode & S_IXOTH) perms[9] = 'x'; + + if (mode & S_ISUID) { + if (mode & S_IXUSR) + perms[3] = 's'; + else + perms[3] = 'S'; + } + + if (mode & S_ISGID) { + if (mode & S_IXGRP) + perms[6] = 's'; + else + perms[6] = 'S'; + } + + if (S_ISDIR(mode)) + perms[0] = 'd'; + else if (S_ISLNK(mode)) { + perms[0] = 'l'; + } + else if (S_ISFIFO(mode)) + perms[0] = 'p'; + else if (S_ISSOCK(mode)) + perms[0] = 'l'; + else if (S_ISCHR(mode)) { + perms[0] = 'c'; + } else if (S_ISBLK(mode)) { + perms[0] = 'b'; + } +} + +static int statFile(char * dir, char * fn, int flags, struct stat * sbp) { + char * filename; + + if (dir) { + filename = alloca(strlen(dir) + strlen(fn) + 2); + sprintf(filename, "%s/%s", dir, fn); + } else + filename = fn; + + if (!(flags & SENDDIR_FOLLOWLINKS) || stat(filename, sbp)) { + if (lstat(filename, sbp)) { + return 1; + } + } + + return 0; +} + +char * fileStatStr(char * dir, char * fn, struct stat * sbp, int flags) { + char * info; + char perms[12]; + char sizefield[15]; + char ownerfield[9], groupfield[9]; + char timefield[20] = ""; + char * linkto; + char * namefield = fn; + time_t themtime; + time_t currenttime; + char * name; + int thisYear = 0; + int thisMonth = 0; + struct tm * tstruct; + int i; + char * filename; + + if (!sbp) { + sbp = alloca(sizeof(*sbp)); + if (statFile(dir, fn, flags, sbp)) + return NULL; + } + + permsString(sbp->st_mode, perms); + + currenttime = time(NULL); + tstruct = localtime(¤ttime); + thisYear = tstruct->tm_year; + thisMonth = tstruct->tm_mon; + + name = idSearchByUid(sbp->st_uid); + if (name) + sprintf(ownerfield, "%-8s", name); + else + sprintf(ownerfield, "%-8d", (int) sbp->st_uid); + + name = idSearchByGid(sbp->st_gid); + if (name) + sprintf(groupfield, "%-8s", name); + else + sprintf(groupfield, "%-8d", (int) sbp->st_gid); + + if (S_ISLNK(sbp->st_mode)) { + /* they don't reall want to see "opt -> /usr/opt@" */ + + linkto = alloca(1024); + strcpy(linkto, "(link)"); + + filename = alloca(strlen(dir) + strlen(fn) + 2); + sprintf(filename, "%s/%s", dir, fn); + + i = readlink(filename, linkto, 1023); + if (i < 1) + strcpy(linkto, "(cannot read symlink)"); + else + linkto[i] = 0; + + namefield = alloca(strlen(fn) + strlen(linkto) + 10); + sprintf(namefield, "%s -> %s", fn, linkto); + + sprintf(sizefield, "%d", i); + } else if (S_ISCHR(sbp->st_mode)) { + perms[0] = 'c'; + sprintf(sizefield, "%3d, %3d", major(sbp->st_rdev), + minor(sbp->st_rdev)); + } else if (S_ISBLK(sbp->st_mode)) { + perms[0] = 'b'; + sprintf(sizefield, "%3d, %3d", major(sbp->st_rdev), + minor(sbp->st_rdev)); + } else { + sprintf(sizefield, "%8ld", sbp->st_size); + } + + /* this is important if sizeof(int_32) ! sizeof(time_t) */ + themtime = sbp->st_mtime; + tstruct = localtime(&themtime); + + if (tstruct->tm_year == thisYear || + ((tstruct->tm_year + 1) == thisYear && tstruct->tm_mon > thisMonth)) + strftime(timefield, sizeof(timefield) - 1, "%b %d %H:%M", tstruct); + else + strftime(timefield, sizeof(timefield) - 1, "%b %d %Y", tstruct); + + info = malloc(strlen(namefield) + strlen(timefield) + 85); + + sprintf(info, "%s %3d %8s %8s %8s %s %s", perms, (int) sbp->st_nlink, + ownerfield, groupfield, sizefield, timefield, namefield); + + return info; +} + +/* Like listFiles(), but don't explode directories or wildcards */ +static int implicitListFile(int sock, char * path, + char * fn, struct stat * sbp, int flags) { + char * info; + char fileType; + + if (flags & SENDDIR_LONG) { + info = fileStatStr(path, fn, sbp, flags); + if (info) { + write(sock, info, strlen(info)); + free(info); + } + } else { + write(sock, fn, strlen(fn)); + } + + if (flags & SENDDIR_FILETYPE) { + if (S_ISSOCK(sbp->st_mode)) { + fileType = '='; + } else if (S_ISFIFO(sbp->st_mode)) { + fileType = '|'; + } else if (S_ISDIR(sbp->st_mode)) { + fileType = '/'; + } else if (S_IRWXO & sbp->st_mode) { + fileType = '*'; + } else { + fileType = '\0'; + } + + if (fileType) write(sock, &fileType, 1); + } + + write(sock, "\n", 1); + + return 0; +} + +static int nameCmp(const void * a, const void * b) { + const struct fileInfo * one = a; + const struct fileInfo * two = b; + + return (strcmp(one->name, two->name)); +} + +static int sizeCmp(const void * a, const void * b) { + const struct fileInfo * one = a; + const struct fileInfo * two = b; + + /* list newer files first */ + + if (one->sb.st_size < two->sb.st_size) + return 1; + else if (one->sb.st_size > two->sb.st_size) + return -1; + + return 0; +} + +static int mtimeCmp(const void * a, const void * b) { + const struct fileInfo * one = a; + const struct fileInfo * two = b; + + if (one->sb.st_mtime < two->sb.st_mtime) + return -1; + else if (one->sb.st_mtime > two->sb.st_mtime) + return 1; + + return 0; +} + +static void multicolumnListing(int sock, struct fileInfo * files, + int filesCount, int flags) { + int i, j, k; + int maxWidth = 0; + char format[20]; + char * fileType = " "; + char * buf, * name = NULL; + int rows, columns; + + if (!filesCount) return; + + for (i = 0; i < filesCount; i++) { + j = strlen(files[i].name); + if (j > maxWidth) maxWidth = j; + } + + maxWidth += 3; + buf = alloca(maxWidth + 1); + + if (flags & SENDDIR_FILETYPE) + name = alloca(maxWidth); + + columns = 80 / maxWidth; + if (columns == 0) columns = 1; + + sprintf(format, "%%-%ds", 80 / columns); + + rows = filesCount / columns; + if (filesCount % columns) rows++; + + for (i = 0; i < rows; i++) { + j = i; + while (j < filesCount) { + if (flags & SENDDIR_FILETYPE) { + if (S_ISDIR(files[j].sb.st_mode)) + fileType = "/"; + else if (S_ISSOCK(files[j].sb.st_mode)) + fileType = "="; + else if (S_ISFIFO(files[j].sb.st_mode)) + fileType = "|"; + else if (S_ISLNK(files[j].sb.st_mode)) + fileType = "@"; + else + fileType = " "; + + strcpy(name, files[j].name); + strcat(name, fileType); + } else + name = files[j].name; + + if ((j + rows) < filesCount) + k = sprintf(buf, format, name); + else + k = sprintf(buf, "%s", name); + + j += rows; + + write(sock, buf, k); + } + + write(sock, "\n", 1); + } +} + +static int sendDirContents(int sock, char * path, char * fn, int flags) { + struct dirent * ent; + int start, direction; + DIR * dir; + int filesAlloced, filesCount, i; + struct fileInfo * files, * newfiles; + int failed = 0; + int total = 0; + char buf[20]; + char * fullpath; + char * subdir; + + filesAlloced = 15; + filesCount = 0; + files = malloc(sizeof(*files) * filesAlloced); + + if (fn) { + fullpath = alloca(strlen(path) + strlen(fn) + 2); + sprintf(fullpath, "%s/%s", path, fn); + } else + fullpath = path; + + dir = opendir(fullpath); + + do { + errno = 0; + ent = readdir(dir); + if (errno) { + fprintf(stderr, "Error reading directory entry: %s\n", + strerror(errno)); + failed = 1; + } else if (ent && (*ent->d_name != '.' || (flags & SENDDIR_ALL))) { + if (filesCount == filesAlloced) { + filesAlloced += 15; + newfiles = realloc(files, sizeof(*files) * filesAlloced); + files = newfiles; + } + + if (!failed) { + files[filesCount].name = strdup(ent->d_name); + + if (statFile(fullpath, files[filesCount].name, flags, + &files[filesCount].sb)) { + fprintf(stderr, "stat of %s failed: %s\n" , + files[filesCount].name, strerror(errno)); + failed = 1; + } else { + total += files[filesCount].sb.st_size / + 1024; + } + + filesCount++; + } + } + } while (ent && !failed); + + closedir(dir); + + if (!failed) { + if (flags & SENDDIR_SORTMTIME) { + qsort(files, filesCount, sizeof(*files), mtimeCmp); + } else if (flags & SENDDIR_SORTSIZE) { + qsort(files, filesCount, sizeof(*files), sizeCmp); + } else if (!(flags & SENDDIR_SORTNONE)) { + qsort(files, filesCount, sizeof(*files), nameCmp); + } + + if (flags & SENDDIR_SORTREVERSE) { + direction = -1; + start = filesCount - 1; + } else { + direction = 1; + start = 0; + } + + if (fn) { + write(sock, fn, strlen(fn)); + write(sock, ":\n", 2); + } + + if (flags & SENDDIR_MULTICOLUMN) { + multicolumnListing(sock, files, filesCount, flags); + } else { + if (flags & SENDDIR_LONG) { + i = sprintf(buf, "total %d\n", total); + write(sock, buf, i); + } + + for (i = start; i >= 0 && i < filesCount; i += direction) { + implicitListFile(sock, fullpath, files[i].name, + &files[i].sb, flags); + } + } + + if (flags & SENDDIR_RECURSE) { + for (i = start; i >= 0 && i < filesCount && !failed; + i += direction) { + if (S_ISDIR(files[i].sb.st_mode) && + strcmp(files[i].name, ".") && + strcmp(files[i].name, "..")) { + write(sock, "\n", 1); + + if (fn) { + subdir = malloc(strlen(fn) + strlen(files[i].name) + 2); + sprintf(subdir, "%s/%s", fn, files[i].name); + } else { + subdir = files[i].name; + } + + failed = sendDirContents(sock, path, subdir, flags); + + if (fn) free(subdir); + } + } + } + } + + for (i = 0; i < filesCount; i++) { + free(files[i].name); + } + free(files); + + return failed; +} + +/* implements 'ls' */ +void listFiles(char * path, char * fn, int flags) { + struct stat sb; + int i, rc; + char * filename, * this; + int isExplicit = 1; + glob_t matches; + int failed = 0; + + if (!fn) { + fn = "."; + isExplicit = 0; + } + + filename = malloc(strlen(fn) + strlen(path) + 2); + sprintf(filename, "%s/%s", path, fn); + + rc = glob(filename, GLOB_NOSORT, NULL, &matches); + if (rc == GLOB_NOMATCH) { + fprintf(stderr, "File not found.\n"); + return; + } + free(filename); + + for (i = 0; i < matches.gl_pathc && !failed; i++) { + this = matches.gl_pathv[i] + strlen(path); + if (*this) + this++; + else + this = "."; + + if (!statFile(path, this, flags, &sb)) { + if (S_ISDIR(sb.st_mode) && !(flags & SENDDIR_SIMPLEDIRS)) { + filename = malloc(strlen(path) + strlen(this) + 2); + sprintf(filename, "%s/%s", path, this); + + failed = sendDirContents(1, filename, NULL, flags); + free(filename); + } else { + implicitListFile(1, path, this, &sb, flags); + } + } else { + write(1, matches.gl_pathv[i], strlen(matches.gl_pathv[i])); + write(1, ": file not found.\n", 18); + } + } + + globfree(&matches); + + close(1); +} diff --git a/collage/ls.h b/collage/ls.h new file mode 100644 index 000000000..fed3ac5b2 --- /dev/null +++ b/collage/ls.h @@ -0,0 +1,20 @@ +#ifndef H_LS +#define H_LS + +#define SENDDIR_ALL (1 << 0) +#define SENDDIR_LONG (1 << 1) +#define SENDDIR_RECURSE (1 << 2) +#define SENDDIR_SIMPLEDIRS (1 << 3) +#define SENDDIR_NUMIDS (1 << 4) +#define SENDDIR_FILETYPE (1 << 5) +#define SENDDIR_FOLLOWLINKS (1 << 6) +#define SENDDIR_SORTNONE (1 << 7) +#define SENDDIR_SORTMTIME (1 << 8) +#define SENDDIR_SORTSIZE (1 << 9) +#define SENDDIR_SORTREVERSE (1 << 9) +#define SENDDIR_MULTICOLUMN (1 << 10) + +char * fileStatStr(char * dir, char * fn, struct stat * sbp, int flags); +void listFiles(char * path, char * fn, int flags); + +#endif diff --git a/collage/mkcollagelinks b/collage/mkcollagelinks new file mode 100755 index 000000000..4da43d3fc --- /dev/null +++ b/collage/mkcollagelinks @@ -0,0 +1,6 @@ +#!/bin/bash + +read line +while read line; do + ln -sf $1 $line +done |