From cc8ed39b240180b58810784f844e253263594ac3 Mon Sep 17 00:00:00 2001 From: Eric Andersen Date: Tue, 5 Oct 1999 16:24:54 +0000 Subject: Initial revision --- coreutils/cat.c | 54 ++++++ coreutils/chgrp.c | 89 +++++++++ coreutils/chmod.c | 163 ++++++++++++++++ coreutils/chown.c | 63 +++++++ coreutils/chroot.c | 32 ++++ coreutils/cp.c | 89 +++++++++ coreutils/date.c | 305 ++++++++++++++++++++++++++++++ coreutils/dd.c | 307 ++++++++++++++++++++++++++++++ coreutils/df.c | 103 ++++++++++ coreutils/length.c | 13 ++ coreutils/ln.c | 52 +++++ coreutils/ls.c | 542 +++++++++++++++++++++++++++++++++++++++++++++++++++++ coreutils/mkdir.c | 58 ++++++ coreutils/mknod.c | 52 +++++ coreutils/mv.c | 38 ++++ coreutils/printf.c | 531 +++++++++++++++++++++++++++++++++++++++++++++++++++ coreutils/pwd.c | 18 ++ coreutils/rm.c | 30 +++ coreutils/rmdir.c | 17 ++ coreutils/sleep.c | 15 ++ coreutils/sync.c | 11 ++ coreutils/touch.c | 20 ++ 22 files changed, 2602 insertions(+) create mode 100644 coreutils/cat.c create mode 100644 coreutils/chgrp.c create mode 100644 coreutils/chmod.c create mode 100644 coreutils/chown.c create mode 100644 coreutils/chroot.c create mode 100644 coreutils/cp.c create mode 100644 coreutils/date.c create mode 100644 coreutils/dd.c create mode 100644 coreutils/df.c create mode 100644 coreutils/length.c create mode 100644 coreutils/ln.c create mode 100644 coreutils/ls.c create mode 100644 coreutils/mkdir.c create mode 100644 coreutils/mknod.c create mode 100644 coreutils/mv.c create mode 100644 coreutils/printf.c create mode 100644 coreutils/pwd.c create mode 100644 coreutils/rm.c create mode 100644 coreutils/rmdir.c create mode 100644 coreutils/sleep.c create mode 100644 coreutils/sync.c create mode 100644 coreutils/touch.c (limited to 'coreutils') diff --git a/coreutils/cat.c b/coreutils/cat.c new file mode 100644 index 000000000..12faf55ab --- /dev/null +++ b/coreutils/cat.c @@ -0,0 +1,54 @@ +/* + * Mini Cat implementation for busybox + * + * Copyright (C) 1998 by Erik Andersen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "internal.h" +#include + +const char cat_usage[] = "[file ...]"; + +extern int cat_more_main(int argc, char **argv) +{ + int c; + FILE *file = stdin; + + if (argc < 2) { + fprintf(stderr, "Usage: %s %s", *argv, cat_usage); + return 1; + } + argc--; + argv++; + + while (argc-- > 0) { + file = fopen(*argv, "r"); + if (file == NULL) { + name_and_error(*argv); + return 1; + } + while ((c = getc(file)) != EOF) + putc(c, stdout); + fclose(file); + fflush(stdout); + + argc--; + argv++; + } + return 0; +} diff --git a/coreutils/chgrp.c b/coreutils/chgrp.c new file mode 100644 index 000000000..038c665dd --- /dev/null +++ b/coreutils/chgrp.c @@ -0,0 +1,89 @@ +/* + * Mini chgrp implementation for busybox + * + * Copyright (C) 1998 by Erik Andersen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "internal.h" +#include +#include + +const char chgrp_usage[] = "chgrp [OPTION]... GROUP FILE...\n" + "Change the group membership of each FILE to GROUP.\n" + "\n\tOptions:\n" "\t-R\tchange files and directories recursively\n"; + +int chgrp_main(int argc, char **argv) +{ + const char *cp; + int gid; + struct group *grp; + struct stat statBuf; + + if (argc < 2) { + fprintf(stderr, "Usage: %s %s", *argv, chgrp_usage); + return 1; + } + argc--; + argv++; + + cp = argv[1]; + if (isDecimal(*cp)) { + gid = 0; + while (isDecimal(*cp)) + gid = gid * 10 + (*cp++ - '0'); + if (*cp) { + fprintf(stderr, "Bad gid value\n"); + return -1; + } + } else { + grp = getgrnam(cp); + if (grp == NULL) { + fprintf(stderr, "Unknown group name\n"); + return -1; + } + gid = grp->gr_gid; + } + argc--; + argv++; + while (argc-- > 1) { + argv++; + if ((stat(*argv, &statBuf) < 0) || + (chown(*argv, statBuf.st_uid, gid) < 0)) { + perror(*argv); + } + } + return 1; +} + + + + + + + + + +#if 0 +int +recursive(const char *fileName, BOOL followLinks, const char *pattern, + int (*fileAction) (const char *fileName, + const struct stat * statbuf), + int (*dirAction) (const char *fileName, + const struct stat * statbuf)) + +#endif diff --git a/coreutils/chmod.c b/coreutils/chmod.c new file mode 100644 index 000000000..225c92d10 --- /dev/null +++ b/coreutils/chmod.c @@ -0,0 +1,163 @@ +#include +#include +#include +#include +#include "internal.h" + +const char chmod_usage[] = "chmod [-R] mode file [file ...]\n" +"\nmode may be an octal integer representing the bit pattern for the\n" +"\tnew mode, or a symbolic value matching the pattern\n" +"\t[ugoa]{+|-|=}[rwxst] .\n" +"\t\tu:\tUser\n" +"\t\tg:\tGroup\n" +"\t\to:\tOthers\n" +"\t\ta:\tAll\n" +"\n" +"\n+:\tAdd privilege\n" +"\n-:\tRemove privilege\n" +"\n=:\tSet privilege\n" +"\n" +"\t\tr:\tRead\n" +"\t\tw:\tWrite\n" +"\t\tx:\tExecute\n" +"\t\ts:\tSet User ID\n" +"\t\tt:\t\"Sticky\" Text\n" +"\n" +"\tModes may be concatenated, as in \"u=rwx,g=rx,o=rx,-t,-s\n" +"\n" +"\t-R:\tRecursively change the mode of all files and directories\n" +"\t\tunder the argument directory."; + +int +parse_mode( + const char * s +,mode_t * or +,mode_t * and +,int * group_execute) +{ + /* [ugoa]{+|-|=}[rwxstl] */ + mode_t mode = 0; + mode_t groups = S_ISVTX; + char type; + char c; + + do { + for ( ; ; ) { + switch ( c = *s++ ) { + case '\0': + return -1; + case 'u': + groups |= S_ISUID|S_IRWXU; + continue; + case 'g': + groups |= S_ISGID|S_IRWXG; + continue; + case 'o': + groups |= S_IRWXO; + continue; + case 'a': + groups |= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO; + continue; + case '+': + case '=': + case '-': + type = c; + if ( groups == S_ISVTX ) /* The default is "all" */ + groups |= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO; + break; + default: + if ( c >= '0' && c <= '7' && mode == 0 && groups == S_ISVTX ) { + *and = 0; + *or = strtol(--s, 0, 010); + return 0; + } + else + return -1; + } + break; + } + + while ( (c = *s++) != '\0' ) { + switch ( c ) { + case ',': + break; + case 'r': + mode |= S_IRUSR|S_IRGRP|S_IROTH; + continue; + case 'w': + mode |= S_IWUSR|S_IWGRP|S_IWOTH; + continue; + case 'x': + mode |= S_IXUSR|S_IXGRP|S_IXOTH; + continue; + case 's': + if ( group_execute != 0 && (groups & S_IRWXG) ) { + if ( *group_execute < 0 ) + return -1; + if ( type != '-' ) { + mode |= S_IXGRP; + *group_execute = 1; + } + } + mode |= S_ISUID|S_ISGID; + continue; + case 'l': + if ( *group_execute > 0 ) + return -1; + if ( type != '-' ) { + *and &= ~S_IXGRP; + *group_execute = -1; + } + mode |= S_ISGID; + groups |= S_ISGID; + continue; + case 't': + mode |= S_ISVTX; + continue; + default: + return -1; + } + break; + } + switch ( type ) { + case '=': + *and &= ~(groups); + /* fall through */ + case '+': + *or |= mode & groups; + break; + case '-': + *and &= ~(mode & groups); + *or &= *and; + break; + } + } while ( c == ',' ); + return 0; +} + +extern int +chmod_main(struct FileInfo * i, int argc, char * * argv) +{ + i->andWithMode = S_ISVTX|S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO; + i->orWithMode = 0; + + while ( argc >= 3 ) { + if ( parse_mode(argv[1], &i->orWithMode, &i->andWithMode, 0) + == 0 ) { + argc--; + argv++; + } + else if ( strcmp(argv[1], "-R") == 0 ) { + i->recursive = 1; + argc--; + argv++; + } + else + break; + } + + i->changeMode = 1; + i->complainInPostProcess = 1; + + return monadic_main(i, argc, argv); +} diff --git a/coreutils/chown.c b/coreutils/chown.c new file mode 100644 index 000000000..a611f92f1 --- /dev/null +++ b/coreutils/chown.c @@ -0,0 +1,63 @@ +#include "internal.h" +#include +#include +#include +#include + +const char chown_usage[] = "chown [-R] user-name file [file ...]\n" +"\n\tThe group list is kept in the file /etc/groups.\n\n" +"\t-R:\tRecursively change the mode of all files and directories\n" +"\t\tunder the argument directory."; + +int +parse_user_name(const char * s, struct FileInfo * i) +{ + struct passwd * p; + char * dot = strchr(s, '.'); + + if (! dot ) + dot = strchr(s, ':'); + + if ( dot ) + *dot = '\0'; + + if ( (p = getpwnam(s)) == 0 ) { + fprintf(stderr, "%s: no such user.\n", s); + return 1; + } + i->userID = p->pw_uid; + + if ( dot ) { + struct group * g = getgrnam(++dot); + if ( g == 0 ) { + fprintf(stderr, "%s: no such group.\n", dot); + return 1; + } + i->groupID = g->gr_gid; + i->changeGroupID = 1; + } + return 0; +} + +extern int +chown_main(struct FileInfo * i, int argc, char * * argv) +{ + int status; + + while ( argc >= 3 && strcmp("-R", argv[1]) == 0 ) { + i->recursive = 1; + argc--; + argv++; + } + + if ( (status = parse_user_name(argv[1], i)) != 0 ) + return status; + + argv++; + argc--; + + i->changeUserID = 1; + i->complainInPostProcess = 1; + + return monadic_main(i, argc, argv); +} diff --git a/coreutils/chroot.c b/coreutils/chroot.c new file mode 100644 index 000000000..ca0bfcf3f --- /dev/null +++ b/coreutils/chroot.c @@ -0,0 +1,32 @@ +#include "internal.h" +#include +#include + + +const char chroot_usage[] = "chroot directory [command]\n" + "Run a command with special root directory.\n"; + +extern int +chroot_main (struct FileInfo *i, int argc, char **argv) +{ + char *prog; + + if (chroot (argv[1])) + { + name_and_error ("cannot chroot to that directory"); + return 1; + } + if (argc > 2) + { + execvp (argv[2], argv + 2); + } + else + { + prog = getenv ("SHELL"); + if (!prog) + prog = "/bin/sh"; + execlp (prog, prog, NULL); + } + name_and_error ("cannot exec"); + return 1; +} diff --git a/coreutils/cp.c b/coreutils/cp.c new file mode 100644 index 000000000..078a57c56 --- /dev/null +++ b/coreutils/cp.c @@ -0,0 +1,89 @@ +#include "internal.h" +#include +#include +#include +#include +#include + +const char cp_usage[] = "cp [-r] source-file destination-file\n" +"\t\tcp [-r] source-file [source-file ...] destination-directory\n" +"\n" +"\tCopy the source files to the destination.\n" +"\n" +"\t-r:\tRecursively copy all files and directories\n" +"\t\tunder the argument directory."; + +extern int +cp_fn(const struct FileInfo * i) +{ + int sourceFd; + int destinationFd; + const char * destination = i->destination; + struct stat destination_stat; + int status; + char buf[8192]; + char d[PATH_MAX]; + + if ( (i->stat.st_mode & S_IFMT) == S_IFDIR ) { + if ( mkdir(destination, i->stat.st_mode & ~S_IFMT) + != 0 && errno != EEXIST ) { + name_and_error(destination); + return 1; + } + return 0; + } + if ( (sourceFd = open(i->source, O_RDONLY)) < 0 ) { + name_and_error(i->source); + return 1; + } + if ( stat(destination, &destination_stat) == 0 ) { + if ( i->stat.st_ino == destination_stat.st_ino + && i->stat.st_dev == destination_stat.st_dev ) { + fprintf(stderr + ,"copy of %s to %s would copy file to itself.\n" + ,i->source + ,destination); + close(sourceFd); + return 1; + } + } + /* + * If the destination is a directory, create a file within it. + */ + if ( (destination_stat.st_mode & S_IFMT) == S_IFDIR ) { + destination = join_paths( + d + ,i->destination + ,&i->source[i->directoryLength]); + + if ( stat(destination, &destination_stat) == 0 ) { + if ( i->stat.st_ino == destination_stat.st_ino + && i->stat.st_dev == destination_stat.st_dev ) { + fprintf(stderr + ,"copy of %s to %s would copy file to itself.\n" + ,i->source + ,destination); + close(sourceFd); + return 1; + } + } + } + + destinationFd = creat(destination, i->stat.st_mode & 07777); + + while ( (status = read(sourceFd, buf, sizeof(buf))) > 0 ) { + if ( write(destinationFd, buf, status) != status ) { + name_and_error(destination); + close(sourceFd); + close(destinationFd); + return 1; + } + } + close(sourceFd); + close(destinationFd); + if ( status < 0 ) { + name_and_error(i->source); + return 1; + } + return 0; +} diff --git a/coreutils/date.c b/coreutils/date.c new file mode 100644 index 000000000..a52a9a4a8 --- /dev/null +++ b/coreutils/date.c @@ -0,0 +1,305 @@ +#include "internal.h" +#include +#include +#include +#include +#include +#include +#include + + +/* This 'date' command supports only 2 time setting formats, + all the GNU strftime stuff (its in libc, lets use it), + setting time using UTC and displaying int, as well as + an RFC 822 complient date output for shell scripting + mail commands */ + +const char date_usage[] = "date [-uR] [+FORMAT|+%f] [ [-s|-d] MMDDhhmm[[CC]YY]\n | [[[[CCYY.]MM.DD-]hh:mm[:ss]]]] ]"; + +static struct option const long_options[] = +{ + {"date", required_argument, NULL, 'd'}, + /* {"rfc-822", no_argument, NULL, 'R'}, + {"set", required_argument, NULL, 's'}, + {"uct", no_argument, NULL, 'u'}, + {"utc", no_argument, NULL, 'u'}, + {"universal", no_argument, NULL, 'u'}, */ + {NULL, 0, NULL, 0} +}; + + + +/* Input parsing code is always bulky - used heavy duty libc stuff as + much as possible, missed out a lot of bounds checking */ + +/* Default input handling to save suprising some people */ + +struct tm * +date_conv_time(struct tm *tm_time, const char *t_string) { + int nr; + + nr = sscanf(t_string, "%2d%2d%2d%2d%d", + &(tm_time->tm_mon), + &(tm_time->tm_mday), + &(tm_time->tm_hour), + &(tm_time->tm_min), + &(tm_time->tm_year)); + + if(nr < 4 || nr > 5) { + fprintf(stderr, "date: invalid date `%s'\n", t_string); + exit(1); + } + + /* correct for century - minor Y2K problem here? */ + if(tm_time->tm_year >= 1900) + tm_time->tm_year -= 1900; + /* adjust date */ + tm_time->tm_mon -= 1; + + return(tm_time); + +} + + +/* The new stuff for LRP */ + +struct tm * +date_conv_ftime(struct tm *tm_time, const char *t_string) { + struct tm itm_time, jtm_time, ktm_time, \ + ltm_time, mtm_time, ntm_time; + + itm_time = *tm_time; + jtm_time = *tm_time; + ktm_time = *tm_time; + ltm_time = *tm_time; + mtm_time = *tm_time; + ntm_time = *tm_time; + + /* Parse input and assign appropriately to tm_time */ + + if(sscanf(t_string, "%d:%d:%d", + &itm_time.tm_hour, + &itm_time.tm_min, + &itm_time.tm_sec) == 3 ) { + + *tm_time = itm_time; + return(tm_time); + + } else if (sscanf(t_string, "%d:%d", + &jtm_time.tm_hour, + &jtm_time.tm_min) == 2) { + + *tm_time = jtm_time; + return(tm_time); + + } else if (sscanf(t_string, "%d.%d-%d:%d:%d", + &ktm_time.tm_mon, + &ktm_time.tm_mday, + &ktm_time.tm_hour, + &ktm_time.tm_min, + &ktm_time.tm_sec) == 5) { + + ktm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */ + *tm_time = ktm_time; + return(tm_time); + + } else if (sscanf(t_string, "%d.%d-%d:%d", + <m_time.tm_mon, + <m_time.tm_mday, + <m_time.tm_hour, + <m_time.tm_min) == 4) { + + ltm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */ + *tm_time = ltm_time; + return(tm_time); + + } else if (sscanf(t_string, "%d.%d.%d-%d:%d:%d", + &mtm_time.tm_year, + &mtm_time.tm_mon, + &mtm_time.tm_mday, + &mtm_time.tm_hour, + &mtm_time.tm_min, + &mtm_time.tm_sec) == 6) { + + mtm_time.tm_year -= 1900; /* Adjust years */ + mtm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */ + *tm_time = mtm_time; + return(tm_time); + + } else if (sscanf(t_string, "%d.%d.%d-%d:%d", + &ntm_time.tm_year, + &ntm_time.tm_mon, + &ntm_time.tm_mday, + &ntm_time.tm_hour, + &ntm_time.tm_min) == 5) { + ntm_time.tm_year -= 1900; /* Adjust years */ + ntm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */ + *tm_time = ntm_time; + return(tm_time); + + } + + fprintf(stderr, "date: invalid date `%s'\n", t_string); + + exit(1); + +} + + +void +date_err(void) { + fprintf(stderr, "date: only one date argument can be given at a time.\n"); + exit(1); +} + +int +date_main(struct FileInfo * i, int argc, char * * argv) +{ + char *date_str = NULL; + char *date_fmt = NULL; + char *t_buff; + int set_time = 0; + int rfc822 = 0; + int utc = 0; + int use_arg = 0; + int n_args; + time_t tm; + struct tm tm_time; + char optc; + + /* Interpret command line args */ + + + while ((optc = getopt_long (argc, argv, "d:Rs:u", long_options, NULL)) + != EOF) { + switch (optc) { + case 0: + break; + + case 'R': + rfc822 = 1; + break; + + case 's': + set_time = 1; + if(date_str != NULL) date_err(); + date_str = optarg; + break; + + case 'u': + utc = 1; + if (putenv ("TZ=UTC0") != 0) { + fprintf(stderr,"date: memory exhausted\n"); + return(1); + } +#if LOCALTIME_CACHE + tzset (); +#endif break; + + case 'd': + use_arg = 1; + if(date_str != NULL) date_err(); + date_str = optarg; + break; + + default: + usage(date_usage); + break; + } + } + + + n_args = argc - optind; + + while (n_args--){ + switch(argv[optind][0]) { + case '+': + /* Date format strings */ + if(date_fmt != NULL) { + fprintf(stderr, "date: only one date format can be given.\n"); + return(1); + } + date_fmt = &argv[optind][1]; + break; + + case '\0': + break; + + default: + /* Anything left over must be a date string to set the time */ + set_time = 1; + if(date_str != NULL) date_err(); + date_str = argv[optind]; + break; + } + optind++; + } + + + /* Now we have parsed all the information except the date format + which depends on whether the clock is being set or read */ + + time(&tm); + memcpy(&tm_time, localtime(&tm), sizeof(tm_time)); + /* Zero out fields - take her back to midnight!*/ + if(date_str != NULL) { + tm_time.tm_sec = 0; + tm_time.tm_min = 0; + tm_time.tm_hour = 0; + } + + /* Process any date input to UNIX time since 1 Jan 1970 */ + if(date_str != NULL) { + + if(strchr(date_str, ':') != NULL) { + date_conv_ftime(&tm_time, date_str); + } else { + date_conv_time(&tm_time, date_str); + } + + /* Correct any day of week and day of year etc fields */ + tm = mktime(&tm_time); + if (tm < 0 ) { + fprintf(stderr, "date: invalid date `%s'\n", date_str); + exit(1); + } + + /* if setting time, set it */ + if(set_time) { + if( stime(&tm) < 0) { + fprintf(stderr, "date: can't set date.\n"); + exit(1); + } + } + } + + /* Display output */ + + /* Deal with format string */ + if(date_fmt == NULL) { + date_fmt = (rfc822 + ? (utc + ? "%a, %_d %b %Y %H:%M:%S GMT" + : "%a, %_d %b %Y %H:%M:%S %z") + : "%a %b %e %H:%M:%S %Z %Y"); + + } else if ( *date_fmt == '\0' ) { + /* Imitate what GNU 'date' does with NO format string! */ + printf ("\n"); + return(0); + } + + /* Handle special conversions */ + + if( strncmp( date_fmt, "%f", 2) == 0 ) { + date_fmt = "%Y.%m.%d-%H:%M:%S"; + } + + /* Print OUTPUT (after ALL that!) */ + t_buff = malloc(201); + strftime(t_buff, 200, date_fmt, &tm_time); + printf("%s\n", t_buff); + + return(0); + +} diff --git a/coreutils/dd.c b/coreutils/dd.c new file mode 100644 index 000000000..8f1b9d409 --- /dev/null +++ b/coreutils/dd.c @@ -0,0 +1,307 @@ +/* + * Copyright (c) 1999 by David I. Bell + * Permission is granted to use, distribute, or modify this source, + * provided that this copyright notice remains intact. + * + * The "dd" command, originally taken from sash. + * + * Permission to distribute this code under the GPL has been granted. + * Majorly modified, and bugs fixed for busybox by Erik Andersen + */ + +#include "internal.h" +#ifdef BB_DD + +const char dd_usage[] = +"Copy a file, converting and formatting according to options\n\ +\n\ +usage: [if=name] [of=name] [bs=n] [count=n]\n\ +\tif=FILE\tread from FILE instead of stdin\n\ +\tof=FILE\twrite to FILE instead of stout\n\ +\tbs=n\tread and write N bytes at a time\n\ +\tcount=n\tcopy only n input blocks\n\ +\n\ +BYTES may be suffixed: by k for x1024, b for x512, and w for x2.\n"; + + +#include +#include +#include +#include +#include +#include + + +#define PAR_NONE 0 +#define PAR_IF 1 +#define PAR_OF 2 +#define PAR_BS 3 +#define PAR_COUNT 4 + + +typedef struct +{ + const char * name; + int value; +} PARAM; + + +static const PARAM params[] = +{ + {"if", PAR_IF}, + {"of", PAR_OF}, + {"bs", PAR_BS}, + {"count", PAR_COUNT}, + {NULL, PAR_NONE} +}; + + +static long getNum(const char * cp); + +extern int +dd_main (struct FileInfo *unused, int argc, char **argv) +{ + const char * str; + const PARAM * par; + const char * inFile; + const char * outFile; + char * cp; + int inFd; + int outFd; + int inCc=0; + int outCc; + int blockSize; + long count; + long intotal; + long outTotal; + unsigned char* buf; + unsigned char localBuf[BUF_SIZE]; + + inFile = NULL; + outFile = NULL; + blockSize = 512; + count = 1; + + + while (--argc > 0) + { + str = *++argv; + cp = strchr(str, '='); + + if (cp == NULL) + { + fprintf(stderr, "Bad dd argument\n"); + goto usage; + } + + *cp++ = '\0'; + + for (par = params; par->name; par++) + { + if (strcmp(str, par->name) == 0) + break; + } + + switch (par->value) + { + case PAR_IF: + if (inFile) + { + fprintf(stderr, "Multiple input files illegal\n"); + goto usage; + } + + //fprintf(stderr, "if=%s\n", cp); + inFile = cp; + break; + + case PAR_OF: + if (outFile) + { + fprintf(stderr, "Multiple output files illegal\n"); + goto usage; + } + + //fprintf(stderr, "of=%s\n", cp); + outFile = cp; + break; + + case PAR_BS: + blockSize = getNum(cp); + //fprintf(stderr, "bs=%d\n", blockSize); + + if (blockSize <= 0) + { + fprintf(stderr, "Bad block size value\n"); + goto usage; + } + + break; + + case PAR_COUNT: + count = getNum(cp); + //fprintf(stderr, "count=%ld\n", count); + + if (count < 0) + { + fprintf(stderr, "Bad count value\n"); + goto usage; + } + + break; + + default: + goto usage; + } + } + + buf = localBuf; + + if (blockSize > sizeof(localBuf)) + { + buf = malloc(blockSize); + + if (buf == NULL) + { + fprintf(stderr, "Cannot allocate buffer\n"); + return 1; + } + } + + intotal = 0; + outTotal = 0; + + if (inFile == NULL) + inFd = STDIN; + else + inFd = open(inFile, 0); + + if (inFd < 0) + { + perror(inFile); + + if (buf != localBuf) + free(buf); + + return 1; + } + + if (outFile == NULL) + outFd = STDOUT; + else + outFd = creat(outFile, 0666); + + if (outFd < 0) + { + perror(outFile); + close(inFd); + + if (buf != localBuf) + free(buf); + + return 1; + } + + while ( outTotal < count*blockSize ) + { + inCc = read(inFd, buf, blockSize); + if (inCc < 0) { + perror(inFile); + goto cleanup; + } + //fprintf(stderr, "read in =%d\n", inCc); + intotal += inCc; + cp = buf; + + + while ( intotal > outTotal ) + { + if (outTotal+inCc > count*blockSize) + inCc=count*blockSize-outTotal; + outCc = write(outFd, cp, inCc); + if (outCc < 0) + { + perror(outFile); + goto cleanup; + } + //fprintf(stderr, "wrote out =%d\n", outCc); + + inCc -= outCc; + cp += outCc; + outTotal += outCc; + //fprintf(stderr, "outTotal=%ld\n", outTotal); + } + } + + if (inCc < 0) + perror(inFile); + +cleanup: + close(inFd); + + if (close(outFd) < 0) + perror(outFile); + + if (buf != localBuf) + free(buf); + + printf("%ld+%d records in\n", intotal / blockSize, + (intotal % blockSize) != 0); + + printf("%ld+%d records out\n", outTotal / blockSize, + (outTotal % blockSize) != 0); + return 0; +usage: + + fprintf(stderr, "%s", dd_usage); + return 1; +} + + +/* + * Read a number with a possible multiplier. + * Returns -1 if the number format is illegal. + */ +static long +getNum(const char * cp) +{ + long value; + + if (!isDecimal(*cp)) + return -1; + + value = 0; + + while (isDecimal(*cp)) + value = value * 10 + *cp++ - '0'; + + switch (*cp++) + { + case 'k': + value *= 1024; + break; + + case 'b': + value *= 512; + break; + + case 'w': + value *= 2; + break; + + case '\0': + return value; + + default: + return -1; + } + + if (*cp) + return -1; + + return value; +} + +#endif +/* END CODE */ + diff --git a/coreutils/df.c b/coreutils/df.c new file mode 100644 index 000000000..a0692afc5 --- /dev/null +++ b/coreutils/df.c @@ -0,0 +1,103 @@ +#include "internal.h" +#include +#include +#include +#include + +const char df_usage[] = "df [filesystem ...]\n" +"\n" +"\tPrint the filesystem space used and space available.\n"; + + +static int +df(const char * device, const char * mountPoint) +{ + struct statfs s; + long blocks_used; + long blocks_percent_used; + + if ( statfs(mountPoint, &s) != 0 ) { + name_and_error(mountPoint); + return 1; + } + + if ( s.f_blocks > 0 ) { + blocks_used = s.f_blocks - s.f_bfree; + blocks_percent_used = (long) + (blocks_used * 100.0 / (blocks_used + s.f_bavail) + 0.5); + +/* + printf( + "%-20s %7ld %7ld %7ld %5ld%% %s\n" + ,device + ,s.f_blocks + ,s.f_blocks - s.f_bfree + ,s.f_bavail + ,blocks_percent_used + ,mountPoint); +*/ + + printf( + "%-20s %7.0f %7.0f %7.0f %5ld%% %s\n" + ,device + ,s.f_blocks * (s.f_bsize / 1024.0) + ,(s.f_blocks - s.f_bfree) * (s.f_bsize / 1024.0) + ,s.f_bavail * (s.f_bsize / 1024.0) + ,blocks_percent_used + ,mountPoint); + + } + + return 0; +} + +extern int +df_main(struct FileInfo * i, int argc, char * * argv) +{ + static const char header[] = + "Filesystem 1024-blocks Used Available Capacity Mounted on\n"; + printf(header); + + if ( argc > 1 ) { + struct mntent * mountEntry; + int status; + + while ( argc > 1 ) { + if ( (mountEntry = findMountPoint(argv[1], "/etc/mtab")) == 0 + && (mountEntry = findMountPoint(argv[1], "/proc/mounts")) == 0 ) + { + fprintf(stderr, "%s: can't find mount point.\n" + ,argv[1]); + return 1; + } + status = df(mountEntry->mnt_fsname, mountEntry->mnt_dir); + if ( status != 0 ) + return status; + argc--; + argv++; + } + return 0; + } + else { + FILE * mountTable; + struct mntent * mountEntry; + + if ( (mountTable = setmntent("/etc/mtab", "r")) == 0 + && (mountTable = setmntent("/proc/mounts", "r")) == 0 + ) { + name_and_error("/etc/mtab"); + return 1; + } + + while ( (mountEntry = getmntent(mountTable)) != 0 ) { + int status = df( + mountEntry->mnt_fsname + ,mountEntry->mnt_dir); + if ( status != 0 ) + return status; + } + endmntent(mountTable); + } + + return 0; +} diff --git a/coreutils/length.c b/coreutils/length.c new file mode 100644 index 000000000..284bbfdf9 --- /dev/null +++ b/coreutils/length.c @@ -0,0 +1,13 @@ +#include "internal.h" +#include +#include +#include + +const char length_usage[] = "length string"; + +int +length_main(struct FileInfo * i, int argc, char * * argv) +{ + printf("%d\n", strlen(argv[1])); + return 0; +} diff --git a/coreutils/ln.c b/coreutils/ln.c new file mode 100644 index 000000000..3e87b579e --- /dev/null +++ b/coreutils/ln.c @@ -0,0 +1,52 @@ +#include "internal.h" +#include +#include +#include +#include + +const char ln_usage[] = "ln [-s] [-f] original-name additional-name\n" +"\n" +"\tAdd a new name that refers to the same file as \"original-name\"\n" +"\n" +"\t-s:\tUse a \"symbolic\" link, instead of a \"hard\" link.\n" +"\t-f:\tRemove existing destination files.\n"; + +int +ln_fn(const struct FileInfo * i) +{ + int status = 0; + char d[PATH_MAX]; + const char * destination = i->destination; + + if ( !i->makeSymbolicLink && (i->stat.st_mode & S_IFMT) == S_IFDIR ) { + fprintf(stderr, "Please use \"ln -s\" to link directories.\n"); + return 1; + } + + /* + * If the destination is a directory, create a file within it. + */ + if ( is_a_directory(i->destination) ) { + destination = join_paths( + d + ,i->destination + ,&i->source[i->directoryLength]); + } + + if ( i->force ) + status = ( unlink(destination) && errno != ENOENT ); + + if ( status == 0 ) { + if ( i->makeSymbolicLink ) + status = symlink(i->source, destination); + else + status = link(i->source, destination); + } + + if ( status != 0 ) { + name_and_error(destination); + return 1; + } + else + return 0; +} diff --git a/coreutils/ls.c b/coreutils/ls.c new file mode 100644 index 000000000..2566beea0 --- /dev/null +++ b/coreutils/ls.c @@ -0,0 +1,542 @@ +#include "internal.h" +/* + * tiny-ls.c version 0.1.0: A minimalist 'ls' + * Copyright (C) 1996 Brian Candler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * To achieve a small memory footprint, this version of 'ls' doesn't do any + * file sorting, and only has the most essential command line switches + * (i.e. the ones I couldn't live without :-) All features which involve + * linking in substantial chunks of libc can be disabled. + * + * Although I don't really want to add new features to this program to + * keep it small, I *am* interested to receive bug fixes and ways to make + * it more portable. + * + * KNOWN BUGS: + * 1. messy output if you mix files and directories on the command line + * 2. ls -l of a directory doesn't give "total " header + * 3. ls of a symlink to a directory doesn't list directory contents + * 4. hidden files can make column width too large + * NON-OPTIMAL BEHAVIOUR: + * 1. autowidth reads directories twice + * 2. if you do a short directory listing without filetype characters + * appended, there's no need to stat each one + * PORTABILITY: + * 1. requires lstat (BSD) - how do you do it without? + */ + +#define FEATURE_USERNAME /* show username/groupnames (libc6 uses NSS) */ +#define FEATURE_TIMESTAMPS /* show file timestamps */ +#define FEATURE_AUTOWIDTH /* calculate terminal & column widths */ +#define FEATURE_FILETYPECHAR /* enable -p and -F */ + +#undef OP_BUF_SIZE 1024 /* leave undefined for unbuffered output */ + +#define TERMINAL_WIDTH 80 /* use 79 if your terminal has linefold bug */ +#define COLUMN_WIDTH 14 /* default if AUTOWIDTH not defined */ +#define COLUMN_GAP 2 /* includes the file type char, if present */ + +/************************************************************************/ + +#define HAS_REWINDDIR + +#if 1 /* FIXME libc 6 */ +# include +#else +# include +#endif +#include +#include +#include +#include +#include +#include +#ifdef FEATURE_USERNAME +#include +#include +#endif +#ifdef FEATURE_TIMESTAMPS +#include +#endif + +#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f) +#define TYPECHAR(mode) ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)]) +#ifdef FEATURE_FILETYPECHAR +#define APPCHAR(mode) ("\0|\0\0/\0\0\0\0\0@\0=\0\0\0" [TYPEINDEX(mode)]) +#endif + +#ifndef MAJOR +#define MAJOR(dev) (((dev)>>8)&0xff) +#define MINOR(dev) ((dev)&0xff) +#endif + +#define MODE1 "rwxrwxrwx" +#define MODE0 "---------" +#define SMODE1 "..s..s..t" +#define SMODE0 "..S..S..T" + +/* The 9 mode bits to test */ + +static const umode_t MBIT[] = { + S_IRUSR, S_IWUSR, S_IXUSR, + S_IRGRP, S_IWGRP, S_IXGRP, + S_IROTH, S_IWOTH, S_IXOTH +}; + +/* The special bits. If set, display SMODE0/1 instead of MODE0/1 */ + +static const umode_t SBIT[] = { + 0, 0, S_ISUID, + 0, 0, S_ISGID, + 0, 0, S_ISVTX +}; + +#define FMT_AUTO 0 +#define FMT_LONG 1 /* one record per line, extended info */ +#define FMT_SINGLE 2 /* one record per line */ +#define FMT_ROWS 3 /* print across rows */ +#define FMT_COLUMNS 3 /* fill columns (same, since we don't sort) */ + +#define TIME_MOD 0 +#define TIME_CHANGE 1 +#define TIME_ACCESS 2 + +#define DISP_FTYPE 1 /* show character for file type */ +#define DISP_EXEC 2 /* show '*' if regular executable file */ +#define DISP_HIDDEN 4 /* show files starting . (except . and ..) */ +#define DISP_DOT 8 /* show . and .. */ +#define DISP_NUMERIC 16 /* numeric uid and gid */ +#define DISP_FULLTIME 32 /* show extended time display */ +#define DIR_NOLIST 64 /* show directory as itself, not contents */ +#define DISP_DIRNAME 128 /* show directory name (for internal use) */ +#define DIR_RECURSE 256 /* -R (not yet implemented) */ + +static unsigned char display_fmt = FMT_AUTO; +static unsigned short opts = 0; +static unsigned short column = 0; + +#ifdef FEATURE_AUTOWIDTH +static unsigned short terminal_width = 0, column_width = 0; +#else +#define terminal_width TERMINAL_WIDTH +#define column_width COLUMN_WIDTH +#endif + +#ifdef FEATURE_TIMESTAMPS +static unsigned char time_fmt = TIME_MOD; +#endif + +#define wr(data,len) fwrite(data, 1, len, stdout) + +static void writenum(long val, short minwidth) +{ + char scratch[20]; + + char *p = scratch + sizeof(scratch); + short len = 0; + short neg = (val < 0); + + if (neg) val = -val; + do + *--p = (val % 10) + '0', len++, val /= 10; + while (val); + if (neg) + *--p = '-', len++; + while (len < minwidth) + *--p = ' ', len++; + wr(p, len); + column += len; +} + +static void newline(void) +{ + if (column > 0) { + wr("\n", 1); + column = 0; + } +} + +static void tab(short col) +{ + static const char spaces[] = " "; + #define nspaces ((sizeof spaces)-1) /* null terminator! */ + + short n = col - column; + + if (n > 0) { + column = col; + while (n > nspaces) { + wr(spaces, nspaces); + n -= nspaces; + } + /* must be 1...(sizeof spaces) left */ + wr(spaces, n); + } + #undef nspaces +} + +#ifdef FEATURE_FILETYPECHAR +static char append_char(umode_t mode) +{ + if (!(opts & DISP_FTYPE)) + return '\0'; + if ((opts & DISP_EXEC) && S_ISREG(mode) && (mode & (S_IXUSR|S_IXGRP|S_IXOTH))) + return '*'; + return APPCHAR(mode); +} +#endif + +/** + ** + ** Display a file or directory as a single item + ** (in either long or short format) + ** + **/ + +static void list_single(const char *name, struct stat *info) +{ + char scratch[20]; + short len = strlen(name); +#ifdef FEATURE_FILETYPECHAR + char append = append_char(info->st_mode); +#endif + + if (display_fmt == FMT_LONG) { + umode_t mode = info->st_mode; + int i; + + scratch[0] = TYPECHAR(mode); + for (i=0; i<9; i++) + if (mode & SBIT[i]) + scratch[i+1] = (mode & MBIT[i]) + ? SMODE1[i] + : SMODE0[i]; + else + scratch[i+1] = (mode & MBIT[i]) + ? MODE1[i] + : MODE0[i]; + newline(); + wr(scratch, 10); + column=10; + writenum((long)info->st_nlink,(short)4); + fputs(" ", stdout); +#ifdef FEATURE_USERNAME + if (!(opts & DISP_NUMERIC)) { + struct passwd *pw = getpwuid(info->st_uid); + if (pw) + fputs(pw->pw_name, stdout); + else + writenum((long)info->st_uid,(short)0); + } else +#endif + writenum((long)info->st_uid,(short)0); + tab(24); +#ifdef FEATURE_USERNAME + if (!(opts & DISP_NUMERIC)) { + struct group *gr = getgrgid(info->st_gid); + if (gr) + fputs(gr->gr_name, stdout); + else + writenum((long)info->st_gid,(short)0); + } else +#endif + writenum((long)info->st_gid,(short)0); + tab(33); + if (S_ISBLK(mode) || S_ISCHR(mode)) { + writenum((long)MAJOR(info->st_rdev),(short)3); + fputs(", ", stdout); + writenum((long)MINOR(info->st_rdev),(short)3); + } + else + writenum((long)info->st_size,(short)8); + fputs(" ", stdout); +#ifdef FEATURE_TIMESTAMPS + { + time_t cal; + char *string; + + switch(time_fmt) { + case TIME_CHANGE: + cal=info->st_ctime; break; + case TIME_ACCESS: + cal=info->st_atime; break; + default: + cal=info->st_mtime; break; + } + string=ctime(&cal); + if (opts & DISP_FULLTIME) + wr(string,24); + else { + time_t age = time(NULL) - cal; + wr(string+4,7); /* mmm_dd_ */ + if(age < 3600L*24*365/2 && age > -15*60) + /* hh:mm if less than 6 months old */ + wr(string+11,5); + else + /* _yyyy otherwise */ + wr(string+19,5); + } + wr(" ", 1); + } +#else + fputs("--- -- ----- ", stdout); +#endif + wr(name, len); + if (S_ISLNK(mode)) { + wr(" -> ", 4); + len = readlink(name, scratch, sizeof scratch); + if (len > 0) fwrite(scratch, 1, len, stdout); +#ifdef FEATURE_FILETYPECHAR + /* show type of destination */ + if (opts & DISP_FTYPE) { + if (!stat(name, info)) { + append = append_char(info->st_mode); + if (append) + fputc(append, stdout); + } + } +#endif + } +#ifdef FEATURE_FILETYPECHAR + else if (append) + wr(&append, 1); +#endif + } else { + static short nexttab = 0; + + /* sort out column alignment */ + if (column == 0) + ; /* nothing to do */ + else if (display_fmt == FMT_SINGLE) + newline(); + else { + if (nexttab + column_width > terminal_width +#ifndef FEATURE_AUTOWIDTH + || nexttab + len >= terminal_width +#endif + ) + newline(); + else + tab(nexttab); + } + /* work out where next column starts */ +#ifdef FEATURE_AUTOWIDTH + /* we know the calculated width is big enough */ + nexttab = column + column_width + COLUMN_GAP; +#else + /* might cover more than one fixed-width column */ + nexttab = column; + do + nexttab += column_width + COLUMN_GAP; + while (nexttab < (column + len + COLUMN_GAP)); +#endif + /* now write the data */ + wr(name, len); + column = column + len; +#ifdef FEATURE_FILETYPECHAR + if (append) + wr(&append, 1), column++; +#endif + } +} + +/** + ** + ** List the given file or directory, expanding a directory + ** to show its contents if required + ** + **/ + +static int list_item(const char *name) +{ + struct stat info; + DIR *dir; + struct dirent *entry; + char fullname[MAXNAMLEN+1], *fnend; + + if (lstat(name, &info)) + goto listerr; + + if (!S_ISDIR(info.st_mode) || + (opts & DIR_NOLIST)) { + list_single(name, &info); + return 0; + } + + /* Otherwise, it's a directory we want to list the contents of */ + + if (opts & DISP_DIRNAME) { /* identify the directory */ + if (column) + wr("\n\n", 2), column = 0; + wr(name, strlen(name)); + wr(":\n", 2); + } + + dir = opendir(name); + if (!dir) goto listerr; +#ifdef FEATURE_AUTOWIDTH + column_width = 0; + while ((entry = readdir(dir)) != NULL) { + short w = strlen(entry->d_name); + if (column_width < w) + column_width = w; + } +#ifdef HAS_REWINDDIR + rewinddir(dir); +#else + closedir(dir); + dir = opendir(name); + if (!dir) goto listerr; +#endif +#endif + + /* List the contents */ + + strcpy(fullname,name); /* *** ignore '.' by itself */ + fnend=fullname+strlen(fullname); + if (fnend[-1] != '/') + *fnend++ = '/'; + + while ((entry = readdir(dir)) != NULL) { + const char *en=entry->d_name; + if (en[0] == '.') { + if (!en[1] || (en[1] == '.' && !en[2])) { /* . or .. */ + if (!(opts & DISP_DOT)) + continue; + } + else if (!(opts & DISP_HIDDEN)) + continue; + } + /* FIXME: avoid stat if not required */ + strcpy(fnend, entry->d_name); + if (lstat(fullname, &info)) + goto direrr; /* (shouldn't fail) */ + list_single(entry->d_name, &info); + } + closedir(dir); + return 0; + +direrr: + closedir(dir); +listerr: + newline(); + name_and_error(name); + return 1; +} + +const char ls_usage[] = "Usage: ls [-1a" +#ifdef FEATURE_TIMESTAMPS + "c" +#endif + "d" +#ifdef FEATURE_TIMESTAMPS + "e" +#endif + "ln" +#ifdef FEATURE_FILETYPECHAR + "p" +#endif +#ifdef FEATURE_TIMESTAMPS + "u" +#endif + "xAC" +#ifdef FEATURE_FILETYPECHAR + "F" +#endif +#ifdef FEATURE_RECURSIVE + "R" +#endif + "] [filenames...]\n"; + +extern int +ls_main(struct FileInfo * not_used, int argc, char * * argv) +{ + int argi=1, i; + + /* process options */ + while (argi < argc && argv[argi][0] == '-') { + const char *p = &argv[argi][1]; + + if (!*p) goto print_usage_message; /* "-" by itself not allowed */ + if (*p == '-') { + if (!p[1]) { /* "--" forces end of options */ + argi++; + break; + } + /* it's a long option name - we don't support them */ + goto print_usage_message; + } + + while (*p) + switch (*p++) { + case 'l': display_fmt = FMT_LONG; break; + case '1': display_fmt = FMT_SINGLE; break; + case 'x': display_fmt = FMT_ROWS; break; + case 'C': display_fmt = FMT_COLUMNS; break; +#ifdef FEATURE_FILETYPECHAR + case 'p': opts |= DISP_FTYPE; break; + case 'F': opts |= DISP_FTYPE|DISP_EXEC; break; +#endif + case 'A': opts |= DISP_HIDDEN; break; + case 'a': opts |= DISP_HIDDEN|DISP_DOT; break; + case 'n': opts |= DISP_NUMERIC; break; + case 'd': opts |= DIR_NOLIST; break; +#ifdef FEATURE_RECURSIVE + case 'R': opts |= DIR_RECURSE; break; +#endif +#ifdef FEATURE_TIMESTAMPS + case 'u': time_fmt = TIME_ACCESS; break; + case 'c': time_fmt = TIME_CHANGE; break; + case 'e': opts |= DISP_FULLTIME; break; +#endif + default: goto print_usage_message; + } + + argi++; + } + + /* choose a display format */ + if (display_fmt == FMT_AUTO) + display_fmt = isatty(STDOUT_FILENO) ? FMT_COLUMNS : FMT_SINGLE; + if (argi < argc - 1) + opts |= DISP_DIRNAME; /* 2 or more items? label directories */ +#ifdef FEATURE_AUTOWIDTH + /* could add a -w option and/or TIOCGWINSZ call */ + if (terminal_width < 1) terminal_width = TERMINAL_WIDTH; + + for (i = argi; i < argc; i++) { + int len = strlen(argv[i]); + if (column_width < len) + column_width = len; + } +#endif + + /* process files specified, or current directory if none */ + i=0; + if (argi == argc) + i = list_item("."); + while (argi < argc) + i |= list_item(argv[argi++]); + newline(); + return i; + +print_usage_message: + usage(ls_usage); + return 1; +} diff --git a/coreutils/mkdir.c b/coreutils/mkdir.c new file mode 100644 index 000000000..8f1fa04db --- /dev/null +++ b/coreutils/mkdir.c @@ -0,0 +1,58 @@ +#include "internal.h" +#include +#include + +const char mkdir_usage[] = "mkdir [-m mode] directory [directory ...]\n" +"\tCreate directories.\n" +"\n" +"\t-m mode:\tSpecifiy the mode for the new directory\n" +"\t\tunder the argument directory."; + +/*make directories skipping the last part of the path. Used here and by untar*/ +int mkdir_until(const char *fpath, const struct FileInfo * fi) +{ + char path[PATH_MAX]; + char * s = path; + + strcpy(path, fpath); + if ( s[0] == '\0' && s[1] == '\0' ) { + usage(mkdir_usage); + return 1; + } + s++; + while ( *s != '\0' ) { + if ( *s == '/' ) { + int status; + + *s = '\0'; + status = mkdir(path, (fi?fi->orWithMode:0700) ); + *s = '/'; + + if ( status != 0 ) { + if ( errno != EEXIST ) { + name_and_error(fpath); + return 1; + } + } + + } + s++; + } + return 0; +} + +int +mkdir_fn(const struct FileInfo * i) +{ + if ( i->makeParentDirectories ) { + if(mkdir_until(i->source, i)) return 1; + } + + if ( mkdir(i->source, i->orWithMode) != 0 && errno != EEXIST ) { + name_and_error(i->source); + return 1; + } + else + return 0; +} + diff --git a/coreutils/mknod.c b/coreutils/mknod.c new file mode 100644 index 000000000..b18394bec --- /dev/null +++ b/coreutils/mknod.c @@ -0,0 +1,52 @@ +#include "internal.h" +#include +#include +#include +#include +#include + +const char mknod_usage[] = "mknod file b|c|u|p major minor\n" +"\tMake special files.\n" +"\n" +"\tb:\tMake a block (buffered) device.\n" +"\tc or u:\tMake a character (un-buffered) device.\n" +"\tp:\tMake a named pipe. Major and minor are ignored for named pipes.\n"; + +int +mknod_main(struct FileInfo * i, int argc, char * * argv) +{ + mode_t mode = 0; + dev_t dev = 0; + + switch(argv[2][0]) { + case 'c': + case 'u': + mode = S_IFCHR; + break; + case 'b': + mode = S_IFBLK; + break; + case 'p': + mode = S_IFIFO; + break; + default: + usage(mknod_usage); + return 1; + } + + if ( mode == S_IFCHR || mode == S_IFBLK ) { + dev = (atoi(argv[3]) << 8) | atoi(argv[4]); + if ( argc != 5 ) { + usage(mknod_usage); + return 1; + } + } + + mode |= 0666; + + if ( mknod(argv[1], mode, dev) != 0 ) { + name_and_error(argv[1]); + return 1; + } + return 0; +} diff --git a/coreutils/mv.c b/coreutils/mv.c new file mode 100644 index 000000000..22c4a1207 --- /dev/null +++ b/coreutils/mv.c @@ -0,0 +1,38 @@ +#include "internal.h" +#include +#include + +const char mv_usage[] = "mv source-file destination-file\n" +"\t\tmv source-file [source-file ...] destination-directory\n" +"\n" +"\tMove the source files to the destination.\n" +"\n"; + +extern int +mv_fn(const struct FileInfo * i) +{ + struct stat destination_stat; + char d[1024]; + struct FileInfo n; + + if ( stat(i->destination, &destination_stat) == 0 ) { + if ( i->stat.st_ino == destination_stat.st_ino + && i->stat.st_dev == destination_stat.st_dev ) + return 0; /* Move file to itself. */ + } + if ( (destination_stat.st_mode & S_IFMT) == S_IFDIR ) { + n = *i; + n.destination = join_paths(d, i->destination, basename(i->source)); + i = &n; + } + if ( rename(i->source, i->destination) == 0 ) + return 0; + else if ( errno == EXDEV && is_a_directory(i->source) ) { + fprintf(stderr + ,"%s: Can't move directory across filesystems.\n" + ,i->source); + return 1; + } + else + return cp_fn(i); +} diff --git a/coreutils/printf.c b/coreutils/printf.c new file mode 100644 index 000000000..e79843c80 --- /dev/null +++ b/coreutils/printf.c @@ -0,0 +1,531 @@ +// I may still need some more cleaning...fix my error checking + +#include "internal.h" +#ifdef BB_PRINTF + +/* printf - format and print data + Copyright (C) 90, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Usage: printf format [argument...] + + A front end to the printf function that lets it be used from the shell. + + Backslash escapes: + + \" = double quote + \\ = backslash + \a = alert (bell) + \b = backspace + \c = produce no further output + \f = form feed + \n = new line + \r = carriage return + \t = horizontal tab + \v = vertical tab + \0ooo = octal number (ooo is 0 to 3 digits) + \xhhh = hexadecimal number (hhh is 1 to 3 digits) + + Additional directive: + + %b = print an argument string, interpreting backslash escapes + + The `format' argument is re-used as many times as necessary + to convert all of the given arguments. + + David MacKenzie */ + + +// 19990508 Busy Boxed! Dave Cinege + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifndef S_IFMT +# define S_IFMT 0170000 +#endif +#if !defined(S_ISBLK) && defined(S_IFBLK) +# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +#endif +#if !defined(S_ISCHR) && defined(S_IFCHR) +# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#endif +#if !defined(S_ISDIR) && defined(S_IFDIR) +# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif +#if !defined(S_ISREG) && defined(S_IFREG) +# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#endif +#if !defined(S_ISFIFO) && defined(S_IFIFO) +# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +#endif +#if !defined(S_ISLNK) && defined(S_IFLNK) +# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#endif +#if !defined(S_ISSOCK) && defined(S_IFSOCK) +# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) +#endif +#if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */ +# define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB) +# define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC) +#endif +#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */ +# define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK) +#endif + +#define IN_CTYPE_DOMAIN(c) 1 + +#ifdef isblank +# define ISBLANK(c) (IN_CTYPE_DOMAIN (c) && isblank (c)) +#else +# define ISBLANK(c) ((c) == ' ' || (c) == '\t') +#endif +#ifdef isgraph +# define ISGRAPH(c) (IN_CTYPE_DOMAIN (c) && isgraph (c)) +#else +# define ISGRAPH(c) (IN_CTYPE_DOMAIN (c) && isprint (c) && !isspace (c)) +#endif + +#define ISPRINT(c) (IN_CTYPE_DOMAIN (c) && isprint (c)) +#define ISALNUM(c) (IN_CTYPE_DOMAIN (c) && isalnum (c)) +#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c)) +#define ISCNTRL(c) (IN_CTYPE_DOMAIN (c) && iscntrl (c)) +#define ISLOWER(c) (IN_CTYPE_DOMAIN (c) && islower (c)) +#define ISPUNCT(c) (IN_CTYPE_DOMAIN (c) && ispunct (c)) +#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c)) +#define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c)) +#define ISXDIGIT(c) (IN_CTYPE_DOMAIN (c) && isxdigit (c)) +#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c)) +#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9) + +#define isodigit(c) ((c) >= '0' && (c) <= '7') +#define hextobin(c) ((c)>='a'&&(c)<='f' ? (c)-'a'+10 : (c)>='A'&&(c)<='F' ? (c)-'A'+10 : (c)-'0') +#define octtobin(c) ((c) - '0') + +char *xmalloc (); + +static double xstrtod __P ((char *s)); +static int print_esc __P ((char *escstart)); +static int print_formatted __P ((char *format, int argc, char **argv)); +static long xstrtol __P ((char *s)); +static unsigned long xstrtoul __P ((char *s)); +static void print_direc __P ((char *start, size_t length, int field_width, int precision, char *argument)); +static void print_esc_char __P ((int c)); +static void print_esc_string __P ((char *str)); +static void verify __P ((char *s, char *end)); + +/* The value to return to the calling program. */ +static int exit_status; + +const char printf_usage[] = "Usage: printf format [argument...]\n"; + +int +printf_main(struct FileInfo * i, int argc, char * * argv) +{ + char *format; + int args_used; + + exit_status = 0; + + format = argv[1]; + argc -= 2; + argv += 2; + + do + { + args_used = print_formatted (format, argc, argv); + argc -= args_used; + argv += args_used; + } + while (args_used > 0 && argc > 0); + +/* + if (argc > 0) + fprintf(stderr, "excess args ignored"); +*/ + + exit (exit_status); +} + +/* Print the text in FORMAT, using ARGV (with ARGC elements) for + arguments to any `%' directives. + Return the number of elements of ARGV used. */ + +static int +print_formatted (char *format, int argc, char **argv) +{ + int save_argc = argc; /* Preserve original value. */ + char *f; /* Pointer into `format'. */ + char *direc_start; /* Start of % directive. */ + size_t direc_length; /* Length of % directive. */ + int field_width; /* Arg to first '*', or -1 if none. */ + int precision; /* Arg to second '*', or -1 if none. */ + + for (f = format; *f; ++f) + { + switch (*f) + { + case '%': + direc_start = f++; + direc_length = 1; + field_width = precision = -1; + if (*f == '%') + { + putchar ('%'); + break; + } + if (*f == 'b') + { + if (argc > 0) + { + print_esc_string (*argv); + ++argv; + --argc; + } + break; + } + if (strchr ("-+ #", *f)) + { + ++f; + ++direc_length; + } + if (*f == '*') + { + ++f; + ++direc_length; + if (argc > 0) + { + field_width = xstrtoul (*argv); + ++argv; + --argc; + } + else + field_width = 0; + } + else + while (ISDIGIT (*f)) + { + ++f; + ++direc_length; + } + if (*f == '.') + { + ++f; + ++direc_length; + if (*f == '*') + { + ++f; + ++direc_length; + if (argc > 0) + { + precision = xstrtoul (*argv); + ++argv; + --argc; + } + else + precision = 0; + } + else + while (ISDIGIT (*f)) + { + ++f; + ++direc_length; + } + } + if (*f == 'l' || *f == 'L' || *f == 'h') + { + ++f; + ++direc_length; + } + /* + if (!strchr ("diouxXfeEgGcs", *f)) + fprintf(stderr, "%%%c: invalid directive", *f); + */ + ++direc_length; + if (argc > 0) + { + print_direc (direc_start, direc_length, field_width, + precision, *argv); + ++argv; + --argc; + } + else + print_direc (direc_start, direc_length, field_width, + precision, ""); + break; + + case '\\': + f += print_esc (f); + break; + + default: + putchar (*f); + } + } + + return save_argc - argc; +} + +/* Print a \ escape sequence starting at ESCSTART. + Return the number of characters in the escape sequence + besides the backslash. */ + +static int +print_esc (char *escstart) +{ + register char *p = escstart + 1; + int esc_value = 0; /* Value of \nnn escape. */ + int esc_length; /* Length of \nnn escape. */ + + /* \0ooo and \xhhh escapes have maximum length of 3 chars. */ + if (*p == 'x') + { + for (esc_length = 0, ++p; + esc_length < 3 && ISXDIGIT (*p); + ++esc_length, ++p) + esc_value = esc_value * 16 + hextobin (*p); +/* if (esc_length == 0) + fprintf(stderr, "missing hex in esc"); +*/ + putchar (esc_value); + } + else if (*p == '0') + { + for (esc_length = 0, ++p; + esc_length < 3 && isodigit (*p); + ++esc_length, ++p) + esc_value = esc_value * 8 + octtobin (*p); + putchar (esc_value); + } + else if (strchr ("\"\\abcfnrtv", *p)) + print_esc_char (*p++); +/* else + fprintf(stderr, "\\%c: invalid esc", *p); +*/ + return p - escstart - 1; +} + +/* Output a single-character \ escape. */ + +static void +print_esc_char (int c) +{ + switch (c) + { + case 'a': /* Alert. */ + putchar (7); + break; + case 'b': /* Backspace. */ + putchar (8); + break; + case 'c': /* Cancel the rest of the output. */ + exit (0); + break; + case 'f': /* Form feed. */ + putchar (12); + break; + case 'n': /* New line. */ + putchar (10); + break; + case 'r': /* Carriage return. */ + putchar (13); + break; + case 't': /* Horizontal tab. */ + putchar (9); + break; + case 'v': /* Vertical tab. */ + putchar (11); + break; + default: + putchar (c); + break; + } +} + +/* Print string STR, evaluating \ escapes. */ + +static void +print_esc_string (char *str) +{ + for (; *str; str++) + if (*str == '\\') + str += print_esc (str); + else + putchar (*str); +} + +static void +print_direc (char *start, size_t length, int field_width, int precision, char *argument) +{ + char *p; /* Null-terminated copy of % directive. */ + + p = xmalloc ((unsigned) (length + 1)); + strncpy (p, start, length); + p[length] = 0; + + switch (p[length - 1]) + { + case 'd': + case 'i': + if (field_width < 0) + { + if (precision < 0) + printf (p, xstrtol (argument)); + else + printf (p, precision, xstrtol (argument)); + } + else + { + if (precision < 0) + printf (p, field_width, xstrtol (argument)); + else + printf (p, field_width, precision, xstrtol (argument)); + } + break; + + case 'o': + case 'u': + case 'x': + case 'X': + if (field_width < 0) + { + if (precision < 0) + printf (p, xstrtoul (argument)); + else + printf (p, precision, xstrtoul (argument)); + } + else + { + if (precision < 0) + printf (p, field_width, xstrtoul (argument)); + else + printf (p, field_width, precision, xstrtoul (argument)); + } + break; + + case 'f': + case 'e': + case 'E': + case 'g': + case 'G': + if (field_width < 0) + { + if (precision < 0) + printf (p, xstrtod (argument)); + else + printf (p, precision, xstrtod (argument)); + } + else + { + if (precision < 0) + printf (p, field_width, xstrtod (argument)); + else + printf (p, field_width, precision, xstrtod (argument)); + } + break; + + case 'c': + printf (p, *argument); + break; + + case 's': + if (field_width < 0) + { + if (precision < 0) + printf (p, argument); + else + printf (p, precision, argument); + } + else + { + if (precision < 0) + printf (p, field_width, argument); + else + printf (p, field_width, precision, argument); + } + break; + } + + free (p); +} + +static unsigned long +xstrtoul (char *s) +{ + char *end; + unsigned long val; + + errno = 0; + val = strtoul (s, &end, 0); + verify (s, end); + return val; +} + +static long +xstrtol (char *s) +{ + char *end; + long val; + + errno = 0; + val = strtol (s, &end, 0); + verify (s, end); + return val; +} + +static double +xstrtod (char *s) +{ + char *end; + double val; + + errno = 0; + val = strtod (s, &end); + verify (s, end); + return val; +} + +static void +verify (char *s, char *end) +{ + if (errno) + { + fprintf(stderr, "%s", s); + exit_status = 1; + } + else if (*end) + { + /* + if (s == end) + fprintf(stderr, "%s: expected numeric", s); + else + fprintf(stderr, "%s: not completely converted", s); + */ + exit_status = 1; + } +} + +#endif diff --git a/coreutils/pwd.c b/coreutils/pwd.c new file mode 100644 index 000000000..d9ab54e48 --- /dev/null +++ b/coreutils/pwd.c @@ -0,0 +1,18 @@ +#include "internal.h" +#include + +const char pwd_usage[] = "Print the current directory.\n"; + +extern int +pwd_main(struct FileInfo * i, int argc, char * * argv) +{ + char buf[1024]; + + if ( getcwd(buf, sizeof(buf)) == NULL ) { + name_and_error("get working directory"); + return 1; + } + + printf("%s\n", buf); + return 0; +} diff --git a/coreutils/rm.c b/coreutils/rm.c new file mode 100644 index 000000000..dc35b0297 --- /dev/null +++ b/coreutils/rm.c @@ -0,0 +1,30 @@ +#include "internal.h" +#include + +const char rm_usage[] = "rm [-r] file [file ...]\n" +"\n" +"\tDelete files.\n" +"\n" +"\t-r:\tRecursively remove files and directories.\n"; + +extern int +rm_main(struct FileInfo * i, int argc, char * * argv) +{ + i->processDirectoriesAfterTheirContents = 1; + return monadic_main(i, argc, argv); +} + +extern int +rm_fn(const struct FileInfo * i) +{ + if ( i->recursive + && !i->isSymbolicLink + && (i->stat.st_mode & S_IFMT) == S_IFDIR ) + return rmdir_fn(i); + else if ( unlink(i->source) != 0 && errno != ENOENT && !i->force ) { + name_and_error(i->source); + return 1; + } + else + return 0; +} diff --git a/coreutils/rmdir.c b/coreutils/rmdir.c new file mode 100644 index 000000000..069e68546 --- /dev/null +++ b/coreutils/rmdir.c @@ -0,0 +1,17 @@ +#include "internal.h" +#include + +const char rmdir_usage[] = "rmdir directory [directory ...]\n" +"\n" +"\tDelete directories.\n"; + +extern int +rmdir_fn(const struct FileInfo * i) +{ + if ( rmdir(i->source) != 0 && errno != ENOENT && !i->force ) { + name_and_error(i->source); + return 1; + } + else + return 0; +} diff --git a/coreutils/sleep.c b/coreutils/sleep.c new file mode 100644 index 000000000..e48e14b2f --- /dev/null +++ b/coreutils/sleep.c @@ -0,0 +1,15 @@ +#include "internal.h" +#include + +const char sleep_usage[] = "sleep seconds\n" +"\n" +"\tPause program execution for the given number of seconds.\n"; + +extern int +sleep_main(struct FileInfo * i, int argc, char * * argv) +{ + if ( sleep(atoi(argv[1])) != 0 ) + return -1; + else + return 0; +} diff --git a/coreutils/sync.c b/coreutils/sync.c new file mode 100644 index 000000000..6fa5b380b --- /dev/null +++ b/coreutils/sync.c @@ -0,0 +1,11 @@ +#include "internal.h" + +const char sync_usage[] = "sync\n" +"\n" +"\tWrite all buffered filesystem blocks to disk.\n"; + +extern int +sync_main(struct FileInfo * i, int argc, char * * argv) +{ + return sync(); +} diff --git a/coreutils/touch.c b/coreutils/touch.c new file mode 100644 index 000000000..ca4b98108 --- /dev/null +++ b/coreutils/touch.c @@ -0,0 +1,20 @@ +#include "internal.h" +#include +#include +#include + +const char touch_usage[] = "touch [-c] file [file ...]\n" +"\n" +"\tUpdate the last-modified date on the given file[s].\n"; + +extern int +touch_fn(const struct FileInfo * i) +{ + if ( (utime(i->source, 0) != 0) && (i->create != 1) ) { + if ( fopen(i->source, "w") == NULL ) { + name_and_error(i->source); + return 1; + } + } + return 0; +} -- cgit v1.2.3