diff options
Diffstat (limited to 'cpukit/libmisc/shell')
109 files changed, 19281 insertions, 0 deletions
diff --git a/cpukit/libmisc/shell/README b/cpukit/libmisc/shell/README new file mode 100644 index 0000000000..9798becc37 --- /dev/null +++ b/cpukit/libmisc/shell/README @@ -0,0 +1,27 @@ +# +# $Id$ +# + +This directory contains a shell user extension +primary features: + + + create a user shell terminal task. + +This code has not been extensively tested. It is provided as a tool +for RTEMS users to open more shell terminal. +Suggestions and comments are appreciated. + +NOTES: + +1. printf() & getchar() works but you can't use + 0,1,2 like fildes. You need to use fileno(stdin),fileno(stdout),... + +2. You only need a termios dev to start a new session, add your new commands + and enjoy it. + +3. Telnetd daemon uses this (browse libnetworking/rtems_telnetd) + Enjoy it. + +FUTURE: + +1. Adding new commands in cmds.c to give file manegement to shell. diff --git a/cpukit/libmisc/shell/cat_file.c b/cpukit/libmisc/shell/cat_file.c new file mode 100644 index 0000000000..1a5efb4418 --- /dev/null +++ b/cpukit/libmisc/shell/cat_file.c @@ -0,0 +1,37 @@ +/* + * CAT Command Implementation + * + * Author: + * WORK: fernando.ruiz@ctv.es + * HOME: correo@fernando-ruiz.com + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> + +int rtems_shell_cat_file(FILE * out,const char * name) { + FILE * fd; + int c; + + if (out) { + fd = fopen(name,"r"); + if (!fd) { + return -1; + } + while ((c=fgetc(fd))!=EOF) + fputc(c,out); + fclose(fd); + } + return 0; +} + + diff --git a/cpukit/libmisc/shell/cmds.c b/cpukit/libmisc/shell/cmds.c new file mode 100644 index 0000000000..e8d6c581df --- /dev/null +++ b/cpukit/libmisc/shell/cmds.c @@ -0,0 +1,77 @@ +/* + * XXX -- Just monitor commands until those can be integrated better + * + * Author: Fernando RUIZ CASAS + * Work: fernando.ruiz@ctv.es + * Home: correo@fernando-ruiz.com + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include <rtems.h> +#include <rtems/monitor.h> +#include <rtems/shell.h> +#include "internal.h" + +/*-----------------------------------------------------------* + * with this you can call at all the rtems monitor commands. + * Not all work fine but you can show the rtems status and more. + *-----------------------------------------------------------*/ +int rtems_shell_main_monitor(int argc, char **argv) { + const rtems_monitor_command_entry_t *command = NULL; + + if (argc < 1) { + return 1; + } + + command = rtems_monitor_command_lookup(argv [0]); + + if (command == NULL) { + return 1; + } + + command->command_function(argc, argv, &command->command_arg, 0); + + return 0; +} + +static bool rtems_shell_register_command(const rtems_monitor_command_entry_t *e, void *arg __attribute__((unused))) +{ + /* Exclude EXIT (alias quit)*/ + if (strcmp("exit", e->command) != 0) { + rtems_shell_cmd_t *shell_cmd = + (rtems_shell_cmd_t *) malloc(sizeof(rtems_shell_cmd_t)); + + if (shell_cmd != NULL) { + shell_cmd->name = e->command; + shell_cmd->topic = "monitor"; + shell_cmd->usage = e->usage; + shell_cmd->command = rtems_shell_main_monitor; + shell_cmd->alias = NULL; + shell_cmd->next = NULL; + + if (rtems_shell_add_cmd_struct(shell_cmd) == NULL) { + free(shell_cmd); + } + } + } + + return true; +} + +void rtems_shell_register_monitor_commands(void) +{ + rtems_monitor_command_iterate(rtems_shell_register_command, NULL); +} diff --git a/cpukit/libmisc/shell/cmp-ls.c b/cpukit/libmisc/shell/cmp-ls.c new file mode 100644 index 0000000000..793e607fe1 --- /dev/null +++ b/cpukit/libmisc/shell/cmp-ls.c @@ -0,0 +1,204 @@ +/* $NetBSD: cmp.c,v 1.17 2003/08/07 09:05:14 agc Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Michael Fischbein. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if 0 +#include <sys/cdefs.h> +#ifndef lint +#if 0 +static char sccsid[] = "@(#)cmp.c 8.1 (Berkeley) 5/31/93"; +#else +__RCSID("$NetBSD: cmp.c,v 1.17 2003/08/07 09:05:14 agc Exp $"); +#endif +#endif /* not lint */ +#endif + +#include <sys/types.h> +#include <sys/stat.h> + +#include <fts.h> +#include <string.h> + +#include "extern-ls.h" + +#if defined(__rtems__) || defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || \ + defined(_XOPEN_SOURCE) || defined(__NetBSD__) +#define ATIMENSEC_CMP(x, op, y) ((x)->st_atime op (y)->st_atime) +#define CTIMENSEC_CMP(x, op, y) ((x)->st_ctime op (y)->st_ctime) +#define MTIMENSEC_CMP(x, op, y) ((x)->st_mtime op (y)->st_mtime) +#else +#define ATIMENSEC_CMP(x, op, y) \ + ((x)->st_atime.tv_nsec op (y)->st_atime.tv_nsec) +#define CTIMENSEC_CMP(x, op, y) \ + ((x)->st_ctime.tv_nsec op (y)->st_ctime.tv_nsec) +#define MTIMENSEC_CMP(x, op, y) \ + ((x)->st_mtime.tv_nsec op (y)->st_mtime.tv_nsec) +#endif + +int +namecmp(const FTSENT *a, const FTSENT *b) +{ + + return (strcmp(a->fts_name, b->fts_name)); +} + +int +revnamecmp(const FTSENT *a, const FTSENT *b) +{ + + return (strcmp(b->fts_name, a->fts_name)); +} + +int +modcmp(const FTSENT *a, const FTSENT *b) +{ + + if (b->fts_statp->st_mtime > a->fts_statp->st_mtime) + return (1); + else if (b->fts_statp->st_mtime < a->fts_statp->st_mtime) + return (-1); + else if (MTIMENSEC_CMP(b->fts_statp, >, a->fts_statp)) + return (1); + else if (MTIMENSEC_CMP(b->fts_statp, <, a->fts_statp)) + return (-1); + else + return (namecmp(a, b)); +} + +int +revmodcmp(const FTSENT *a, const FTSENT *b) +{ + + if (b->fts_statp->st_mtime > a->fts_statp->st_mtime) + return (-1); + else if (b->fts_statp->st_mtime < a->fts_statp->st_mtime) + return (1); + else if (MTIMENSEC_CMP(b->fts_statp, >, a->fts_statp)) + return (-1); + else if (MTIMENSEC_CMP(b->fts_statp, <, a->fts_statp)) + return (1); + else + return (revnamecmp(a, b)); +} + +int +acccmp(const FTSENT *a, const FTSENT *b) +{ + + if (b->fts_statp->st_atime > a->fts_statp->st_atime) + return (1); + else if (b->fts_statp->st_atime < a->fts_statp->st_atime) + return (-1); + else if (ATIMENSEC_CMP(b->fts_statp, >, a->fts_statp)) + return (1); + else if (ATIMENSEC_CMP(b->fts_statp, <, a->fts_statp)) + return (-1); + else + return (namecmp(a, b)); +} + +int +revacccmp(const FTSENT *a, const FTSENT *b) +{ + + if (b->fts_statp->st_atime > a->fts_statp->st_atime) + return (-1); + else if (b->fts_statp->st_atime < a->fts_statp->st_atime) + return (1); + else if (ATIMENSEC_CMP(b->fts_statp, >, a->fts_statp)) + return (-1); + else if (ATIMENSEC_CMP(b->fts_statp, <, a->fts_statp)) + return (1); + else + return (revnamecmp(a, b)); +} + +int +statcmp(const FTSENT *a, const FTSENT *b) +{ + + if (b->fts_statp->st_ctime > a->fts_statp->st_ctime) + return (1); + else if (b->fts_statp->st_ctime < a->fts_statp->st_ctime) + return (-1); + else if (CTIMENSEC_CMP(b->fts_statp, >, a->fts_statp)) + return (1); + else if (CTIMENSEC_CMP(b->fts_statp, <, a->fts_statp)) + return (-1); + else + return (namecmp(a, b)); +} + +int +revstatcmp(const FTSENT *a, const FTSENT *b) +{ + + if (b->fts_statp->st_ctime > a->fts_statp->st_ctime) + return (-1); + else if (b->fts_statp->st_ctime < a->fts_statp->st_ctime) + return (1); + else if (CTIMENSEC_CMP(b->fts_statp, >, a->fts_statp)) + return (-1); + else if (CTIMENSEC_CMP(b->fts_statp, <, a->fts_statp)) + return (1); + else + return (revnamecmp(a, b)); +} + +int +sizecmp(const FTSENT *a, const FTSENT *b) +{ + + if (b->fts_statp->st_size > a->fts_statp->st_size) + return (1); + if (b->fts_statp->st_size < a->fts_statp->st_size) + return (-1); + else + return (namecmp(a, b)); +} + +int +revsizecmp(const FTSENT *a, const FTSENT *b) +{ + + if (b->fts_statp->st_size > a->fts_statp->st_size) + return (-1); + if (b->fts_statp->st_size < a->fts_statp->st_size) + return (1); + else + return (revnamecmp(a, b)); +} diff --git a/cpukit/libmisc/shell/dd-args.c b/cpukit/libmisc/shell/dd-args.c new file mode 100644 index 0000000000..a271287166 --- /dev/null +++ b/cpukit/libmisc/shell/dd-args.c @@ -0,0 +1,507 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego and Lance + * Visser of Convex Computer Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)args.c 8.3 (Berkeley) 4/2/94"; +#endif +#endif /* not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/bin/dd/args.c,v 1.40 2004/08/15 19:10:05 rwatson Exp $"); + +#include <sys/types.h> + +#include <err.h> +#include <errno.h> +#include <inttypes.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> + +#include "dd.h" +#include "extern-dd.h" + +#define strtouq strtoul +#define strtoq strtol + +static int c_arg(const void *, const void *); +static int c_conv(const void *, const void *); +static void f_bs(rtems_shell_dd_globals* globals, char *); +static void f_cbs(rtems_shell_dd_globals* globals, char *); +static void f_conv(rtems_shell_dd_globals* globals, char *); +static void f_count(rtems_shell_dd_globals* globals, char *); +static void f_files(rtems_shell_dd_globals* globals, char *); +static void f_fillchar(rtems_shell_dd_globals* globals, char *); +static void f_ibs(rtems_shell_dd_globals* globals, char *); +static void f_if(rtems_shell_dd_globals* globals, char *); +static void f_obs(rtems_shell_dd_globals* globals, char *); +static void f_of(rtems_shell_dd_globals* globals, char *); +static void f_seek(rtems_shell_dd_globals* globals, char *); +static void f_skip(rtems_shell_dd_globals* globals, char *); +static uintmax_t get_num(rtems_shell_dd_globals* globals, const char *); +static off_t get_off_t(rtems_shell_dd_globals* globals, const char *); + +static const struct arg { + const char *name; + void (*f)(rtems_shell_dd_globals* globals, char *); + uint_least32_t set, noset; +} args[] = { + { "bs", f_bs, C_BS, C_BS|C_IBS|C_OBS|C_OSYNC }, + { "cbs", f_cbs, C_CBS, C_CBS }, + { "conv", f_conv, 0, 0 }, + { "count", f_count, C_COUNT, C_COUNT }, + { "files", f_files, C_FILES, C_FILES }, + { "fillchar", f_fillchar, C_FILL, C_FILL }, + { "ibs", f_ibs, C_IBS, C_BS|C_IBS }, + { "if", f_if, C_IF, C_IF }, + { "iseek", f_skip, C_SKIP, C_SKIP }, + { "obs", f_obs, C_OBS, C_BS|C_OBS }, + { "of", f_of, C_OF, C_OF }, + { "oseek", f_seek, C_SEEK, C_SEEK }, + { "seek", f_seek, C_SEEK, C_SEEK }, + { "skip", f_skip, C_SKIP, C_SKIP }, +}; + +static char *oper; + +/* + * args -- parse JCL syntax of dd. + */ +void +jcl(rtems_shell_dd_globals* globals, char **argv) +{ + struct arg *ap, tmp; + char *arg; + + oper = NULL; + + in.dbsz = out.dbsz = 512; + + while ((oper = *++argv) != NULL) { +// if ((oper = strdup(oper)) == NULL) +// errx(exit_jump, 1, "unable to allocate space for the argument \"%s\"", *argv); + if ((arg = strchr(oper, '=')) == NULL) + errx(exit_jump, 1, "unknown operand %s", oper); + *arg++ = '\0'; + if (!*arg) + errx(exit_jump, 1, "no value specified for %s", oper); + tmp.name = oper; + if (!(ap = (struct arg *)bsearch(&tmp, args, + sizeof(args)/sizeof(struct arg), sizeof(struct arg), + c_arg))) + errx(exit_jump, 1, "unknown operand %s", tmp.name); + if (ddflags & ap->noset) + errx(exit_jump, 1, "%s: illegal argument combination or already set", + tmp.name); + ddflags |= ap->set; + ap->f(globals, arg); + } + + /* Final sanity checks. */ + + if (ddflags & C_BS) { + /* + * Bs is turned off by any conversion -- we assume the user + * just wanted to set both the input and output block sizes + * and didn't want the bs semantics, so we don't warn. + */ + if (ddflags & (C_BLOCK | C_LCASE | C_SWAB | C_UCASE | + C_UNBLOCK)) + ddflags &= ~C_BS; + + /* Bs supersedes ibs and obs. */ + if (ddflags & C_BS && ddflags & (C_IBS | C_OBS)) + warnx("bs supersedes ibs and obs"); + } + + /* + * Ascii/ebcdic and cbs implies block/unblock. + * Block/unblock requires cbs and vice-versa. + */ + if (ddflags & (C_BLOCK | C_UNBLOCK)) { + if (!(ddflags & C_CBS)) + errx(exit_jump, 1, "record operations require cbs"); + if (cbsz == 0) + errx(exit_jump, 1, "cbs cannot be zero"); + cfunc = ddflags & C_BLOCK ? block : unblock; + } else if (ddflags & C_CBS) { + if (ddflags & (C_ASCII | C_EBCDIC)) { + if (ddflags & C_ASCII) { + ddflags |= C_UNBLOCK; + cfunc = unblock; + } else { + ddflags |= C_BLOCK; + cfunc = block; + } + } else + errx(exit_jump, 1, "cbs meaningless if not doing record operations"); + } else + cfunc = def; + + /* + * Bail out if the calculation of a file offset would overflow. + */ + if (in.offset > OFF_MAX / (ssize_t)in.dbsz || + out.offset > OFF_MAX / (ssize_t)out.dbsz) + errx(exit_jump, 1, "seek offsets cannot be larger than %jd", + (intmax_t)OFF_MAX); +} + +static int +c_arg(const void *a, const void *b) +{ + + return (strcmp(((const struct arg *)a)->name, + ((const struct arg *)b)->name)); +} + +static void +f_bs(rtems_shell_dd_globals* globals, char *arg) +{ + uintmax_t res; + + res = get_num(globals, arg); + if (res < 1 || res > SSIZE_MAX) + errx(exit_jump, 1, "bs must be between 1 and %jd", (intmax_t)SSIZE_MAX); + in.dbsz = out.dbsz = (size_t)res; +} + +static void +f_cbs(rtems_shell_dd_globals* globals, char *arg) +{ + uintmax_t res; + + res = get_num(globals, arg); + if (res < 1 || res > SSIZE_MAX) + errx(exit_jump, 1, "cbs must be between 1 and %jd", (intmax_t)SSIZE_MAX); + cbsz = (size_t)res; +} + +static void +f_count(rtems_shell_dd_globals* globals, char *arg) +{ + intmax_t res; + + res = (intmax_t)get_num(globals, arg); + if (res < 0) + errx(exit_jump, 1, "count cannot be negative"); + if (res == 0) + cpy_cnt = (uintmax_t)-1; + else + cpy_cnt = (uintmax_t)res; +} + +static void +f_files(rtems_shell_dd_globals* globals, char *arg) +{ + + files_cnt = get_num(globals, arg); + if (files_cnt < 1) + errx(exit_jump, 1, "files must be between 1 and %jd", (uintmax_t)-1); +} + +static void +f_fillchar(rtems_shell_dd_globals* globals, char *arg) +{ + + if (strlen(arg) != 1) + errx(exit_jump, 1, "need exactly one fill char"); + + fill_char = arg[0]; +} + +static void +f_ibs(rtems_shell_dd_globals* globals, char *arg) +{ + uintmax_t res; + + if (!(ddflags & C_BS)) { + res = get_num(globals, arg); + if (res < 1 || res > SSIZE_MAX) + errx(exit_jump, 1, "ibs must be between 1 and %jd", + (intmax_t)SSIZE_MAX); + in.dbsz = (size_t)res; + } +} + +static void +f_if(rtems_shell_dd_globals* globals, char *arg) +{ + + in.name = strdup(arg); +} + +static void +f_obs(rtems_shell_dd_globals* globals, char *arg) +{ + uintmax_t res; + + if (!(ddflags & C_BS)) { + res = get_num(globals, arg); + if (res < 1 || res > SSIZE_MAX) + errx(exit_jump, 1, "obs must be between 1 and %jd", + (intmax_t)SSIZE_MAX); + out.dbsz = (size_t)res; + } +} + +static void +f_of(rtems_shell_dd_globals* globals, char *arg) +{ + + out.name = strdup(arg); +} + +static void +f_seek(rtems_shell_dd_globals* globals, char *arg) +{ + + out.offset = get_off_t(globals, arg); +} + +static void +f_skip(rtems_shell_dd_globals* globals, char *arg) +{ + + in.offset = get_off_t(globals, arg); +} + +static const struct conv { + const char *name; + uint_least32_t set, noset; + const u_char *ctab_; +} clist[] = { + { "ascii", C_ASCII, C_EBCDIC, e2a_POSIX }, + { "block", C_BLOCK, C_UNBLOCK, NULL }, + { "ebcdic", C_EBCDIC, C_ASCII, a2e_POSIX }, + { "ibm", C_EBCDIC, C_ASCII, a2ibm_POSIX }, + { "lcase", C_LCASE, C_UCASE, NULL }, + { "noerror", C_NOERROR, 0, NULL }, + { "notrunc", C_NOTRUNC, 0, NULL }, + { "oldascii", C_ASCII, C_EBCDIC, e2a_32V }, + { "oldebcdic", C_EBCDIC, C_ASCII, a2e_32V }, + { "oldibm", C_EBCDIC, C_ASCII, a2ibm_32V }, + { "osync", C_OSYNC, C_BS, NULL }, + { "pareven", C_PAREVEN, C_PARODD|C_PARSET|C_PARNONE, NULL}, + { "parnone", C_PARNONE, C_PARODD|C_PARSET|C_PAREVEN, NULL}, + { "parodd", C_PARODD, C_PAREVEN|C_PARSET|C_PARNONE, NULL}, + { "parset", C_PARSET, C_PARODD|C_PAREVEN|C_PARNONE, NULL}, + { "sparse", C_SPARSE, 0, NULL }, + { "swab", C_SWAB, 0, NULL }, + { "sync", C_SYNC, 0, NULL }, + { "ucase", C_UCASE, C_LCASE, NULL }, + { "unblock", C_UNBLOCK, C_BLOCK, NULL }, +}; + +static void +f_conv(rtems_shell_dd_globals* globals, char *arg) +{ + struct conv *cp, tmp; + + while (arg != NULL) { + tmp.name = strsep(&arg, ","); + cp = bsearch(&tmp, clist, sizeof(clist) / sizeof(struct conv), + sizeof(struct conv), c_conv); + if (cp == NULL) + errx(exit_jump, 1, "unknown conversion %s", tmp.name); + if (ddflags & cp->noset) + errx(exit_jump, 1, "%s: illegal conversion combination", tmp.name); + ddflags |= cp->set; + if (cp->ctab_) + ctab = cp->ctab_; + } +} + +static int +c_conv(const void *a, const void *b) +{ + + return (strcmp(((const struct conv *)a)->name, + ((const struct conv *)b)->name)); +} + +/* + * Convert an expression of the following forms to a uintmax_t. + * 1) A positive decimal number. + * 2) A positive decimal number followed by a 'b' or 'B' (mult by 512). + * 3) A positive decimal number followed by a 'k' or 'K' (mult by 1 << 10). + * 4) A positive decimal number followed by a 'm' or 'M' (mult by 1 << 20). + * 5) A positive decimal number followed by a 'g' or 'G' (mult by 1 << 30). + * 5) A positive decimal number followed by a 'w' or 'W' (mult by sizeof int). + * 6) Two or more positive decimal numbers (with/without [BbKkMmGgWw]) + * separated by 'x' or 'X' (also '*' for backwards compatibility), + * specifying the product of the indicated values. + */ +static uintmax_t +get_num(rtems_shell_dd_globals* globals, const char *val) +{ + uintmax_t num, mult, prevnum; + char *expr; + + errno = 0; + num = strtouq(val, &expr, 0); + if (errno != 0) /* Overflow or underflow. */ + err(exit_jump, 1, "%s", oper); + + if (expr == val) /* No valid digits. */ + errx(exit_jump, 1, "%s: illegal numeric value", oper); + + mult = 0; + switch (*expr) { + case 'B': + case 'b': + mult = UINT32_C(512); + break; + case 'K': + case 'k': + mult = UINT32_C(1) << 10; + break; + case 'M': + case 'm': + mult = UINT32_C(1) << 20; + break; + case 'G': + case 'g': + mult = UINT32_C(1) << 30; + break; + case 'W': + case 'w': + mult = sizeof(int); + break; + default: + ; + } + + if (mult != 0) { + prevnum = num; + num *= mult; + /* Check for overflow. */ + if (num / mult != prevnum) + goto erange; + expr++; + } + + switch (*expr) { + case '\0': + break; + case '*': /* Backward compatible. */ + case 'X': + case 'x': + mult = get_num(globals, expr + 1); + prevnum = num; + num *= mult; + if (num / mult == prevnum) + break; +erange: + errx(exit_jump, 1, "%s: %s", oper, strerror(ERANGE)); + default: + errx(exit_jump, 1, "%s: illegal numeric value", oper); + } + return (num); +} + +/* + * Convert an expression of the following forms to an off_t. This is the + * same as get_num(), but it uses signed numbers. + * + * The major problem here is that an off_t may not necessarily be a intmax_t. + */ +static off_t +get_off_t(rtems_shell_dd_globals* globals, const char *val) +{ + intmax_t num, mult, prevnum; + char *expr; + + errno = 0; + num = strtoq(val, &expr, 0); + if (errno != 0) /* Overflow or underflow. */ + err(exit_jump, 1, "%s", oper); + + if (expr == val) /* No valid digits. */ + errx(exit_jump, 1, "%s: illegal numeric value", oper); + + mult = 0; + switch (*expr) { + case 'B': + case 'b': + mult = UINT32_C(512); + break; + case 'K': + case 'k': + mult = UINT32_C(1) << 10; + break; + case 'M': + case 'm': + mult = UINT32_C(1) << 20; + break; + case 'G': + case 'g': + mult = UINT32_C(1) << 30; + break; + case 'W': + case 'w': + mult = sizeof(int); + break; + } + + if (mult != 0) { + prevnum = num; + num *= mult; + /* Check for overflow. */ + if ((prevnum > 0) != (num > 0) || num / mult != prevnum) + goto erange; + expr++; + } + + switch (*expr) { + case '\0': + break; + case '*': /* Backward compatible. */ + case 'X': + case 'x': + mult = (intmax_t)get_off_t(globals, expr + 1); + prevnum = num; + num *= mult; + if ((prevnum > 0) == (num > 0) && num / mult == prevnum) + break; +erange: + errx(exit_jump, 1, "%s: %s", oper, strerror(ERANGE)); + default: + errx(exit_jump, 1, "%s: illegal numeric value", oper); + } + return (num); +} diff --git a/cpukit/libmisc/shell/dd-conv.c b/cpukit/libmisc/shell/dd-conv.c new file mode 100644 index 0000000000..81dba4798b --- /dev/null +++ b/cpukit/libmisc/shell/dd-conv.c @@ -0,0 +1,272 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego and Lance + * Visser of Convex Computer Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)conv.c 8.3 (Berkeley) 4/2/94"; +#endif +#endif /* not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/bin/dd/conv.c,v 1.19 2004/04/06 20:06:45 markm Exp $"); + +#include <sys/param.h> + +#include <err.h> +#include <inttypes.h> +#include <string.h> + +#include "dd.h" +#include "extern-dd.h" + +/* + * def -- + * Copy input to output. Input is buffered until reaches obs, and then + * output until less than obs remains. Only a single buffer is used. + * Worst case buffer calculation is (ibs + obs - 1). + */ +void +def(rtems_shell_dd_globals* globals) +{ + u_char *inp; + const u_char *t; + size_t cnt; + + if ((t = ctab) != NULL) + for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp) + *inp = t[*inp]; + + /* Make the output buffer look right. */ + out.dbp = in.dbp; + out.dbcnt = in.dbcnt; + + if (in.dbcnt >= out.dbsz) { + /* If the output buffer is full, write it. */ + dd_out(globals, 0); + + /* + * Ddout copies the leftover output to the beginning of + * the buffer and resets the output buffer. Reset the + * input buffer to match it. + */ + in.dbp = out.dbp; + in.dbcnt = out.dbcnt; + } +} + +void +def_close(rtems_shell_dd_globals* globals) +{ + /* Just update the count, everything is already in the buffer. */ + if (in.dbcnt) + out.dbcnt = in.dbcnt; +} + +/* + * Copy variable length newline terminated records with a max size cbsz + * bytes to output. Records less than cbs are padded with spaces. + * + * max in buffer: MAX(ibs, cbsz) + * max out buffer: obs + cbsz + */ +void +block(rtems_shell_dd_globals* globals) +{ + u_char *inp, *outp; + const u_char *t; + size_t cnt, maxlen; + static int intrunc; + int ch; + + /* + * Record truncation can cross block boundaries. If currently in a + * truncation state, keep tossing characters until reach a newline. + * Start at the beginning of the buffer, as the input buffer is always + * left empty. + */ + if (intrunc) { + for (inp = in.db, cnt = in.dbrcnt; cnt && *inp++ != '\n'; --cnt) + ; + if (!cnt) { + in.dbcnt = 0; + in.dbp = in.db; + return; + } + intrunc = 0; + /* Adjust the input buffer numbers. */ + in.dbcnt = cnt - 1; + in.dbp = inp + cnt - 1; + } + + /* + * Copy records (max cbsz size chunks) into the output buffer. The + * translation is done as we copy into the output buffer. + */ + ch = 0; + for (inp = in.dbp - in.dbcnt, outp = out.dbp; in.dbcnt;) { + maxlen = MIN(cbsz, in.dbcnt); + if ((t = ctab) != NULL) + for (cnt = 0; cnt < maxlen && (ch = *inp++) != '\n'; + ++cnt) + *outp++ = t[ch]; + else + for (cnt = 0; cnt < maxlen && (ch = *inp++) != '\n'; + ++cnt) + *outp++ = ch; + /* + * Check for short record without a newline. Reassemble the + * input block. + */ + if (ch != '\n' && in.dbcnt < cbsz) { + (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt); + break; + } + + /* Adjust the input buffer numbers. */ + in.dbcnt -= cnt; + if (ch == '\n') + --in.dbcnt; + + /* Pad short records with spaces. */ + if (cnt < cbsz) + (void)memset(outp, ctab ? ctab[' '] : ' ', cbsz - cnt); + else { + /* + * If the next character wouldn't have ended the + * block, it's a truncation. + */ + if (!in.dbcnt || *inp != '\n') + ++st.trunc; + + /* Toss characters to a newline. */ + for (; in.dbcnt && *inp++ != '\n'; --in.dbcnt) + ; + if (!in.dbcnt) + intrunc = 1; + else + --in.dbcnt; + } + + /* Adjust output buffer numbers. */ + out.dbp += cbsz; + if ((out.dbcnt += cbsz) >= out.dbsz) + dd_out(globals, 0); + outp = out.dbp; + } + in.dbp = in.db + in.dbcnt; +} + +void +block_close(rtems_shell_dd_globals* globals) +{ + /* + * Copy any remaining data into the output buffer and pad to a record. + * Don't worry about truncation or translation, the input buffer is + * always empty when truncating, and no characters have been added for + * translation. The bottom line is that anything left in the input + * buffer is a truncated record. Anything left in the output buffer + * just wasn't big enough. + */ + if (in.dbcnt) { + ++st.trunc; + (void)memmove(out.dbp, in.dbp - in.dbcnt, in.dbcnt); + (void)memset(out.dbp + in.dbcnt, ctab ? ctab[' '] : ' ', + cbsz - in.dbcnt); + out.dbcnt += cbsz; + } +} + +/* + * Convert fixed length (cbsz) records to variable length. Deletes any + * trailing blanks and appends a newline. + * + * max in buffer: MAX(ibs, cbsz) + cbsz + * max out buffer: obs + cbsz + */ +void +unblock(rtems_shell_dd_globals* globals) +{ + u_char *inp; + const u_char *t; + size_t cnt; + + /* Translation and case conversion. */ + if ((t = ctab) != NULL) + for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp) + *inp = t[*inp]; + /* + * Copy records (max cbsz size chunks) into the output buffer. The + * translation has to already be done or we might not recognize the + * spaces. + */ + for (inp = in.db; in.dbcnt >= cbsz; inp += cbsz, in.dbcnt -= cbsz) { + for (t = inp + cbsz - 1; t >= inp && *t == ' '; --t) + ; + if (t >= inp) { + cnt = t - inp + 1; + (void)memmove(out.dbp, inp, cnt); + out.dbp += cnt; + out.dbcnt += cnt; + } + *out.dbp++ = '\n'; + if (++out.dbcnt >= out.dbsz) + dd_out(globals, 0); + } + if (in.dbcnt) + (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt); + in.dbp = in.db + in.dbcnt; +} + +void +unblock_close(rtems_shell_dd_globals* globals) +{ + u_char *t; + size_t cnt; + + if (in.dbcnt) { + warnx("%s: short input record", in.name); + for (t = in.db + in.dbcnt - 1; t >= in.db && *t == ' '; --t) + ; + if (t >= in.db) { + cnt = t - in.db + 1; + (void)memmove(out.dbp, in.db, cnt); + out.dbp += cnt; + out.dbcnt += cnt; + } + ++out.dbcnt; + *out.dbp++ = '\n'; + } +} diff --git a/cpukit/libmisc/shell/dd-conv_tab.c b/cpukit/libmisc/shell/dd-conv_tab.c new file mode 100644 index 0000000000..782ed97be1 --- /dev/null +++ b/cpukit/libmisc/shell/dd-conv_tab.c @@ -0,0 +1,288 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego and Lance + * Visser of Convex Computer Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)conv_tab.c 8.1 (Berkeley) 5/31/93"; +#endif +#endif /* not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/bin/dd/conv_tab.c,v 1.12 2004/04/06 20:06:45 markm Exp $"); + +#include <sys/types.h> + +/* + * There are currently six tables: + * + * ebcdic -> ascii 32V conv=oldascii + * ascii -> ebcdic 32V conv=oldebcdic + * ascii -> ibm ebcdic 32V conv=oldibm + * + * ebcdic -> ascii POSIX/S5 conv=ascii + * ascii -> ebcdic POSIX/S5 conv=ebcdic + * ascii -> ibm ebcdic POSIX/S5 conv=ibm + * + * Other tables are built from these if multiple conversions are being + * done. + * + * Tables used for conversions to/from IBM and EBCDIC to support an extension + * to POSIX P1003.2/D11. The tables referencing POSIX contain data extracted + * from tables 4-3 and 4-4 in P1003.2/Draft 11. The historic tables were + * constructed by running against a file with all possible byte values. + * + * More information can be obtained in "Correspondences of 8-Bit and Hollerith + * Codes for Computer Environments-A USASI Tutorial", Communications of the + * ACM, Volume 11, Number 11, November 1968, pp. 783-789. + */ + +u_char casetab[256]; + +/* EBCDIC to ASCII -- 32V compatible. */ +const u_char e2a_32V[] = { + 0000, 0001, 0002, 0003, 0234, 0011, 0206, 0177, /* 0000 */ + 0227, 0215, 0216, 0013, 0014, 0015, 0016, 0017, /* 0010 */ + 0020, 0021, 0022, 0023, 0235, 0205, 0010, 0207, /* 0020 */ + 0030, 0031, 0222, 0217, 0034, 0035, 0036, 0037, /* 0030 */ + 0200, 0201, 0202, 0203, 0204, 0012, 0027, 0033, /* 0040 */ + 0210, 0211, 0212, 0213, 0214, 0005, 0006, 0007, /* 0050 */ + 0220, 0221, 0026, 0223, 0224, 0225, 0226, 0004, /* 0060 */ + 0230, 0231, 0232, 0233, 0024, 0025, 0236, 0032, /* 0070 */ + 0040, 0240, 0241, 0242, 0243, 0244, 0245, 0246, /* 0100 */ + 0247, 0250, 0133, 0056, 0074, 0050, 0053, 0041, /* 0110 */ + 0046, 0251, 0252, 0253, 0254, 0255, 0256, 0257, /* 0120 */ + 0260, 0261, 0135, 0044, 0052, 0051, 0073, 0136, /* 0130 */ + 0055, 0057, 0262, 0263, 0264, 0265, 0266, 0267, /* 0140 */ + 0270, 0271, 0174, 0054, 0045, 0137, 0076, 0077, /* 0150 */ + 0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301, /* 0160 */ + 0302, 0140, 0072, 0043, 0100, 0047, 0075, 0042, /* 0170 */ + 0303, 0141, 0142, 0143, 0144, 0145, 0146, 0147, /* 0200 */ + 0150, 0151, 0304, 0305, 0306, 0307, 0310, 0311, /* 0210 */ + 0312, 0152, 0153, 0154, 0155, 0156, 0157, 0160, /* 0220 */ + 0161, 0162, 0313, 0314, 0315, 0316, 0317, 0320, /* 0230 */ + 0321, 0176, 0163, 0164, 0165, 0166, 0167, 0170, /* 0240 */ + 0171, 0172, 0322, 0323, 0324, 0325, 0326, 0327, /* 0250 */ + 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337, /* 0260 */ + 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347, /* 0270 */ + 0173, 0101, 0102, 0103, 0104, 0105, 0106, 0107, /* 0300 */ + 0110, 0111, 0350, 0351, 0352, 0353, 0354, 0355, /* 0310 */ + 0175, 0112, 0113, 0114, 0115, 0116, 0117, 0120, /* 0320 */ + 0121, 0122, 0356, 0357, 0360, 0361, 0362, 0363, /* 0330 */ + 0134, 0237, 0123, 0124, 0125, 0126, 0127, 0130, /* 0340 */ + 0131, 0132, 0364, 0365, 0366, 0367, 0370, 0371, /* 0350 */ + 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067, /* 0360 */ + 0070, 0071, 0372, 0373, 0374, 0375, 0376, 0377, /* 0370 */ +}; + +/* ASCII to EBCDIC -- 32V compatible. */ +const u_char a2e_32V[] = { + 0000, 0001, 0002, 0003, 0067, 0055, 0056, 0057, /* 0000 */ + 0026, 0005, 0045, 0013, 0014, 0015, 0016, 0017, /* 0010 */ + 0020, 0021, 0022, 0023, 0074, 0075, 0062, 0046, /* 0020 */ + 0030, 0031, 0077, 0047, 0034, 0035, 0036, 0037, /* 0030 */ + 0100, 0117, 0177, 0173, 0133, 0154, 0120, 0175, /* 0040 */ + 0115, 0135, 0134, 0116, 0153, 0140, 0113, 0141, /* 0050 */ + 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, /* 0060 */ + 0370, 0371, 0172, 0136, 0114, 0176, 0156, 0157, /* 0070 */ + 0174, 0301, 0302, 0303, 0304, 0305, 0306, 0307, /* 0100 */ + 0310, 0311, 0321, 0322, 0323, 0324, 0325, 0326, /* 0110 */ + 0327, 0330, 0331, 0342, 0343, 0344, 0345, 0346, /* 0120 */ + 0347, 0350, 0351, 0112, 0340, 0132, 0137, 0155, /* 0130 */ + 0171, 0201, 0202, 0203, 0204, 0205, 0206, 0207, /* 0140 */ + 0210, 0211, 0221, 0222, 0223, 0224, 0225, 0226, /* 0150 */ + 0227, 0230, 0231, 0242, 0243, 0244, 0245, 0246, /* 0160 */ + 0247, 0250, 0251, 0300, 0152, 0320, 0241, 0007, /* 0170 */ + 0040, 0041, 0042, 0043, 0044, 0025, 0006, 0027, /* 0200 */ + 0050, 0051, 0052, 0053, 0054, 0011, 0012, 0033, /* 0210 */ + 0060, 0061, 0032, 0063, 0064, 0065, 0066, 0010, /* 0220 */ + 0070, 0071, 0072, 0073, 0004, 0024, 0076, 0341, /* 0230 */ + 0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110, /* 0240 */ + 0111, 0121, 0122, 0123, 0124, 0125, 0126, 0127, /* 0250 */ + 0130, 0131, 0142, 0143, 0144, 0145, 0146, 0147, /* 0260 */ + 0150, 0151, 0160, 0161, 0162, 0163, 0164, 0165, /* 0270 */ + 0166, 0167, 0170, 0200, 0212, 0213, 0214, 0215, /* 0300 */ + 0216, 0217, 0220, 0232, 0233, 0234, 0235, 0236, /* 0310 */ + 0237, 0240, 0252, 0253, 0254, 0255, 0256, 0257, /* 0320 */ + 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, /* 0330 */ + 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, /* 0340 */ + 0312, 0313, 0314, 0315, 0316, 0317, 0332, 0333, /* 0350 */ + 0334, 0335, 0336, 0337, 0352, 0353, 0354, 0355, /* 0360 */ + 0356, 0357, 0372, 0373, 0374, 0375, 0376, 0377, /* 0370 */ +}; + +/* ASCII to IBM EBCDIC -- 32V compatible. */ +const u_char a2ibm_32V[] = { + 0000, 0001, 0002, 0003, 0067, 0055, 0056, 0057, /* 0000 */ + 0026, 0005, 0045, 0013, 0014, 0015, 0016, 0017, /* 0010 */ + 0020, 0021, 0022, 0023, 0074, 0075, 0062, 0046, /* 0020 */ + 0030, 0031, 0077, 0047, 0034, 0035, 0036, 0037, /* 0030 */ + 0100, 0132, 0177, 0173, 0133, 0154, 0120, 0175, /* 0040 */ + 0115, 0135, 0134, 0116, 0153, 0140, 0113, 0141, /* 0050 */ + 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, /* 0060 */ + 0370, 0371, 0172, 0136, 0114, 0176, 0156, 0157, /* 0070 */ + 0174, 0301, 0302, 0303, 0304, 0305, 0306, 0307, /* 0100 */ + 0310, 0311, 0321, 0322, 0323, 0324, 0325, 0326, /* 0110 */ + 0327, 0330, 0331, 0342, 0343, 0344, 0345, 0346, /* 0120 */ + 0347, 0350, 0351, 0255, 0340, 0275, 0137, 0155, /* 0130 */ + 0171, 0201, 0202, 0203, 0204, 0205, 0206, 0207, /* 0140 */ + 0210, 0211, 0221, 0222, 0223, 0224, 0225, 0226, /* 0150 */ + 0227, 0230, 0231, 0242, 0243, 0244, 0245, 0246, /* 0160 */ + 0247, 0250, 0251, 0300, 0117, 0320, 0241, 0007, /* 0170 */ + 0040, 0041, 0042, 0043, 0044, 0025, 0006, 0027, /* 0200 */ + 0050, 0051, 0052, 0053, 0054, 0011, 0012, 0033, /* 0210 */ + 0060, 0061, 0032, 0063, 0064, 0065, 0066, 0010, /* 0220 */ + 0070, 0071, 0072, 0073, 0004, 0024, 0076, 0341, /* 0230 */ + 0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110, /* 0240 */ + 0111, 0121, 0122, 0123, 0124, 0125, 0126, 0127, /* 0250 */ + 0130, 0131, 0142, 0143, 0144, 0145, 0146, 0147, /* 0260 */ + 0150, 0151, 0160, 0161, 0162, 0163, 0164, 0165, /* 0270 */ + 0166, 0167, 0170, 0200, 0212, 0213, 0214, 0215, /* 0300 */ + 0216, 0217, 0220, 0232, 0233, 0234, 0235, 0236, /* 0310 */ + 0237, 0240, 0252, 0253, 0254, 0255, 0256, 0257, /* 0320 */ + 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, /* 0330 */ + 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, /* 0340 */ + 0312, 0313, 0314, 0315, 0316, 0317, 0332, 0333, /* 0350 */ + 0334, 0335, 0336, 0337, 0352, 0353, 0354, 0355, /* 0360 */ + 0356, 0357, 0372, 0373, 0374, 0375, 0376, 0377, /* 0370 */ +}; + +/* EBCDIC to ASCII -- POSIX and System V compatible. */ +const u_char e2a_POSIX[] = { + 0000, 0001, 0002, 0003, 0234, 0011, 0206, 0177, /* 0000 */ + 0227, 0215, 0216, 0013, 0014, 0015, 0016, 0017, /* 0010 */ + 0020, 0021, 0022, 0023, 0235, 0205, 0010, 0207, /* 0020 */ + 0030, 0031, 0222, 0217, 0034, 0035, 0036, 0037, /* 0030 */ + 0200, 0201, 0202, 0203, 0204, 0012, 0027, 0033, /* 0040 */ + 0210, 0211, 0212, 0213, 0214, 0005, 0006, 0007, /* 0050 */ + 0220, 0221, 0026, 0223, 0224, 0225, 0226, 0004, /* 0060 */ + 0230, 0231, 0232, 0233, 0024, 0025, 0236, 0032, /* 0070 */ + 0040, 0240, 0241, 0242, 0243, 0244, 0245, 0246, /* 0100 */ + 0247, 0250, 0325, 0056, 0074, 0050, 0053, 0174, /* 0110 */ + 0046, 0251, 0252, 0253, 0254, 0255, 0256, 0257, /* 0120 */ + 0260, 0261, 0041, 0044, 0052, 0051, 0073, 0176, /* 0130 */ + 0055, 0057, 0262, 0263, 0264, 0265, 0266, 0267, /* 0140 */ + 0270, 0271, 0313, 0054, 0045, 0137, 0076, 0077, /* 0150 */ + 0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301, /* 0160 */ + 0302, 0140, 0072, 0043, 0100, 0047, 0075, 0042, /* 0170 */ + 0303, 0141, 0142, 0143, 0144, 0145, 0146, 0147, /* 0200 */ + 0150, 0151, 0304, 0305, 0306, 0307, 0310, 0311, /* 0210 */ + 0312, 0152, 0153, 0154, 0155, 0156, 0157, 0160, /* 0220 */ + 0161, 0162, 0136, 0314, 0315, 0316, 0317, 0320, /* 0230 */ + 0321, 0345, 0163, 0164, 0165, 0166, 0167, 0170, /* 0240 */ + 0171, 0172, 0322, 0323, 0324, 0133, 0326, 0327, /* 0250 */ + 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337, /* 0260 */ + 0340, 0341, 0342, 0343, 0344, 0135, 0346, 0347, /* 0270 */ + 0173, 0101, 0102, 0103, 0104, 0105, 0106, 0107, /* 0300 */ + 0110, 0111, 0350, 0351, 0352, 0353, 0354, 0355, /* 0310 */ + 0175, 0112, 0113, 0114, 0115, 0116, 0117, 0120, /* 0320 */ + 0121, 0122, 0356, 0357, 0360, 0361, 0362, 0363, /* 0330 */ + 0134, 0237, 0123, 0124, 0125, 0126, 0127, 0130, /* 0340 */ + 0131, 0132, 0364, 0365, 0366, 0367, 0370, 0371, /* 0350 */ + 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067, /* 0360 */ + 0070, 0071, 0372, 0373, 0374, 0375, 0376, 0377, /* 0370 */ +}; + +/* ASCII to EBCDIC -- POSIX and System V compatible. */ +const u_char a2e_POSIX[] = { + 0000, 0001, 0002, 0003, 0067, 0055, 0056, 0057, /* 0000 */ + 0026, 0005, 0045, 0013, 0014, 0015, 0016, 0017, /* 0010 */ + 0020, 0021, 0022, 0023, 0074, 0075, 0062, 0046, /* 0020 */ + 0030, 0031, 0077, 0047, 0034, 0035, 0036, 0037, /* 0030 */ + 0100, 0132, 0177, 0173, 0133, 0154, 0120, 0175, /* 0040 */ + 0115, 0135, 0134, 0116, 0153, 0140, 0113, 0141, /* 0050 */ + 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, /* 0060 */ + 0370, 0371, 0172, 0136, 0114, 0176, 0156, 0157, /* 0070 */ + 0174, 0301, 0302, 0303, 0304, 0305, 0306, 0307, /* 0100 */ + 0310, 0311, 0321, 0322, 0323, 0324, 0325, 0326, /* 0110 */ + 0327, 0330, 0331, 0342, 0343, 0344, 0345, 0346, /* 0120 */ + 0347, 0350, 0351, 0255, 0340, 0275, 0232, 0155, /* 0130 */ + 0171, 0201, 0202, 0203, 0204, 0205, 0206, 0207, /* 0140 */ + 0210, 0211, 0221, 0222, 0223, 0224, 0225, 0226, /* 0150 */ + 0227, 0230, 0231, 0242, 0243, 0244, 0245, 0246, /* 0160 */ + 0247, 0250, 0251, 0300, 0117, 0320, 0137, 0007, /* 0170 */ + 0040, 0041, 0042, 0043, 0044, 0025, 0006, 0027, /* 0200 */ + 0050, 0051, 0052, 0053, 0054, 0011, 0012, 0033, /* 0210 */ + 0060, 0061, 0032, 0063, 0064, 0065, 0066, 0010, /* 0220 */ + 0070, 0071, 0072, 0073, 0004, 0024, 0076, 0341, /* 0230 */ + 0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110, /* 0240 */ + 0111, 0121, 0122, 0123, 0124, 0125, 0126, 0127, /* 0250 */ + 0130, 0131, 0142, 0143, 0144, 0145, 0146, 0147, /* 0260 */ + 0150, 0151, 0160, 0161, 0162, 0163, 0164, 0165, /* 0270 */ + 0166, 0167, 0170, 0200, 0212, 0213, 0214, 0215, /* 0300 */ + 0216, 0217, 0220, 0152, 0233, 0234, 0235, 0236, /* 0310 */ + 0237, 0240, 0252, 0253, 0254, 0112, 0256, 0257, /* 0320 */ + 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, /* 0330 */ + 0270, 0271, 0272, 0273, 0274, 0241, 0276, 0277, /* 0340 */ + 0312, 0313, 0314, 0315, 0316, 0317, 0332, 0333, /* 0350 */ + 0334, 0335, 0336, 0337, 0352, 0353, 0354, 0355, /* 0360 */ + 0356, 0357, 0372, 0373, 0374, 0375, 0376, 0377, /* 0370 */ +}; + +/* ASCII to IBM EBCDIC -- POSIX and System V compatible. */ +const u_char a2ibm_POSIX[] = { + 0000, 0001, 0002, 0003, 0067, 0055, 0056, 0057, /* 0000 */ + 0026, 0005, 0045, 0013, 0014, 0015, 0016, 0017, /* 0010 */ + 0020, 0021, 0022, 0023, 0074, 0075, 0062, 0046, /* 0020 */ + 0030, 0031, 0077, 0047, 0034, 0035, 0036, 0037, /* 0030 */ + 0100, 0132, 0177, 0173, 0133, 0154, 0120, 0175, /* 0040 */ + 0115, 0135, 0134, 0116, 0153, 0140, 0113, 0141, /* 0050 */ + 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, /* 0060 */ + 0370, 0371, 0172, 0136, 0114, 0176, 0156, 0157, /* 0070 */ + 0174, 0301, 0302, 0303, 0304, 0305, 0306, 0307, /* 0100 */ + 0310, 0311, 0321, 0322, 0323, 0324, 0325, 0326, /* 0110 */ + 0327, 0330, 0331, 0342, 0343, 0344, 0345, 0346, /* 0120 */ + 0347, 0350, 0351, 0255, 0340, 0275, 0137, 0155, /* 0130 */ + 0171, 0201, 0202, 0203, 0204, 0205, 0206, 0207, /* 0140 */ + 0210, 0211, 0221, 0222, 0223, 0224, 0225, 0226, /* 0150 */ + 0227, 0230, 0231, 0242, 0243, 0244, 0245, 0246, /* 0160 */ + 0247, 0250, 0251, 0300, 0117, 0320, 0241, 0007, /* 0170 */ + 0040, 0041, 0042, 0043, 0044, 0025, 0006, 0027, /* 0200 */ + 0050, 0051, 0052, 0053, 0054, 0011, 0012, 0033, /* 0210 */ + 0060, 0061, 0032, 0063, 0064, 0065, 0066, 0010, /* 0220 */ + 0070, 0071, 0072, 0073, 0004, 0024, 0076, 0341, /* 0230 */ + 0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110, /* 0240 */ + 0111, 0121, 0122, 0123, 0124, 0125, 0126, 0127, /* 0250 */ + 0130, 0131, 0142, 0143, 0144, 0145, 0146, 0147, /* 0260 */ + 0150, 0151, 0160, 0161, 0162, 0163, 0164, 0165, /* 0270 */ + 0166, 0167, 0170, 0200, 0212, 0213, 0214, 0215, /* 0300 */ + 0216, 0217, 0220, 0232, 0233, 0234, 0235, 0236, /* 0310 */ + 0237, 0240, 0252, 0253, 0254, 0255, 0256, 0257, /* 0320 */ + 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, /* 0330 */ + 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, /* 0340 */ + 0312, 0313, 0314, 0315, 0316, 0317, 0332, 0333, /* 0350 */ + 0334, 0335, 0336, 0337, 0352, 0353, 0354, 0355, /* 0360 */ + 0356, 0357, 0372, 0373, 0374, 0375, 0376, 0377, /* 0370 */ +}; diff --git a/cpukit/libmisc/shell/dd-misc.c b/cpukit/libmisc/shell/dd-misc.c new file mode 100644 index 0000000000..dc5cc0eb09 --- /dev/null +++ b/cpukit/libmisc/shell/dd-misc.c @@ -0,0 +1,112 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego and Lance + * Visser of Convex Computer Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)misc.c 8.3 (Berkeley) 4/2/94"; +#endif +#endif /* not lint */ +#if 0 +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/bin/dd/misc.c,v 1.27 2004/04/06 20:06:46 markm Exp $"); +#endif + +#include <sys/types.h> +#include <sys/time.h> + +#include <errno.h> +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "dd.h" +#include "extern-dd.h" + +void +summary(rtems_shell_dd_globals* globals) +{ + struct timeval tv; + double secs; + char buf[100]; + + (void)gettimeofday(&tv, (struct timezone *)NULL); + secs = tv.tv_sec + tv.tv_usec * 1e-6 - st.start; + if (secs < 1e-6) + secs = 1e-6; + /* Use snprintf(3) so that we don't reenter stdio(3). */ + (void)snprintf(buf, sizeof(buf), + "%ju+%ju records in\n%ju+%ju records out\n", + st.in_full, st.in_part, st.out_full, st.out_part); + (void)write(STDERR_FILENO, buf, strlen(buf)); + if (st.swab) { + (void)snprintf(buf, sizeof(buf), "%ju odd length swab %s\n", + st.swab, (st.swab == 1) ? "block" : "blocks"); + (void)write(STDERR_FILENO, buf, strlen(buf)); + } + if (st.trunc) { + (void)snprintf(buf, sizeof(buf), "%ju truncated %s\n", + st.trunc, (st.trunc == 1) ? "block" : "blocks"); + (void)write(STDERR_FILENO, buf, strlen(buf)); + } + (void)snprintf(buf, sizeof(buf), + "%ju bytes transferred in %.6f secs (%.0f bytes/sec)\n", + st.bytes, secs, st.bytes / secs); + (void)write(STDERR_FILENO, buf, strlen(buf)); +} + +/* ARGSUSED */ +void +summaryx(rtems_shell_dd_globals* globals, int __unused) +{ + int save_errno = errno; + + summary(globals); + errno = save_errno; +} + +#if RTEMS_REMOVED +/* ARGSUSED */ +void +terminate(int sig) +{ + + summary(); + _exit(sig == 0 ? 0 : 1); +} +#endif diff --git a/cpukit/libmisc/shell/dd-position.c b/cpukit/libmisc/shell/dd-position.c new file mode 100644 index 0000000000..7586faddf8 --- /dev/null +++ b/cpukit/libmisc/shell/dd-position.c @@ -0,0 +1,193 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego and Lance + * Visser of Convex Computer Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)position.c 8.3 (Berkeley) 4/2/94"; +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/bin/dd/position.c,v 1.23 2004/04/06 20:06:46 markm Exp $"); +#endif +#endif /* not lint */ + +#include <sys/types.h> +#if RTEMS_REMOVED +#include <sys/mtio.h> +#endif + +#include <err.h> +#include <errno.h> +#include <inttypes.h> +#include <unistd.h> + +#include "dd.h" +#include "extern-dd.h" + +/* + * Position input/output data streams before starting the copy. Device type + * dependent. Seekable devices use lseek, and the rest position by reading. + * Seeking past the end of file can cause null blocks to be written to the + * output. + */ +void +pos_in(rtems_shell_dd_globals* globals) +{ + off_t cnt; + int warned; + ssize_t nr; + size_t bcnt; + + /* If known to be seekable, try to seek on it. */ + if (in.flags & ISSEEK) { + errno = 0; + if (lseek(in.fd, in.offset * in.dbsz, SEEK_CUR) == -1 && + errno != 0) + err(exit_jump, 1, "%s", in.name); + return; + } + + /* Don't try to read a really weird amount (like negative). */ + if (in.offset < 0) + errx(exit_jump, 1, "%s: illegal offset", "iseek/skip"); + + /* + * Read the data. If a pipe, read until satisfy the number of bytes + * being skipped. No differentiation for reading complete and partial + * blocks for other devices. + */ + for (bcnt = in.dbsz, cnt = in.offset, warned = 0; cnt;) { + if ((nr = read(in.fd, in.db, bcnt)) > 0) { + if (in.flags & ISPIPE) { + if (!(bcnt -= nr)) { + bcnt = in.dbsz; + --cnt; + } + } else + --cnt; + continue; + } + + if (nr == 0) { + if (files_cnt > 1) { + --files_cnt; + continue; + } + errx(exit_jump, 1, "skip reached end of input"); + } + + /* + * Input error -- either EOF with no more files, or I/O error. + * If noerror not set die. POSIX requires that the warning + * message be followed by an I/O display. + */ + if (ddflags & C_NOERROR) { + if (!warned) { + warn("%s", in.name); + warned = 1; + summary(globals); + } + continue; + } + err(exit_jump, 1, "%s", in.name); + } +} + +void +pos_out(rtems_shell_dd_globals* globals) +{ +#if RTEMS_REMOVED + struct mtop t_op; + off_t cnt; + ssize_t n; +#endif + + /* + * If not a tape, try seeking on the file. Seeking on a pipe is + * going to fail, but don't protect the user -- they shouldn't + * have specified the seek operand. + */ + if (out.flags & (ISSEEK | ISPIPE)) { + errno = 0; + if (lseek(out.fd, out.offset * out.dbsz, SEEK_CUR) == -1 && + errno != 0) + err(exit_jump, 1, "%s", out.name); + return; + } + + /* Don't try to read a really weird amount (like negative). */ + if (out.offset < 0) + errx(exit_jump, 1, "%s: illegal offset", "oseek/seek"); + +#if RTEMS_REMOVED + /* If no read access, try using mtio. */ + if (out.flags & NOREAD) { + t_op.mt_op = MTFSR; + t_op.mt_count = out.offset; + + if (ioctl(out.fd, MTIOCTOP, &t_op) == -1) + err(1, "%s", out.name); + return; + } + + /* Read it. */ + for (cnt = 0; cnt < out.offset; ++cnt) { + if ((n = read(out.fd, out.db, out.dbsz)) > 0) + continue; + + if (n == -1) + err(1, "%s", out.name); + + /* + * If reach EOF, fill with NUL characters; first, back up over + * the EOF mark. Note, cnt has not yet been incremented, so + * the EOF read does not count as a seek'd block. + */ + t_op.mt_op = MTBSR; + t_op.mt_count = 1; + if (ioctl(out.fd, MTIOCTOP, &t_op) == -1) + err(1, "%s", out.name); + + while (cnt++ < out.offset) { + n = write(out.fd, out.db, out.dbsz); + if (n == -1) + err(1, "%s", out.name); + if ((size_t)n != out.dbsz) + errx(1, "%s: write failure", out.name); + } + break; + } +#endif +} diff --git a/cpukit/libmisc/shell/dd.h b/cpukit/libmisc/shell/dd.h new file mode 100644 index 0000000000..dc80765d48 --- /dev/null +++ b/cpukit/libmisc/shell/dd.h @@ -0,0 +1,108 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego and Lance + * Visser of Convex Computer Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)dd.h 8.3 (Berkeley) 4/2/94 + * $FreeBSD: src/bin/dd/dd.h,v 1.22 2004/08/15 19:10:05 rwatson Exp $ + */ + +#ifndef _DD_H_ +#define _DD_H_ + +#include <stddef.h> + +#define OFF_MAX LONG_MAX + +/* Input/output stream state. */ +typedef struct { + u_char *db; /* buffer address */ + u_char *dbp; /* current buffer I/O address */ + /* XXX ssize_t? */ + size_t dbcnt; /* current buffer byte count */ + size_t dbrcnt; /* last read byte count */ + size_t dbsz; /* buffer size */ + +#define ISCHR 0x01 /* character device (warn on short) */ +#define ISPIPE 0x02 /* pipe-like (see position.c) */ +#define ISTAPE 0x04 /* tape */ +#define ISSEEK 0x08 /* valid to seek on */ +#define NOREAD 0x10 /* not readable */ +#define ISTRUNC 0x20 /* valid to ftruncate() */ + u_int flags; + + const char *name; /* name */ + int fd; /* file descriptor */ + off_t offset; /* # of blocks to skip */ +} IO; + +typedef struct { + uintmax_t in_full; /* # of full input blocks */ + uintmax_t in_part; /* # of partial input blocks */ + uintmax_t out_full; /* # of full output blocks */ + uintmax_t out_part; /* # of partial output blocks */ + uintmax_t trunc; /* # of truncated records */ + uintmax_t swab; /* # of odd-length swab blocks */ + uintmax_t bytes; /* # of bytes written */ + double start; /* start time of dd */ +} STAT; + +/* Flags (in ddflags). */ +#define C_ASCII 0x00001 +#define C_BLOCK 0x00002 +#define C_BS 0x00004 +#define C_CBS 0x00008 +#define C_COUNT 0x00010 +#define C_EBCDIC 0x00020 +#define C_FILES 0x00040 +#define C_IBS 0x00080 +#define C_IF 0x00100 +#define C_LCASE 0x00200 +#define C_NOERROR 0x00400 +#define C_NOTRUNC 0x00800 +#define C_OBS 0x01000 +#define C_OF 0x02000 +#define C_OSYNC 0x04000 +#define C_PAREVEN 0x08000 +#define C_PARNONE 0x100000 +#define C_PARODD 0x200000 +#define C_PARSET 0x400000 +#define C_SEEK 0x800000 +#define C_SKIP 0x1000000 +#define C_SPARSE 0x2000000 +#define C_SWAB 0x4000000 +#define C_SYNC 0x8000000 +#define C_UCASE 0x10000000 +#define C_UNBLOCK 0x20000000 +#define C_FILL 0x40000000 + +#define C_PARITY (C_PAREVEN | C_PARODD | C_PARNONE | C_PARSET) + +#endif diff --git a/cpukit/libmisc/shell/err.c b/cpukit/libmisc/shell/err.c new file mode 100644 index 0000000000..610ea598a2 --- /dev/null +++ b/cpukit/libmisc/shell/err.c @@ -0,0 +1,64 @@ +/* $NetBSD: err.c,v 1.25 2005/09/13 13:51:50 christos Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)err.c 8.1 (Berkeley) 6/4/93"; +#else +__RCSID("$NetBSD: err.c,v 1.25 2005/09/13 13:51:50 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#include <err.h> +#include <stdarg.h> + +#ifdef __weak_alias +__weak_alias(err, _err) +#endif + +__dead void +err(jmp_buf* exit_jmp, int eval, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + verr(exit_jmp, eval, fmt, ap); + va_end(ap); +} diff --git a/cpukit/libmisc/shell/err.h b/cpukit/libmisc/shell/err.h new file mode 100644 index 0000000000..f028d3b151 --- /dev/null +++ b/cpukit/libmisc/shell/err.h @@ -0,0 +1,84 @@ +/* $NetBSD: err.h,v 1.14 2005/02/03 04:39:32 perry Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)err.h 8.1 (Berkeley) 6/2/93 + */ + +#ifndef _ERR_H_ +#define _ERR_H_ + +/* + * Don't use va_list in the err/warn prototypes. Va_list is typedef'd in two + * places (<machine/varargs.h> and <machine/stdarg.h>), so if we include one + * of them here we may collide with the utility's includes. It's unreasonable + * for utilities to have to include one of them to include err.h, so we get + * _BSD_VA_LIST_ from <machine/ansi.h> and use it. + */ +#include <machine/ansi.h> +#include <sys/cdefs.h> + +#include <stdarg.h> +#define _BSD_VA_LIST_ va_list + +#define __dead + +#define err rtems_shell_err +#define verr rtems_shell_verr +#define errx rtems_shell_errx +#define verrx rtems_shell_verrx +#define warn rtems_shell_warn +#define vwarn rtems_shell_vwarn +#define warnx rtems_shell_warnx +#define vwarnx rtems_shell_vwarnx + +#include <setjmp.h> + +extern jmp_buf rtems_shell_bsd_exit_recover; + +__BEGIN_DECLS +__dead void err(jmp_buf*, int, const char *, ...) + __attribute__((__noreturn__, __format__(__printf__, 3, 4))); +__dead void verr(jmp_buf*, int, const char *, _BSD_VA_LIST_) + __attribute__((__noreturn__, __format__(__printf__, 3, 0))); +__dead void errx(jmp_buf*, int, const char *, ...) + __attribute__((__noreturn__, __format__(__printf__, 3, 4))); +__dead void verrx(jmp_buf*, int, const char *, _BSD_VA_LIST_) + __attribute__((__noreturn__, __format__(__printf__, 3, 0))); +void warn(const char *, ...) + __attribute__((__format__(__printf__, 1, 2))); +void vwarn(const char *, _BSD_VA_LIST_) + __attribute__((__format__(__printf__, 1, 0))); +void warnx(const char *, ...) + __attribute__((__format__(__printf__, 1, 2))); +void vwarnx(const char *, _BSD_VA_LIST_) + __attribute__((__format__(__printf__, 1, 0))); +__END_DECLS + +#endif /* !_ERR_H_ */ diff --git a/cpukit/libmisc/shell/errx.c b/cpukit/libmisc/shell/errx.c new file mode 100644 index 0000000000..04e15e128b --- /dev/null +++ b/cpukit/libmisc/shell/errx.c @@ -0,0 +1,64 @@ +/* $NetBSD: errx.c,v 1.13 2005/09/13 13:51:50 christos Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)err.c 8.1 (Berkeley) 6/4/93"; +#else +__RCSID("$NetBSD: errx.c,v 1.13 2005/09/13 13:51:50 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#include <err.h> +#include <stdarg.h> + +#ifdef __weak_alias +__weak_alias(errx, _errx) +#endif + +__dead void +errx(jmp_buf* exit_jmp, int eval, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + verrx(exit_jmp, eval, fmt, ap); + va_end(ap); +} diff --git a/cpukit/libmisc/shell/extern-cp.h b/cpukit/libmisc/shell/extern-cp.h new file mode 100644 index 0000000000..093b30ff10 --- /dev/null +++ b/cpukit/libmisc/shell/extern-cp.h @@ -0,0 +1,91 @@ +/* $NetBSD: extern.h,v 1.12 2005/10/15 18:22:18 christos Exp $ */ + +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)extern.h 8.2 (Berkeley) 4/1/94 + */ + +#ifndef _EXTERN_CP_H_ +#define _EXTERN_CP_H_ + +#define PATH_T RTEMS_SHELL_CP_PATH_T + +typedef struct { + char *p_end; /* pointer to NULL at end of path */ + char *target_end; /* pointer to end of target base */ + char p_path[MAXPATHLEN + 1]; /* pointer to the start of a path */ +} PATH_T; + +#include <setjmp.h> + +typedef struct { + PATH_T to; + int info; + uid_t myuid; + int fflag, iflag, lflag, nflag, pflag, vflag; + mode_t myumask; + jmp_buf exit_jmp; +} rtems_shell_cp_globals; + +#define to cp_globals->to +#define info cp_globals->info +#define myuid cp_globals->myuid +#define fflag cp_globals->fflag +#define iflag cp_globals->iflag +#define lflag cp_globals->lflag +#define nflag cp_globals->nflag +#define pflag cp_globals->pflag +#define vflag cp_globals->vflag +#define myumask cp_globals->myumask +#define exit_jump &(cp_globals->exit_jmp) + +#define copy_fifo rtems_shell_cp_copy_fifo +#define copy_file rtems_shell_cp_copy_file +#define copy_link rtems_shell_cp_copy_link +#define copy_special rtems_shell_cp_copy_special +#define set_utimes rtems_shell_cp_set_utimes +#define setfile rtems_shell_cp_setfile +#define usage rtems_shell_cp_usage + +#include <sys/cdefs.h> + +__BEGIN_DECLS +int copy_fifo(rtems_shell_cp_globals* cp_globals, struct stat *, int); +int copy_file(rtems_shell_cp_globals* cp_globals, FTSENT *, int); +int copy_link(rtems_shell_cp_globals* cp_globals, FTSENT *, int); +int copy_special(rtems_shell_cp_globals* cp_globals, struct stat *, int); +int set_utimes(const char *, struct stat *); +int setfile(rtems_shell_cp_globals* cp_globals, struct stat *, int); +int preserve_dir_acls(struct stat *, char *, char *); +int preserve_fd_acls(int, int); +void usage(rtems_shell_cp_globals* cp_globals); + +__END_DECLS + +#endif /* !_EXTERN_H_ */ diff --git a/cpukit/libmisc/shell/extern-dd.h b/cpukit/libmisc/shell/extern-dd.h new file mode 100644 index 0000000000..405d460ef3 --- /dev/null +++ b/cpukit/libmisc/shell/extern-dd.h @@ -0,0 +1,106 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego and Lance + * Visser of Convex Computer Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)extern.h 8.3 (Berkeley) 4/2/94 + * $FreeBSD: src/bin/dd/extern.h,v 1.15 2004/08/15 19:10:05 rwatson Exp $ + */ + +#ifndef _EXTERN_DD_H_ +#define _EXTERN_DD_H_ + +#include <setjmp.h> + +typedef struct rtems_shell_dd_globals_t { + IO in, out; /* input/output state */ + STAT st; /* statistics */ + void (*cfunc)(struct rtems_shell_dd_globals_t* globals); /* conversion function */ + uintmax_t cpy_cnt; /* # of blocks to copy */ + u_int ddflags; /* conversion options */ + size_t cbsz; /* conversion block size */ + uintmax_t files_cnt; /* # of files to copy */ + const u_char *ctab; /* conversion table */ + char fill_char; /* Character to fill with if defined */ + u_char casetab[256]; + int exit_code; + jmp_buf exit_jmp; +} rtems_shell_dd_globals; + +#define in globals->in +#define out globals->out +#define st globals->st +#define cfunc globals->cfunc +#define cpy_cnt globals->cpy_cnt +#define ddflags globals->ddflags +#define cbsz globals->cbsz +#define files_cnt globals->files_cnt +#define casetab globals->casetab +#define ctab globals->ctab +#define fill_char globals->fill_char +#define exit_jump &(globals->exit_jmp) + +#define block rtems_shell_dd_block +#define block_close rtems_shell_dd_block_close +#define dd_out rtems_shell_dd_dd_out +#define def rtems_shell_dd_def +#define def_close rtems_shell_dd_def_close +#define jcl rtems_shell_dd_jcl +#define pos_in rtems_shell_dd_pos_in +#define pos_out rtems_shell_dd_pos_out +#define summary rtems_shell_dd_summary +#define summaryx rtems_shell_dd_summaryx +#define terminate rtems_shell_dd_terminate +#define unblock rtems_shell_dd_unblock +#define unblock_close rtems_shell_dd_unblock_close + +void block(rtems_shell_dd_globals* ); +void block_close(rtems_shell_dd_globals* ); +void dd_out(rtems_shell_dd_globals* , int); +void def(rtems_shell_dd_globals* globals); +void def_close(rtems_shell_dd_globals* ); +void jcl(rtems_shell_dd_globals* , char **); +void pos_in(rtems_shell_dd_globals* ); +void pos_out(rtems_shell_dd_globals* ); +void summary(rtems_shell_dd_globals* ); +void summaryx(rtems_shell_dd_globals* , int); +void terminate(int); +void unblock(rtems_shell_dd_globals* globals); +void unblock_close(rtems_shell_dd_globals* globals); + +extern const u_char a2e_32V[256], a2e_POSIX[256]; +extern const u_char e2a_32V[256], e2a_POSIX[256]; +extern const u_char a2ibm_32V[256], a2ibm_POSIX[256]; + +void rtems_shell_dd_exit(rtems_shell_dd_globals* globals, int code); + +#define exit(ec) rtems_shell_dd_exit(globals, ec) + +#endif /* !_EXTERN_H_ */ diff --git a/cpukit/libmisc/shell/extern-ls.h b/cpukit/libmisc/shell/extern-ls.h new file mode 100644 index 0000000000..33f713b66e --- /dev/null +++ b/cpukit/libmisc/shell/extern-ls.h @@ -0,0 +1,192 @@ +/*- + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Michael Fischbein. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)ls.h 8.1 (Berkeley) 5/31/93 + * $FreeBSD: src/bin/ls/ls.h,v 1.23 2008/04/04 03:57:46 grog Exp $ + */ + +#ifndef _EXTERN_LS_H_ +#define _EXTERN_LS_H_ + +#define NO_PRINT 1 +//#define COLORLS 1 + +#include <sys/cdefs.h> +#include <setjmp.h> + +#define major(d) rtems_filesystem_dev_major_t(d) +#define minor(d) rtems_filesystem_dev_minor_t(d) + +const char *user_from_uid(uid_t uid, int nouser); + +typedef struct { + int blocksize; + int termwidth; + int sortkey; + int rval; + int output; + time_t now; + + int f_accesstime; + int f_column; + int f_columnacross; + int f_flags; + int f_grouponly; + int f_humanize; + int f_inode; + int f_listdir; + int f_listdot; + int f_longform; + int f_nonprint; + int f_nosort; + int f_numericonly; + int f_octal; + int f_octal_escape; + int f_recursive; + int f_reversesort; + int f_sectime; + int f_singlecol; + int f_size; + int f_statustime; + int f_stream; + int f_type; + int f_typedir; + int f_whiteout; + + int exit_code; + jmp_buf exit_jmp; +} rtems_shell_ls_globals; + +#define blocksize globals->blocksize +#define termwidth globals->termwidth +#define sortkey globals->sortkey +#define rval globals->rval +#define output globals->output +#define now globals->now + +#define f_accesstime globals->f_accesstime +#define f_column globals->f_column +#define f_columnacross globals->f_columnacross +#define f_flags globals->f_flags +#define f_grouponly globals->f_grouponly +#define f_humanize globals->f_humanize +#define f_inode globals->f_inode +#define f_listdir globals->f_listdir +#define f_listdot globals->f_listdot +#define f_longform globals->f_longform +#define f_nonprint globals->f_nonprint +#define f_nosort globals->f_nosort +#define f_numericonly globals->f_numericonly +#define f_octal globals->f_octal +#define f_octal_escape globals->f_octal_escape +#define f_recursive globals->f_recursive +#define f_reversesort globals->f_reversesort +#define f_sectime globals->f_sectime +#define f_singlecol globals->f_singlecol +#define f_size globals->f_size +#define f_statustime globals->f_statustime +#define f_stream globals->f_stream +#define f_type globals->f_type +#define f_typedir globals->f_typedir +#define f_whiteout globals->f_whiteout + +#define exit_jump &(globals->exit_jmp) + +void rtems_shell_ls_exit(rtems_shell_ls_globals* globals, int code); + +#define exit(ec) rtems_shell_ls_exit(globals, ec) + + +typedef struct { + FTSENT *list; + u_int64_t btotal; + u_int64_t stotal; + int entries; + int maxlen; + int s_block; + int s_flags; + int s_group; + int s_inode; + int s_nlink; + int s_size; + int s_user; + int s_major; + int s_minor; +} DISPLAY; + +typedef struct { + char *user; + char *group; + char *flags; + char data[1]; +} NAMES; + +#define acccmp rtems_shell_ls_acccmp +#define revacccmp rtems_shell_ls_revacccmp +#define modcmp rtems_shell_ls_modcmp +#define revmodcmp rtems_shell_ls_revmodcmp +#define namecmp rtems_shell_ls_namecmp +#define revnamecmp rtems_shell_ls_revnamecmp +#define statcmp rtems_shell_ls_statcmp +#define revstatcmp rtems_shell_ls_revstatcmp +#define sizecmp rtems_shell_ls_sizecmp +#define revsizecmp rtems_shell_ls_revsizecmp +#define printescaped rtems_shell_ls_printescaped +#define printacol rtems_shell_ls_printacol +#define printcol rtems_shell_ls_printcol +#define printlong rtems_shell_ls_printlong +#define printscol rtems_shell_ls_printscol +#define printstream rtems_shell_ls_printstream +#define usage rtems_shell_ls_usage + +int acccmp(const FTSENT *, const FTSENT *); +int revacccmp(const FTSENT *, const FTSENT *); +int modcmp(const FTSENT *, const FTSENT *); +int revmodcmp(const FTSENT *, const FTSENT *); +int namecmp(const FTSENT *, const FTSENT *); +int revnamecmp(const FTSENT *, const FTSENT *); +int statcmp(const FTSENT *, const FTSENT *); +int revstatcmp(const FTSENT *, const FTSENT *); +int sizecmp(const FTSENT *, const FTSENT *); +int revsizecmp(const FTSENT *, const FTSENT *); + +int printescaped(rtems_shell_ls_globals* globals, const char *); +void printacol(rtems_shell_ls_globals* globals, DISPLAY *); +void printcol(rtems_shell_ls_globals* globals, DISPLAY *); +void printlong(rtems_shell_ls_globals* globals, DISPLAY *); +void printscol(rtems_shell_ls_globals* globals, DISPLAY *); +void printstream(rtems_shell_ls_globals* globals, DISPLAY *); +int safe_print(rtems_shell_ls_globals* globals, const char *); +void usage(rtems_shell_ls_globals* globals); + +void strmode(mode_t mode, char *p); + +#endif /* !_EXTERN_H_ */ diff --git a/cpukit/libmisc/shell/fdisk.c b/cpukit/libmisc/shell/fdisk.c new file mode 100644 index 0000000000..37a2e217dc --- /dev/null +++ b/cpukit/libmisc/shell/fdisk.c @@ -0,0 +1,280 @@ +/** + * @file + * + * Block device partition management. + */ + +/* + * Copyright (c) 2009 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <rtems/bdpart.h> +#include <rtems/error.h> +#include <rtems/shell.h> + +#define RTEMS_BDPART_SHELL_ERROR( fmt, ...) \ + do { \ + printf( "error: " fmt "\n", ##__VA_ARGS__); \ + return -1; \ + } while (0) + +#define RTEMS_BDPART_SHELL_ERROR_SC( sc, fmt, ...) \ + if ((sc) != RTEMS_SUCCESSFUL) { \ + printf( "error: " fmt ": %s\n", ##__VA_ARGS__, rtems_status_text( sc)); \ + return -1; \ + } + +typedef enum { + RTEMS_BDPART_SHELL_FS, + RTEMS_BDPART_SHELL_N, + RTEMS_BDPART_SHELL_MBR, + RTEMS_BDPART_SHELL_GPT +} rtems_bdpart_shell_state; + +static const char rtems_bdpart_shell_usage [] = + "disk format and utility functions\n" + "\n" + "fdisk DISK_NAME\n" + "\tprints the partition table\n" + "\n" + "fdisk DISK_NAME [FS N1 [N2 ... ]] ... [write] [FORMAT]\n" + "\tcreates a new partition table\n" + "\n" + "fdisk DISK_NAME register\n" + "\tcreates a logical disk for each partition of the disk\n" + "\n" + "fdisk DISK_NAME unregister\n" + "\tdeletes the logical disks associated with the partitions of the disk\n" + "\n" + "fdisk DISK_NAME mount\n" + "\tmounts the file system of each partition of the disk\n" + "\n" + "fdisk DISK_NAME unmount\n" + "\tunmounts the file system of each partition of the disk\n" + "\n" + "option values:\n" + "\tDISK_NAME: absolute path to disk device like '/dev/hda'\n" + "\tN*: weights of positive integers\n" + "\tFS: 0x00 ... 0xff, fat12, fat16, fat32, data\n" + "\twrite: write the new partition table to the disk\n" + "\tFORMAT: mbr [[no]dos], gpt"; + +static int rtems_bdpart_shell_main( int argc, char **argv) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + rtems_bdpart_format format; + rtems_bdpart_partition pt [RTEMS_BDPART_PARTITION_NUMBER_HINT]; + unsigned dist [RTEMS_BDPART_PARTITION_NUMBER_HINT]; + size_t count = RTEMS_BDPART_PARTITION_NUMBER_HINT; + const char *disk_name = NULL; + const char *mount_base = "/mnt"; + bool do_create = false; + bool do_read = false; + bool do_write = false; + bool do_register = false; + bool do_unregister = false; + bool do_mount = false; + bool do_unmount = false; + bool do_dump = false; + + if (argc < 2) { + puts( rtems_bdpart_shell_usage); + return -1; + } + + disk_name = argv [1]; + + if (argc == 2) { + do_read = true; + do_dump = true; + } else if (argc == 3) { + /* Check option */ + if (strcmp( argv [2], "register") == 0) { + do_read = true; + do_register = true; + } else if (strcmp( argv [2], "unregister") == 0) { + do_read = true; + do_unregister = true; + } else if (strcmp( argv [2], "mount") == 0) { + do_read = true; + do_mount = true; + } else if (strcmp( argv [2], "unmount") == 0) { + do_read = true; + do_unmount = true; + } else { + RTEMS_BDPART_SHELL_ERROR( "unexpected option: %s", argv [2]); + } + } else { + rtems_bdpart_shell_state state = RTEMS_BDPART_SHELL_FS; + uint8_t current_type = RTEMS_BDPART_MBR_FAT_32; + size_t i = 0; + int ai = 0; + + /* Clear partition table */ + memset( pt, 0, sizeof( pt)); + + /* Default format */ + format.type = RTEMS_BDPART_FORMAT_MBR; + format.mbr.disk_id = 0; + format.mbr.dos_compatibility = true; + + for (ai = 2; ai < argc; ++ai) { + char *s = argv [ai]; + unsigned long v = 0; + char *end = NULL; + + if (strlen( s) == 0) { + continue; + } else if (strcmp( s, "write") == 0) { + do_write = true; + continue; + } else if (strcmp( s, "mbr") == 0) { + state = RTEMS_BDPART_SHELL_MBR; + format.type = RTEMS_BDPART_FORMAT_MBR; + continue; + } else if (strcmp( s, "gpt") == 0) { + state = RTEMS_BDPART_SHELL_GPT; + format.type = RTEMS_BDPART_FORMAT_GPT; + continue; + } + + switch (state) { + case RTEMS_BDPART_SHELL_FS: + v = strtoul( s, &end, 16); + if (*end == '\0') { + if (v <= 0xffU) { + current_type = (uint8_t) v; + } else { + RTEMS_BDPART_SHELL_ERROR( "type value out of range: %s", argv [ai]); + } + } else if (strcmp( s, "fat32") == 0) { + current_type = RTEMS_BDPART_MBR_FAT_32; + } else if (strcmp( s, "data") == 0) { + current_type = RTEMS_BDPART_MBR_DATA; + } else if (strcmp( s, "fat16") == 0) { + current_type = RTEMS_BDPART_MBR_FAT_16; + } else if (strcmp( s, "fat12") == 0) { + current_type = RTEMS_BDPART_MBR_FAT_12; + } else { + RTEMS_BDPART_SHELL_ERROR( "unexpected option: %s", argv [ai]); + } + state = RTEMS_BDPART_SHELL_N; + break; + case RTEMS_BDPART_SHELL_N: + v = strtoul( s, &end, 10); + if (*end == '\0') { + rtems_bdpart_to_partition_type( current_type, pt [i].type); + dist [i] = v; + if (i < count) { + ++i; + } else { + RTEMS_BDPART_SHELL_ERROR( "too many partitions"); + } + } else { + --ai; + state = RTEMS_BDPART_SHELL_FS; + } + break; + case RTEMS_BDPART_SHELL_MBR: + if (strcmp( s, "dos") == 0) { + format.mbr.dos_compatibility = true; + } else if (strcmp( s, "nodos") == 0) { + format.mbr.dos_compatibility = false; + } else { + RTEMS_BDPART_SHELL_ERROR( "unexpected option: %s", argv [ai]); + } + break; + case RTEMS_BDPART_SHELL_GPT: + RTEMS_BDPART_SHELL_ERROR( "unexpected option: %s", argv [ai]); + default: + RTEMS_BDPART_SHELL_ERROR( "fdisk interal error"); + } + } + + /* Partition number */ + count = i; + + /* Actions */ + do_create = true; + do_dump = true; + if (do_write) { + do_read = true; + } + } + + if (do_create) { + /* Create partitions */ + sc = rtems_bdpart_create( disk_name, &format, pt, dist, count); + RTEMS_BDPART_SHELL_ERROR_SC( sc, "cannot create partitions for '%s'", disk_name); + } + + if (do_write) { + /* Write partitions */ + sc = rtems_bdpart_write( disk_name, &format, pt, count); + RTEMS_BDPART_SHELL_ERROR_SC( sc, "cannot write partitions to '%s'", disk_name); + } + + if (do_read) { + /* Read partitions */ + count = RTEMS_BDPART_PARTITION_NUMBER_HINT; + sc = rtems_bdpart_read( disk_name, &format, pt, &count); + RTEMS_BDPART_SHELL_ERROR_SC( sc, "cannot read partitions from '%s'", disk_name); + } + + if (do_register) { + /* Register partitions */ + sc = rtems_bdpart_register( disk_name, pt, count); + RTEMS_BDPART_SHELL_ERROR_SC( sc, "cannot register partitions of '%s'", disk_name); + } + + if (do_unregister) { + /* Unregister partitions */ + sc = rtems_bdpart_unregister( disk_name, pt, count); + RTEMS_BDPART_SHELL_ERROR_SC( sc, "cannot unregister partitions of '%s'", disk_name); + } + + if (do_mount) { + /* Mount partitions */ + sc = rtems_bdpart_mount( disk_name, pt, count, mount_base); + RTEMS_BDPART_SHELL_ERROR_SC( sc, "cannot mount partitions of '%s' to '%s'", disk_name, mount_base); + } + + if (do_unmount) { + /* Unmount partitions */ + sc = rtems_bdpart_unmount( disk_name, pt, count, mount_base); + RTEMS_BDPART_SHELL_ERROR_SC( sc, "cannot unmount partitions of '%s'", disk_name); + } + + if (do_dump) { + /* Dump partitions */ + rtems_bdpart_dump( pt, count); + } + + return 0; +} + +struct rtems_shell_cmd_tt rtems_shell_FDISK_Command = { + .name = "fdisk", + .usage = rtems_bdpart_shell_usage, + .topic = "files", + .command = rtems_bdpart_shell_main, + .alias = NULL, + .next = NULL +}; diff --git a/cpukit/libmisc/shell/filemode.c b/cpukit/libmisc/shell/filemode.c new file mode 100644 index 0000000000..9a5d0440b4 --- /dev/null +++ b/cpukit/libmisc/shell/filemode.c @@ -0,0 +1,154 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strmode.c 8.3 (Berkeley) 8/15/94"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/lib/libc/string/strmode.c,v 1.5 2007/01/09 00:28:12 imp Exp $"); + +#include <sys/types.h> +#include <sys/stat.h> +#include <string.h> + +void +strmode( + mode_t mode, + char *p) +{ + /* print type */ + switch (mode & S_IFMT) { + case S_IFDIR: /* directory */ + *p++ = 'd'; + break; + case S_IFCHR: /* character special */ + *p++ = 'c'; + break; + case S_IFBLK: /* block special */ + *p++ = 'b'; + break; + case S_IFREG: /* regular */ + *p++ = '-'; + break; + case S_IFLNK: /* symbolic link */ + *p++ = 'l'; + break; + case S_IFSOCK: /* socket */ + *p++ = 's'; + break; +#ifdef S_IFIFO + case S_IFIFO: /* fifo */ + *p++ = 'p'; + break; +#endif +#ifdef S_IFWHT + case S_IFWHT: /* whiteout */ + *p++ = 'w'; + break; +#endif + default: /* unknown */ + *p++ = '?'; + break; + } + /* usr */ + if (mode & S_IRUSR) + *p++ = 'r'; + else + *p++ = '-'; + if (mode & S_IWUSR) + *p++ = 'w'; + else + *p++ = '-'; + switch (mode & (S_IXUSR | S_ISUID)) { + case 0: + *p++ = '-'; + break; + case S_IXUSR: + *p++ = 'x'; + break; + case S_ISUID: + *p++ = 'S'; + break; + case S_IXUSR | S_ISUID: + *p++ = 's'; + break; + } + /* group */ + if (mode & S_IRGRP) + *p++ = 'r'; + else + *p++ = '-'; + if (mode & S_IWGRP) + *p++ = 'w'; + else + *p++ = '-'; + switch (mode & (S_IXGRP | S_ISGID)) { + case 0: + *p++ = '-'; + break; + case S_IXGRP: + *p++ = 'x'; + break; + case S_ISGID: + *p++ = 'S'; + break; + case S_IXGRP | S_ISGID: + *p++ = 's'; + break; + } + /* other */ + if (mode & S_IROTH) + *p++ = 'r'; + else + *p++ = '-'; + if (mode & S_IWOTH) + *p++ = 'w'; + else + *p++ = '-'; + switch (mode & (S_IXOTH | S_ISVTX)) { + case 0: + *p++ = '-'; + break; + case S_IXOTH: + *p++ = 'x'; + break; + case S_ISVTX: + *p++ = 'T'; + break; + case S_IXOTH | S_ISVTX: + *p++ = 't'; + break; + } + *p++ = ' '; /* will be a '+' if ACL's implemented */ + *p = '\0'; +} diff --git a/cpukit/libmisc/shell/fts.c b/cpukit/libmisc/shell/fts.c new file mode 100644 index 0000000000..2fd91b874c --- /dev/null +++ b/cpukit/libmisc/shell/fts.c @@ -0,0 +1,1244 @@ +/* $NetBSD: fts.c,v 1.40 2009/11/02 17:17:34 stacktic Exp $ */ + +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94"; +#else +__RCSID("$NetBSD: fts.c,v 1.40 2009/11/02 17:17:34 stacktic Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#ifndef __rtems__ +#include "namespace.h" +#endif +#include <limits.h> +#include <sys/param.h> +#include <sys/stat.h> + +#include <assert.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <fts.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> + +#define _DIAGASSERT(a) +#undef FTS_WHITEOUT +#define dirfd(dp) __dirfd(dp) + +#if ! HAVE_NBTOOL_CONFIG_H +#define HAVE_STRUCT_DIRENT_D_NAMLEN +#endif + +static FTSENT *fts_alloc(FTS *, const char *, size_t); +static FTSENT *fts_build(FTS *, int); +static void fts_free(FTSENT *); +static void fts_lfree(FTSENT *); +static void fts_load(FTS *, FTSENT *); +static size_t fts_maxarglen(char * const *); +static size_t fts_pow2(size_t); +static int fts_palloc(FTS *, size_t); +static void fts_padjust(FTS *, FTSENT *); +static FTSENT *fts_sort(FTS *, FTSENT *, size_t); +static unsigned short fts_stat(FTS *, FTSENT *, int); +static int fts_safe_changedir(const FTS *, const FTSENT *, int, + const char *); + +#if defined(ALIGNBYTES) && defined(ALIGN) +#define FTS_ALLOC_ALIGNED 1 +/* FIXME: Redefine because some versions of + * RTEMS newlib and the BSDs ship a broken ALIGN */ +#undef ALIGN +#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) & ~ALIGNBYTES) +#else +#undef FTS_ALLOC_ALIGNED +#endif + +#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2]))) + +#define CLR(opt) (sp->fts_options &= ~(opt)) +#define ISSET(opt) (sp->fts_options & (opt)) +#define SET(opt) (sp->fts_options |= (opt)) + +#define CHDIR(sp, path) (!ISSET(FTS_NOCHDIR) && chdir(path)) +#define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd)) + +/* fts_build flags */ +#define BCHILD 1 /* fts_children */ +#define BNAMES 2 /* fts_children, names only */ +#define BREAD 3 /* fts_read */ + +#ifndef DTF_HIDEW +#undef FTS_WHITEOUT +#endif + +FTS * +fts_open(char * const *argv, int options, + int (*compar)(const FTSENT **, const FTSENT **)) +{ + FTS *sp; + FTSENT *p, *root; + size_t nitems; + FTSENT *parent, *tmp = NULL; /* pacify gcc */ + size_t len; + + _DIAGASSERT(argv != NULL); + + /* Options check. */ + if (options & ~FTS_OPTIONMASK) { + errno = EINVAL; + return (NULL); + } + + /* Allocate/initialize the stream */ + if ((sp = malloc((unsigned int)sizeof(FTS))) == NULL) + return (NULL); + memset(sp, 0, sizeof(FTS)); + sp->fts_compar = compar; + sp->fts_options = options; + + /* Logical walks turn on NOCHDIR; symbolic links are too hard. */ + if (ISSET(FTS_LOGICAL)) + SET(FTS_NOCHDIR); + + /* + * Start out with 1K of path space, and enough, in any case, + * to hold the user's paths. + */ + if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN))) + goto mem1; + + /* Allocate/initialize root's parent. */ + if ((parent = fts_alloc(sp, "", 0)) == NULL) + goto mem2; + parent->fts_level = FTS_ROOTPARENTLEVEL; + + /* Allocate/initialize root(s). */ + for (root = NULL, nitems = 0; *argv; ++argv, ++nitems) { + /* Don't allow zero-length paths. */ + if ((len = strlen(*argv)) == 0) { + errno = ENOENT; + goto mem3; + } + + if ((p = fts_alloc(sp, *argv, len)) == NULL) + goto mem3; + p->fts_level = FTS_ROOTLEVEL; + p->fts_parent = parent; + p->fts_accpath = p->fts_name; + p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW)); + + /* Command-line "." and ".." are real directories. */ + if (p->fts_info == FTS_DOT) + p->fts_info = FTS_D; + + /* + * If comparison routine supplied, traverse in sorted + * order; otherwise traverse in the order specified. + */ + if (compar) { + p->fts_link = root; + root = p; + } else { + p->fts_link = NULL; + if (root == NULL) + tmp = root = p; + else { + tmp->fts_link = p; + tmp = p; + } + } + } + if (compar && nitems > 1) + root = fts_sort(sp, root, nitems); + + /* + * Allocate a dummy pointer and make fts_read think that we've just + * finished the node before the root(s); set p->fts_info to FTS_INIT + * so that everything about the "current" node is ignored. + */ + if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL) + goto mem3; + sp->fts_cur->fts_link = root; + sp->fts_cur->fts_info = FTS_INIT; + + /* + * If using chdir(2), grab a file descriptor pointing to dot to insure + * that we can get back here; this could be avoided for some paths, + * but almost certainly not worth the effort. Slashes, symbolic links, + * and ".." are all fairly nasty problems. Note, if we can't get the + * descriptor we run anyway, just more slowly. + */ + if (!ISSET(FTS_NOCHDIR)) { + if ((sp->fts_rfd = open(".", O_RDONLY, 0)) == -1) + SET(FTS_NOCHDIR); + else if (fcntl(sp->fts_rfd, F_SETFD, FD_CLOEXEC) == -1) { + close(sp->fts_rfd); + SET(FTS_NOCHDIR); + } + } + + if (nitems == 0) + fts_free(parent); + + return (sp); + +mem3: fts_lfree(root); + fts_free(parent); +mem2: free(sp->fts_path); +mem1: free(sp); + return (NULL); +} + +static void +fts_load(FTS *sp, FTSENT *p) +{ + size_t len; + char *cp; + + _DIAGASSERT(sp != NULL); + _DIAGASSERT(p != NULL); + + /* + * Load the stream structure for the next traversal. Since we don't + * actually enter the directory until after the preorder visit, set + * the fts_accpath field specially so the chdir gets done to the right + * place and the user can access the first node. From fts_open it's + * known that the path will fit. + */ + len = p->fts_pathlen = p->fts_namelen; + memmove(sp->fts_path, p->fts_name, len + 1); + if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) { + len = strlen(++cp); + memmove(p->fts_name, cp, len + 1); + p->fts_namelen = len; + } + p->fts_accpath = p->fts_path = sp->fts_path; + sp->fts_dev = p->fts_dev; +} + +int +fts_close(FTS *sp) +{ + FTSENT *freep, *p; + int saved_errno = 0; + + _DIAGASSERT(sp != NULL); + + /* + * This still works if we haven't read anything -- the dummy structure + * points to the root list, so we step through to the end of the root + * list which has a valid parent pointer. + */ + if (sp->fts_cur) { + if (sp->fts_cur->fts_flags & FTS_SYMFOLLOW) + (void)close(sp->fts_cur->fts_symfd); + for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) { + freep = p; + p = p->fts_link ? p->fts_link : p->fts_parent; + fts_free(freep); + } + fts_free(p); + } + + /* Free up child linked list, sort array, path buffer. */ + if (sp->fts_child) + fts_lfree(sp->fts_child); + if (sp->fts_array) + free(sp->fts_array); + free(sp->fts_path); + + /* Return to original directory, save errno if necessary. */ + if (!ISSET(FTS_NOCHDIR)) { + if (fchdir(sp->fts_rfd) == -1) + saved_errno = errno; + (void)close(sp->fts_rfd); + } + + /* Free up the stream pointer. */ + free(sp); + if (saved_errno) { + errno = saved_errno; + return -1; + } + + return 0; +} + +#if !defined(__FTS_COMPAT_TAILINGSLASH) + +/* + * Special case of "/" at the end of the path so that slashes aren't + * appended which would cause paths to be written as "....//foo". + */ +#define NAPPEND(p) \ + (p->fts_path[p->fts_pathlen - 1] == '/' \ + ? p->fts_pathlen - 1 : p->fts_pathlen) + +#else /* !defined(__FTS_COMPAT_TAILINGSLASH) */ + +/* + * compatibility with the old behaviour. + * + * Special case a root of "/" so that slashes aren't appended which would + * cause paths to be written as "//foo". + */ + +#define NAPPEND(p) \ + (p->fts_level == FTS_ROOTLEVEL && p->fts_pathlen == 1 && \ + p->fts_path[0] == '/' ? 0 : p->fts_pathlen) + +#endif /* !defined(__FTS_COMPAT_TAILINGSLASH) */ + +FTSENT * +fts_read(FTS *sp) +{ + FTSENT *p, *tmp; + int instr; + char *t; + int saved_errno; + + _DIAGASSERT(sp != NULL); + + /* If finished or unrecoverable error, return NULL. */ + if (sp->fts_cur == NULL || ISSET(FTS_STOP)) + return (NULL); + + /* Set current node pointer. */ + p = sp->fts_cur; + + /* Save and zero out user instructions. */ + instr = p->fts_instr; + p->fts_instr = FTS_NOINSTR; + + /* Any type of file may be re-visited; re-stat and re-turn. */ + if (instr == FTS_AGAIN) { + p->fts_info = fts_stat(sp, p, 0); + return (p); + } + + /* + * Following a symlink -- SLNONE test allows application to see + * SLNONE and recover. If indirecting through a symlink, have + * keep a pointer to current location. If unable to get that + * pointer, follow fails. + */ + if (instr == FTS_FOLLOW && + (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) { + p->fts_info = fts_stat(sp, p, 1); + if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { + if ((p->fts_symfd = open(".", O_RDONLY, 0)) == -1) { + p->fts_errno = errno; + p->fts_info = FTS_ERR; + } else if (fcntl(p->fts_symfd, F_SETFD, FD_CLOEXEC) == -1) { + p->fts_errno = errno; + p->fts_info = FTS_ERR; + close(p->fts_symfd); + } else + p->fts_flags |= FTS_SYMFOLLOW; + } + return (p); + } + + /* Directory in pre-order. */ + if (p->fts_info == FTS_D) { + /* If skipped or crossed mount point, do post-order visit. */ + if (instr == FTS_SKIP || + (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) { + if (p->fts_flags & FTS_SYMFOLLOW) + (void)close(p->fts_symfd); + if (sp->fts_child) { + fts_lfree(sp->fts_child); + sp->fts_child = NULL; + } + p->fts_info = FTS_DP; + return (p); + } + + /* Rebuild if only read the names and now traversing. */ + if (sp->fts_child && ISSET(FTS_NAMEONLY)) { + CLR(FTS_NAMEONLY); + fts_lfree(sp->fts_child); + sp->fts_child = NULL; + } + + /* + * Cd to the subdirectory. + * + * If have already read and now fail to chdir, whack the list + * to make the names come out right, and set the parent errno + * so the application will eventually get an error condition. + * Set the FTS_DONTCHDIR flag so that when we logically change + * directories back to the parent we don't do a chdir. + * + * If haven't read do so. If the read fails, fts_build sets + * FTS_STOP or the fts_info field of the node. + */ + if (sp->fts_child) { + if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) { + p->fts_errno = errno; + p->fts_flags |= FTS_DONTCHDIR; + for (p = sp->fts_child; p; p = p->fts_link) + p->fts_accpath = + p->fts_parent->fts_accpath; + } + } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) { + if (ISSET(FTS_STOP)) + return (NULL); + return (p); + } + p = sp->fts_child; + sp->fts_child = NULL; + goto name; + } + + /* Move to the next node on this level. */ +next: tmp = p; + if ((p = p->fts_link) != NULL) { + fts_free(tmp); + + /* + * If reached the top, return to the original directory, and + * load the paths for the next root. + */ + if (p->fts_level == FTS_ROOTLEVEL) { + if (FCHDIR(sp, sp->fts_rfd)) { + SET(FTS_STOP); + return (NULL); + } + fts_load(sp, p); + return (sp->fts_cur = p); + } + + /* + * User may have called fts_set on the node. If skipped, + * ignore. If followed, get a file descriptor so we can + * get back if necessary. + */ + if (p->fts_instr == FTS_SKIP) + goto next; + if (p->fts_instr == FTS_FOLLOW) { + p->fts_info = fts_stat(sp, p, 1); + if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { + if ((p->fts_symfd = + open(".", O_RDONLY, 0)) == -1) { + p->fts_errno = errno; + p->fts_info = FTS_ERR; + } else if (fcntl(p->fts_symfd, F_SETFD, FD_CLOEXEC) == -1) { + p->fts_errno = errno; + p->fts_info = FTS_ERR; + close(p->fts_symfd); + } else + p->fts_flags |= FTS_SYMFOLLOW; + } + p->fts_instr = FTS_NOINSTR; + } + +name: t = sp->fts_path + NAPPEND(p->fts_parent); + *t++ = '/'; + memmove(t, p->fts_name, (size_t)(p->fts_namelen + 1)); + return (sp->fts_cur = p); + } + + /* Move up to the parent node. */ + p = tmp->fts_parent; + fts_free(tmp); + + if (p->fts_level == FTS_ROOTPARENTLEVEL) { + /* + * Done; free everything up and set errno to 0 so the user + * can distinguish between error and EOF. + */ + fts_free(p); + errno = 0; + return (sp->fts_cur = NULL); + } + + /* Nul terminate the pathname. */ + sp->fts_path[p->fts_pathlen] = '\0'; + + /* + * Return to the parent directory. If at a root node or came through + * a symlink, go back through the file descriptor. Otherwise, cd up + * one directory. + */ + if (p->fts_level == FTS_ROOTLEVEL) { + if (FCHDIR(sp, sp->fts_rfd)) { + SET(FTS_STOP); + return (NULL); + } + } else if (p->fts_flags & FTS_SYMFOLLOW) { + if (FCHDIR(sp, p->fts_symfd)) { + saved_errno = errno; + (void)close(p->fts_symfd); + errno = saved_errno; + SET(FTS_STOP); + return (NULL); + } + (void)close(p->fts_symfd); + } else if (!(p->fts_flags & FTS_DONTCHDIR) && + fts_safe_changedir(sp, p->fts_parent, -1, "..")) { + SET(FTS_STOP); + return (NULL); + } + p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP; + return (sp->fts_cur = p); +} + +/* + * Fts_set takes the stream as an argument although it's not used in this + * implementation; it would be necessary if anyone wanted to add global + * semantics to fts using fts_set. An error return is allowed for similar + * reasons. + */ +/* ARGSUSED */ +int +fts_set(FTS *sp, FTSENT *p, int instr) +{ + + _DIAGASSERT(sp != NULL); + _DIAGASSERT(p != NULL); + + if (instr && instr != FTS_AGAIN && instr != FTS_FOLLOW && + instr != FTS_NOINSTR && instr != FTS_SKIP) { + errno = EINVAL; + return (1); + } + p->fts_instr = instr; + return (0); +} + +FTSENT * +fts_children(FTS *sp, int instr) +{ + FTSENT *p; + int fd; + + _DIAGASSERT(sp != NULL); + + if (instr && instr != FTS_NAMEONLY) { + errno = EINVAL; + return (NULL); + } + + /* Set current node pointer. */ + p = sp->fts_cur; + + /* + * Errno set to 0 so user can distinguish empty directory from + * an error. + */ + errno = 0; + + /* Fatal errors stop here. */ + if (ISSET(FTS_STOP)) + return (NULL); + + /* Return logical hierarchy of user's arguments. */ + if (p->fts_info == FTS_INIT) + return (p->fts_link); + + /* + * If not a directory being visited in pre-order, stop here. Could + * allow FTS_DNR, assuming the user has fixed the problem, but the + * same effect is available with FTS_AGAIN. + */ + if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */) + return (NULL); + + /* Free up any previous child list. */ + if (sp->fts_child) + fts_lfree(sp->fts_child); + + if (instr == FTS_NAMEONLY) { + SET(FTS_NAMEONLY); + instr = BNAMES; + } else + instr = BCHILD; + + /* + * If using chdir on a relative path and called BEFORE fts_read does + * its chdir to the root of a traversal, we can lose -- we need to + * chdir into the subdirectory, and we don't know where the current + * directory is, so we can't get back so that the upcoming chdir by + * fts_read will work. + */ + if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' || + ISSET(FTS_NOCHDIR)) + return (sp->fts_child = fts_build(sp, instr)); + + if ((fd = open(".", O_RDONLY, 0)) == -1) + return (sp->fts_child = NULL); + sp->fts_child = fts_build(sp, instr); + if (fchdir(fd)) { + (void)close(fd); + return (NULL); + } + (void)close(fd); + return (sp->fts_child); +} + +/* + * This is the tricky part -- do not casually change *anything* in here. The + * idea is to build the linked list of entries that are used by fts_children + * and fts_read. There are lots of special cases. + * + * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is + * set and it's a physical walk (so that symbolic links can't be directories), + * we can do things quickly. First, if it's a 4.4BSD file system, the type + * of the file is in the directory entry. Otherwise, we assume that the number + * of subdirectories in a node is equal to the number of links to the parent. + * The former skips all stat calls. The latter skips stat calls in any leaf + * directories and for any files after the subdirectories in the directory have + * been found, cutting the stat calls by about 2/3. + */ +static FTSENT * +fts_build(FTS *sp, int type) +{ + struct dirent *dp; + FTSENT *p, *head; + size_t nitems; + FTSENT *cur, *tail; + DIR *dirp; + void *oldaddr; + size_t dnamlen; + int cderrno, descend, level, nlinks, saved_errno, nostat, doadjust; + size_t len, maxlen; +#ifdef FTS_WHITEOUT + int oflag; +#endif + char *cp = NULL; /* pacify gcc */ + + _DIAGASSERT(sp != NULL); + + /* Set current node pointer. */ + cur = sp->fts_cur; + + /* + * Open the directory for reading. If this fails, we're done. + * If being called from fts_read, set the fts_info field. + */ +#ifdef FTS_WHITEOUT + if (ISSET(FTS_WHITEOUT)) + oflag = DTF_NODUP|DTF_REWIND; + else + oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND; +#else +#define __opendir2(path, flag) opendir(path) +#endif + if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) { + if (type == BREAD) { + cur->fts_info = FTS_DNR; + cur->fts_errno = errno; + } + return (NULL); + } + + /* + * Nlinks is the number of possible entries of type directory in the + * directory if we're cheating on stat calls, 0 if we're not doing + * any stat calls at all, -1 if we're doing stats on everything. + */ + if (type == BNAMES) { + nlinks = 0; + nostat = 1; + } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) { + nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2); + nostat = 1; + } else { + nlinks = -1; + nostat = 0; + } + +#ifdef notdef + (void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink); + (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n", + ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT)); +#endif + /* + * If we're going to need to stat anything or we want to descend + * and stay in the directory, chdir. If this fails we keep going, + * but set a flag so we don't chdir after the post-order visit. + * We won't be able to stat anything, but we can still return the + * names themselves. Note, that since fts_read won't be able to + * chdir into the directory, it will have to return different path + * names than before, i.e. "a/b" instead of "b". Since the node + * has already been visited in pre-order, have to wait until the + * post-order visit to return the error. There is a special case + * here, if there was nothing to stat then it's not an error to + * not be able to stat. This is all fairly nasty. If a program + * needed sorted entries or stat information, they had better be + * checking FTS_NS on the returned nodes. + */ + cderrno = 0; + if (nlinks || type == BREAD) { + if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) { + if (nlinks && type == BREAD) + cur->fts_errno = errno; + cur->fts_flags |= FTS_DONTCHDIR; + descend = 0; + cderrno = errno; + } else + descend = 1; + } else + descend = 0; + + /* + * Figure out the max file name length that can be stored in the + * current path -- the inner loop allocates more path as necessary. + * We really wouldn't have to do the maxlen calculations here, we + * could do them in fts_read before returning the path, but it's a + * lot easier here since the length is part of the dirent structure. + * + * If not changing directories set a pointer so that can just append + * each new name into the path. + */ + len = NAPPEND(cur); + if (ISSET(FTS_NOCHDIR)) { + cp = sp->fts_path + len; + *cp++ = '/'; + } + len++; + maxlen = sp->fts_pathlen - len; + +#if defined(__FTS_COMPAT_LEVEL) + if (cur->fts_level == SHRT_MAX) { + (void)closedir(dirp); + cur->fts_info = FTS_ERR; + SET(FTS_STOP); + errno = ENAMETOOLONG; + return (NULL); + } +#endif + + level = cur->fts_level + 1; + + /* Read the directory, attaching each entry to the `link' pointer. */ + doadjust = 0; + for (head = tail = NULL, nitems = 0; (dp = readdir(dirp)) != NULL;) { + + if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) + continue; + +#if defined(HAVE_STRUCT_DIRENT_D_NAMLEN) + dnamlen = dp->d_namlen; +#else + dnamlen = strlen(dp->d_name); +#endif + if ((p = fts_alloc(sp, dp->d_name, dnamlen)) == NULL) + goto mem1; + if (dnamlen >= maxlen) { /* include space for NUL */ + oldaddr = sp->fts_path; + if (fts_palloc(sp, dnamlen + len + 1)) { + /* + * No more memory for path or structures. Save + * errno, free up the current structure and the + * structures already allocated. + */ +mem1: saved_errno = errno; + if (p) + fts_free(p); + fts_lfree(head); + (void)closedir(dirp); + errno = saved_errno; + cur->fts_info = FTS_ERR; + SET(FTS_STOP); + return (NULL); + } + /* Did realloc() change the pointer? */ + if (oldaddr != sp->fts_path) { + doadjust = 1; + if (ISSET(FTS_NOCHDIR)) + cp = sp->fts_path + len; + } + maxlen = sp->fts_pathlen - len; + } + +#if defined(__FTS_COMPAT_LENGTH) + if (len + dnamlen >= USHRT_MAX) { + /* + * In an FTSENT, fts_pathlen is an unsigned short + * so it is possible to wraparound here. + * If we do, free up the current structure and the + * structures already allocated, then error out + * with ENAMETOOLONG. + */ + fts_free(p); + fts_lfree(head); + (void)closedir(dirp); + cur->fts_info = FTS_ERR; + SET(FTS_STOP); + errno = ENAMETOOLONG; + return (NULL); + } +#endif + p->fts_level = level; + p->fts_pathlen = len + dnamlen; + p->fts_parent = sp->fts_cur; + +#ifdef FTS_WHITEOUT + if (dp->d_type == DT_WHT) + p->fts_flags |= FTS_ISW; +#endif + + if (cderrno) { + if (nlinks) { + p->fts_info = FTS_NS; + p->fts_errno = cderrno; + } /* else + p->fts_info = FTS_NSOK; + */ + /* Coverity Scan Id 1 says above is dead code */ + p->fts_accpath = cur->fts_accpath; + } else if (nlinks == 0 +#ifdef DT_DIR + || (nostat && + dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN) +#endif + ) { + p->fts_accpath = + ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name; + p->fts_info = FTS_NSOK; + } else { + /* Build a file name for fts_stat to stat. */ + if (ISSET(FTS_NOCHDIR)) { + p->fts_accpath = p->fts_path; + memmove(cp, p->fts_name, + (size_t)(p->fts_namelen + 1)); + } else + p->fts_accpath = p->fts_name; + /* Stat it. */ + p->fts_info = fts_stat(sp, p, 0); + + /* Decrement link count if applicable. */ + if (nlinks > 0 && (p->fts_info == FTS_D || + p->fts_info == FTS_DC || p->fts_info == FTS_DOT)) + --nlinks; + } + + /* We walk in directory order so "ls -f" doesn't get upset. */ + p->fts_link = NULL; + if (head == NULL) + head = tail = p; + else { + tail->fts_link = p; + tail = p; + } + ++nitems; + } + (void)closedir(dirp); + + /* + * If had to realloc the path, adjust the addresses for the rest + * of the tree. + */ + if (doadjust) + fts_padjust(sp, head); + + /* + * If not changing directories, reset the path back to original + * state. + */ + if (ISSET(FTS_NOCHDIR)) { + if (len == sp->fts_pathlen || nitems == 0) + --cp; + *cp = '\0'; + } + + /* + * If descended after called from fts_children or after called from + * fts_read and nothing found, get back. At the root level we use + * the saved fd; if one of fts_open()'s arguments is a relative path + * to an empty directory, we wind up here with no other way back. If + * can't get back, we're done. + */ + if (descend && (type == BCHILD || !nitems) && + (cur->fts_level == FTS_ROOTLEVEL ? + FCHDIR(sp, sp->fts_rfd) : + fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) { + cur->fts_info = FTS_ERR; + SET(FTS_STOP); + return (NULL); + } + + /* If didn't find anything, return NULL. */ + if (!nitems) { + if (type == BREAD) + cur->fts_info = FTS_DP; + return (NULL); + } + + /* Sort the entries. */ + if (sp->fts_compar && nitems > 1) + head = fts_sort(sp, head, nitems); + return (head); +} + +static unsigned short +fts_stat(FTS *sp, FTSENT *p, int follow) +{ + FTSENT *t; + dev_t dev; + __fts_ino_t ino; + __fts_stat_t *sbp, sb; + int saved_errno; + + _DIAGASSERT(sp != NULL); + _DIAGASSERT(p != NULL); + + /* If user needs stat info, stat buffer already allocated. */ + sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp; + +#ifdef FTS_WHITEOUT + /* check for whiteout */ + if (p->fts_flags & FTS_ISW) { + if (sbp != &sb) { + memset(sbp, '\0', sizeof (*sbp)); + sbp->st_mode = S_IFWHT; + } + return (FTS_W); + } +#endif + + /* + * If doing a logical walk, or application requested FTS_FOLLOW, do + * a stat(2). If that fails, check for a non-existent symlink. If + * fail, set the errno from the stat call. + */ + if (ISSET(FTS_LOGICAL) || follow) { + if (stat(p->fts_accpath, sbp)) { + saved_errno = errno; + if (!lstat(p->fts_accpath, sbp)) { + errno = 0; + return (FTS_SLNONE); + } + p->fts_errno = saved_errno; + goto err; + } + } else if (lstat(p->fts_accpath, sbp)) { + p->fts_errno = errno; +err: memset(sbp, 0, sizeof(*sbp)); + return (FTS_NS); + } + + if (S_ISDIR(sbp->st_mode)) { + /* + * Set the device/inode. Used to find cycles and check for + * crossing mount points. Also remember the link count, used + * in fts_build to limit the number of stat calls. It is + * understood that these fields are only referenced if fts_info + * is set to FTS_D. + */ + dev = p->fts_dev = sbp->st_dev; + ino = p->fts_ino = sbp->st_ino; + p->fts_nlink = sbp->st_nlink; + + if (ISDOT(p->fts_name)) + return (FTS_DOT); + + /* + * Cycle detection is done by brute force when the directory + * is first encountered. If the tree gets deep enough or the + * number of symbolic links to directories is high enough, + * something faster might be worthwhile. + */ + for (t = p->fts_parent; + t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent) + if (ino == t->fts_ino && dev == t->fts_dev) { + p->fts_cycle = t; + return (FTS_DC); + } + return (FTS_D); + } + if (S_ISLNK(sbp->st_mode)) + return (FTS_SL); + if (S_ISREG(sbp->st_mode)) + return (FTS_F); + return (FTS_DEFAULT); +} + +static FTSENT * +fts_sort(FTS *sp, FTSENT *head, size_t nitems) +{ + FTSENT **ap, *p; + + _DIAGASSERT(sp != NULL); + _DIAGASSERT(head != NULL); + + /* + * Construct an array of pointers to the structures and call qsort(3). + * Reassemble the array in the order returned by qsort. If unable to + * sort for memory reasons, return the directory entries in their + * current order. Allocate enough space for the current needs plus + * 40 so don't realloc one entry at a time. + */ + if (nitems > sp->fts_nitems) { + FTSENT **new; + + new = realloc(sp->fts_array, sizeof(FTSENT *) * (nitems + 40)); + if (new == 0) + return (head); + sp->fts_array = new; + sp->fts_nitems = nitems + 40; + } + for (ap = sp->fts_array, p = head; p; p = p->fts_link) + *ap++ = p; + qsort((void *)sp->fts_array, nitems, sizeof(FTSENT *), + (int (*)(const void *, const void *))sp->fts_compar); + for (head = *(ap = sp->fts_array); --nitems; ++ap) + ap[0]->fts_link = ap[1]; + ap[0]->fts_link = NULL; + return (head); +} + +static FTSENT * +fts_alloc(FTS *sp, const char *name, size_t namelen) +{ + FTSENT *p; +#if defined(FTS_ALLOC_ALIGNED) + size_t len; +#endif + + _DIAGASSERT(sp != NULL); + _DIAGASSERT(name != NULL); + +#if defined(FTS_ALLOC_ALIGNED) + /* + * The file name is a variable length array and no stat structure is + * necessary if the user has set the nostat bit. Allocate the FTSENT + * structure, the file name and the stat structure in one chunk, but + * be careful that the stat structure is reasonably aligned. Since the + * fts_name field is declared to be of size 1, the fts_name pointer is + * namelen + 2 before the first possible address of the stat structure. + */ + len = sizeof(FTSENT) + namelen; + if (!ISSET(FTS_NOSTAT)) + len += sizeof(*(p->fts_statp)) + ALIGNBYTES; + if ((p = malloc(len)) == NULL) + return (NULL); + + if (!ISSET(FTS_NOSTAT)) + p->fts_statp = (__fts_stat_t *)ALIGN(p->fts_name + namelen + 2); +#else + if ((p = malloc(sizeof(FTSENT) + namelen)) == NULL) + return (NULL); + + if (!ISSET(FTS_NOSTAT)) + if ((p->fts_statp = malloc(sizeof(*(p->fts_statp)))) == NULL) { + free(p); + return (NULL); + } +#endif + + if (ISSET(FTS_NOSTAT)) + p->fts_statp = NULL; + + /* Copy the name plus the trailing NULL. */ + memmove(p->fts_name, name, namelen + 1); + + p->fts_namelen = namelen; + p->fts_path = sp->fts_path; + p->fts_errno = 0; + p->fts_flags = 0; + p->fts_instr = FTS_NOINSTR; + p->fts_number = 0; + p->fts_pointer = NULL; + return (p); +} + +static void +fts_free(FTSENT *p) +{ +#if !defined(FTS_ALLOC_ALIGNED) + if (p->fts_statp) + free(p->fts_statp); +#endif + free(p); +} + +static void +fts_lfree(FTSENT *head) +{ + FTSENT *p; + + /* XXX: head may be NULL ? */ + + /* Free a linked list of structures. */ + while ((p = head) != NULL) { + head = head->fts_link; + fts_free(p); + } +} + +static size_t +fts_pow2(size_t x) +{ + + x--; + x |= x>>1; + x |= x>>2; + x |= x>>4; + x |= x>>8; +#if (SIZEOF_SIZE_T * CHAR_BIT) > 16 + x |= x>>16; +#endif +#if (SIZEOF_SIZE_T * CHAR_BIT) > 32 + x |= x>>32; +#endif +#if (SIZEOF_SIZE_T * CHAR_BIT) > 64 + x |= x>>64; +#endif + x++; + return (x); +} + +/* + * Allow essentially unlimited paths; find, rm, ls should all work on any tree. + * Most systems will allow creation of paths much longer than MAXPATHLEN, even + * though the kernel won't resolve them. Round up the new size to a power of 2, + * so we don't realloc the path 2 bytes at a time. + */ +static int +fts_palloc(FTS *sp, size_t size) +{ + char *new; + + _DIAGASSERT(sp != NULL); + +#ifdef __FTS_COMPAT_LENGTH + /* Protect against fts_pathlen overflow. */ + if (size > USHRT_MAX + 1) { + errno = ENAMETOOLONG; + return (1); + } +#endif + size = fts_pow2(size); + new = realloc(sp->fts_path, size); + if (new == 0) + return (1); + sp->fts_path = new; + sp->fts_pathlen = size; + return (0); +} + +/* + * When the path is realloc'd, have to fix all of the pointers in structures + * already returned. + */ +static void +fts_padjust(FTS *sp, FTSENT *head) +{ + FTSENT *p; + char *addr; + + _DIAGASSERT(sp != NULL); + +#define ADJUST(p) do { \ + if ((p)->fts_accpath != (p)->fts_name) \ + (p)->fts_accpath = \ + addr + ((p)->fts_accpath - (p)->fts_path); \ + (p)->fts_path = addr; \ +} while (/*CONSTCOND*/0) + + addr = sp->fts_path; + + /* Adjust the current set of children. */ + for (p = sp->fts_child; p; p = p->fts_link) + ADJUST(p); + + /* Adjust the rest of the tree, including the current level. */ + for (p = head; p->fts_level >= FTS_ROOTLEVEL;) { + ADJUST(p); + p = p->fts_link ? p->fts_link : p->fts_parent; + } +} + +static size_t +fts_maxarglen(char * const *argv) +{ + size_t len, max; + + _DIAGASSERT(argv != NULL); + + for (max = 0; *argv; ++argv) + if ((len = strlen(*argv)) > max) + max = len; + return (max + 1); +} + +/* + * Change to dir specified by fd or p->fts_accpath without getting + * tricked by someone changing the world out from underneath us. + * Assumes p->fts_dev and p->fts_ino are filled in. + */ +static int +fts_safe_changedir(const FTS *sp, const FTSENT *p, int fd, const char *path) +{ + int oldfd = fd, ret = -1; + __fts_stat_t sb; + + if (ISSET(FTS_NOCHDIR)) + return 0; + + if (oldfd < 0 && (fd = open(path, O_RDONLY)) == -1) + return -1; + + if (fstat(fd, &sb) == -1) + goto bail; + + if (sb.st_ino != p->fts_ino || sb.st_dev != p->fts_dev) { + errno = ENOENT; + goto bail; + } + + ret = fchdir(fd); + +bail: + if (oldfd < 0) { + int save_errno = errno; + (void)close(fd); + errno = save_errno; + } + return ret; +} diff --git a/cpukit/libmisc/shell/fts.h b/cpukit/libmisc/shell/fts.h new file mode 100644 index 0000000000..68e9d46c3e --- /dev/null +++ b/cpukit/libmisc/shell/fts.h @@ -0,0 +1,146 @@ +/* $NetBSD: fts.h,v 1.14 2005/09/13 01:44:32 christos Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)fts.h 8.3 (Berkeley) 8/14/94 + */ + +#ifndef _FTS_H_ +#define _FTS_H_ + +#ifndef __fts_stat_t +#define __fts_stat_t struct stat +#endif +#ifndef __fts_nlink_t +#define __fts_nlink_t nlink_t +#endif +#ifndef __fts_ino_t +#define __fts_ino_t ino_t +#endif + +typedef struct { + struct _ftsent *fts_cur; /* current node */ + struct _ftsent *fts_child; /* linked list of children */ + struct _ftsent **fts_array; /* sort array */ + dev_t fts_dev; /* starting device # */ + char *fts_path; /* path for this descent */ + int fts_rfd; /* fd for root */ + u_int fts_pathlen; /* sizeof(path) */ + u_int fts_nitems; /* elements in the sort array */ + int (*fts_compar) /* compare function */ + (const struct _ftsent **, const struct _ftsent **); + +#define FTS_COMFOLLOW 0x001 /* follow command line symlinks */ +#define FTS_LOGICAL 0x002 /* logical walk */ +#define FTS_NOCHDIR 0x004 /* don't change directories */ +#define FTS_NOSTAT 0x008 /* don't get stat info */ +#define FTS_PHYSICAL 0x010 /* physical walk */ +#define FTS_SEEDOT 0x020 /* return dot and dot-dot */ +#define FTS_XDEV 0x040 /* don't cross devices */ +#define FTS_WHITEOUT 0x080 /* return whiteout information */ +#define FTS_OPTIONMASK 0x0ff /* valid user option mask */ + +#define FTS_NAMEONLY 0x100 /* (private) child names only */ +#define FTS_STOP 0x200 /* (private) unrecoverable error */ + int fts_options; /* fts_open options, global flags */ +} FTS; + +typedef struct _ftsent { + struct _ftsent *fts_cycle; /* cycle node */ + struct _ftsent *fts_parent; /* parent directory */ + struct _ftsent *fts_link; /* next file in directory */ + long fts_number; /* local numeric value */ + void *fts_pointer; /* local address value */ + char *fts_accpath; /* access path */ + char *fts_path; /* root path */ + int fts_errno; /* errno for this node */ + int fts_symfd; /* fd for symlink */ + u_short fts_pathlen; /* strlen(fts_path) */ + u_short fts_namelen; /* strlen(fts_name) */ + + __fts_ino_t fts_ino; /* inode */ + dev_t fts_dev; /* device */ + __fts_nlink_t fts_nlink; /* link count */ + +#define FTS_ROOTPARENTLEVEL -1 +#define FTS_ROOTLEVEL 0 + short fts_level; /* depth (-1 to N) */ + +#define FTS_D 1 /* preorder directory */ +#define FTS_DC 2 /* directory that causes cycles */ +#define FTS_DEFAULT 3 /* none of the above */ +#define FTS_DNR 4 /* unreadable directory */ +#define FTS_DOT 5 /* dot or dot-dot */ +#define FTS_DP 6 /* postorder directory */ +#define FTS_ERR 7 /* error; errno is set */ +#define FTS_F 8 /* regular file */ +#define FTS_INIT 9 /* initialized only */ +#define FTS_NS 10 /* stat(2) failed */ +#define FTS_NSOK 11 /* no stat(2) requested */ +#define FTS_SL 12 /* symbolic link */ +#define FTS_SLNONE 13 /* symbolic link without target */ +#define FTS_W 14 /* whiteout object */ + u_short fts_info; /* user flags for FTSENT structure */ + +#define FTS_DONTCHDIR 0x01 /* don't chdir .. to the parent */ +#define FTS_SYMFOLLOW 0x02 /* followed a symlink to get here */ +#define FTS_ISW 0x04 /* this is a whiteout object */ + u_short fts_flags; /* private flags for FTSENT structure */ + +#define FTS_AGAIN 1 /* read node again */ +#define FTS_FOLLOW 2 /* follow symbolic link */ +#define FTS_NOINSTR 3 /* no instructions */ +#define FTS_SKIP 4 /* discard node */ + u_short fts_instr; /* fts_set() instructions */ + + __fts_stat_t *fts_statp; /* stat(2) information */ + char fts_name[1]; /* file name */ +} FTSENT; + +#include <sys/cdefs.h> + +#define __RENAME(n) +#define fts_children rtems_shell_fts_children +#define fts_close rtems_shell_fts_close +#define fts_open rtems_shell_fts_open +#define fts_read rtems_shell_fts_read +#define fts_set rtems_shell_fts_set + +__BEGIN_DECLS +#ifndef __LIBC12_SOURCE__ +FTSENT *fts_children(FTS *, int) __RENAME(__fts_children30); +int fts_close(FTS *) __RENAME(__fts_close30); +FTS *fts_open(char * const *, int, + int (*)(const FTSENT **, const FTSENT **)) __RENAME(__fts_open30); +FTSENT *fts_read(FTS *) __RENAME(__fts_read30); +int fts_set(FTS *, FTSENT *, int) __RENAME(__fts_set30); +#endif +__END_DECLS + +#endif /* !_FTS_H_ */ diff --git a/cpukit/libmisc/shell/hexdump-conv.c b/cpukit/libmisc/shell/hexdump-conv.c new file mode 100644 index 0000000000..44390baa32 --- /dev/null +++ b/cpukit/libmisc/shell/hexdump-conv.c @@ -0,0 +1,186 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef lint +static const char sccsid[] = "@(#)conv.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/usr.bin/hexdump/conv.c,v 1.9 2006/07/31 14:17:04 jkoshy Exp $"); + +#include <sys/types.h> + +#include <assert.h> +#include <ctype.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <wchar.h> +#include <wctype.h> +#include "hexdump.h" + +void +conv_c(rtems_shell_hexdump_globals* globals, PR *pr, u_char *p, size_t bufsize) +{ + char buf[10]; + char const *str; + wchar_t wc; + size_t clen, oclen; + int converr, pad, width; + char peekbuf[MB_LEN_MAX]; + + if (pr->mbleft > 0) { + str = "**"; + pr->mbleft--; + goto strpr; + } + + switch(*p) { + case '\0': + str = "\\0"; + goto strpr; + /* case '\a': */ + case '\007': + str = "\\a"; + goto strpr; + case '\b': + str = "\\b"; + goto strpr; + case '\f': + str = "\\f"; + goto strpr; + case '\n': + str = "\\n"; + goto strpr; + case '\r': + str = "\\r"; + goto strpr; + case '\t': + str = "\\t"; + goto strpr; + case '\v': + str = "\\v"; + goto strpr; + default: + break; + } + /* + * Multibyte characters are disabled for hexdump(1) for backwards + * compatibility and consistency (none of its other output formats + * recognize them correctly). + */ + converr = 0; + if (odmode && MB_CUR_MAX > 1) { + oclen = 0; +retry: + clen = mbrtowc(&wc, (char*)p, bufsize, &pr->mbstate); + if (clen == 0) + clen = 1; + else if (clen == (size_t)-1 || (clen == (size_t)-2 && + buf == peekbuf)) { + memset(&pr->mbstate, 0, sizeof(pr->mbstate)); + wc = *p; + clen = 1; + converr = 1; + } else if (clen == (size_t)-2) { + /* + * Incomplete character; peek ahead and see if we + * can complete it. + */ + oclen = bufsize; + bufsize = peek(globals, p = (u_char*)peekbuf, MB_CUR_MAX); + goto retry; + } + clen += oclen; + } else { + wc = *p; + clen = 1; + } + if (!converr && iswprint(wc)) { + if (!odmode) { + *pr->cchar = 'c'; + (void)printf(pr->fmt, (int)wc); + } else { + *pr->cchar = 'C'; + assert(strcmp(pr->fmt, "%3C") == 0); + width = wcwidth(wc); + assert(width >= 0); + pad = 3 - width; + if (pad < 0) + pad = 0; + (void)printf("%*s%lc", pad, "", wc); + pr->mbleft = clen - 1; + } + } else { + (void)sprintf(buf, "%03o", (int)*p); + str = buf; +strpr: *pr->cchar = 's'; + (void)printf(pr->fmt, str); + } +} + +void +conv_u(rtems_shell_hexdump_globals* globals, PR *pr, u_char *p) +{ + static char const * list[] = { + "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel", + "bs", "ht", "lf", "vt", "ff", "cr", "so", "si", + "dle", "dcl", "dc2", "dc3", "dc4", "nak", "syn", "etb", + "can", "em", "sub", "esc", "fs", "gs", "rs", "us", + }; + + /* od used nl, not lf */ + if (*p <= 0x1f) { + *pr->cchar = 's'; + if (odmode && *p == 0x0a) + (void)printf(pr->fmt, "nl"); + else + (void)printf(pr->fmt, list[*p]); + } else if (*p == 0x7f) { + *pr->cchar = 's'; + (void)printf(pr->fmt, "del"); + } else if (odmode && *p == 0x20) { /* od replaced space with sp */ + *pr->cchar = 's'; + (void)printf(pr->fmt, " sp"); + } else if (isprint(*p)) { + *pr->cchar = 'c'; + (void)printf(pr->fmt, *p); + } else { + *pr->cchar = 'x'; + (void)printf(pr->fmt, (int)*p); + } +} diff --git a/cpukit/libmisc/shell/hexdump-display.c b/cpukit/libmisc/shell/hexdump-display.c new file mode 100644 index 0000000000..3e33fba143 --- /dev/null +++ b/cpukit/libmisc/shell/hexdump-display.c @@ -0,0 +1,431 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)display.c 8.1 (Berkeley) 6/6/93"; +#endif +#endif /* not lint */ +#if 0 +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/usr.bin/hexdump/display.c,v 1.22 2004/08/04 02:47:32 tjr Exp $"); +#endif + +#include <sys/param.h> +#include <sys/stat.h> + +#include <stdint.h> + +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "hexdump.h" + +#define bcmp(s1,s2,sz) memcmp(s1,s2,sz) +#define bcopy(s,d,sz) memcpy(d,s,sz) +#define bzero(s,sz) memset(s,0,sz) +#define index(s,c) strchr(s,c) + +#if RTEMS_REMOVED +enum _vflag vflag = FIRST; + +static off_t address; /* address/offset in stream */ +static off_t eaddress; /* end address */ +#endif + +static void print(rtems_shell_hexdump_globals*, PR *, u_char *); + +void +display(rtems_shell_hexdump_globals* globals) +{ + FS *fs; + FU *fu; + PR *pr; + int cnt; + u_char *bp; + off_t saveaddress; + u_char savech, *savebp; + + savech = 0; + while ((bp = get(globals))) + for (fs = fshead, savebp = bp, saveaddress = address; fs; + fs = fs->nextfs, bp = savebp, address = saveaddress) + for (fu = fs->nextfu; fu; fu = fu->nextfu) { + if (fu->flags&F_IGNORE) + break; + for (cnt = fu->reps; cnt; --cnt) + for (pr = fu->nextpr; pr; address += pr->bcnt, + bp += pr->bcnt, pr = pr->nextpr) { + if (eaddress && address >= eaddress && + !(pr->flags & (F_TEXT|F_BPAD))) + bpad(pr); + if (cnt == 1 && pr->nospace) { + savech = *pr->nospace; + *pr->nospace = '\0'; + } + print(globals, pr, bp); + if (cnt == 1 && pr->nospace) + *pr->nospace = savech; + } + } + if (endfu) { + /* + * If eaddress not set, error or file size was multiple of + * blocksize, and no partial block ever found. + */ + if (!eaddress) { + if (!address) + return; + eaddress = address; + } + for (pr = endfu->nextpr; pr; pr = pr->nextpr) + switch(pr->flags) { + case F_ADDRESS: + (void)printf(pr->fmt, (quad_t)eaddress); + break; + case F_TEXT: + (void)printf("%s", pr->fmt); + break; + } + } +} + +static void +print(rtems_shell_hexdump_globals* globals, PR *pr, u_char *bp) +{ + long double ldbl; + double f8; + float f4; + int16_t s2; + int8_t s8; + int32_t s4; + u_int16_t u2; + u_int32_t u4; + u_int64_t u8; + + switch(pr->flags) { + case F_ADDRESS: + (void)printf(pr->fmt, (quad_t)address); + break; + case F_BPAD: + (void)printf(pr->fmt, ""); + break; + case F_C: + conv_c(globals, pr, bp, eaddress ? eaddress - address : + blocksize - address % blocksize); + break; + case F_CHAR: + (void)printf(pr->fmt, *bp); + break; + case F_DBL: + switch(pr->bcnt) { + case 4: + bcopy(bp, &f4, sizeof(f4)); + (void)printf(pr->fmt, f4); + break; + case 8: + bcopy(bp, &f8, sizeof(f8)); + (void)printf(pr->fmt, f8); + break; + default: + if (pr->bcnt == sizeof(long double)) { + bcopy(bp, &ldbl, sizeof(ldbl)); + (void)printf(pr->fmt, ldbl); + } + break; + } + break; + case F_INT: + switch(pr->bcnt) { + case 1: + (void)printf(pr->fmt, (quad_t)(signed char)*bp); + break; + case 2: + bcopy(bp, &s2, sizeof(s2)); + (void)printf(pr->fmt, (quad_t)s2); + break; + case 4: + bcopy(bp, &s4, sizeof(s4)); + (void)printf(pr->fmt, (quad_t)s4); + break; + case 8: + bcopy(bp, &s8, sizeof(s8)); + (void)printf(pr->fmt, s8); + break; + } + break; + case F_P: + (void)printf(pr->fmt, isprint(*bp) ? *bp : '.'); + break; + case F_STR: + (void)printf(pr->fmt, (char *)bp); + break; + case F_TEXT: + (void)printf("%s", pr->fmt); + break; + case F_U: + conv_u(globals, pr, bp); + break; + case F_UINT: + switch(pr->bcnt) { + case 1: + (void)printf(pr->fmt, (u_quad_t)*bp); + break; + case 2: + bcopy(bp, &u2, sizeof(u2)); + (void)printf(pr->fmt, (u_quad_t)u2); + break; + case 4: + bcopy(bp, &u4, sizeof(u4)); + (void)printf(pr->fmt, (u_quad_t)u4); + break; + case 8: + bcopy(bp, &u8, sizeof(u8)); + (void)printf(pr->fmt, u8); + break; + } + break; + } +} + +void +bpad(PR *pr) +{ + static char const *spec = " -0+#"; + char *p1, *p2; + + /* + * Remove all conversion flags; '-' is the only one valid + * with %s, and it's not useful here. + */ + pr->flags = F_BPAD; + pr->cchar[0] = 's'; + pr->cchar[1] = '\0'; + for (p1 = pr->fmt; *p1 != '%'; ++p1); + for (p2 = ++p1; *p1 && index(spec, *p1); ++p1); + while ((*p2++ = *p1++)); +} + +static char **_argv; + +u_char * +get(rtems_shell_hexdump_globals* globals) +{ +#if RTEMS_REMOVED + static int ateof = 1; + static u_char *curp, *savp; +#endif + int n; + int need, nread; + int valid_save = 0; + u_char *tmpp; + + if (!curp) { + if ((curp = calloc(1, blocksize)) == NULL) + err(exit_jump, 1, NULL); + if ((savp = calloc(1, blocksize)) == NULL) + err(exit_jump, 1, NULL); + } else { + tmpp = curp; + curp = savp; + savp = tmpp; + address += blocksize; + valid_save = 1; + } + for (need = blocksize, nread = 0;;) { + /* + * if read the right number of bytes, or at EOF for one file, + * and no other files are available, zero-pad the rest of the + * block and set the end flag. + */ + if (!length || (ateof && !next(globals, (char **)NULL))) { + if (odmode && address < skip) + errx(exit_jump, 1, "cannot skip past end of input"); + if (need == blocksize) + return((u_char *)NULL); + /* + * XXX bcmp() is not quite right in the presence + * of multibyte characters. + */ + if (vflag != ALL && + valid_save && + bcmp(curp, savp, nread) == 0) { + if (vflag != DUP) + (void)printf("*\n"); + return((u_char *)NULL); + } + bzero((char *)curp + nread, need); + eaddress = address + nread; + return(curp); + } + n = fread((char *)curp + nread, sizeof(u_char), + length == -1 ? need : MIN(length, need), hdstdin); + if (!n) { + if (ferror(hdstdin)) + warn("%s", _argv[-1]); + ateof = 1; + continue; + } + ateof = 0; + if (length != -1) + length -= n; + if (!(need -= n)) { + /* + * XXX bcmp() is not quite right in the presence + * of multibyte characters. + */ + if (vflag == ALL || vflag == FIRST || + valid_save == 0 || + bcmp(curp, savp, blocksize) != 0) { + if (vflag == DUP || vflag == FIRST) + vflag = WAIT; + return(curp); + } + if (vflag == WAIT) + (void)printf("*\n"); + vflag = DUP; + address += blocksize; + need = blocksize; + nread = 0; + } + else + nread += n; + } +} + +size_t +peek(rtems_shell_hexdump_globals* globals, u_char *buf, size_t nbytes) +{ + size_t n, nread; + int c; + + if (length != -1 && nbytes > (unsigned int)length) + nbytes = length; + nread = 0; + while (nread < nbytes && (c = getchar()) != EOF) { + *buf++ = c; + nread++; + } + n = nread; + while (n-- > 0) { + c = *--buf; + ungetc(c, hdstdin); + } + return (nread); +} + +int +next(rtems_shell_hexdump_globals* globals, char **argv) +{ +#if RTEMS_REMOVED + static int done; +#endif + int statok; + + if (argv) { + _argv = argv; + return(1); + } + for (;;) { + if (*_argv) { + done = 1; + if (!hdstdin) { + hdstdin = malloc(sizeof(FILE)); + if (!hdstdin) + { + errno = ENOMEM; + err(exit_jump, 1, "file name allocation"); + } + memset (hdstdin, 0, sizeof(FILE)); + } + if (!(hdstdin = freopen(*_argv, "r", hdstdin))) { + warn("%s", *_argv); + exitval = 1; + ++_argv; + continue; + } + statok = 1; + } else { + errno = ECANCELED; + err(exit_jump, 1, "no file (stdin no supported)"); + if (done++) + return(0); + statok = 0; + } + if (skip) + doskip(globals, statok ? *_argv : "stdin", statok); + if (*_argv) + ++_argv; + if (!skip) + return(1); + } + /* NOTREACHED */ +} + +void +doskip(rtems_shell_hexdump_globals* globals, const char *fname, int statok) +{ + int cnt; + struct stat sb; + + if (statok) { + if (fstat(fileno(hdstdin), &sb)) + err(exit_jump, 1, "%s", fname); + /* can seek block devices on RTEMS */ + if (0 && S_ISREG(sb.st_mode) && skip >= sb.st_size) { + address += sb.st_size; + skip -= sb.st_size; + return; + } + if (1 || S_ISREG(sb.st_mode)) { + if (fseeko(hdstdin, skip, SEEK_SET)) + err(exit_jump, 1, "%s", fname); + address += skip; + skip = 0; + } else { + for (cnt = 0; cnt < skip; ++cnt) + if (getchar() == EOF) + break; + address += cnt; + skip -= cnt; + } + } +} diff --git a/cpukit/libmisc/shell/hexdump-odsyntax.c b/cpukit/libmisc/shell/hexdump-odsyntax.c new file mode 100644 index 0000000000..24e8d59e73 --- /dev/null +++ b/cpukit/libmisc/shell/hexdump-odsyntax.c @@ -0,0 +1,451 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)odsyntax.c 8.2 (Berkeley) 5/4/95"; +#endif /* not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/usr.bin/hexdump/odsyntax.c,v 1.17 2004/07/22 13:14:42 johan Exp $"); +#endif + +#include <sys/types.h> + +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <float.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "hexdump.h" + +#define __need_getopt_newlib +#include <getopt.h> + +#define PADDING " " + +#if RTEMS_REMOVED +int odmode; +#endif + +static void odadd(rtems_shell_hexdump_globals*, const char *); +static void odformat(rtems_shell_hexdump_globals*, const char *); +static const char *odformatfp(rtems_shell_hexdump_globals*, char, const char *); +static const char *odformatint(rtems_shell_hexdump_globals*, char, const char *); +static void odoffset(rtems_shell_hexdump_globals*, int, char ***); +static void odusage(rtems_shell_hexdump_globals*); + +void +oldsyntax(rtems_shell_hexdump_globals* globals, int argc, char ***argvp) +{ + static char empty[] = "", padding[] = PADDING; + int ch; + char **argv, *end; + + struct getopt_data getopt_reent; + memset(&getopt_reent, 0, sizeof(getopt_data)); + + /* Add initial (default) address format. -A may change it later. */ +#define TYPE_OFFSET 7 + add(globals, "\"%07.7_Ao\n\""); + add(globals, "\"%07.7_ao \""); + + odmode = 1; + argv = *argvp; + while ((ch = getopt_r(argc, argv, "A:aBbcDdeFfHhIij:LlN:Oost:vXx", &getopt_reent)) != -1) + switch (ch) { + case 'A': + switch (*optarg) { + case 'd': case 'o': case 'x': + fshead->nextfu->fmt[TYPE_OFFSET] = *optarg; + fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = + *optarg; + break; + case 'n': + fshead->nextfu->fmt = empty; + fshead->nextfs->nextfu->fmt = padding; + break; + default: + errx(exit_jump, 1, "%s: invalid address base", optarg); + } + break; + case 'a': + odformat(globals, "a"); + break; + case 'B': + case 'o': + odformat(globals, "o2"); + break; + case 'b': + odformat(globals, "o1"); + break; + case 'c': + odformat(globals, "c"); + break; + case 'd': + odformat(globals, "u2"); + break; + case 'D': + odformat(globals, "u4"); + break; + case 'e': /* undocumented in od */ + case 'F': + odformat(globals, "fD"); + break; + case 'f': + odformat(globals, "fF"); + break; + case 'H': + case 'X': + odformat(globals, "x4"); + break; + case 'h': + case 'x': + odformat(globals, "x2"); + break; + case 'I': + case 'L': + case 'l': + odformat(globals, "dL"); + break; + case 'i': + odformat(globals, "dI"); + break; + case 'j': + errno = 0; + skip = strtoll(optarg, &end, 0); + if (*end == 'b') + skip *= 512; + else if (*end == 'k') + skip *= 1024; + else if (*end == 'm') + skip *= 1048576L; + if (errno != 0 || skip < 0 || strlen(end) > 1) + errx(exit_jump, 1, "%s: invalid skip amount", optarg); + break; + case 'N': + if ((length = atoi(optarg)) <= 0) + errx(exit_jump, 1, "%s: invalid length", optarg); + break; + case 'O': + odformat(globals, "o4"); + break; + case 's': + odformat(globals, "d2"); + break; + case 't': + odformat(globals, optarg); + break; + case 'v': + vflag = ALL; + break; + case '?': + default: + odusage(globals); + } + + if (fshead->nextfs->nextfs == NULL) + odformat(globals, "oS"); + + argc -= getopt_reent.optind; + *argvp += getopt_reent.optind; + + if (argc) + odoffset(globals, argc, argvp); +} + +static void +odusage(rtems_shell_hexdump_globals* globals) +{ + + fprintf(stderr, +"usage: od [-aBbcDdeFfHhIiLlOosvXx] [-A base] [-j skip] [-N length] [-t type]\n"); + fprintf(stderr, +" [[+]offset[.][Bb]] [file ...]\n"); + exit(1); +} + +static void +odoffset(rtems_shell_hexdump_globals* globals, int argc, char ***argvp) +{ + char *p, *num, *end; + int base; + + /* + * The offset syntax of od(1) was genuinely bizarre. First, if + * it started with a plus it had to be an offset. Otherwise, if + * there were at least two arguments, a number or lower-case 'x' + * followed by a number makes it an offset. By default it was + * octal; if it started with 'x' or '0x' it was hex. If it ended + * in a '.', it was decimal. If a 'b' or 'B' was appended, it + * multiplied the number by 512 or 1024 byte units. There was + * no way to assign a block count to a hex offset. + * + * We assume it's a file if the offset is bad. + */ + p = argc == 1 ? (*argvp)[0] : (*argvp)[1]; + + if (*p != '+' && (argc < 2 || + (!isdigit((unsigned char)p[0]) && (p[0] != 'x' || !isxdigit((unsigned char)p[1]))))) + return; + + base = 0; + /* + * skip over leading '+', 'x[0-9a-fA-f]' or '0x', and + * set base. + */ + if (p[0] == '+') + ++p; + if (p[0] == 'x' && isxdigit((unsigned char)p[1])) { + ++p; + base = 16; + } else if (p[0] == '0' && p[1] == 'x') { + p += 2; + base = 16; + } + + /* skip over the number */ + if (base == 16) + for (num = p; isxdigit((unsigned char)*p); ++p); + else + for (num = p; isdigit((unsigned char)*p); ++p); + + /* check for no number */ + if (num == p) + return; + + /* if terminates with a '.', base is decimal */ + if (*p == '.') { + if (base) + return; + base = 10; + } + + skip = strtoll(num, &end, base ? base : 8); + + /* if end isn't the same as p, we got a non-octal digit */ + if (end != p) { + skip = 0; + return; + } + + if (*p) { + if (*p == 'B') { + skip *= 1024; + ++p; + } else if (*p == 'b') { + skip *= 512; + ++p; + } + } + + if (*p) { + skip = 0; + return; + } + + /* + * If the offset uses a non-octal base, the base of the offset + * is changed as well. This isn't pretty, but it's easy. + */ + if (base == 16) { + fshead->nextfu->fmt[TYPE_OFFSET] = 'x'; + fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'x'; + } else if (base == 10) { + fshead->nextfu->fmt[TYPE_OFFSET] = 'd'; + fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'd'; + } + + /* Terminate file list. */ + (*argvp)[1] = NULL; +} + +static void +odformat(rtems_shell_hexdump_globals* globals, const char *fmt) +{ + char fchar; + + while (*fmt != '\0') { + switch ((fchar = *fmt++)) { + case 'a': + odadd(globals, "16/1 \"%3_u \" \"\\n\""); + break; + case 'c': + odadd(globals, "16/1 \"%3_c \" \"\\n\""); + break; + case 'o': case 'u': case 'd': case 'x': + fmt = odformatint(globals, fchar, fmt); + break; + case 'f': + fmt = odformatfp(globals, fchar, fmt); + break; + default: + errx(exit_jump, 1, "%c: unrecognised format character", fchar); + } + } +} +#define __unused + +static const char * +odformatfp(rtems_shell_hexdump_globals* globals, char fchar __unused, const char *fmt) +{ + size_t isize; + int digits; + char *end, *hdfmt; + + isize = sizeof(double); + switch (*fmt) { + case 'F': + isize = sizeof(float); + fmt++; + break; + case 'D': + isize = sizeof(double); + fmt++; + break; + case 'L': + isize = sizeof(long double); + fmt++; + break; + default: + if (isdigit((unsigned char)*fmt)) { + errno = 0; + isize = (size_t)strtoul(fmt, &end, 10); + if (errno != 0 || isize == 0) + errx(exit_jump, 1, "%s: invalid size", fmt); + fmt = (const char *)end; + } + } + if (isize == sizeof(float) ) { + digits = FLT_DIG; + } else if (isize == sizeof(double)) { + digits = DBL_DIG; + } else if (isize == sizeof(long double)) { + digits = LDBL_DIG; + } else { + errx(exit_jump, 1, "unsupported floating point size %zu", + isize); + } + + asprintf(&hdfmt, "%lu/%lu \" %%%d.%de \" \"\\n\"", + 16UL / (u_long)isize, (u_long)isize, digits + 8, digits); + if (hdfmt == NULL) + err(exit_jump, 1, NULL); + odadd(globals, hdfmt); + free(hdfmt); + + return (fmt); +} + +static const char * +odformatint(rtems_shell_hexdump_globals* globals, char fchar, const char *fmt) +{ + unsigned long long n; + size_t isize; + int digits; + char *end, *hdfmt; + + isize = sizeof(int); + switch (*fmt) { + case 'C': + isize = sizeof(char); + fmt++; + break; + case 'I': + isize = sizeof(int); + fmt++; + break; + case 'L': + isize = sizeof(long); + fmt++; + break; + case 'S': + isize = sizeof(short); + fmt++; + break; + default: + if (isdigit((unsigned char)*fmt)) { + errno = 0; + isize = (size_t)strtoul(fmt, &end, 10); + if (errno != 0 || isize == 0) + errx(exit_jump, 1, "%s: invalid size", fmt); + if (isize != sizeof(char) && isize != sizeof(short) && + isize != sizeof(int) && isize != sizeof(long)) + errx(exit_jump, 1, "unsupported int size %lu", + (u_long)isize); + fmt = (const char *)end; + } + } + + /* + * Calculate the maximum number of digits we need to + * fit the number. Overestimate for decimal with log + * base 8. We need one extra space for signed numbers + * to store the sign. + */ + n = (1ULL << (8 * isize)) - 1; + digits = 0; + while (n != 0) { + digits++; + n >>= (fchar == 'x') ? 4 : 3; + } + if (fchar == 'd') + digits++; + asprintf(&hdfmt, "%lu/%lu \"%*s%%%s%d%c\" \"\\n\"", + 16UL / (u_long)isize, (u_long)isize, (int)(4 * isize - digits), + "", (fchar == 'd' || fchar == 'u') ? "" : "0", digits, fchar); + if (hdfmt == NULL) + err(exit_jump, 1, NULL); + odadd(globals, hdfmt); + free(hdfmt); + + return (fmt); +} + +static void +odadd(rtems_shell_hexdump_globals* globals, const char *fmt) +{ + static int needpad; + + if (needpad) + add(globals, "\""PADDING"\""); + add(globals, fmt); + needpad = 1; +} diff --git a/cpukit/libmisc/shell/hexdump-parse.c b/cpukit/libmisc/shell/hexdump-parse.c new file mode 100644 index 0000000000..1c35ba4649 --- /dev/null +++ b/cpukit/libmisc/shell/hexdump-parse.c @@ -0,0 +1,531 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)parse.c 8.1 (Berkeley) 6/6/93"; +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/usr.bin/hexdump/parse.c,v 1.14 2006/08/09 19:12:10 maxim Exp $"); +#endif +#endif /* not lint */ + +#include <sys/types.h> + +#include <err.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <string.h> + +#define index(s,c) strchr(s,c) + +#include "hexdump.h" + +#if RTEMS_REMOVED +FU *endfu; /* format at end-of-data */ +#endif + +void +addfile(rtems_shell_hexdump_globals* globals, char *name) +{ + unsigned char *p; + FILE *fp; + int ch; + char buf[2048 + 1]; + + if ((fp = fopen(name, "r")) == NULL) + err(exit_jump, 1, "%s", name); + while (fgets(buf, sizeof(buf), fp)) { + if (!(p = (unsigned char*)index(buf, '\n'))) { + warnx("line too long"); + while ((ch = getchar()) != '\n' && ch != EOF); + continue; + } + *p = '\0'; + for (p = (unsigned char*) buf; *p && isspace(*p); ++p); + if (!*p || *p == '#') + continue; + add(globals, (char*)p); + } + (void)fclose(fp); +} + +void +add(rtems_shell_hexdump_globals* globals, const char *fmt) +{ + unsigned const char *p, *savep; + static FS **nextfs; + FS *tfs; + FU *tfu, **nextfu; + + /* start new linked list of format units */ + if ((tfs = calloc(1, sizeof(FS))) == NULL) + err(exit_jump, 1, NULL); + if (!fshead) + fshead = tfs; + else + *nextfs = tfs; + nextfs = &tfs->nextfs; + nextfu = &tfs->nextfu; + + /* take the format string and break it up into format units */ + for (p = (unsigned const char*)fmt;;) { + /* skip leading white space */ + for (; isspace(*p); ++p); + if (!*p) + break; + + /* allocate a new format unit and link it in */ + if ((tfu = calloc(1, sizeof(FU))) == NULL) + err(exit_jump, 1, NULL); + *nextfu = tfu; + nextfu = &tfu->nextfu; + tfu->reps = 1; + + /* if leading digit, repetition count */ + if (isdigit(*p)) { + for (savep = p; isdigit(*p); ++p); + if (!isspace(*p) && *p != '/') + badfmt(globals, fmt); + /* may overwrite either white space or slash */ + tfu->reps = atoi((char*)savep); + tfu->flags = F_SETREP; + /* skip trailing white space */ + for (++p; isspace(*p); ++p); + } + + /* skip slash and trailing white space */ + if (*p == '/') + while (isspace(*++p)); + + /* byte count */ + if (isdigit(*p)) { + for (savep = p; isdigit(*p); ++p); + if (!isspace(*p)) + badfmt(globals, fmt); + tfu->bcnt = atoi((char*)savep); + /* skip trailing white space */ + for (++p; isspace(*p); ++p); + } + + /* format */ + if (*p != '"') + badfmt(globals, fmt); + for (savep = ++p; *p != '"';) + if (*p++ == 0) + badfmt(globals, fmt); + if (!(tfu->fmt = malloc(p - savep + 1))) + err(exit_jump, 1, NULL); + (void) strncpy(tfu->fmt, (char*)savep, p - savep); + tfu->fmt[p - savep] = '\0'; + escape(tfu->fmt); + p++; + } +} + +static const char *spec = ".#-+ 0123456789"; + +int +size(rtems_shell_hexdump_globals* globals, FS *fs) +{ + FU *fu; + int bcnt, cursize; + unsigned char *fmt; + int prec; + + /* figure out the data block size needed for each format unit */ + for (cursize = 0, fu = fs->nextfu; fu; fu = fu->nextfu) { + if (fu->bcnt) { + cursize += fu->bcnt * fu->reps; + continue; + } + for (bcnt = prec = 0, fmt = (unsigned char*) fu->fmt; *fmt; ++fmt) { + if (*fmt != '%') + continue; + /* + * skip any special chars -- save precision in + * case it's a %s format. + */ + while (index(spec + 1, *++fmt)); + if (*fmt == '.' && isdigit(*++fmt)) { + prec = atoi((char*)fmt); + while (isdigit(*++fmt)); + } + switch(*fmt) { + case 'c': + bcnt += 1; + break; + case 'd': case 'i': case 'o': case 'u': + case 'x': case 'X': + bcnt += 4; + break; + case 'e': case 'E': case 'f': case 'g': case 'G': + bcnt += 8; + break; + case 's': + bcnt += prec; + break; + case '_': + switch(*++fmt) { + case 'c': case 'p': case 'u': + bcnt += 1; + break; + } + } + } + cursize += bcnt * fu->reps; + } + return (cursize); +} + +void +rewrite(rtems_shell_hexdump_globals* globals, FS *fs) +{ + enum { NOTOKAY, USEBCNT, USEPREC } sokay; + PR *pr, **nextpr; + FU *fu; + unsigned char *p1, *p2, *fmtp; + char savech, cs[3]; + int nconv, prec; + size_t len; + + pr = NULL; + nextpr = NULL; + prec = 0; + + for (fu = fs->nextfu; fu; fu = fu->nextfu) { + /* + * Break each format unit into print units; each conversion + * character gets its own. + */ + for (nconv = 0, fmtp = (unsigned char*)fu->fmt; *fmtp; nextpr = &pr->nextpr) { + if ((pr = calloc(1, sizeof(PR))) == NULL) + err(exit_jump, 1, NULL); + if (!fu->nextpr) + fu->nextpr = pr; + else { + if (nextpr) + *nextpr = pr; + } + + /* Skip preceding text and up to the next % sign. */ + for (p1 = fmtp; *p1 && *p1 != '%'; ++p1); + + /* Only text in the string. */ + if (!*p1) { + pr->fmt = (char*)fmtp; + pr->flags = F_TEXT; + break; + } + + /* + * Get precision for %s -- if have a byte count, don't + * need it. + */ + if (fu->bcnt) { + sokay = USEBCNT; + /* Skip to conversion character. */ + for (++p1; index(spec, *p1); ++p1); + } else { + /* Skip any special chars, field width. */ + while (index(spec + 1, *++p1)); + if (*p1 == '.' && isdigit(*++p1)) { + sokay = USEPREC; + prec = atoi((char*)p1); + while (isdigit(*++p1)); + } else + sokay = NOTOKAY; + } + + p2 = p1 + 1; /* Set end pointer. */ + cs[0] = *p1; /* Set conversion string. */ + cs[1] = '\0'; + + /* + * Figure out the byte count for each conversion; + * rewrite the format as necessary, set up blank- + * padding for end of data. + */ + switch(cs[0]) { + case 'c': + pr->flags = F_CHAR; + switch(fu->bcnt) { + case 0: case 1: + pr->bcnt = 1; + break; + default: + p1[1] = '\0'; + badcnt(globals, (char*)p1); + } + break; + case 'd': case 'i': + pr->flags = F_INT; + goto isint; + case 'o': case 'u': case 'x': case 'X': + pr->flags = F_UINT; +isint: cs[2] = '\0'; + cs[1] = cs[0]; + cs[0] = 'q'; + switch(fu->bcnt) { + case 0: case 4: + pr->bcnt = 4; + break; + case 1: + pr->bcnt = 1; + break; + case 2: + pr->bcnt = 2; + break; + default: + p1[1] = '\0'; + badcnt(globals, (char*)p1); + } + break; + case 'e': case 'E': case 'f': case 'g': case 'G': + pr->flags = F_DBL; + switch(fu->bcnt) { + case 0: case 8: + pr->bcnt = 8; + break; + case 4: + pr->bcnt = 4; + break; + default: + if (fu->bcnt == sizeof(long double)) { + cs[2] = '\0'; + cs[1] = cs[0]; + cs[0] = 'L'; + pr->bcnt = sizeof(long double); + } else { + p1[1] = '\0'; + badcnt(globals, (char*)p1); + } + } + break; + case 's': + pr->flags = F_STR; + switch(sokay) { + case NOTOKAY: + badsfmt(globals); + case USEBCNT: + pr->bcnt = fu->bcnt; + break; + case USEPREC: + pr->bcnt = prec; + break; + } + break; + case '_': + ++p2; + switch(p1[1]) { + case 'A': + endfu = fu; + fu->flags |= F_IGNORE; + /* FALLTHROUGH */ + case 'a': + pr->flags = F_ADDRESS; + ++p2; + switch(p1[2]) { + case 'd': case 'o': case'x': + cs[0] = 'q'; + cs[1] = p1[2]; + cs[2] = '\0'; + break; + default: + p1[3] = '\0'; + badconv(globals, (char*)p1); + } + break; + case 'c': + pr->flags = F_C; + /* cs[0] = 'c'; set in conv_c */ + goto isint2; + case 'p': + pr->flags = F_P; + cs[0] = 'c'; + goto isint2; + case 'u': + pr->flags = F_U; + /* cs[0] = 'c'; set in conv_u */ +isint2: switch(fu->bcnt) { + case 0: case 1: + pr->bcnt = 1; + break; + default: + p1[2] = '\0'; + badcnt(globals, (char*)p1); + } + break; + default: + p1[2] = '\0'; + badconv(globals, (char*)p1); + } + break; + default: + p1[1] = '\0'; + badconv(globals, (char*)p1); + } + + /* + * Copy to PR format string, set conversion character + * pointer, update original. + */ + savech = *p2; + p1[0] = '\0'; + len = strlen((char*)fmtp) + strlen(cs) + 1; + if ((pr->fmt = calloc(1, len)) == NULL) + err(exit_jump, 1, NULL); + snprintf(pr->fmt, len, "%s%s", fmtp, cs); + *p2 = savech; + pr->cchar = pr->fmt + (p1 - fmtp); + fmtp = p2; + + /* Only one conversion character if byte count. */ + if (!(pr->flags&F_ADDRESS) && fu->bcnt && nconv++) + errx(exit_jump, 1, "byte count with multiple conversion characters"); + } + /* + * If format unit byte count not specified, figure it out + * so can adjust rep count later. + */ + if (!fu->bcnt) + for (pr = fu->nextpr; pr; pr = pr->nextpr) + fu->bcnt += pr->bcnt; + } + if (pr) { + free(pr); + pr = NULL; + } + /* + * If the format string interprets any data at all, and it's + * not the same as the blocksize, and its last format unit + * interprets any data at all, and has no iteration count, + * repeat it as necessary. + * + * If, rep count is greater than 1, no trailing whitespace + * gets output from the last iteration of the format unit. + */ + for (fu = fs->nextfu; fu; fu = fu->nextfu) { + if (!fu->nextfu && fs->bcnt < blocksize && + !(fu->flags&F_SETREP) && fu->bcnt) + fu->reps += (blocksize - fs->bcnt) / fu->bcnt; + if (fu->reps > 1) { + for (pr = fu->nextpr;; pr = pr->nextpr) + if (!pr->nextpr) + break; + for (p1 = (unsigned char*)pr->fmt, p2 = NULL; *p1; ++p1) + p2 = isspace(*p1) ? p1 : NULL; + if (p2) + pr->nospace = (char*)p2; + } + } +#ifdef DEBUG + for (fu = fs->nextfu; fu; fu = fu->nextfu) { + (void)printf("fmt:"); + for (pr = fu->nextpr; pr; pr = pr->nextpr) + (void)printf(" {%s}", pr->fmt); + (void)printf("\n"); + } +#endif +} + +void +escape(char *p1) +{ + char *p2; + + /* alphabetic escape sequences have to be done in place */ + for (p2 = p1;; ++p1, ++p2) { + if (!*p1) { + *p2 = *p1; + break; + } + if (*p1 == '\\') + switch(*++p1) { + case 'a': + /* *p2 = '\a'; */ + *p2 = '\007'; + break; + case 'b': + *p2 = '\b'; + break; + case 'f': + *p2 = '\f'; + break; + case 'n': + *p2 = '\n'; + break; + case 'r': + *p2 = '\r'; + break; + case 't': + *p2 = '\t'; + break; + case 'v': + *p2 = '\v'; + break; + default: + *p2 = *p1; + break; + } + } +} + +void +badcnt(rtems_shell_hexdump_globals* globals, char *s) +{ + errx(exit_jump, 1, "%s: bad byte count", s); +} + +void +badsfmt(rtems_shell_hexdump_globals* globals) +{ + errx(exit_jump, 1, "%%s: requires a precision or a byte count"); +} + +void +badfmt(rtems_shell_hexdump_globals* globals, const char *fmt) +{ + errx(exit_jump, 1, "\"%s\": bad format", fmt); +} + +void +badconv(rtems_shell_hexdump_globals* globals, char *ch) +{ + errx(exit_jump, 1, "%%%s: bad conversion character", ch); +} diff --git a/cpukit/libmisc/shell/hexdump.h b/cpukit/libmisc/shell/hexdump.h new file mode 100644 index 0000000000..5b0e61b966 --- /dev/null +++ b/cpukit/libmisc/shell/hexdump.h @@ -0,0 +1,183 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)hexdump.h 8.1 (Berkeley) 6/6/93 + * $FreeBSD: src/usr.bin/hexdump/hexdump.h,v 1.9 2004/07/11 01:11:12 tjr Exp $ + */ + +#include <wchar.h> + +typedef struct _pr { + struct _pr *nextpr; /* next print unit */ +#define F_ADDRESS 0x001 /* print offset */ +#define F_BPAD 0x002 /* blank pad */ +#define F_C 0x004 /* %_c */ +#define F_CHAR 0x008 /* %c */ +#define F_DBL 0x010 /* %[EefGf] */ +#define F_INT 0x020 /* %[di] */ +#define F_P 0x040 /* %_p */ +#define F_STR 0x080 /* %s */ +#define F_U 0x100 /* %_u */ +#define F_UINT 0x200 /* %[ouXx] */ +#define F_TEXT 0x400 /* no conversions */ + u_int flags; /* flag values */ + int bcnt; /* byte count */ + char *cchar; /* conversion character */ + char *fmt; /* printf format */ + char *nospace; /* no whitespace version */ + int mbleft; /* bytes left of multibyte char. */ + mbstate_t mbstate; /* conversion state */ +} PR; + +typedef struct _fu { + struct _fu *nextfu; /* next format unit */ + struct _pr *nextpr; /* next print unit */ +#define F_IGNORE 0x01 /* %_A */ +#define F_SETREP 0x02 /* rep count set, not default */ + u_int flags; /* flag values */ + int reps; /* repetition count */ + int bcnt; /* byte count */ + char *fmt; /* format string */ +} FU; + +typedef struct _fs { /* format strings */ + struct _fs *nextfs; /* linked list of format strings */ + struct _fu *nextfu; /* linked list of format units */ + int bcnt; +} FS; + +#if 0 +extern FS *fshead; /* head of format strings list */ +extern FU *endfu; /* format at end-of-data */ +extern int blocksize; /* data block size */ +extern int exitval; /* final exit value */ +extern int odmode; /* are we acting as od(1)? */ +extern int length; /* amount of data to read */ +extern off_t skip; /* amount of data to skip at start */ +enum _vflag { ALL, DUP, FIRST, WAIT }; /* -v values */ +extern enum _vflag vflag; +#endif + +#include <setjmp.h> +#include <stdio.h> + +enum _vflag { ALL, DUP, FIRST, WAIT }; /* -v values */ +typedef struct rtems_shell_hexdump_globals_t { + FS *fshead; /* head of format strings list */ + FU *endfu; /* format at end-of-data */ + int blocksize; /* data block size */ + int exitval; /* final exit value */ + int odmode; /* are we acting as od(1)? */ + int length; /* amount of data to read */ + off_t skip; /* amount of data to skip at start */ + enum _vflag vflag; + + off_t address; + off_t eaddress; + int ateof; + u_char *curp; + u_char *savp; + int done; + + FILE* hdstdin; + + int exit_code; + jmp_buf exit_jmp; +} rtems_shell_hexdump_globals; + +#define fshead globals->fshead +#define endfu globals->endfu +#define blocksize globals->blocksize +#define exitval globals->exitval +#define odmode globals->odmode +#define length globals->length +#define skip globals->skip +#define vflag globals->vflag + +#define address globals->address +#define eaddress globals->eaddress +#define ateof globals->ateof +#define curp globals->curp +#define savp globals->savp +#define done globals->done + +#define hdstdin globals->hdstdin + +#define exit_jump &(globals->exit_jmp) + +#define add rtems_shell_hexdump_add +#define addfile rtems_shell_hexdump_addfile +#define badcnt rtems_shell_hexdump_badcnt +#define badconv rtems_shell_hexdump_badconv +#define badfmt rtems_shell_hexdump_badfmt +#define badsfmt rtems_shell_hexdump_badsfmt +#define bpad rtems_shell_hexdump_bpad +#define conv_c rtems_shell_hexdump_conv_c +#define conv_u rtems_shell_hexdump_conv_u +#define display rtems_shell_hexdump_display +#define doskip rtems_shell_hexdump_doskip +#define escape rtems_shell_hexdump_escape +#define get rtems_shell_hexdump_get +#define newsyntax rtems_shell_hexdump_newsyntax +#define next rtems_shell_hexdump_next +#define nomem rtems_shell_hexdump_nomem +#define oldsyntax rtems_shell_hexdump_oldsyntax +#define peek rtems_shell_hexdump_peek +#define rewrite rtems_shell_hexdump_rewrite +#define size rtems_shell_hexdump_size +#define usage rtems_shell_hexdump_usage + +void add(rtems_shell_hexdump_globals*, const char *); +void addfile(rtems_shell_hexdump_globals*, char *); +void badcnt(rtems_shell_hexdump_globals*, char *); +void badconv(rtems_shell_hexdump_globals*, char *); +void badfmt(rtems_shell_hexdump_globals*, const char *); +void badsfmt(rtems_shell_hexdump_globals*); +void bpad(PR *); +void conv_c(rtems_shell_hexdump_globals*, PR *, u_char *, size_t); +void conv_u(rtems_shell_hexdump_globals*, PR *, u_char *); +void display(rtems_shell_hexdump_globals*); +void doskip(rtems_shell_hexdump_globals*, const char *, int); +void escape(char *); +u_char *get(rtems_shell_hexdump_globals*); +void newsyntax(rtems_shell_hexdump_globals*, int, char ***); +int next(rtems_shell_hexdump_globals*, char **); +void nomem(void); +void oldsyntax(rtems_shell_hexdump_globals*, int, char ***); +size_t peek(rtems_shell_hexdump_globals*, u_char *, size_t); +void rewrite(rtems_shell_hexdump_globals*, FS *); +int size(rtems_shell_hexdump_globals*, FS *); +void usage(rtems_shell_hexdump_globals*); + +#define exit(ec) rtems_shell_hexdump_exit(globals, ec) + +void rtems_shell_hexdump_exit(rtems_shell_hexdump_globals* globals, int code); diff --git a/cpukit/libmisc/shell/hexsyntax.c b/cpukit/libmisc/shell/hexsyntax.c new file mode 100644 index 0000000000..0f80738172 --- /dev/null +++ b/cpukit/libmisc/shell/hexsyntax.c @@ -0,0 +1,158 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)hexsyntax.c 8.2 (Berkeley) 5/4/95"; +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/usr.bin/hexdump/hexsyntax.c,v 1.12 2002/09/04 23:29:01 dwmalone Exp $"); +#endif +#endif /* not lint */ + +#include <sys/types.h> + +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#define rindex(s,c) strrchr(s,c) + +#include "hexdump.h" + +#define __need_getopt_newlib +#include <getopt.h> + +#if RTEMS_REMOVED +off_t skip; /* bytes to skip */ +#endif + +void +newsyntax(rtems_shell_hexdump_globals* globals, int argc, char ***argvp) +{ + int ch; + char *p, **argv; + + struct getopt_data getopt_reent; + memset(&getopt_reent, 0, sizeof(getopt_data)); + + argv = *argvp; + if ((p = rindex(argv[0], 'h')) != NULL && + strcmp(p, "hd") == 0) { + /* "Canonical" format, implies -C. */ + add(globals, "\"%08.8_Ax\n\""); + add(globals, "\"%08.8_ax \" 8/1 \"%02x \" \" \" 8/1 \"%02x \" "); + add(globals, "\" |\" 16/1 \"%_p\" \"|\\n\""); + } + while ((ch = getopt_r(argc, argv, "bcCde:f:n:os:vx", &getopt_reent)) != -1) + switch (ch) { + case 'b': + add(globals, "\"%07.7_Ax\n\""); + add(globals, "\"%07.7_ax \" 16/1 \"%03o \" \"\\n\""); + break; + case 'c': + add(globals, "\"%07.7_Ax\n\""); + add(globals, "\"%07.7_ax \" 16/1 \"%3_c \" \"\\n\""); + break; + case 'C': + add(globals, "\"%08.8_Ax\n\""); + add(globals, "\"%08.8_ax \" 8/1 \"%02x \" \" \" 8/1 \"%02x \" "); + add(globals, "\" |\" 16/1 \"%_p\" \"|\\n\""); + break; + case 'd': + add(globals, "\"%07.7_Ax\n\""); + add(globals, "\"%07.7_ax \" 8/2 \" %05u \" \"\\n\""); + break; + case 'e': + add(globals, getopt_reent.optarg); + break; + case 'f': + addfile(globals, getopt_reent.optarg); + break; + case 'n': + if ((length = atoi(getopt_reent.optarg)) < 0) + errx(exit_jump, 1, "%s: bad length value", getopt_reent.optarg); + break; + case 'o': + add(globals, "\"%07.7_Ax\n\""); + add(globals, "\"%07.7_ax \" 8/2 \" %06o \" \"\\n\""); + break; + case 's': + if ((skip = strtoll(getopt_reent.optarg, &p, 0)) < 0) + errx(exit_jump, 1, "%s: bad skip value", getopt_reent.optarg); + switch(*p) { + case 'b': + skip *= 512; + break; + case 'k': + skip *= 1024; + break; + case 'm': + skip *= 1048576; + break; + } + break; + case 'v': + vflag = ALL; + break; + case 'x': + add(globals, "\"%07.7_Ax\n\""); + add(globals, "\"%07.7_ax \" 8/2 \" %04x \" \"\\n\""); + break; + case '?': + usage(globals); + } + + if (!fshead) { + add(globals, "\"%07.7_Ax\n\""); + add(globals, "\"%07.7_ax \" 8/2 \"%04x \" \"\\n\""); + } + + *argvp += getopt_reent.optind; +} + +void +usage(rtems_shell_hexdump_globals* globals) +{ + (void)fprintf(stderr, "%s\n%s\n%s\n%s\n", +"usage: hexdump [-bcCdovx] [-e fmt] [-f fmt_file] [-n length]", +" [-s skip] [file ...]", +" hd [-bcdovx] [-e fmt] [-f fmt_file] [-n length]", +" [-s skip] [file ...]"); + exit(1); +} diff --git a/cpukit/libmisc/shell/internal.h b/cpukit/libmisc/shell/internal.h new file mode 100644 index 0000000000..aadd346092 --- /dev/null +++ b/cpukit/libmisc/shell/internal.h @@ -0,0 +1,37 @@ +/* + * Shell Internal Information + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifndef _RTEMS_SHELL_INTERNAL_H +#define _RTEMS_SHELL_INTERNAL_H + +struct rtems_shell_topic_tt; +typedef struct rtems_shell_topic_tt rtems_shell_topic_t; + +struct rtems_shell_topic_tt { + const char *topic; + rtems_shell_topic_t *next; +}; + + +extern rtems_shell_cmd_t * rtems_shell_first_cmd; +extern rtems_shell_topic_t * rtems_shell_first_topic; + +rtems_shell_topic_t * rtems_shell_lookup_topic(const char *topic); + + +void rtems_shell_register_monitor_commands(void); +void rtems_shell_initialize_command_set(void); + +void rtems_shell_print_heap_info( + const char *c, + Heap_Information *h +); + +#endif diff --git a/cpukit/libmisc/shell/login_check.c b/cpukit/libmisc/shell/login_check.c new file mode 100644 index 0000000000..d744ee5954 --- /dev/null +++ b/cpukit/libmisc/shell/login_check.c @@ -0,0 +1,62 @@ +/** + * @file + * + * @brief Shell login check function. + */ + +/* + * Copyright (c) 2009 embedded brains GmbH and others. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * Based on work from Chris Johns and Fernando Ruiz. + * + * Derived from file "cpukit/libmisc/shell/shell.c". + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> +#include <unistd.h> +#include <pwd.h> + +#include <rtems/shell.h> +#include <rtems/userenv.h> + +bool rtems_shell_login_check( + const char *user, + const char *passphrase +) +{ + struct passwd *pw = getpwnam( user); + + /* Valid user? */ + if (pw != NULL && strcmp( pw->pw_passwd, "!") != 0) { + setuid( pw->pw_uid); + setgid( pw->pw_gid); + rtems_current_user_env->euid = 0; + rtems_current_user_env->egid = 0; + chown( rtems_current_shell_env->devname, pw->pw_uid, 0); + rtems_current_user_env->euid = pw->pw_uid; + rtems_current_user_env->egid = pw->pw_gid; + if (strcmp( pw->pw_passwd, "*") == 0) { + /* TODO: /etc/shadow */ + return true; + } else { + /* TODO: crypt() */ + return true; + } + } + + return false; +} diff --git a/cpukit/libmisc/shell/login_prompt.c b/cpukit/libmisc/shell/login_prompt.c new file mode 100644 index 0000000000..7e93078805 --- /dev/null +++ b/cpukit/libmisc/shell/login_prompt.c @@ -0,0 +1,209 @@ +/** + * @file + * + * @brief Shell login prompt functions. + */ + +/* + * Authorship + * ---------- + * Parts of this software was created by + * Till Straumann <strauman@slac.stanford.edu>, 2003-2007 + * Stanford Linear Accelerator Center, Stanford University. + * + * Acknowledgement of sponsorship + * ------------------------------ + * Parts of this software was produced by + * the Stanford Linear Accelerator Center, Stanford University, + * under Contract DE-AC03-76SFO0515 with the Department of Energy. + * + * Government disclaimer of liability + * ---------------------------------- + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, or + * assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately owned + * rights. + * + * Stanford disclaimer of liability + * -------------------------------- + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * Stanford disclaimer of copyright + * -------------------------------- + * Stanford University, owner of the copyright, hereby disclaims its + * copyright and all other rights in this software. Hence, anyone may + * freely use it for any purpose without restriction. + * + * Maintenance of notices + * ---------------------- + * In the interest of clarity regarding the origin and status of this + * SLAC software, this and all the preceding Stanford University notices + * are to remain affixed to any copy or derivative of this software made + * or distributed by the recipient and are to be affixed to any copy of + * software made or distributed by the recipient that contains a copy or + * derivative of this software. + * + * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 + * + * Copyright (c) 2009 embedded brains GmbH and others. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * Based on work from Chris Johns, Fernando Ruiz and Till Straumann. + * + * Derived from files "cpukit/libmisc/shell/shell.c" and + * "cpukit/telnetd/check_passwd.c". + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <termios.h> +#include <unistd.h> +#include <ctype.h> +#include <errno.h> + +#include <rtems/shell.h> + +static int rtems_shell_discard( int c, FILE *stream) +{ + return c; +} + +static bool rtems_shell_get_text( + FILE *in, + FILE *out, + char *line, + size_t size +) +{ + int fd_in = fileno( in); + int (*put)( int, FILE *) = + out != NULL && isatty( fd_in) + ? fputc + : rtems_shell_discard; + size_t i = 0; + + if (size < 1) { + return false; + } + + tcdrain( fd_in); + if (out != NULL){ + tcdrain( fileno(out) ); + } + + while (true) { + int c = fgetc(in); + + switch (c) { + case EOF: + clearerr( in ); + return false; + case '\n': + case '\r': + put('\n', out); + line [i] = '\0'; + return true; + case 127: + case '\b': + if (i > 0) { + put('\b', out); + put(' ', out); + put('\b', out); + --i; + } else { + put('\a', out); + } + break; + default: + if (!iscntrl( c)) { + if (i < size - 1) { + line [i] = (char) c; + ++i; + put( c, out); + } else { + put('\a', out); + } + } else { + put('\a', out); + } + break; + } + } + return true; +} + +bool rtems_shell_login_prompt( + FILE *in, + FILE *out, + const char *device, + rtems_shell_login_check_t check +) +{ + int fd_in = fileno(in); + struct termios termios_previous; + bool restore_termios = false; + int i = 0; + bool result = false; + + if (tcgetattr( fd_in, &termios_previous) == 0) { + struct termios termios_new = termios_previous; + + /* + * Stay in canonical mode so we can tell EOF and dropped connections. + * But read one character at a time and do not echo it. + */ + termios_new.c_lflag &= (unsigned char) ~ECHO; + termios_new.c_cc [VTIME] = 0; + termios_new.c_cc [VMIN] = 1; + + restore_termios = tcsetattr( fd_in, TCSANOW, &termios_new) == 0; + } + + for (i = 0; i < 3; ++i) { + char user [32]; + char passphrase [128]; + + fprintf( out, "%s login: ", device ); + fflush( out ); + result = rtems_shell_get_text( in, out, user, sizeof(user) ); + if ( !result ) + break; + + fflush( in); + fprintf( out, "Password: "); + fflush( out); + result = rtems_shell_get_text( in, NULL, passphrase, sizeof(passphrase) ); + if ( !result ) + break; + fputc( '\n', out); + + result = check( user, passphrase ); + if (result) + break; + + fprintf( out, "Login incorrect\n\n"); + sleep( 2); + } + + if (restore_termios) { + /* What to do if restoring the flags fails? */ + tcsetattr( fd_in, TCSANOW, &termios_previous); + } + + return result; +} diff --git a/cpukit/libmisc/shell/main_alias.c b/cpukit/libmisc/shell/main_alias.c new file mode 100644 index 0000000000..9f1b094eaa --- /dev/null +++ b/cpukit/libmisc/shell/main_alias.c @@ -0,0 +1,45 @@ +/* + * ALIAS Shell Command Implmentation + * + * Author: Fernando RUIZ CASAS + * Work: fernando.ruiz@ctv.es + * Home: correo@fernando-ruiz.com + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include "internal.h" + +int rtems_shell_rtems_main_alias(int argc, char **argv) +{ + if (argc<3) { + fprintf(stderr,"too few arguments\n"); + return 1; + } + + if (!rtems_shell_alias_cmd(argv[1],argv[2])) { + fprintf(stderr,"unable to make an alias(%s,%s)\n",argv[1],argv[2]); + } + return 0; +} + +rtems_shell_cmd_t rtems_shell_ALIAS_Command = { + "alias", /* name */ + "alias old new", /* usage */ + "misc", /* topic */ + rtems_shell_rtems_main_alias, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_blksync.c b/cpukit/libmisc/shell/main_blksync.c new file mode 100644 index 0000000000..bf8369570e --- /dev/null +++ b/cpukit/libmisc/shell/main_blksync.c @@ -0,0 +1,77 @@ +/* + * RM Shell Command Implmentation + * + * Author: Fernando RUIZ CASAS + * Work: fernando.ruiz@ctv.es + * Home: correo@fernando-ruiz.com + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include <rtems/bdbuf.h> +#include <rtems/blkdev.h> +#include "internal.h" + +int rtems_shell_main_blksync( + int argc, + char *argv[] +) +{ + const char* driver = NULL; + int arg; + int fd; + + for (arg = 1; arg < argc; arg++) { + if (argv[arg][0] == '-') { + fprintf( stderr, "%s: invalid option: %s\n", argv[0], argv[arg]); + return 1; + } else { + if (!driver) + driver = argv[arg]; + else { + fprintf( stderr, "%s: only one driver name allowed: %s\n", + argv[0], argv[arg]); + return 1; + } + } + } + + fd = open (driver, O_WRONLY, 0); + if (fd < 0) { + fprintf( stderr, "%s: driver open failed: %s\n", argv[0], strerror (errno)); + return 1; + } + + if (ioctl (fd, RTEMS_BLKIO_SYNCDEV) < 0) { + fprintf( stderr, "%s: driver sync failed: %s\n", argv[0], strerror (errno)); + return 1; + } + + close (fd); + return 0; +} + +rtems_shell_cmd_t rtems_shell_BLKSYNC_Command = { + "blksync", /* name */ + "blksync driver # sync the block driver", /* usage */ + "files", /* topic */ + rtems_shell_main_blksync, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_cat.c b/cpukit/libmisc/shell/main_cat.c new file mode 100644 index 0000000000..6efd7a09c8 --- /dev/null +++ b/cpukit/libmisc/shell/main_cat.c @@ -0,0 +1,60 @@ +/* + * CAT Shell Command Implmentation + * + * Author: Fernando RUIZ CASAS + * Work: fernando.ruiz@ctv.es + * Home: correo@fernando-ruiz.com + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <termios.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <dirent.h> +#include <time.h> +#include <fcntl.h> +#include <unistd.h> +#include <pwd.h> +#include <grp.h> +#include <errno.h> +#include <sys/types.h> +#include <stddef.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include "internal.h" + +int rtems_shell_main_cat(int argc, char *argv[]) +{ + int n; + int sc; + + for ( n=1; n < argc ; n++) { + sc = rtems_shell_cat_file(stdout, argv[n]); + if ( sc == -1 ) { + fprintf(stderr, "%s: %s: %s\n", argv[0], argv[n], strerror(errno)); + return -1; + } + } + return 0; +} + +rtems_shell_cmd_t rtems_shell_CAT_Command = { + "cat", /* name */ + "cat n1 [n2 [n3...]] # show the ascii contents", /* usage */ + "files", /* topic */ + rtems_shell_main_cat , /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_cd.c b/cpukit/libmisc/shell/main_cd.c new file mode 100644 index 0000000000..e3ed35fa63 --- /dev/null +++ b/cpukit/libmisc/shell/main_cd.c @@ -0,0 +1,26 @@ +/* + * CD Shell Command Implmentation + * + * Author: Fernando RUIZ CASAS + * Work: fernando.ruiz@ctv.es + * Home: correo@fernando-ruiz.com + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/shell.h> +#include "internal.h" + +rtems_shell_alias_t rtems_shell_CD_Alias = { + "chdir", /* command */ + "cd" /* alias */ +}; diff --git a/cpukit/libmisc/shell/main_chdir.c b/cpukit/libmisc/shell/main_chdir.c new file mode 100644 index 0000000000..2273f5c956 --- /dev/null +++ b/cpukit/libmisc/shell/main_chdir.c @@ -0,0 +1,54 @@ +/* + * CHDIR Shell Command Implmentation + * + * Author: Fernando RUIZ CASAS + * Work: fernando.ruiz@ctv.es + * Home: correo@fernando-ruiz.com + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include "internal.h" + +int rtems_shell_main_chdir( + int argc, + char *argv[] +) +{ + char *dir; + + dir = "/"; + + if (argc > 1) + dir = argv[1]; + + if (chdir(dir)) { + fprintf(stderr, "chdir to '%s' failed:%s\n", dir,strerror(errno)); + return errno; + } + return 0; +} + +rtems_shell_cmd_t rtems_shell_CHDIR_Command = { + "chdir", /* name */ + "chdir [dir] # change the current directory", /* usage */ + "files", /* topic */ + rtems_shell_main_chdir, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_chmod.c b/cpukit/libmisc/shell/main_chmod.c new file mode 100644 index 0000000000..3c6ae68310 --- /dev/null +++ b/cpukit/libmisc/shell/main_chmod.c @@ -0,0 +1,70 @@ +/* + * CHMOD Shell Command Implmentation + * + * Author: Fernando RUIZ CASAS + * Work: fernando.ruiz@ctv.es + * Home: correo@fernando-ruiz.com + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include <rtems/stringto.h> +#include "internal.h" + +int rtems_shell_main_chmod( + int argc, + char *argv[] +) +{ + int n; + mode_t mode; + unsigned long tmp; + + if (argc < 2) { + fprintf(stderr,"%s: too few arguments\n", argv[0]); + return -1; + } + + /* + * Convert arguments into numbers + */ + if ( rtems_string_to_unsigned_long(argv[1], &tmp, NULL, 0) ) { + printf( "Mode argument (%s) is not a number\n", argv[1] ); + return -1; + } + mode = (mode_t) (tmp & 0777); + + /* + * Now change the files modes + */ + for (n=2 ; n < argc ; n++) + chmod(argv[n++], mode); + + return 0; +} + +rtems_shell_cmd_t rtems_shell_CHMOD_Command = { + "chmod", /* name */ + "chmod 0777 n1 n2... # change filemode", /* usage */ + "files", /* topic */ + rtems_shell_main_chmod, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_chroot.c b/cpukit/libmisc/shell/main_chroot.c new file mode 100644 index 0000000000..ffdfb9ca3b --- /dev/null +++ b/cpukit/libmisc/shell/main_chroot.c @@ -0,0 +1,53 @@ +/* + * CHROOT Shell Command Implmentation + * + * Author: Fernando RUIZ CASAS + * Work: fernando.ruiz@ctv.es + * Home: correo@fernando-ruiz.com + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include "internal.h" + +int rtems_shell_main_chroot( + int argc, + char * argv[] +) +{ + char *new_root = "/"; + + if (argc == 2) + new_root = argv[1]; + + if ( chroot(new_root) < 0 ) { + fprintf(stderr,"chroot %s (%s)\n", new_root, strerror(errno)); + return -1; + } + + return 0; +} + +rtems_shell_cmd_t rtems_shell_CHROOT_Command = { + "chroot", /* name */ + "chroot [dir] # change the root directory", /* usage */ + "files", /* topic */ + rtems_shell_main_chroot, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_cp.c b/cpukit/libmisc/shell/main_cp.c new file mode 100644 index 0000000000..5b56235abd --- /dev/null +++ b/cpukit/libmisc/shell/main_cp.c @@ -0,0 +1,555 @@ +/* $NetBSD: cp.c,v 1.39 2005/10/24 12:59:07 kleink Exp $ */ + +/* + * Copyright (c) 1988, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * David Hitz of Auspex Systems Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if 0 +#ifndef lint +__COPYRIGHT( +"@(#) Copyright (c) 1988, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"); +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)cp.c 8.5 (Berkeley) 4/29/95"; +#else +__RCSID("$NetBSD: cp.c,v 1.39 2005/10/24 12:59:07 kleink Exp $"); +#endif +#endif /* not lint */ +#endif +/* + * Cp copies source files to target files. + * + * The global PATH_T structure "to" always contains the path to the + * current target file. Since fts(3) does not change directories, + * this path can be either absolute or dot-relative. + * + * The basic algorithm is to initialize "to" and use fts(3) to traverse + * the file hierarchy rooted in the argument list. A trivial case is the + * case of 'cp file1 file2'. The more interesting case is the case of + * 'cp file1 file2 ... fileN dir' where the hierarchy is traversed and the + * path (relative to the root of the traversal) is appended to dir (stored + * in "to") to form the final target path. + */ + +#include <rtems.h> +#include <rtems/shell.h> +#include <rtems/shellconfig.h> +#define __need_getopt_newlib +#include <getopt.h> + +#include <sys/param.h> +#include <sys/stat.h> + +#include <err.h> +#include <errno.h> +#include <fts.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "extern-cp.h" + +#define S_ISTXT 0 + +#define STRIP_TRAILING_SLASH(p) { \ + while ((p).p_end > (p).p_path + 1 && (p).p_end[-1] == '/') \ + *--(p).p_end = 0; \ +} + +enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE }; + +static int Rflag, rflag; + +static int main_cp(rtems_shell_cp_globals* cp_globals, int, char *[]); +static int copy(rtems_shell_cp_globals* cp_globals, char *[], enum op, int); +static int mastercmp(const FTSENT **, const FTSENT **); + +void +rtems_shell_cp_exit (rtems_shell_cp_globals* cp_global, int code __attribute__((unused))) +{ + longjmp (cp_global->exit_jmp, 1); +} + +int +rtems_shell_main_cp(int argc, char *argv[]) +{ + rtems_shell_cp_globals cp_globals; + memset (&cp_globals, 0, sizeof (cp_globals)); + Rflag = rflag = 0; + if (setjmp (cp_globals.exit_jmp) == 0) + return main_cp (&cp_globals, argc, argv); + return 1; +} + +int +main_cp(rtems_shell_cp_globals* cp_globals, int argc, char *argv[]) +{ + struct stat to_stat, tmp_stat; + enum op type; + int Hflag, Lflag, Pflag, ch, fts_options, r, have_trailing_slash; + char *target; + struct getopt_data getopt_reent; + + Hflag = Lflag = Pflag = 0; + memset(&getopt_reent, 0, sizeof(getopt_data)); + + while ((ch = getopt_r(argc, argv, "HLPRafilnprv", &getopt_reent)) != -1) + switch (ch) { + case 'H': + Hflag = 1; + Lflag = Pflag = 0; + break; + case 'L': + Lflag = 1; + Hflag = Pflag = 0; + break; + case 'P': + Pflag = 1; + Hflag = Lflag = 0; + break; + case 'R': + Rflag = 1; + break; + case 'a': + Pflag = 1; + pflag = 1; + Rflag = 1; + Hflag = Lflag = 0; + break; + case 'f': + fflag = 1; + iflag = nflag = 0; + break; + case 'i': + iflag = 1; + fflag = nflag = 0; + break; + case 'l': + lflag = 1; + break; + case 'n': + nflag = 1; + fflag = iflag = 0; + break; + case 'p': + pflag = 1; + break; + case 'r': + rflag = Lflag = 1; + Hflag = Pflag = 0; + break; + case 'v': + vflag = 1; + break; + default: + usage(cp_globals); + break; + } + argc -= getopt_reent.optind; + argv += getopt_reent.optind; + + if (argc < 2) + usage(cp_globals); + + fts_options = FTS_NOCHDIR | FTS_PHYSICAL; + if (Rflag && rflag) + errx(exit_jump, 1, "the -R and -r options may not be specified together"); + if (rflag) + Rflag = 1; + if (Rflag) { + if (Hflag) + fts_options |= FTS_COMFOLLOW; + if (Lflag) { + fts_options &= ~FTS_PHYSICAL; + fts_options |= FTS_LOGICAL; + } + } else { + fts_options &= ~FTS_PHYSICAL; + fts_options |= FTS_LOGICAL | FTS_COMFOLLOW; + } +#if 0 + (void)signal(SIGINFO, siginfo); +#endif + + /* Save the target base in "to". */ + target = argv[--argc]; + if (strlcpy(to.p_path, target, sizeof(to.p_path)) >= sizeof(to.p_path)) + errx(exit_jump, 1, "%s: name too long", target); + to.p_end = to.p_path + strlen(to.p_path); + if (to.p_path == to.p_end) { + *to.p_end++ = '.'; + *to.p_end = 0; + } + have_trailing_slash = (to.p_end[-1] == '/'); + if (have_trailing_slash) + STRIP_TRAILING_SLASH(to); + to.target_end = to.p_end; + + /* Set end of argument list for fts(3). */ + argv[argc] = NULL; + + /* + * Cp has two distinct cases: + * + * cp [-R] source target + * cp [-R] source1 ... sourceN directory + * + * In both cases, source can be either a file or a directory. + * + * In (1), the target becomes a copy of the source. That is, if the + * source is a file, the target will be a file, and likewise for + * directories. + * + * In (2), the real target is not directory, but "directory/source". + */ + r = stat(to.p_path, &to_stat); + if (r == -1 && errno != ENOENT) + err(exit_jump, 1, "%s", to.p_path); + if (r == -1 || !S_ISDIR(to_stat.st_mode)) { + /* + * Case (1). Target is not a directory. + */ + if (argc > 1) + errx(exit_jump, 1, "%s is not a directory", to.p_path); + + /* + * Need to detect the case: + * cp -R dir foo + * Where dir is a directory and foo does not exist, where + * we want pathname concatenations turned on but not for + * the initial mkdir(). + */ + if (r == -1) { + if (Rflag && (Lflag || Hflag)) + stat(*argv, &tmp_stat); + else + lstat(*argv, &tmp_stat); + + if (S_ISDIR(tmp_stat.st_mode) && Rflag) + type = DIR_TO_DNE; + else + type = FILE_TO_FILE; + } else + type = FILE_TO_FILE; + + if (have_trailing_slash && type == FILE_TO_FILE) { + if (r == -1) + errx(exit_jump, 1, "directory %s does not exist", + to.p_path); + else + errx(exit_jump, 1, "%s is not a directory", to.p_path); + } + } else + /* + * Case (2). Target is a directory. + */ + type = FILE_TO_DIR; + + return copy(cp_globals, argv, type, fts_options); +} + +int +copy(rtems_shell_cp_globals* cp_globals, + char *argv[], enum op type, int fts_options) +{ + struct stat to_stat; + FTS *ftsp; + FTSENT *curr; + int base = 0, dne, badcp, rval; + size_t nlen; + char *p, *target_mid; + mode_t mask, mode; + + /* + * Keep an inverted copy of the umask, for use in correcting + * permissions on created directories when not using -p. + */ + mask = ~umask(0777); + umask(~mask); + + if ((ftsp = fts_open(argv, fts_options, mastercmp)) == NULL) + err(exit_jump, 1, "fts_open"); + for (badcp = rval = 0; (curr = fts_read(ftsp)) != NULL; badcp = 0) { + switch (curr->fts_info) { + case FTS_NS: + case FTS_DNR: + case FTS_ERR: + warnx("%s: %s", + curr->fts_path, strerror(curr->fts_errno)); + badcp = rval = 1; + continue; + case FTS_DC: /* Warn, continue. */ + warnx("%s: directory causes a cycle", curr->fts_path); + badcp = rval = 1; + continue; + default: + ; + } + + /* + * If we are in case (2) or (3) above, we need to append the + * source name to the target name. + */ + if (type != FILE_TO_FILE) { + /* + * Need to remember the roots of traversals to create + * correct pathnames. If there's a directory being + * copied to a non-existent directory, e.g. + * cp -R a/dir noexist + * the resulting path name should be noexist/foo, not + * noexist/dir/foo (where foo is a file in dir), which + * is the case where the target exists. + * + * Also, check for "..". This is for correct path + * concatenation for paths ending in "..", e.g. + * cp -R .. /tmp + * Paths ending in ".." are changed to ".". This is + * tricky, but seems the easiest way to fix the problem. + * + * XXX + * Since the first level MUST be FTS_ROOTLEVEL, base + * is always initialized. + */ + if (curr->fts_level == FTS_ROOTLEVEL) { + if (type != DIR_TO_DNE) { + p = strrchr(curr->fts_path, '/'); + base = (p == NULL) ? 0 : + (int)(p - curr->fts_path + 1); + + if (!strcmp(&curr->fts_path[base], + "..")) + base += 1; + } else + base = curr->fts_pathlen; + } + + p = &curr->fts_path[base]; + nlen = curr->fts_pathlen - base; + target_mid = to.target_end; + if (*p != '/' && target_mid[-1] != '/') + *target_mid++ = '/'; + *target_mid = 0; + if (target_mid - to.p_path + nlen >= PATH_MAX) { + warnx("%s%s: name too long (not copied)", + to.p_path, p); + badcp = rval = 1; + continue; + } + (void)strncat(target_mid, p, nlen); + to.p_end = target_mid + nlen; + *to.p_end = 0; + STRIP_TRAILING_SLASH(to); + } + + if (curr->fts_info == FTS_DP) { + /* + * We are nearly finished with this directory. If we + * didn't actually copy it, or otherwise don't need to + * change its attributes, then we are done. + */ + if (!curr->fts_number) + continue; + /* + * If -p is in effect, set all the attributes. + * Otherwise, set the correct permissions, limited + * by the umask. Optimise by avoiding a chmod() + * if possible (which is usually the case if we + * made the directory). Note that mkdir() does not + * honour setuid, setgid and sticky bits, but we + * normally want to preserve them on directories. + */ + if (pflag) { + if (setfile(cp_globals, curr->fts_statp, -1)) + rval = 1; + if (preserve_dir_acls(curr->fts_statp, + curr->fts_accpath, to.p_path) != 0) + rval = 1; + } else { + mode = curr->fts_statp->st_mode; + if ((mode & (S_ISUID | S_ISGID | S_ISTXT)) || + ((mode | S_IRWXU) & mask) != (mode & mask)) + if (chmod(to.p_path, mode & mask) != 0){ + warn("chmod: %s", to.p_path); + rval = 1; + } + } + continue; + } + + /* Not an error but need to remember it happened */ + if (stat(to.p_path, &to_stat) == -1) + dne = 1; + else { + if (to_stat.st_dev == curr->fts_statp->st_dev && + to_stat.st_ino == curr->fts_statp->st_ino) { + warnx("%s and %s are identical (not copied).", + to.p_path, curr->fts_path); + badcp = rval = 1; + if (S_ISDIR(curr->fts_statp->st_mode)) + (void)fts_set(ftsp, curr, FTS_SKIP); + continue; + } + if (!S_ISDIR(curr->fts_statp->st_mode) && + S_ISDIR(to_stat.st_mode)) { + warnx("cannot overwrite directory %s with " + "non-directory %s", + to.p_path, curr->fts_path); + badcp = rval = 1; + continue; + } + dne = 0; + } + + switch (curr->fts_statp->st_mode & S_IFMT) { + case S_IFLNK: + /* Catch special case of a non-dangling symlink */ + if ((fts_options & FTS_LOGICAL) || + ((fts_options & FTS_COMFOLLOW) && + curr->fts_level == 0)) { + if (copy_file(cp_globals, curr, dne)) + badcp = rval = 1; + } else { + if (copy_link(cp_globals, curr, !dne)) + badcp = rval = 1; + } + break; + case S_IFDIR: + if (!Rflag) { + warnx("%s is a directory (not copied).", + curr->fts_path); + (void)fts_set(ftsp, curr, FTS_SKIP); + badcp = rval = 1; + break; + } + /* + * If the directory doesn't exist, create the new + * one with the from file mode plus owner RWX bits, + * modified by the umask. Trade-off between being + * able to write the directory (if from directory is + * 555) and not causing a permissions race. If the + * umask blocks owner writes, we fail.. + */ + if (dne) { + if (mkdir(to.p_path, + curr->fts_statp->st_mode | S_IRWXU) < 0) + err(exit_jump, 1, "%s", to.p_path); + } else if (!S_ISDIR(to_stat.st_mode)) { + errno = ENOTDIR; + err(exit_jump, 1, "%s", to.p_path); + } + /* + * Arrange to correct directory attributes later + * (in the post-order phase) if this is a new + * directory, or if the -p flag is in effect. + */ + curr->fts_number = pflag || dne; + break; + case S_IFBLK: + case S_IFCHR: + if (Rflag) { + if (copy_special(cp_globals, curr->fts_statp, !dne)) + badcp = rval = 1; + } else { + if (copy_file(cp_globals, curr, dne)) + badcp = rval = 1; + } + break; + case S_IFSOCK: + warnx("%s is a socket (not copied).", + curr->fts_path); + case S_IFIFO: + if (Rflag) { + if (copy_fifo(cp_globals, curr->fts_statp, !dne)) + badcp = rval = 1; + } else { + if (copy_file(cp_globals, curr, dne)) + badcp = rval = 1; + } + break; + default: + if (copy_file(cp_globals, curr, dne)) + badcp = rval = 1; + break; + } + if (vflag && !badcp) + (void)printf("%s -> %s\n", curr->fts_path, to.p_path); + } + if (errno) + err(exit_jump, 1, "fts_read"); + fts_close(ftsp); + return (rval); +} + +/* + * mastercmp -- + * The comparison function for the copy order. The order is to copy + * non-directory files before directory files. The reason for this + * is because files tend to be in the same cylinder group as their + * parent directory, whereas directories tend not to be. Copying the + * files first reduces seeking. + */ +int +mastercmp(const FTSENT **a, const FTSENT **b) +{ + int a_info, b_info; + + a_info = (*a)->fts_info; + if (a_info == FTS_ERR || a_info == FTS_NS || a_info == FTS_DNR) + return (0); + b_info = (*b)->fts_info; + if (b_info == FTS_ERR || b_info == FTS_NS || b_info == FTS_DNR) + return (0); + if (a_info == FTS_D) + return (-1); + if (b_info == FTS_D) + return (1); + return (0); +} + +rtems_shell_cmd_t rtems_shell_CP_Command = { + "cp", /* name */ + "cp [-R [-H | -L | -P]] [-f | -i] [-pv] src target", /* usage */ + "files", /* topic */ + rtems_shell_main_cp, /* command */ + NULL, /* alias */ + NULL /* next */ +}; + diff --git a/cpukit/libmisc/shell/main_cpuuse.c b/cpukit/libmisc/shell/main_cpuuse.c new file mode 100644 index 0000000000..b2329934bd --- /dev/null +++ b/cpukit/libmisc/shell/main_cpuuse.c @@ -0,0 +1,61 @@ +/* + * CPUUSE Command Implementation + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> + +#include <rtems.h> +#include <rtems/cpuuse.h> +#include <rtems/shell.h> +#include "internal.h" + +int rtems_shell_main_cpuuse( + int argc, + char *argv[] +) +{ + /* + * When invoked with no arguments, print the report. + */ + if ( argc == 1 ) { + rtems_cpu_usage_report_with_plugin(stdout, (rtems_printk_plugin_t)fprintf); + return 0; + } + + /* + * When invoked with the single argument -r, reset the statistics. + */ + if ( argc == 2 && !strcmp( argv[1], "-r" ) ) { + printf( "Resetting CPU Usage information\n" ); + rtems_cpu_usage_reset(); + return 0; + } + + /* + * OK. The user did something wrong. + */ + fprintf( stderr, "%s: [-r]\n", argv[0] ); + return -1; +} + +rtems_shell_cmd_t rtems_shell_CPUUSE_Command = { + "cpuuse", /* name */ + "[-r] print or reset per thread cpu usage", /* usage */ + "rtems", /* topic */ + rtems_shell_main_cpuuse, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_date.c b/cpukit/libmisc/shell/main_date.c new file mode 100644 index 0000000000..da6faa0e53 --- /dev/null +++ b/cpukit/libmisc/shell/main_date.c @@ -0,0 +1,80 @@ +/* + * DATE Shell Command Implmentation + * + * OAuthor: Fernando RUIZ CASAS + * Work: fernando.ruiz@ctv.es + * Home: correo@fernando-ruiz.com + * + * Significantly rewritten by Joel Sherrill <joel.sherrill@oarcorp.com>. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include "internal.h" + +int rtems_shell_main_date( + int argc, + char *argv[] +) +{ + /* + * Print the current date and time in default format. + */ + if ( argc == 1 ) { + time_t t; + + time(&t); + printf("%s", ctime(&t)); + return 0; + } + + /* + * Set the current date and time + */ + if ( argc == 3 ) { + char buf[128]; + struct tm TOD; + struct timespec timesp; + char *result; + + snprintf( buf, sizeof(buf), "%s %s", argv[1], argv[2] ); + result = strptime( + buf, + "%Y-%m-%d %T", + &TOD + ); + if ( result && !*result ) { + timesp.tv_sec = mktime( &TOD ); + timesp.tv_nsec = 0; + clock_settime( CLOCK_REALTIME, ×p ); + return 0; + } + } + + fprintf( stderr, "%s: Usage: [YYYY-MM-DD HH:MM:SS]\n", argv[0] ); + return -1; +} + +rtems_shell_cmd_t rtems_shell_DATE_Command = { + "date", /* name */ + "date [YYYY-MM-DD HH:MM:SS]", /* usage */ + "misc", /* topic */ + rtems_shell_main_date, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_dd.c b/cpukit/libmisc/shell/main_dd.c new file mode 100644 index 0000000000..930d382a97 --- /dev/null +++ b/cpukit/libmisc/shell/main_dd.c @@ -0,0 +1,565 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego and Lance + * Visser of Convex Computer Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if 0 +#ifndef lint +static char const copyright[] = +"@(#) Copyright (c) 1991, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)dd.c 8.5 (Berkeley) 4/2/94"; +#endif /* not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/bin/dd/dd.c,v 1.43 2004/08/15 19:10:05 rwatson Exp $"); +#endif + +#include <rtems.h> +#include <rtems/shell.h> +#include <rtems/shellconfig.h> + +#include <sys/param.h> +#include <sys/stat.h> +#if RTEMS_REMOVED +#include <sys/conf.h> +#include <sys/disklabel.h> +#endif +#include <sys/filio.h> +#include <sys/time.h> + +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <inttypes.h> +#include <locale.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "dd.h" +#include "extern-dd.h" + +#define DD_DEFFILEMODE 0 + +static void dd_close(rtems_shell_dd_globals* globals); +static void dd_in(rtems_shell_dd_globals* globals); +static void getfdtype(rtems_shell_dd_globals* globals, IO *); +static void setup(rtems_shell_dd_globals* globals); + +#if RTEMS_REMOVED +IO in, out; /* input/output state */ +STAT st; /* statistics */ +void (*cfunc)(void); /* conversion function */ +uintmax_t cpy_cnt; /* # of blocks to copy */ +static off_t pending = 0; /* pending seek if sparse */ +u_int ddflags = 0; /* conversion options */ +size_t cbsz; /* conversion block size */ +uintmax_t files_cnt = 1; /* # of files to copy */ +const u_char *ctab; /* conversion table */ +char fill_char; /* Character to fill with if defined */ +#endif + +static off_t pending = 0; /* pending seek if sparse */ + +void +rtems_shell_dd_exit (rtems_shell_dd_globals* globals, int code) +{ + globals->exit_code = code; + longjmp (globals->exit_jmp, 1); +} + +static int main_dd(rtems_shell_dd_globals* globals, int argc, char *argv[]); + +int +rtems_shell_main_dd(int argc, char *argv[]) +{ + rtems_shell_dd_globals dd_globals; + rtems_shell_dd_globals* globals = &dd_globals; + memset (globals, 0, sizeof (dd_globals)); + pending = 0; + ddflags = 0; + files_cnt = 1; + dd_globals.exit_code = 1; + if (setjmp (dd_globals.exit_jmp) == 0) + dd_globals.exit_code = main_dd (globals, argc, argv); + if (in.fd) + close(in.fd); + if (out.fd) + close(out.fd); + if (in.name) + free((void*)in.name); + if (out.name) + free((void*)out.name); + if (in.db) + free(in.db); + if (out.db && (in.db != out.db)) + free(out.db); + return dd_globals.exit_code; +} + +int +main_dd(rtems_shell_dd_globals* globals, int argc __unused, char *argv[]) +{ + (void)setlocale(LC_CTYPE, ""); + jcl(globals, argv); + setup(globals); + +#if RTEMS_REMOVED + (void)signal(SIGINFO, summaryx); + (void)signal(SIGINT, terminate); + + atexit(summary); +#endif + + while (files_cnt--) + dd_in(globals); + + dd_close(globals); + exit(0); + /* NOTREACHED */ + return 0; +} + +static int +parity(u_char c) +{ + int i; + + i = c ^ (c >> 1) ^ (c >> 2) ^ (c >> 3) ^ + (c >> 4) ^ (c >> 5) ^ (c >> 6) ^ (c >> 7); + return (i & 1); +} + +static void +setup(rtems_shell_dd_globals* globals) +{ + u_int cnt; + struct timeval tv; + + if (in.name == NULL) { + in.name = "stdin"; + in.fd = STDIN_FILENO; + } else { + in.fd = open(in.name, O_RDONLY, 0); + if (in.fd == -1) + err(exit_jump, 1, "%s", in.name); + } + + getfdtype(globals, &in); + + if (files_cnt > 1 && !(in.flags & ISTAPE)) + errx(exit_jump, 1, "files is not supported for non-tape devices"); + + if (out.name == NULL) { + /* No way to check for read access here. */ + out.fd = STDOUT_FILENO; + out.name = "stdout"; + } else { +#define OFLAGS \ + (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC)) + out.fd = open(out.name, O_RDWR | OFLAGS, DD_DEFFILEMODE); + /* + * May not have read access, so try again with write only. + * Without read we may have a problem if output also does + * not support seeks. + */ + if (out.fd == -1) { + out.fd = open(out.name, O_WRONLY | OFLAGS, DD_DEFFILEMODE); + out.flags |= NOREAD; + } + if (out.fd == -1) + err(exit_jump, 1, "%s", out.name); + } + + getfdtype(globals, &out); + + /* + * Allocate space for the input and output buffers. If not doing + * record oriented I/O, only need a single buffer. + */ + if (!(ddflags & (C_BLOCK | C_UNBLOCK))) { + if ((in.db = malloc(out.dbsz + in.dbsz - 1)) == NULL) + err(exit_jump, 1, "input buffer"); + out.db = in.db; + } else if ((in.db = malloc(MAX(in.dbsz, cbsz) + cbsz)) == NULL || + (out.db = malloc(out.dbsz + cbsz)) == NULL) + err(exit_jump, 1, "output buffer"); + in.dbp = in.db; + out.dbp = out.db; + + /* Position the input/output streams. */ + if (in.offset) + pos_in(globals); + if (out.offset) + pos_out(globals); + + /* + * Truncate the output file. If it fails on a type of output file + * that it should _not_ fail on, error out. + */ + if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK) && + out.flags & ISTRUNC) + if (ftruncate(out.fd, out.offset * out.dbsz) == -1) + err(exit_jump, 1, "truncating %s", out.name); + + if (ddflags & (C_LCASE | C_UCASE | C_ASCII | C_EBCDIC | C_PARITY)) { + if (ctab != NULL) { + for (cnt = 0; cnt <= 0377; ++cnt) + casetab[cnt] = ctab[cnt]; + } else { + for (cnt = 0; cnt <= 0377; ++cnt) + casetab[cnt] = cnt; + } + if ((ddflags & C_PARITY) && !(ddflags & C_ASCII)) { + /* + * If the input is not EBCDIC, and we do parity + * processing, strip input parity. + */ + for (cnt = 200; cnt <= 0377; ++cnt) + casetab[cnt] = casetab[cnt & 0x7f]; + } + if (ddflags & C_LCASE) { + for (cnt = 0; cnt <= 0377; ++cnt) + casetab[cnt] = tolower(casetab[cnt]); + } else if (ddflags & C_UCASE) { + for (cnt = 0; cnt <= 0377; ++cnt) + casetab[cnt] = toupper(casetab[cnt]); + } + if ((ddflags & C_PARITY)) { + /* + * This should strictly speaking be a no-op, but I + * wonder what funny LANG settings could get us. + */ + for (cnt = 0; cnt <= 0377; ++cnt) + casetab[cnt] = casetab[cnt] & 0x7f; + } + if ((ddflags & C_PARSET)) { + for (cnt = 0; cnt <= 0377; ++cnt) + casetab[cnt] = casetab[cnt] | 0x80; + } + if ((ddflags & C_PAREVEN)) { + for (cnt = 0; cnt <= 0377; ++cnt) + if (parity(casetab[cnt])) + casetab[cnt] = casetab[cnt] | 0x80; + } + if ((ddflags & C_PARODD)) { + for (cnt = 0; cnt <= 0377; ++cnt) + if (!parity(casetab[cnt])) + casetab[cnt] = casetab[cnt] | 0x80; + } + + ctab = casetab; + } + + (void)gettimeofday(&tv, (struct timezone *)NULL); + st.start = tv.tv_sec + tv.tv_usec * 1e-6; +} + +static void +getfdtype(rtems_shell_dd_globals* globals, IO *io) +{ + struct stat sb; +#if RTEMS_REMOVED + int type; +#endif + + if (fstat(io->fd, &sb) == -1) + err(exit_jump, 1, "%s", io->name); + if (S_ISREG(sb.st_mode)) + io->flags |= ISTRUNC; +#if RTEMS_REMOVED + if (S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode)) { + if (ioctl(io->fd, FIODTYPE, &type) == -1) { + err(exit_jump, 1, "%s", io->name); + } else { + if (type & D_TAPE) + io->flags |= ISTAPE; + else if (type & (D_DISK | D_MEM)) + io->flags |= ISSEEK; + if (S_ISCHR(sb.st_mode) && (type & D_TAPE) == 0) + io->flags |= ISCHR; + } + return; + } +#else + io->flags |= ISSEEK; +#endif + errno = 0; + if (lseek(io->fd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE) + io->flags |= ISPIPE; + else + io->flags |= ISSEEK; +} + +static void +dd_in(rtems_shell_dd_globals* globals) +{ + ssize_t n; + + for (;;) { + switch (cpy_cnt) { + case -1: /* count=0 was specified */ + return; + case 0: + break; + default: + if (st.in_full + st.in_part >= (uintmax_t)cpy_cnt) + return; + break; + } + + /* + * Zero the buffer first if sync; if doing block operations, + * use spaces. + */ + if (ddflags & C_SYNC) { + if (ddflags & C_FILL) + memset(in.dbp, fill_char, in.dbsz); + else if (ddflags & (C_BLOCK | C_UNBLOCK)) + memset(in.dbp, ' ', in.dbsz); + else + memset(in.dbp, 0, in.dbsz); + } + + n = read(in.fd, in.dbp, in.dbsz); + if (n == 0) { + in.dbrcnt = 0; + return; + } + + /* Read error. */ + if (n == -1) { + /* + * If noerror not specified, die. POSIX requires that + * the warning message be followed by an I/O display. + */ + if (!(ddflags & C_NOERROR)) + err(exit_jump, 1, "%s", in.name); + warn("%s", in.name); + summary(globals); + + /* + * If it's a seekable file descriptor, seek past the + * error. If your OS doesn't do the right thing for + * raw disks this section should be modified to re-read + * in sector size chunks. + */ + if (in.flags & ISSEEK && + lseek(in.fd, (off_t)in.dbsz, SEEK_CUR)) + warn("%s", in.name); + + /* If sync not specified, omit block and continue. */ + if (!(ddflags & C_SYNC)) + continue; + + /* Read errors count as full blocks. */ + in.dbcnt += in.dbrcnt = in.dbsz; + ++st.in_full; + + /* Handle full input blocks. */ + } else if ((size_t)n == in.dbsz) { + in.dbcnt += in.dbrcnt = n; + ++st.in_full; + + /* Handle partial input blocks. */ + } else { + /* If sync, use the entire block. */ + if (ddflags & C_SYNC) + in.dbcnt += in.dbrcnt = in.dbsz; + else + in.dbcnt += in.dbrcnt = n; + ++st.in_part; + } + + /* + * POSIX states that if bs is set and no other conversions + * than noerror, notrunc or sync are specified, the block + * is output without buffering as it is read. + */ + if (ddflags & C_BS) { + out.dbcnt = in.dbcnt; + dd_out(globals, 1); + in.dbcnt = 0; + continue; + } + + if (ddflags & C_SWAB) { + if ((n = in.dbrcnt) & 1) { + ++st.swab; + --n; + } + swab(in.dbp, in.dbp, (size_t)n); + } + + in.dbp += in.dbrcnt; + (*cfunc)(globals); + } +} + +/* + * Clean up any remaining I/O and flush output. If necessary, the output file + * is truncated. + */ +static void +dd_close(rtems_shell_dd_globals* globals) +{ + if (cfunc == def) + def_close(globals); + else if (cfunc == block) + block_close(globals); + else if (cfunc == unblock) + unblock_close(globals); + if (ddflags & C_OSYNC && out.dbcnt && out.dbcnt < out.dbsz) { + if (ddflags & C_FILL) + memset(out.dbp, fill_char, out.dbsz - out.dbcnt); + else if (ddflags & (C_BLOCK | C_UNBLOCK)) + memset(out.dbp, ' ', out.dbsz - out.dbcnt); + else + memset(out.dbp, 0, out.dbsz - out.dbcnt); + out.dbcnt = out.dbsz; + } + if (out.dbcnt || pending) + dd_out(globals, 1); +} + +void +dd_out(rtems_shell_dd_globals* globals, int force) +{ + u_char *outp; + size_t cnt, i, n; + ssize_t nw; + static int warned; + int sparse; + + /* + * Write one or more blocks out. The common case is writing a full + * output block in a single write; increment the full block stats. + * Otherwise, we're into partial block writes. If a partial write, + * and it's a character device, just warn. If a tape device, quit. + * + * The partial writes represent two cases. 1: Where the input block + * was less than expected so the output block was less than expected. + * 2: Where the input block was the right size but we were forced to + * write the block in multiple chunks. The original versions of dd(1) + * never wrote a block in more than a single write, so the latter case + * never happened. + * + * One special case is if we're forced to do the write -- in that case + * we play games with the buffer size, and it's usually a partial write. + */ + outp = out.db; + for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) { + for (cnt = n;; cnt -= nw) { + sparse = 0; + if (ddflags & C_SPARSE) { + sparse = 1; /* Is buffer sparse? */ + for (i = 0; i < cnt; i++) + if (outp[i] != 0) { + sparse = 0; + break; + } + } + if (sparse && !force) { + pending += cnt; + nw = cnt; + } else { + if (pending != 0) { + if (force) + pending--; + if (lseek(out.fd, pending, SEEK_CUR) == + -1) + err(exit_jump, 2, "%s: seek error creating sparse file", + out.name); + if (force) + write(out.fd, outp, 1); + pending = 0; + } + if (cnt) + nw = write(out.fd, outp, cnt); + else + return; + } + + if (nw <= 0) { + if (nw == 0) + errx(exit_jump, 1, "%s: end of device", out.name); + if (errno != EINTR) + err(exit_jump, 1, "%s", out.name); + nw = 0; + } + outp += nw; + st.bytes += nw; + if ((size_t)nw == n) { + if (n != out.dbsz) + ++st.out_part; + else + ++st.out_full; + break; + } + ++st.out_part; + if ((size_t)nw == cnt) + break; + if (out.flags & ISTAPE) + errx(exit_jump, 1, "%s: short write on tape device", + out.name); + if (out.flags & ISCHR && !warned) { + warned = 1; + warnx("%s: short write on character device", + out.name); + } + } + if ((out.dbcnt -= n) < out.dbsz) + break; + } + + /* Reassemble the output block. */ + if (out.dbcnt) + (void)memmove(out.db, out.dbp - out.dbcnt, out.dbcnt); + out.dbp = out.db + out.dbcnt; +} + +rtems_shell_cmd_t rtems_shell_DD_Command = { + "dd", /* name */ + "dd [OPERAND]...", /* usage */ + "files", /* topic */ + rtems_shell_main_dd, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_debugrfs.c b/cpukit/libmisc/shell/main_debugrfs.c new file mode 100644 index 0000000000..5d4052d43a --- /dev/null +++ b/cpukit/libmisc/shell/main_debugrfs.c @@ -0,0 +1,35 @@ +/* + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include <rtems/stringto.h> +#include <rtems/shellconfig.h> +#include <rtems/rtems-rfs-shell.h> +#include <rtems/fsmount.h> +#include "internal.h" + +#define OPTIONS "[-h]" + +rtems_shell_cmd_t rtems_shell_DEBUGRFS_Command = { + "debugrfs", /* name */ + "debugrfs " OPTIONS, /* usage */ + "files", /* topic */ + rtems_shell_debugrfs, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_dir.c b/cpukit/libmisc/shell/main_dir.c new file mode 100644 index 0000000000..473ab13f80 --- /dev/null +++ b/cpukit/libmisc/shell/main_dir.c @@ -0,0 +1,26 @@ +/* + * DIR Shell Command Implmentation + * + * Author: Fernando RUIZ CASAS + * Work: fernando.ruiz@ctv.es + * Home: correo@fernando-ruiz.com + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/shell.h> +#include "internal.h" + +rtems_shell_alias_t rtems_shell_DIR_Alias = { + "ls", /* command */ + "dir" /* alias */ +}; diff --git a/cpukit/libmisc/shell/main_echo.c b/cpukit/libmisc/shell/main_echo.c new file mode 100644 index 0000000000..8f868a2f29 --- /dev/null +++ b/cpukit/libmisc/shell/main_echo.c @@ -0,0 +1,142 @@ +/* $NetBSD: echo.c,v 1.12 2005/02/06 04:43:43 perry Exp $ */ + +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Kenneth Almquist. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)echo.c 8.1 (Berkeley) 5/31/93 + */ + +/* + * Echo command. + * + * echo is steeped in tradition - several of them! + * netbsd has supported 'echo [-n | -e] args' in spite of -e not being + * documented anywhere. + * Posix requires that -n be supported, output from strings containing + * \ is implementation defined + * The Single Unix Spec requires that \ escapes be treated as if -e + * were set, but that -n not be treated as an option. + * (ksh supports 'echo [-eEn] args', but not -- so that it is actually + * impossible to actually output '-n') + * + * It is suggested that 'printf "%b" "string"' be used to get \ sequences + * expanded. printf is now a builtin of netbsd's sh and csh. + */ + +/* + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include "internal.h" + + + +int rtems_shell_main_echo( + int argc, + char *argv[] +) +{ + char **ap; + char *p; + char c; + int count; + int nflag = 0; + int eflag = 0; + + ap = argv; + if (argc) + ap++; + + if ((p = *ap) != NULL) { + if (!strcmp(p, "-n")) { + nflag = 1; + ap++; + } else if (!strcmp(p, "-e")) { + eflag = 1; + ap++; + } + } + + while ((p = *ap++) != NULL) { + while ((c = *p++) != '\0') { + if (c == '\\' && eflag) { + switch (*p++) { + case 'a': c = '\a'; break; /* bell */ + case 'b': c = '\b'; break; + case 'c': return 0; /* exit */ + case 'e': c = 033; break; /* escape */ + case 'f': c = '\f'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case 'v': c = '\v'; break; + case '\\': break; /* c = '\\' */ + case '0': + c = 0; + count = 3; + while (--count >= 0 && (unsigned)(*p - '0') < 8) + c = (c << 3) + (*p++ - '0'); + break; + default: + /* Output the '/' and char following */ + p--; + break; + } + } + putchar(c); + } + if (*ap) + putchar(' '); + } + if (! nflag) + putchar('\n'); + return 0; +} + +rtems_shell_cmd_t rtems_shell_ECHO_Command = { + "echo", /* name */ + "echo [args]", /* usage */ + "misc", /* topic */ + rtems_shell_main_echo, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_exit.c b/cpukit/libmisc/shell/main_exit.c new file mode 100644 index 0000000000..4d996cde10 --- /dev/null +++ b/cpukit/libmisc/shell/main_exit.c @@ -0,0 +1,26 @@ +/* + * exit Shell Command Implmentation + * + * Author: Fernando RUIZ CASAS + * Work: fernando.ruiz@ctv.es + * Home: correo@fernando-ruiz.com + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/shell.h> +#include "internal.h" + +rtems_shell_alias_t rtems_shell_EXIT_Alias = { + "logoff", /* command */ + "exit" /* alias */ +}; diff --git a/cpukit/libmisc/shell/main_getenv.c b/cpukit/libmisc/shell/main_getenv.c new file mode 100644 index 0000000000..4e4789b632 --- /dev/null +++ b/cpukit/libmisc/shell/main_getenv.c @@ -0,0 +1,49 @@ +/* + * Get an environment vairable. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include "internal.h" + +int rtems_shell_main_getenv(int argc, char *argv[]) +{ + char* string; + + if (argc != 2) + { + printf ("error: only argument is the variable name\n"); + return 1; + } + + string = getenv (argv[1]); + + if (!string) + { + printf ("error: %s not found\n", argv[1]); + return 1; + } + + printf ("%s\n", string); + + return 0; +} + +rtems_shell_cmd_t rtems_shell_GETENV_Command = { + "getenv", /* name */ + "getenv [var]", /* usage */ + "misc", /* topic */ + rtems_shell_main_getenv, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_halt.c b/cpukit/libmisc/shell/main_halt.c new file mode 100644 index 0000000000..f6f9f7e4fd --- /dev/null +++ b/cpukit/libmisc/shell/main_halt.c @@ -0,0 +1,40 @@ +/* + * Halt Command Implementation + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include "internal.h" + +int rtems_shell_main_halt( + int argc __attribute__((unused)), + char *argv[] __attribute__((unused)) +) +{ + exit(0); + return 0; +} + +rtems_shell_cmd_t rtems_shell_HALT_Command = { + "halt", /* name */ + "halt", /* usage */ + "rtems", /* topic */ + rtems_shell_main_halt, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_help.c b/cpukit/libmisc/shell/main_help.c new file mode 100644 index 0000000000..512eb60bbc --- /dev/null +++ b/cpukit/libmisc/shell/main_help.c @@ -0,0 +1,152 @@ +/* + * + * Shell Help Command + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <time.h> + +#include <rtems.h> +#include <rtems/error.h> +#include <rtems/system.h> +#include <rtems/shell.h> + +#include "internal.h" +#include <string.h> + +/* + * show the help for one command. + */ +int rtems_shell_help_cmd( + rtems_shell_cmd_t *shell_cmd +) +{ + const char * pc; + int col,line; + + printf("%-12.12s - ",shell_cmd->name); + col = 14; + line = 1; + if (shell_cmd->alias) { + printf("is an <alias> for command '%s'",shell_cmd->alias->name); + } else if (shell_cmd->usage) { + pc = shell_cmd->usage; + while (*pc) { + switch(*pc) { + case '\r': + break; + case '\n': + putchar('\n'); + col = 0; + break; + default: + putchar(*pc); + col++; + break; + } + pc++; + if (col>78) { /* What daring... 78?*/ + if (*pc) { + putchar('\n'); + col = 0; + } + } + if (!col && *pc) { + printf(" "); + col = 12;line++; + } + } + } + puts(""); + return line; +} + +/* + * show the help. The first command implemented. + * Can you see the header of routine? Known? + * The same with all the commands.... + */ +int rtems_shell_help( + int argc, + char * argv[] +) +{ + int col,line,arg; + rtems_shell_topic_t *topic; + rtems_shell_cmd_t * shell_cmd = rtems_shell_first_cmd; + + if (argc<2) { + printf("help: ('r' repeat last cmd - 'e' edit last cmd)\n" + " TOPIC? The topics are\n"); + topic = rtems_shell_first_topic; + col = 0; + while (topic) { + if (!col){ + col = printf(" %s",topic->topic); + } else { + if ((col+strlen(topic->topic)+2)>78){ + printf("\n"); + col = printf(" %s",topic->topic); + } else { + col+= printf(", %s",topic->topic); + } + } + topic = topic->next; + } + printf("\n"); + return 1; + } + line = 0; + for (arg = 1;arg<argc;arg++) { + if (line>16) { + printf("Press any key to continue...");getchar(); + printf("\n"); + line = 0; + } + topic = rtems_shell_lookup_topic(argv[arg]); + if (!topic){ + if ((shell_cmd = rtems_shell_lookup_cmd(argv[arg])) == NULL) { + printf("help: topic or cmd '%s' not found. Try <help> alone for a list\n", + argv[arg]); + line++; + } else { + line+= rtems_shell_help_cmd(shell_cmd); + } + continue; + } + printf("help: list for the topic '%s'\n",argv[arg]); + line++; + while (shell_cmd) { + if (!strcmp(topic->topic,shell_cmd->topic)) + line+= rtems_shell_help_cmd(shell_cmd); + if (line>16) { + printf("Press any key to continue..."); + getchar(); + printf("\n"); + line = 0; + } + shell_cmd = shell_cmd->next; + } + } + puts(""); + return 0; +} + +rtems_shell_cmd_t rtems_shell_HELP_Command = { + "help", /* name */ + "help [topic] # list of usage of commands", /* usage */ + "help", /* topic */ + rtems_shell_help, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_hexdump.c b/cpukit/libmisc/shell/main_hexdump.c new file mode 100644 index 0000000000..8eb5a4e409 --- /dev/null +++ b/cpukit/libmisc/shell/main_hexdump.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)hexdump.c 8.1 (Berkeley) 6/6/93"; +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/usr.bin/hexdump/hexdump.c,v 1.7 2002/09/04 23:29:01 dwmalone Exp $"); +#endif +#endif /* not lint */ + +#include <rtems.h> +#include <rtems/shell.h> +#include <rtems/shellconfig.h> + +#include <sys/types.h> +#include <locale.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#define rindex(s,c) strrchr(s,c) + +#include "hexdump.h" + +#if RTEMS_REMOVED +FS *fshead; /* head of format strings */ +int blocksize; /* data block size */ +int exitval; /* final exit value */ +int length = -1; /* max bytes to read */ +#endif + +void +rtems_shell_hexdump_exit (rtems_shell_hexdump_globals* globals, int code) +{ + globals->exit_code = code; + longjmp (globals->exit_jmp, 1); +} + +static int main_hexdump(rtems_shell_hexdump_globals* globals, int argc, char *argv[]); + +int +rtems_shell_main_hexdump(int argc, char *argv[]) +{ + rtems_shell_hexdump_globals hexdump_globals; + rtems_shell_hexdump_globals* globals = &hexdump_globals; + memset (globals, 0, sizeof (hexdump_globals)); + vflag = FIRST; + ateof = 1; + hexdump_globals.exit_code = 1; + if (setjmp (hexdump_globals.exit_jmp) == 0) + hexdump_globals.exit_code = main_hexdump (globals, argc, argv); + if (curp) + free (curp); + if (savp) + free (savp); + while (fshead) + { + FS* nextfs = fshead->nextfs; + while (fshead->nextfu) + { + FU* nextfu = fshead->nextfu->nextfu; + if (fshead->nextfu->fmt) + free(fshead->nextfu->fmt); + while (fshead->nextfu->nextpr) + { + PR* nextpr = fshead->nextfu->nextpr->nextpr; + if (((fshead->nextfu->nextpr->flags & F_TEXT) == 0) && + fshead->nextfu->nextpr->fmt) + free(fshead->nextfu->nextpr->fmt); + free(fshead->nextfu->nextpr); + fshead->nextfu->nextpr = nextpr; + } + free(fshead->nextfu); + fshead->nextfu = nextfu; + } + free(fshead); + fshead = nextfs; + } + if (hdstdin) + { + fclose (hdstdin); + free (hdstdin); + } + return hexdump_globals.exit_code; +} + +int +main_hexdump(rtems_shell_hexdump_globals* globals, int argc, char *argv[]) +{ + FS *tfs; + char *p; + +#if RTEMS_REMOVED + (void)setlocale(LC_ALL, ""); +#endif + + if (!(p = rindex(argv[0], 'o')) || strcmp(p, "od")) + newsyntax(globals, argc, &argv); + else + oldsyntax(globals, argc, &argv); + + /* figure out the data block size */ + for (blocksize = 0, tfs = fshead; tfs; tfs = tfs->nextfs) { + tfs->bcnt = size(globals, tfs); + if (blocksize < tfs->bcnt) + blocksize = tfs->bcnt; + } + /* rewrite the rules, do syntax checking */ + for (tfs = fshead; tfs; tfs = tfs->nextfs) + rewrite(globals, tfs); + + (void)next(globals, argv); + display(globals); + exit(exitval); + return exitval; +} + +rtems_shell_cmd_t rtems_shell_HEXDUMP_Command = { + "hexdump", /* name */ + "hexdump [-bcCdovx] [-e fmt] [-f fmt_file] [-n length]\n" /* usage */ + " [-s skip] [file ...]", + "files", /* topic */ + rtems_shell_main_hexdump, /* command */ + NULL, /* alias */ + NULL /* next */ +}; + diff --git a/cpukit/libmisc/shell/main_id.c b/cpukit/libmisc/shell/main_id.c new file mode 100644 index 0000000000..8fa0914597 --- /dev/null +++ b/cpukit/libmisc/shell/main_id.c @@ -0,0 +1,67 @@ +/* + * ID Command Implementation + * + * Author: Fernando RUIZ CASAS + * Work: fernando.ruiz@ctv.es + * Home: correo@fernando-ruiz.com + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <pwd.h> +#include <grp.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include "internal.h" + +int rtems_shell_main_id( + int argc __attribute__((unused)), + char *argv[] __attribute__((unused)) +) +{ + struct passwd *pwd; + struct group *grp; + + pwd = getpwuid(getuid()); + grp = getgrgid(getgid()); + printf( + "uid=%d(%s),gid=%d(%s),", + getuid(), + (pwd) ? pwd->pw_name : "", + getgid(), + (grp) ? grp->gr_name : "" + ); + pwd = getpwuid(geteuid()); + grp = getgrgid(getegid()); + printf( + "euid=%d(%s),egid=%d(%s)\n", + geteuid(), + (pwd) ? pwd->pw_name : "", + getegid(), + (grp) ? grp->gr_name : "" + ); + return 0; +} + +rtems_shell_cmd_t rtems_shell_ID_Command = { + "id", /* name */ + "show uid, gid, euid, and egid", /* usage */ + "misc", /* topic */ + rtems_shell_main_id, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_ifconfig.c b/cpukit/libmisc/shell/main_ifconfig.c new file mode 100644 index 0000000000..9f16207b10 --- /dev/null +++ b/cpukit/libmisc/shell/main_ifconfig.c @@ -0,0 +1,243 @@ +/* + * IFCONFIG Command Implmentation + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> + +#include <netinet/in.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <net/if.h> + + +#include <rtems.h> +#include <rtems/rtems_bsdnet.h> +#include <rtems/shell.h> +#include "internal.h" + +int rtems_shell_main_ifconfig( + int argc, + char *argv[] +) +{ + struct sockaddr_in ipaddr; + struct sockaddr_in dstaddr; + struct sockaddr_in netmask; + struct sockaddr_in broadcast; + char *iface; + int f_ip = 0; + int f_ptp = 0; + int f_netmask = 0; + int f_up = 0; + int f_down = 0; + int f_bcast = 0; + int cur_idx; + int rc; + int flags; + + memset(&ipaddr, 0, sizeof(ipaddr)); + memset(&dstaddr, 0, sizeof(dstaddr)); + memset(&netmask, 0, sizeof(netmask)); + memset(&broadcast, 0, sizeof(broadcast)); + + ipaddr.sin_len = sizeof(ipaddr); + ipaddr.sin_family = AF_INET; + + dstaddr.sin_len = sizeof(dstaddr); + dstaddr.sin_family = AF_INET; + + netmask.sin_len = sizeof(netmask); + netmask.sin_family = AF_INET; + + broadcast.sin_len = sizeof(broadcast); + broadcast.sin_family = AF_INET; + + cur_idx = 0; + if (argc <= 1) { + /* display all interfaces */ + iface = NULL; + cur_idx += 1; + } else { + iface = argv[1]; + if (isdigit((unsigned char)*argv[2])) { + if (inet_pton(AF_INET, argv[2], &ipaddr.sin_addr) < 0) { + printf("bad ip address: %s\n", argv[2]); + return 0; + } + f_ip = 1; + cur_idx += 3; + } else { + cur_idx += 2; + } + } + + if ((f_down !=0) && (f_ip != 0)) { + f_up = 1; + } + + while(argc > cur_idx) { + if (strcmp(argv[cur_idx], "up") == 0) { + f_up = 1; + if (f_down != 0) { + printf("Can't make interface up and down\n"); + } + } else if(strcmp(argv[cur_idx], "down") == 0) { + f_down = 1; + if (f_up != 0) { + printf("Can't make interface up and down\n"); + } + } else if(strcmp(argv[cur_idx], "netmask") == 0) { + if ((cur_idx + 1) >= argc) { + printf("No netmask address\n"); + return -1; + } + if (inet_pton(AF_INET, argv[cur_idx+1], &netmask.sin_addr) < 0) { + printf("bad netmask: %s\n", argv[cur_idx]); + return -1; + } + f_netmask = 1; + cur_idx += 1; + } else if(strcmp(argv[cur_idx], "broadcast") == 0) { + if ((cur_idx + 1) >= argc) { + printf("No broadcast address\n"); + return -1; + } + if (inet_pton(AF_INET, argv[cur_idx+1], &broadcast.sin_addr) < 0) { + printf("bad broadcast: %s\n", argv[cur_idx]); + return -1; + } + f_bcast = 1; + cur_idx += 1; + } else if(strcmp(argv[cur_idx], "pointopoint") == 0) { + if ((cur_idx + 1) >= argc) { + printf("No pointopoint address\n"); + return -1; + } + if (inet_pton(AF_INET, argv[cur_idx+1], &dstaddr.sin_addr) < 0) { + printf("bad pointopoint: %s\n", argv[cur_idx]); + return -1; + } + f_ptp = 1; + cur_idx += 1; + } else { + printf("Bad parameter: %s\n", argv[cur_idx]); + return -1; + } + cur_idx += 1; + } + + printf("ifconfig "); + if (iface != NULL) { + printf("%s ", iface); + if (f_ip != 0) { + char str[256]; + inet_ntop(AF_INET, &ipaddr.sin_addr, str, 256); + printf("%s ", str); + } + + if (f_netmask != 0) { + char str[256]; + inet_ntop(AF_INET, &netmask.sin_addr, str, 256); + printf("netmask %s ", str); + } + + if (f_bcast != 0) { + char str[256]; + inet_ntop(AF_INET, &broadcast.sin_addr, str, 256); + printf("broadcast %s ", str); + } + + if (f_ptp != 0) { + char str[256]; + inet_ntop(AF_INET, &dstaddr.sin_addr, str, 256); + printf("pointopoint %s ", str); + } + + if (f_up != 0) { + printf("up\n"); + } else if (f_down != 0) { + printf("down\n"); + } else { + printf("\n"); + } + } + + if ((iface == NULL) || ((f_ip == 0) && (f_down == 0) && (f_up == 0))) { + rtems_bsdnet_show_if_stats(); + return 0; + } + + flags = 0; + if (f_netmask) { + rc = rtems_bsdnet_ifconfig(iface, SIOCSIFNETMASK, &netmask); + if (rc < 0) { + printf("Could not set netmask: %s\n", strerror(errno)); + return -1; + } + } + + if (f_bcast) { + rc = rtems_bsdnet_ifconfig(iface, SIOCSIFBRDADDR, &broadcast); + if (rc < 0) { + printf("Could not set broadcast: %s\n", strerror(errno)); + return -1; + } + } + + if (f_ptp) { + rc = rtems_bsdnet_ifconfig(iface, SIOCSIFDSTADDR, &dstaddr); + if (rc < 0) { + printf("Could not set destination address: %s\n", strerror(errno)); + return -1; + } + flags |= IFF_POINTOPOINT; + } + + /* This must come _after_ setting the netmask, broadcast addresses */ + if (f_ip) { + rc = rtems_bsdnet_ifconfig(iface, SIOCSIFADDR, &ipaddr); + if (rc < 0) { + printf("Could not set IP address: %s\n", strerror(errno)); + return -1; + } + } + + if (f_up != 0) { + flags |= IFF_UP; + } + + if (f_down != 0) { + printf("Warning: taking interfaces down is not supported\n"); + } + + rc = rtems_bsdnet_ifconfig(iface, SIOCSIFFLAGS, &flags); + if (rc < 0) { + printf("Could not set interface flags: %s\n", strerror(errno)); + return -1; + } + + return 0; +} + +rtems_shell_cmd_t rtems_shell_IFCONFIG_Command = { + "ifconfig", /* name */ + "TBD", /* usage */ + "network", /* topic */ + rtems_shell_main_ifconfig, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_ln.c b/cpukit/libmisc/shell/main_ln.c new file mode 100644 index 0000000000..aff1ffbf91 --- /dev/null +++ b/cpukit/libmisc/shell/main_ln.c @@ -0,0 +1,309 @@ +/* $NetBSD: ln.c,v 1.34 2008/07/20 00:52:40 lukem Exp $ */ + +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if 0 +#ifndef lint +__COPYRIGHT("@(#) Copyright (c) 1987, 1993, 1994\ + The Regents of the University of California. All rights reserved."); +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)ln.c 8.2 (Berkeley) 3/31/94"; +#else +__RCSID("$NetBSD: ln.c,v 1.34 2008/07/20 00:52:40 lukem Exp $"); +#endif +#endif /* not lint */ +#endif + +#include <rtems.h> +#include <rtems/shell.h> +#include <rtems/shellconfig.h> +#define __need_getopt_newlib +#include <getopt.h> + +#include <sys/cdefs.h> +#include <sys/param.h> +#include <sys/stat.h> + +#include <err.h> +#include <errno.h> +#include <locale.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <setjmp.h> + +typedef struct { + int fflag; /* Unlink existing files. */ + int hflag; /* Check new name for symlink first. */ + int iflag; /* Interactive mode. */ + int sflag; /* Symbolic, not hard, link. */ + int vflag; /* Verbose output */ + char linkch; + + int exit_code; + jmp_buf exit_jmp; +} rtems_shell_ln_globals; + +#define fflag globals->fflag +#define hflag globals->hflag +#define iflag globals->iflag +#define sflag globals->sflag +#define vflag globals->vflag +#define linkch globals->linkch + +#define exit_jump &(globals->exit_jmp) + +#define exit(ec) rtems_shell_ln_exit(globals, ec) + +static int main_ln(rtems_shell_ln_globals* , int, char *[]); + +static void +rtems_shell_ln_exit (rtems_shell_ln_globals* globals, int code) +{ + globals->exit_code = code; + longjmp (globals->exit_jmp, 1); +} + +static int main_ln(rtems_shell_ln_globals* globals, int argc, char *argv[]); + +int +rtems_shell_main_ln(int argc, char *argv[]) +{ + rtems_shell_ln_globals ln_globals; + rtems_shell_ln_globals* globals = &ln_globals; + memset (globals, 0, sizeof (ln_globals)); + ln_globals.exit_code = 1; + if (setjmp (ln_globals.exit_jmp) == 0) + return main_ln (globals, argc, argv); + return ln_globals.exit_code; +} + +#if RTEMS_REMOVED +int fflag; /* Unlink existing files. */ +int hflag; /* Check new name for symlink first. */ +int iflag; /* Interactive mode. */ +int sflag; /* Symbolic, not hard, link. */ +int vflag; /* Verbose output */ + + /* System link call. */ +int (*linkf)(const char *, const char *); +char linkch; +#endif + +int (*linkf)(const char *, const char *); + +static int linkit(rtems_shell_ln_globals* , const char *, const char *, int); +static void usage(rtems_shell_ln_globals* ); + +static int +main_ln(rtems_shell_ln_globals* globals, int argc, char *argv[]) +{ + struct stat sb; + int ch, exitval; + char *sourcedir; + + struct getopt_data getopt_reent; + memset(&getopt_reent, 0, sizeof(getopt_data)); + +#if RTEMS_REMOVED + setprogname(argv[0]); + (void)setlocale(LC_ALL, ""); +#endif + + while ((ch = getopt_r(argc, argv, "fhinsv", &getopt_reent)) != -1) + switch (ch) { + case 'f': + fflag = 1; + iflag = 0; + break; + case 'h': + case 'n': + hflag = 1; + break; + case 'i': + iflag = 1; + fflag = 0; + break; + case 's': + sflag = 1; + break; + case 'v': + vflag = 1; + break; + case '?': + default: + usage(globals); + /* NOTREACHED */ + } + + argv += getopt_reent.optind; + argc -= getopt_reent.optind; + + if (sflag) { + linkf = symlink; + linkch = '-'; + } else { + linkf = link; + linkch = '='; + } + + switch(argc) { + case 0: + usage(globals); + /* NOTREACHED */ + case 1: /* ln target */ + exit(linkit(globals, argv[0], ".", 1)); + /* NOTREACHED */ + case 2: /* ln target source */ + exit(linkit(globals, argv[0], argv[1], 0)); + /* NOTREACHED */ + } + + /* ln target1 target2 directory */ + sourcedir = argv[argc - 1]; + if (hflag && lstat(sourcedir, &sb) == 0 && S_ISLNK(sb.st_mode)) { + /* we were asked not to follow symlinks, but found one at + the target--simulate "not a directory" error */ + errno = ENOTDIR; + err(exit_jump, EXIT_FAILURE, "%s", sourcedir); + /* NOTREACHED */ + } + if (stat(sourcedir, &sb)) { + err(exit_jump, EXIT_FAILURE, "%s", sourcedir); + /* NOTREACHED */ + } + if (!S_ISDIR(sb.st_mode)) { + usage(globals); + /* NOTREACHED */ + } + for (exitval = 0; *argv != sourcedir; ++argv) + exitval |= linkit(globals, *argv, sourcedir, 1); + exit(exitval); + /* NOTREACHED */ + return 0; +} + +int +linkit(rtems_shell_ln_globals* globals, const char *source, const char *target, int isdir) +{ + struct stat sb; + const char *p; + char path[MAXPATHLEN]; + int ch, exists, first; + + if (!sflag) { + /* If target doesn't exist, quit now. */ + if (stat(target, &sb)) { + warn("%s", target); + return (1); + } + } + + /* If the source is a directory (and not a symlink if hflag), + append the target's name. */ + if (isdir || + (!lstat(source, &sb) && S_ISDIR(sb.st_mode)) || + (!hflag && !stat(source, &sb) && S_ISDIR(sb.st_mode))) { + if ((p = strrchr(target, '/')) == NULL) + p = target; + else + ++p; + (void)snprintf(path, sizeof(path), "%s/%s", source, p); + source = path; + } + + exists = !lstat(source, &sb); + + /* + * If the file exists, then unlink it forcibly if -f was specified + * and interactively if -i was specified. + */ + if (fflag && exists) { + if (unlink(source)) { + warn("%s", source); + return (1); + } + } else if (iflag && exists) { + fflush(stdout); + (void)fprintf(stderr, "replace %s? ", source); + + first = ch = getchar(); + while (ch != '\n' && ch != EOF) + ch = getchar(); + if (first != 'y' && first != 'Y') { + (void)fprintf(stderr, "not replaced\n"); + return (1); + } + + if (unlink(source)) { + warn("%s", source); + return (1); + } + } + + /* Attempt the link. */ + if ((*linkf)(target, source)) { + warn("%s", source); + return (1); + } + if (vflag) + (void)printf("%s %c> %s\n", source, linkch, target); + + return (0); +} + +void +usage(rtems_shell_ln_globals* globals) +{ +#define getprogname() "ln" + (void)fprintf(stderr, + "usage:\t%s [-fhinsv] file1 file2\n\t%s [-fhinsv] file ... directory\n", + getprogname(), getprogname()); + exit(1); + /* NOTREACHED */ +} + +rtems_shell_cmd_t rtems_shell_LN_Command = { + "ln", /* name */ + "ln ln [-fhinsv] source_file [target_file]", /* usage */ + "files", /* topic */ + rtems_shell_main_ln, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_logoff.c b/cpukit/libmisc/shell/main_logoff.c new file mode 100644 index 0000000000..7258724f04 --- /dev/null +++ b/cpukit/libmisc/shell/main_logoff.c @@ -0,0 +1,44 @@ +/* + * LOGOFF Shell Command Implmentation + * + * Author: Fernando RUIZ CASAS + * Work: fernando.ruiz@ctv.es + * Home: correo@fernando-ruiz.com + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include "internal.h" + +int rtems_shell_main_logoff( + int argc __attribute__((unused)), + char *argv[] __attribute__((unused)) +) +{ + printf("logoff from the system..."); + + rtems_current_shell_env->exit_shell = true; + + return 0; +} + +rtems_shell_cmd_t rtems_shell_LOGOFF_Command = { + "logoff", /* name */ + "logoff from the system", /* usage */ + "misc", /* topic */ + rtems_shell_main_logoff, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_ls.c b/cpukit/libmisc/shell/main_ls.c new file mode 100644 index 0000000000..08072fb723 --- /dev/null +++ b/cpukit/libmisc/shell/main_ls.c @@ -0,0 +1,776 @@ +/* $NetBSD: ls.c,v 1.58 2005/10/26 02:24:22 jschauma Exp $ */ + +/* + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Michael Fischbein. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if 0 +#include <sys/cdefs.h> +#ifndef lint +__COPYRIGHT("@(#) Copyright (c) 1989, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"); +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)ls.c 8.7 (Berkeley) 8/5/94"; +#else +__RCSID("$NetBSD: ls.c,v 1.58 2005/10/26 02:24:22 jschauma Exp $"); +#endif +#endif /* not lint */ +#endif + +#include <rtems.h> +#include <rtems/shell.h> +#include <rtems/shellconfig.h> +#define __need_getopt_newlib +#include <getopt.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> + +#include <dirent.h> +#include <err.h> +#include <errno.h> +#include <fts.h> +#include <locale.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <termios.h> +#include <pwd.h> +#include <grp.h> + +#include "extern-ls.h" + +static void display(rtems_shell_ls_globals* globals, FTSENT *, FTSENT *); +static int mastercmp_listdir(const FTSENT **, const FTSENT **); +static int mastercmp_no_listdir(const FTSENT **, const FTSENT **); +static void traverse(rtems_shell_ls_globals* globals, int, char **, int); + +static void (*printfcn)(rtems_shell_ls_globals* globals, DISPLAY *); +static int (*sortfcn)(const FTSENT *, const FTSENT *); + +#define BY_NAME 0 +#define BY_SIZE 1 +#define BY_TIME 2 + +#if RTEMS_REMOVED +long blocksize; /* block size units */ +int termwidth = 80; /* default terminal width */ +int sortkey = BY_NAME; +int rval = EXIT_SUCCESS; /* exit value - set if error encountered */ + +/* flags */ +int f_accesstime; /* use time of last access */ +int f_column; /* columnated format */ +int f_columnacross; /* columnated format, sorted across */ +int f_flags; /* show flags associated with a file */ +int f_grouponly; /* long listing without owner */ +int f_humanize; /* humanize the size field */ +int f_inode; /* print inode */ +int f_listdir; /* list actual directory, not contents */ +int f_listdot; /* list files beginning with . */ +int f_longform; /* long listing format */ +int f_nonprint; /* show unprintables as ? */ +int f_nosort; /* don't sort output */ +int f_numericonly; /* don't convert uid/gid to name */ +int f_octal; /* print octal escapes for nongraphic characters */ +int f_octal_escape; /* like f_octal but use C escapes if possible */ +int f_recursive; /* ls subdirectories also */ +int f_reversesort; /* reverse whatever sort is used */ +int f_sectime; /* print the real time for all files */ +int f_singlecol; /* use single column output */ +int f_size; /* list size in short listing */ +int f_statustime; /* use time of last mode change */ +int f_stream; /* stream format */ +int f_type; /* add type character for non-regular files */ +int f_typedir; /* add type character for directories */ +int f_whiteout; /* show whiteout entries */ +#endif + +void +rtems_shell_ls_exit (rtems_shell_ls_globals* globals, int code) +{ + globals->exit_code = code; + longjmp (globals->exit_jmp, 1); +} + +static int main_ls(rtems_shell_ls_globals* globals, int argc, char *argv[]); + +int +rtems_shell_main_ls(int argc, char *argv[]) +{ + rtems_shell_ls_globals ls_globals; + rtems_shell_ls_globals* globals = &ls_globals; + memset (globals, 0, sizeof (ls_globals)); + termwidth = 80; + sortkey = BY_NAME; + rval = EXIT_SUCCESS; + ls_globals.exit_code = 1; + if (setjmp (ls_globals.exit_jmp) == 0) + return main_ls (globals, argc, argv); + return ls_globals.exit_code; +} + +int +main_ls(rtems_shell_ls_globals* globals, int argc, char *argv[]) +{ + static char dot[] = ".", *dotav[] = { dot, NULL }; + //struct winsize win; + int ch, fts_options; + int kflag = 0; + const char *p; + + struct getopt_data getopt_reent; + memset(&getopt_reent, 0, sizeof(getopt_data)); + +#if RTEMS_REMOVED + setprogname(argv[0]); +#endif + setlocale(LC_ALL, ""); + + /* Terminal defaults to -Cq, non-terminal defaults to -1. */ + if (isatty(STDOUT_FILENO)) { +#if RTEMS_REMOVED + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0 && + win.ws_col > 0) + termwidth = win.ws_col; + f_column = f_nonprint = 1; +#endif + } else + f_singlecol = 1; + + /* Root is -A automatically. */ + if (!getuid()) + f_listdot = 1; + + fts_options = FTS_PHYSICAL; + while ((ch = getopt_r(argc, argv, + "1ABCFLRSTWabcdfghiklmnopqrstuwx", &getopt_reent)) != -1) { + switch (ch) { + /* + * The -1, -C, -l, -m and -x options all override each other so + * shell aliasing works correctly. + */ + case '1': + f_singlecol = 1; + f_column = f_columnacross = f_longform = f_stream = 0; + break; + case 'C': + f_column = 1; + f_columnacross = f_longform = f_singlecol = f_stream = + 0; + break; + case 'g': + if (f_grouponly != -1) + f_grouponly = 1; + f_longform = 1; + f_column = f_columnacross = f_singlecol = f_stream = 0; + break; + case 'l': + f_longform = 1; + f_column = f_columnacross = f_singlecol = f_stream = 0; + /* Never let -g take precedence over -l. */ + f_grouponly = -1; + break; + case 'm': + f_stream = 1; + f_column = f_columnacross = f_longform = f_singlecol = + 0; + break; + case 'x': + f_columnacross = 1; + f_column = f_longform = f_singlecol = f_stream = 0; + break; + /* The -c and -u options override each other. */ + case 'c': + f_statustime = 1; + f_accesstime = 0; + break; + case 'u': + f_accesstime = 1; + f_statustime = 0; + break; + case 'F': + f_type = 1; + break; + case 'L': + fts_options &= ~FTS_PHYSICAL; + fts_options |= FTS_LOGICAL; + break; + case 'R': + f_recursive = 1; + break; + case 'a': + fts_options |= FTS_SEEDOT; + /* FALLTHROUGH */ + case 'A': + f_listdot = 1; + break; + /* The -B option turns off the -b, -q and -w options. */ + case 'B': + f_nonprint = 0; + f_octal = 1; + f_octal_escape = 0; + break; + /* The -b option turns off the -B, -q and -w options. */ + case 'b': + f_nonprint = 0; + f_octal = 0; + f_octal_escape = 1; + break; + /* The -d option turns off the -R option. */ + case 'd': + f_listdir = 1; + f_recursive = 0; + break; + case 'f': + f_nosort = 1; + break; + case 'i': + f_inode = 1; + break; + case 'k': + blocksize = 1024; + kflag = 1; + break; + /* The -h option forces all sizes to be measured in bytes. */ + case 'h': + f_humanize = 1; + break; + case 'n': + f_numericonly = 1; + break; + case 'o': + f_flags = 1; + break; + case 'p': + f_typedir = 1; + break; + /* The -q option turns off the -B, -b and -w options. */ + case 'q': + f_nonprint = 1; + f_octal = 0; + f_octal_escape = 0; + break; + case 'r': + f_reversesort = 1; + break; + case 'S': + sortkey = BY_SIZE; + break; + case 's': + f_size = 1; + break; + case 'T': + f_sectime = 1; + break; + case 't': + sortkey = BY_TIME; + break; + case 'W': + f_whiteout = 1; + break; + /* The -w option turns off the -B, -b and -q options. */ + case 'w': + f_nonprint = 0; + f_octal = 0; + f_octal_escape = 0; + break; + default: + case '?': + usage(globals); + } + } + argc -= getopt_reent.optind; + argv += getopt_reent.optind; + + if (f_column || f_columnacross || f_stream) { + if ((p = getenv("COLUMNS")) != NULL) + termwidth = atoi(p); + } + + /* + * If both -g and -l options, let -l take precedence. + */ + if (f_grouponly == -1) + f_grouponly = 0; + + /* + * If not -F, -i, -l, -p, -S, -s or -t options, don't require stat + * information. + */ + if (!f_inode && !f_longform && !f_size && !f_type && !f_typedir && + sortkey == BY_NAME) + fts_options |= FTS_NOSTAT; + + /* + * If not -F, -d or -l options, follow any symbolic links listed on + * the command line. + */ + if (!f_longform && !f_listdir && !f_type) + fts_options |= FTS_COMFOLLOW; + + /* + * If -W, show whiteout entries + */ +#ifdef FTS_WHITEOUT + if (f_whiteout) + fts_options |= FTS_WHITEOUT; +#endif + + /* If -l or -s, figure out block size. */ + if (f_inode || f_longform || f_size) { +#if RTEMS_REMOVED + if (!kflag) + (void)getbsize(NULL, &blocksize); +#else + /* Make equal to 1 so ls -l shows the actual blcok count */ + blocksize = 512; +#endif + blocksize /= 512; + } + + /* Select a sort function. */ + if (f_reversesort) { + switch (sortkey) { + case BY_NAME: + sortfcn = revnamecmp; + break; + case BY_SIZE: + sortfcn = revsizecmp; + break; + case BY_TIME: + if (f_accesstime) + sortfcn = revacccmp; + else if (f_statustime) + sortfcn = revstatcmp; + else /* Use modification time. */ + sortfcn = revmodcmp; + break; + } + } else { + switch (sortkey) { + case BY_NAME: + sortfcn = namecmp; + break; + case BY_SIZE: + sortfcn = sizecmp; + break; + case BY_TIME: + if (f_accesstime) + sortfcn = acccmp; + else if (f_statustime) + sortfcn = statcmp; + else /* Use modification time. */ + sortfcn = modcmp; + break; + } + } + + /* Select a print function. */ + if (f_singlecol) + printfcn = printscol; + else if (f_columnacross) + printfcn = printacol; + else if (f_longform) + printfcn = printlong; + else if (f_stream) + printfcn = printstream; + else + printfcn = printcol; + + if (argc) + traverse(globals, argc, argv, fts_options); + else + traverse(globals, 1, dotav, fts_options); + exit(rval); + /* NOTREACHED */ + return 0; +} + +#if RTEMS_REMOVED +static int output; /* If anything output. */ +#endif + +/* + * Traverse() walks the logical directory structure specified by the argv list + * in the order specified by the mastercmp() comparison function. During the + * traversal it passes linked lists of structures to display() which represent + * a superset (may be exact set) of the files to be displayed. + */ +static void +traverse(rtems_shell_ls_globals* globals, int argc, char *argv[], int options) +{ + FTS *ftsp; + FTSENT *p, *chp; + int ch_options; + + if ((ftsp = + fts_open(argv, options, + f_nosort ? NULL : f_listdir ? + mastercmp_listdir : mastercmp_no_listdir)) == NULL) + err(exit_jump, EXIT_FAILURE, NULL); + + display(globals, NULL, fts_children(ftsp, 0)); + if (f_listdir) + { + fts_close(ftsp); + return; + } + + /* + * If not recursing down this tree and don't need stat info, just get + * the names. + */ + ch_options = !f_recursive && options & FTS_NOSTAT ? FTS_NAMEONLY : 0; + + while ((p = fts_read(ftsp)) != NULL) + switch (p->fts_info) { + case FTS_DC: + warnx("%s: directory causes a cycle", p->fts_name); + break; + case FTS_DNR: + case FTS_ERR: + warnx("%s: %s", p->fts_name, strerror(p->fts_errno)); + rval = EXIT_FAILURE; + break; + case FTS_D: + if (p->fts_level != FTS_ROOTLEVEL && + p->fts_name[0] == '.' && !f_listdot) + break; + + /* + * If already output something, put out a newline as + * a separator. If multiple arguments, precede each + * directory with its name. + */ + if (output) + (void)printf("\n%s:\n", p->fts_path); + else if (argc > 1) { + (void)printf("%s:\n", p->fts_path); + output = 1; + } + + chp = fts_children(ftsp, ch_options); + display(globals, p, chp); + + if (!f_recursive && chp != NULL) + (void)fts_set(ftsp, p, FTS_SKIP); + break; + } + fts_close(ftsp); + if (errno) + err(exit_jump, EXIT_FAILURE, "fts_read"); +} + +/* + * Display() takes a linked list of FTSENT structures and passes the list + * along with any other necessary information to the print function. P + * points to the parent directory of the display list. + */ +static void +display(rtems_shell_ls_globals* globals, FTSENT *p, FTSENT *list) +{ + struct stat *sp; + DISPLAY d; + FTSENT *cur; + NAMES *np; + u_int64_t btotal, stotal, maxblock, maxsize; + int maxinode, maxnlink, maxmajor, maxminor; + int bcfile, entries, flen, glen, ulen, maxflags, maxgroup, maxlen; + int maxuser, needstats; + const char *user, *group; + char buf[21]; /* 64 bits == 20 digits, +1 for NUL */ + char nuser[12], ngroup[12]; + char *flags = NULL; + +#ifdef __GNUC__ + /* This outrageous construct just to shut up a GCC warning. */ + (void) &maxsize; +#endif + + /* + * If list is NULL there are two possibilities: that the parent + * directory p has no children, or that fts_children() returned an + * error. We ignore the error case since it will be replicated + * on the next call to fts_read() on the post-order visit to the + * directory p, and will be signalled in traverse(). + */ + if (list == NULL) + return; + + needstats = f_inode || f_longform || f_size; + flen = 0; + maxinode = maxnlink = 0; + bcfile = 0; + maxuser = maxgroup = maxflags = maxlen = 0; + btotal = stotal = maxblock = maxsize = 0; + maxmajor = maxminor = 0; + for (cur = list, entries = 0; cur; cur = cur->fts_link) { + uint64_t size; + if (cur->fts_info == FTS_ERR || cur->fts_info == FTS_NS) { + warnx("%s: %s", + cur->fts_name, strerror(cur->fts_errno)); + cur->fts_number = NO_PRINT; + rval = EXIT_FAILURE; + continue; + } + + /* + * P is NULL if list is the argv list, to which different rules + * apply. + */ + if (p == NULL) { + /* Directories will be displayed later. */ + if (cur->fts_info == FTS_D && !f_listdir) { + cur->fts_number = NO_PRINT; + continue; + } + } else { + /* Only display dot file if -a/-A set. */ + if (cur->fts_name[0] == '.' && !f_listdot) { + cur->fts_number = NO_PRINT; + continue; + } + } + if (cur->fts_namelen > maxlen) + maxlen = cur->fts_namelen; + if (needstats) { + sp = cur->fts_statp; + if (sp->st_size < 0) + size = sp->st_size * -1; + else + size = sp->st_size; + if (sp->st_blocks > maxblock) + maxblock = sp->st_blocks; + if (sp->st_ino > maxinode) + maxinode = sp->st_ino; + if (sp->st_nlink > maxnlink) + maxnlink = sp->st_nlink; + if (size > maxsize) + maxsize = size; + if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode)) { + bcfile = 1; + if (major(sp->st_rdev) > maxmajor) + maxmajor = major(sp->st_rdev); + if (minor(sp->st_rdev) > maxminor) + maxminor = minor(sp->st_rdev); + } + + btotal += sp->st_blocks; + stotal += size; + if (f_longform) { + if (f_numericonly || + (user = user_from_uid(sp->st_uid, 0)) == + NULL) { + (void)snprintf(nuser, sizeof(nuser), + "%u", sp->st_uid); + user = nuser; + } + if (f_numericonly || + (group = group_from_gid(sp->st_gid, 0)) == + NULL) { + (void)snprintf(ngroup, sizeof(ngroup), + "%u", sp->st_gid); + group = ngroup; + } + if ((ulen = strlen(user)) > maxuser) + maxuser = ulen; + if ((glen = strlen(group)) > maxgroup) + maxgroup = glen; +#if RTEMS_REMOVED + if (f_flags) { + flags = + flags_to_string(sp->st_flags, "-"); + if ((flen = strlen(flags)) > maxflags) + maxflags = flen; + } else +#endif + flen = 0; + + if ((np = malloc(sizeof(NAMES) + + ulen + glen + flen + 3)) == NULL) + err(exit_jump, EXIT_FAILURE, NULL); + + np->user = &np->data[0]; + (void)strcpy(np->user, user); + np->group = &np->data[ulen + 1]; + (void)strcpy(np->group, group); + + if (f_flags && flags) { + np->flags = &np->data[ulen + glen + 2]; + (void)strcpy(np->flags, flags); + } + cur->fts_pointer = np; + } + } + ++entries; + } + + if (!entries) + return; + + d.list = list; + d.entries = entries; + d.maxlen = maxlen; + if (needstats) { + d.btotal = btotal; + d.stotal = stotal; + if (f_humanize) { + d.s_block = 4; /* min buf length for humanize_number */ + } else { + (void)snprintf(buf, sizeof(buf), "%llu", + (long long)howmany(maxblock, blocksize)); + d.s_block = strlen(buf); + } + d.s_flags = maxflags; + d.s_group = maxgroup; + (void)snprintf(buf, sizeof(buf), "%u", maxinode); + d.s_inode = strlen(buf); + (void)snprintf(buf, sizeof(buf), "%u", maxnlink); + d.s_nlink = strlen(buf); + if (f_humanize) { + d.s_size = 4; /* min buf length for humanize_number */ + } else { + (void)snprintf(buf, sizeof(buf), "%llu", + (long long)maxsize); + d.s_size = strlen(buf); + } + d.s_user = maxuser; + if (bcfile) { + (void)snprintf(buf, sizeof(buf), "%u", maxmajor); + d.s_major = strlen(buf); + (void)snprintf(buf, sizeof(buf), "%u", maxminor); + d.s_minor = strlen(buf); + if (d.s_major + d.s_minor + 2 > d.s_size) + d.s_size = d.s_major + d.s_minor + 2; + else if (d.s_size - d.s_minor - 2 > d.s_major) + d.s_major = d.s_size - d.s_minor - 2; + } else { + d.s_major = 0; + d.s_minor = 0; + } + } + + printfcn(globals, &d); + output = 1; + + if (f_longform) + for (cur = list; cur; cur = cur->fts_link) + free(cur->fts_pointer); +} + +/* + * Ordering for mastercmp: + * If ordering the argv (fts_level = FTS_ROOTLEVEL) return non-directories + * as larger than directories. Within either group, use the sort function. + * All other levels use the sort function. Error entries remain unsorted. + */ +static int +mastercmp_no_listdir(const FTSENT **a, const FTSENT **b) +{ + int a_info, b_info; + int l_f_listdir = 0; + + a_info = (*a)->fts_info; + if (a_info == FTS_ERR) + return (0); + b_info = (*b)->fts_info; + if (b_info == FTS_ERR) + return (0); + + if (a_info == FTS_NS || b_info == FTS_NS) { + if (b_info != FTS_NS) + return (1); + else if (a_info != FTS_NS) + return (-1); + else + return (namecmp(*a, *b)); + } + + if (a_info != b_info && !l_f_listdir && + (*a)->fts_level == FTS_ROOTLEVEL) { + if (a_info == FTS_D) + return (1); + else if (b_info == FTS_D) + return (-1); + } + return (sortfcn(*a, *b)); +} + +static int +mastercmp_listdir(const FTSENT **a, const FTSENT **b) +{ + int a_info, b_info; + int l_f_listdir = 1; + + a_info = (*a)->fts_info; + if (a_info == FTS_ERR) + return (0); + b_info = (*b)->fts_info; + if (b_info == FTS_ERR) + return (0); + + if (a_info == FTS_NS || b_info == FTS_NS) { + if (b_info != FTS_NS) + return (1); + else if (a_info != FTS_NS) + return (-1); + else + return (namecmp(*a, *b)); + } + + if (a_info != b_info && !l_f_listdir && + (*a)->fts_level == FTS_ROOTLEVEL) { + if (a_info == FTS_D) + return (1); + else if (b_info == FTS_D) + return (-1); + } + return (sortfcn(*a, *b)); +} + +rtems_shell_cmd_t rtems_shell_LS_Command = { + "ls", /* name */ + "ls [dir] # list files in the directory", /* usage */ + "files", /* topic */ + rtems_shell_main_ls, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_mallocinfo.c b/cpukit/libmisc/shell/main_mallocinfo.c new file mode 100644 index 0000000000..12423c7a73 --- /dev/null +++ b/cpukit/libmisc/shell/main_mallocinfo.c @@ -0,0 +1,63 @@ +/* + * MALLOC_INFO Shell Command Implmentation + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <inttypes.h> + +#include <rtems.h> +#include <rtems/malloc.h> +#include <rtems/shell.h> +#include "internal.h" + +extern int malloc_info( region_information_block * ); +extern void rtems_shell_print_unified_work_area_message(void); + +int rtems_shell_main_malloc_info( + int argc, + char *argv[] +) +{ + if ( argc == 2 ) { + rtems_shell_print_unified_work_area_message(); + + if ( !strcmp( argv[1], "info" ) ) { + region_information_block info; + + malloc_info( &info ); + rtems_shell_print_heap_info( "free", &info.Free ); + rtems_shell_print_heap_info( "used", &info.Used ); + return 0; + } else if ( !strcmp( argv[1], "stats" ) ) { + malloc_report_statistics_with_plugin( + stdout, + (rtems_printk_plugin_t) fprintf + ); + return 0; + } + } + fprintf( stderr, "%s: [info|stats]\n", argv[0] ); + return -1; +} + +rtems_shell_cmd_t rtems_shell_MALLOC_INFO_Command = { + "malloc", /* name */ + "[info|stats]", /* usage */ + "mem", /* topic */ + rtems_shell_main_malloc_info, /* command */ + NULL, /* alias */ + NULL /* next */ +}; + diff --git a/cpukit/libmisc/shell/main_mdump.c b/cpukit/libmisc/shell/main_mdump.c new file mode 100644 index 0000000000..d196711363 --- /dev/null +++ b/cpukit/libmisc/shell/main_mdump.c @@ -0,0 +1,96 @@ +/* + * MDUMP Shell Command Implmentation + * + * Author: Fernando RUIZ CASAS + * Work: fernando.ruiz@ctv.es + * Home: correo@fernando-ruiz.com + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <ctype.h> +#include <stdio.h> +#include <inttypes.h> +#include <string.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include <rtems/stringto.h> +#include "internal.h" + +int rtems_shell_main_mdump( + int argc, + char *argv[] +) +{ + unsigned char n; + unsigned char m; + int max; + int res; + void *addr = NULL; + unsigned char *pb; + + if (argc > 1) { + if ( rtems_string_to_pointer(argv[1], &addr, NULL) ) { + printf( "Address argument (%s) is not a number\n", argv[1] ); + return -1; + } + + } + + if (argc > 2) { + if ( rtems_string_to_int(argv[1], &max, NULL, 0) ) { + printf( "Length argument (%s) is not a number\n", argv[1] ); + return -1; + } + if (max <= 0) { + max = 1; /* print 1 item if 0 or neg. */ + res = 0; + } else { + max--; + res = max & 0xf;/* num bytes in last row */ + max >>= 4; /* div by 16 */ + max++; /* num of rows to print */ + if (max > 20) { /* limit to 20 */ + max = 20; + res = 0xf; /* 16 bytes print in last row */ + } + } + } else { + max = 20; + res = 0xf; + } + + pb = addr; + for (m=0; m<max; m++) { + printf("%10p ", pb); + for (n=0;n<=(m==(max-1)?res:0xf);n++) + printf("%02X%c",pb[n],n==7?'-':' '); + for (;n<=0xf;n++) + printf(" %c",n==7?'-':' '); + for (n=0;n<=(m==(max-1)?res:0xf);n++) { + printf("%c", isprint(pb[n]) ? pb[n] : '.'); + } + printf("\n"); + pb += 16; + } + return 0; +} + +rtems_shell_cmd_t rtems_shell_MDUMP_Command = { + "mdump", /* name */ + "mdump [address [length]]", /* usage */ + "mem", /* topic */ + rtems_shell_main_mdump, /* command */ + NULL, /* alias */ + NULL /* next */ +}; + diff --git a/cpukit/libmisc/shell/main_medit.c b/cpukit/libmisc/shell/main_medit.c new file mode 100644 index 0000000000..7905fbe689 --- /dev/null +++ b/cpukit/libmisc/shell/main_medit.c @@ -0,0 +1,79 @@ +/* + * MEDIT Shell Command Implmentation + * + * Author: Fernando RUIZ CASAS + * Work: fernando.ruiz@ctv.es + * Home: correo@fernando-ruiz.com + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <ctype.h> +#include <stdio.h> +#include <string.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include <rtems/stringto.h> +#include "internal.h" + +extern int rtems_shell_main_mdump(int, char *); + +int rtems_shell_main_medit( + int argc, + char *argv[] +) +{ + unsigned char *pb; + void *tmpp; + int n; + int i; + + if ( argc < 3 ) { + fprintf(stderr,"%s: too few arguments\n", argv[0]); + return -1; + } + + /* + * Convert arguments into numbers + */ + if ( rtems_string_to_pointer(argv[1], &tmpp, NULL) ) { + printf( "Address argument (%s) is not a number\n", argv[1] ); + return -1; + } + pb = tmpp; + + /* + * Now edit the memory + */ + n = 0; + for (i=2 ; i<=argc ; i++) { + unsigned char tmpc; + + if ( rtems_string_to_unsigned_char(argv[i], &tmpc, NULL, 0) ) { + printf( "Value (%s) is not a number\n", argv[i] ); + continue; + } + + pb[n++] = tmpc; + } + + return 0; +} + +rtems_shell_cmd_t rtems_shell_MEDIT_Command = { + "medit", /* name */ + "medit address value1 [value2 ...]", /* usage */ + "mem", /* topic */ + rtems_shell_main_medit, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_mfill.c b/cpukit/libmisc/shell/main_mfill.c new file mode 100644 index 0000000000..ecbaec4878 --- /dev/null +++ b/cpukit/libmisc/shell/main_mfill.c @@ -0,0 +1,77 @@ +/* + * MFILL Shell Command Implmentation + * + * Author: Fernando RUIZ CASAS + * Work: fernando.ruiz@ctv.es + * Home: correo@fernando-ruiz.com + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <ctype.h> +#include <stdio.h> +#include <string.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include <rtems/stringto.h> +#include "internal.h" + +int rtems_shell_main_mfill( + int argc, + char *argv[] +) +{ + unsigned long tmp; + void *addr; + size_t size; + unsigned char value; + + if ( argc != 4 ) { + fprintf(stderr,"%s: too few arguments\n", argv[0]); + return -1; + } + + /* + * Convert arguments into numbers + */ + if ( rtems_string_to_pointer(argv[1], &addr, NULL) ) { + printf( "Address argument (%s) is not a number\n", argv[1] ); + return -1; + } + + if ( rtems_string_to_unsigned_long(argv[2], &tmp, NULL, 0) ) { + printf( "Size argument (%s) is not a number\n", argv[2] ); + return -1; + } + size = (size_t) tmp; + + if ( rtems_string_to_unsigned_char(argv[3], &value, NULL, 0) ) { + printf( "Value argument (%s) is not a number\n", argv[3] ); + return -1; + } + + /* + * Now fill the memory. + */ + memset(addr, size, value); + + return 0; +} + +rtems_shell_cmd_t rtems_shell_MFILL_Command = { + "mfill", /* name */ + "mfill address size value", /* usage */ + "mem", /* topic */ + rtems_shell_main_mfill, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_mkdir.c b/cpukit/libmisc/shell/main_mkdir.c new file mode 100644 index 0000000000..e191818923 --- /dev/null +++ b/cpukit/libmisc/shell/main_mkdir.c @@ -0,0 +1,55 @@ +/* + * MKDIR Shell Command Implmentation + * + * Author: Fernando RUIZ CASAS + * Work: fernando.ruiz@ctv.es + * Home: correo@fernando-ruiz.com + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include "internal.h" + +int rtems_shell_main_mkdir( + int argc, + char *argv[] +) +{ + char *dir; + int n; + + n = 1; + while (n<argc) { + dir = argv[n++]; + if (mkdir(dir,S_IRWXU|S_IRWXG|S_IRWXO)) { + fprintf(stderr, "mkdir '%s' failed:%s\n", dir, strerror(errno)); + } + } + return errno; +} + +rtems_shell_cmd_t rtems_shell_MKDIR_Command = { + "mkdir", /* name */ + "mkdir dir # make a directory", /* usage */ + "files", /* topic */ + rtems_shell_main_mkdir, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_mknod.c b/cpukit/libmisc/shell/main_mknod.c new file mode 100644 index 0000000000..e1ebb2a162 --- /dev/null +++ b/cpukit/libmisc/shell/main_mknod.c @@ -0,0 +1,463 @@ +/* $NetBSD: mknod.c,v 1.39 2009/02/13 01:37:23 lukem Exp $ */ + +/*- + * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#if 0 +#ifndef lint +__COPYRIGHT("@(#) Copyright (c) 1998\ + The NetBSD Foundation, Inc. All rights reserved."); +__RCSID("$NetBSD: mknod.c,v 1.39 2009/02/13 01:37:23 lukem Exp $"); +#endif /* not lint */ +#endif + +#include <rtems.h> +#include <rtems/shell.h> +#include <rtems/shellconfig.h> +#define __need_getopt_newlib +#include <getopt.h> + +#include <sys/cdefs.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/param.h> +#if !HAVE_NBTOOL_CONFIG_H && defined(KERN_DRIVERS) +#include <sys/sysctl.h> +#endif + +#include <err.h> +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <pwd.h> +#include <grp.h> +#include <string.h> +#include <ctype.h> + +#include "mknod-pack_dev.h" + +#include <setjmp.h> + +typedef struct { + int exit_code; + jmp_buf exit_jmp; +} rtems_shell_mknod_globals; + +#define exit_jump &(globals->exit_jmp) + +#define exit(ec) rtems_shell_mknod_exit(globals, ec) + +static int gid_name(const char *, gid_t *); +static portdev_t callPack(rtems_shell_mknod_globals* globals, + pack_t *, int, u_long *); + +static int main_mknod(rtems_shell_mknod_globals*, int, char *[]); +static void usage(rtems_shell_mknod_globals* ); + +static void +rtems_shell_mknod_exit (rtems_shell_mknod_globals* globals, int code) +{ + globals->exit_code = code; + longjmp (globals->exit_jmp, 1); +} + +#include "mknod-pack_dev.c" + +int +rtems_shell_main_mknod(int argc, char *argv[]) +{ + rtems_shell_mknod_globals mknod_globals; + rtems_shell_mknod_globals* globals = &mknod_globals; + memset (globals, 0, sizeof (mknod_globals)); + mknod_globals.exit_code = 1; + if (setjmp (mknod_globals.exit_jmp) == 0) + return main_mknod (globals, argc, argv); + return mknod_globals.exit_code; +} + +#define getprogname() "mknod" + +#ifdef KERN_DRIVERS +#error invalid for RTEMS +static struct kinfo_drivers *kern_drivers; +static int num_drivers; + +static void get_device_info(void); +static void print_device_info(char **); +static int major_from_name(const char *, mode_t); +#endif + +#define MAXARGS 3 /* 3 for bsdos, 2 for rest */ + +int +main_mknod(rtems_shell_mknod_globals* globals, int argc, char **argv) +{ + char *name, *p; + mode_t mode; + portdev_t dev; + pack_t *pack; + u_long numbers[MAXARGS]; + int n, ch, fifo, hasformat; + int r_flag = 0; /* force: delete existing entry */ +#ifdef KERN_DRIVERS + int l_flag = 0; /* list device names and numbers */ + int major; +#endif +#if RTEMS_REMOVED + void *modes = 0; +#endif + uid_t uid = -1; + gid_t gid = -1; + int rval; + + struct getopt_data getopt_reent; + memset(&getopt_reent, 0, sizeof(getopt_data)); + + dev = 0; + fifo = hasformat = 0; + pack = pack_native; + +#ifdef KERN_DRIVERS + while ((ch = getopt(argc, argv, "lrRF:g:m:u:")) != -1) { +#else + while ((ch = getopt_r(argc, argv, "rRF:g:m:u:", &getopt_reent)) != -1) { +#endif + switch (ch) { + +#ifdef KERN_DRIVERS + case 'l': + l_flag = 1; + break; +#endif + + case 'r': + r_flag = 1; + break; + + case 'R': + r_flag = 2; + break; + + case 'F': + pack = pack_find(getopt_reent.optarg); + if (pack == NULL) + errx(exit_jump, 1, "invalid format: %s", getopt_reent.optarg); + hasformat++; + break; + + case 'g': + if (getopt_reent.optarg[0] == '#') { + gid = strtol(getopt_reent.optarg + 1, &p, 10); + if (*p == 0) + break; + } + if (gid_name(getopt_reent.optarg, &gid) == 0) + break; + gid = strtol(getopt_reent.optarg, &p, 10); + if (*p == 0) + break; + errx(exit_jump, 1, "%s: invalid group name", getopt_reent.optarg); + + case 'm': +#if RTEMS_REMOVED + modes = setmode(getopt_reent.optarg); + if (modes == NULL) +#endif + err(exit_jump, 1, "Cannot set file mode `%s'", getopt_reent.optarg); + break; + + case 'u': + if (getopt_reent.optarg[0] == '#') { + uid = strtol(getopt_reent.optarg + 1, &p, 10); + if (*p == 0) + break; + } +#if RTEMS_REMOVED + if (uid_from_user(getopt_reent.optarg, &uid) == 0) + break; +#endif + uid = strtol(getopt_reent.optarg, &p, 10); + if (*p == 0) + break; + errx(exit_jump, 1, "%s: invalid user name", getopt_reent.optarg); + + default: + case '?': + usage(globals); + } + } + argc -= getopt_reent.optind; + argv += getopt_reent.optind; + +#ifdef KERN_DRIVERS + if (l_flag) { + print_device_info(argv); + return 0; + } +#endif + + if (argc < 2 || argc > 10) + usage(globals); + + name = *argv; + argc--; + argv++; + + umask(mode = umask(0)); + mode = (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) & ~mode; + + if (argv[0][1] != '\0') + goto badtype; + switch (*argv[0]) { + case 'c': + mode |= S_IFCHR; + break; + + case 'b': + mode |= S_IFBLK; + break; + + case 'p': + if (hasformat) + errx(exit_jump, 1, "format is meaningless for fifos"); + mode |= S_IFIFO; + fifo = 1; + break; + + default: + badtype: + errx(exit_jump, 1, "node type must be 'b', 'c' or 'p'."); + } + argc--; + argv++; + + if (fifo) { + if (argc != 0) + usage(globals); + } else { + if (argc < 1 || argc > MAXARGS) + usage(globals); + } + + for (n = 0; n < argc; n++) { + errno = 0; + numbers[n] = strtoul(argv[n], &p, 0); + if (*p == 0 && errno == 0) + continue; +#ifdef KERN_DRIVERS + if (n == 0) { + major = major_from_name(argv[0], mode); + if (major != -1) { + numbers[0] = major; + continue; + } + if (!isdigit(*(unsigned char *)argv[0])) + errx(1, "unknown driver: %s", argv[0]); + } +#endif + errx(exit_jump, 1, "invalid number: %s", argv[n]); + } + + switch (argc) { + case 0: + dev = 0; + break; + + case 1: + dev = numbers[0]; + break; + + default: + dev = callPack(globals, pack, argc, numbers); + break; + } + +#if RTEMS_REMOVED + if (modes != NULL) + mode = getmode(modes, mode); +#endif + umask(0); + rval = fifo ? mkfifo(name, mode) : mknod(name, mode, dev); + if (rval < 0 && errno == EEXIST && r_flag) { + struct stat sb; + if (lstat(name, &sb) != 0 || (!fifo && sb.st_rdev != dev)) + sb.st_mode = 0; + + if ((sb.st_mode & S_IFMT) == (mode & S_IFMT)) { + if (r_flag == 1) + /* Ignore permissions and user/group */ + return 0; + if (sb.st_mode != mode) + rval = chmod(name, mode); + else + rval = 0; + } else { + unlink(name); + rval = fifo ? mkfifo(name, mode) + : mknod(name, mode, dev); + } + } + if (rval < 0) + err(exit_jump, 1, "%s", name); + if ((uid != (uid_t)-1 || gid != (uid_t)-1) && chown(name, uid, gid) == -1) + /* XXX Should we unlink the files here? */ + warn("%s: uid/gid not changed", name); + + return 0; +} + +static void +usage(rtems_shell_mknod_globals* globals) +{ + const char *progname = getprogname(); + + (void)fprintf(stderr, + "usage: %s [-rR] [-F format] [-m mode] [-u user] [-g group]\n", + progname); + (void)fprintf(stderr, +#ifdef KERN_DRIVERS + " [ name [b | c] [major | driver] minor\n" +#else + " [ name [b | c] major minor\n" +#endif + " | name [b | c] major unit subunit\n" + " | name [b | c] number\n" + " | name p ]\n"); +#ifdef KERN_DRIVERS + (void)fprintf(stderr, " %s -l [driver] ...\n", progname); +#endif + exit(1); +} + +static int +gid_name(const char *name, gid_t *gid) +{ + struct group *g; + + g = getgrnam(name); + if (!g) + return -1; + *gid = g->gr_gid; + return 0; +} + +static portdev_t +callPack(rtems_shell_mknod_globals* globals, pack_t *f, int n, u_long *numbers) +{ + portdev_t d; + const char *error = NULL; + + d = (*f)(n, numbers, &error); + if (error != NULL) + errx(exit_jump, 1, "%s", error); + return d; +} + +#ifdef KERN_DRIVERS +static void +get_device_info(void) +{ + static int mib[2] = {CTL_KERN, KERN_DRIVERS}; + size_t len; + + if (sysctl(mib, 2, NULL, &len, NULL, 0) != 0) + err(1, "kern.drivers" ); + kern_drivers = malloc(len); + if (kern_drivers == NULL) + err(1, "malloc"); + if (sysctl(mib, 2, kern_drivers, &len, NULL, 0) != 0) + err(1, "kern.drivers" ); + + num_drivers = len / sizeof *kern_drivers; +} + +static void +print_device_info(char **names) +{ + int i; + struct kinfo_drivers *kd; + + if (kern_drivers == NULL) + get_device_info(); + + do { + kd = kern_drivers; + for (i = 0; i < num_drivers; kd++, i++) { + if (*names && strcmp(*names, kd->d_name)) + continue; + printf("%s", kd->d_name); + if (kd->d_cmajor != -1) + printf(" character major %d", kd->d_cmajor); + if (kd->d_bmajor != -1) + printf(" block major %d", kd->d_bmajor); + printf("\n"); + } + } while (*names && *++names); +} + +static int +major_from_name(const char *name, mode_t mode) +{ + int i; + struct kinfo_drivers *kd; + + if (kern_drivers == NULL) + get_device_info(); + + kd = kern_drivers; + for (i = 0; i < num_drivers; kd++, i++) { + if (strcmp(name, kd->d_name)) + continue; + if (S_ISCHR(mode)) + return kd->d_cmajor; + return kd->d_bmajor; + } + return -1; +} +#endif + +rtems_shell_cmd_t rtems_shell_MKNOD_Command = { + "mknod", /* name */ + "mknod mknod [-rR] [-F fmt] [-m mode] name [c | b] minor", /* usage */ + "files", /* topic */ + rtems_shell_main_mknod, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_mkrfs.c b/cpukit/libmisc/shell/main_mkrfs.c new file mode 100644 index 0000000000..726b575b03 --- /dev/null +++ b/cpukit/libmisc/shell/main_mkrfs.c @@ -0,0 +1,35 @@ +/* + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include <rtems/stringto.h> +#include <rtems/shellconfig.h> +#include <rtems/rtems-rfs-shell.h> +#include <rtems/fsmount.h> +#include "internal.h" + +#define OPTIONS "[-v] [-s blksz] [-b grpblk] [-i grpinode] [-I] [-o %inode]" + +rtems_shell_cmd_t rtems_shell_MKRFS_Command = { + "mkrfs", /* name */ + "mkrfs " OPTIONS " dev", /* usage */ + "files", /* topic */ + rtems_shell_rfs_format, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_mmove.c b/cpukit/libmisc/shell/main_mmove.c new file mode 100644 index 0000000000..30c6629547 --- /dev/null +++ b/cpukit/libmisc/shell/main_mmove.c @@ -0,0 +1,79 @@ +/* + * MMOVE Shell Command Implmentation + * + * Author: Fernando RUIZ CASAS + * Work: fernando.ruiz@ctv.es + * Home: correo@fernando-ruiz.com + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <ctype.h> +#include <stdio.h> +#include <string.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include <rtems/stringto.h> +#include "internal.h" + +extern int rtems_shell_main_mdump(int, char *); + +int rtems_shell_main_mmove( + int argc, + char *argv[] +) +{ + unsigned long tmp; + void *src; + void *dst; + size_t length; + + if ( argc < 4 ) { + fprintf(stderr,"%s: too few arguments\n", argv[0]); + return -1; + } + + /* + * Convert arguments into numbers + */ + if ( rtems_string_to_pointer(argv[1], &dst, NULL) ) { + printf( "Destination argument (%s) is not a number\n", argv[1] ); + return -1; + } + + if ( rtems_string_to_pointer(argv[2], &src, NULL) ) { + printf( "Source argument (%s) is not a number\n", argv[2] ); + return -1; + } + + if ( rtems_string_to_unsigned_long(argv[3], &tmp, NULL, 0) ) { + printf( "Length argument (%s) is not a number\n", argv[3] ); + return -1; + } + length = (size_t) tmp; + + /* + * Now copy the memory. + */ + memcpy(dst, src, length); + + return 0; +} + +rtems_shell_cmd_t rtems_shell_MMOVE_Command = { + "mmove", /* name */ + "mmove dst src length", /* usage */ + "mem", /* topic */ + rtems_shell_main_mmove, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_mount.c b/cpukit/libmisc/shell/main_mount.c new file mode 100644 index 0000000000..b192a1668d --- /dev/null +++ b/cpukit/libmisc/shell/main_mount.c @@ -0,0 +1,133 @@ +/* + * Shell Command Implmentation + * + * Author: Fernando RUIZ CASAS + * Work: fernando.ruiz@ctv.es + * Home: correo@fernando-ruiz.com + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include <rtems/shellconfig.h> +#include <rtems/libio.h> +#include "internal.h" + +static bool print_filesystem(const rtems_filesystem_table_t *entry, void *arg) +{ + printf("%s ", entry->type); + + return false; +} + +int rtems_shell_main_mount( + int argc, + char *argv[] +) +{ + rtems_filesystem_options_t options = RTEMS_FILESYSTEM_READ_WRITE; + char* type = NULL; + char* source = NULL; + char* target = NULL; + char* fsoptions = NULL; + int arg; + + for (arg = 1; arg < argc; arg++) { + if (argv[arg][0] == '-') { + if (argv[arg][1] == 't') { + arg++; + if (arg == argc) { + fprintf( + stderr, + "%s: -t needs a type of file-system;; see -L.\n", + argv[0] + ); + return 1; + } + type = argv[arg]; + } else if (argv[arg][1] == 'r') { + options = RTEMS_FILESYSTEM_READ_ONLY; + } else if (argv[arg][1] == 'L') { + printf ("File systems: "); + rtems_filesystem_iterate(print_filesystem, NULL); + printf ("\n"); + return 0; + } else if (argv[arg][1] == 'o') { + arg++; + if (arg == argc) { + fprintf( + stderr, + "%s: -o needs a list if filesystem options.\n", + argv[0] + ); + return 1; + } + fsoptions = argv[arg]; + } else { + fprintf (stderr, "unknown option: %s\n", argv[arg]); + return 1; + } + } else { + if (!source) + source = argv[arg]; + else if (!target) + target = argv[arg]; + else { + fprintf ( + stderr, "mount: source and mount only require: %s\n", argv[arg]); + return 1; + } + } + } + + if (!type) { + fprintf (stderr, "mount: no file-system; see the -L option\n"); + return 1; + } + + if (!source) { + fprintf (stderr, "mount: no source\n"); + return 1; + } + + if (!target) { + fprintf (stderr, "mount: no mount point\n"); + return 1; + } + + /* + * Mount the disk. + */ + + if (mount (source, target, type, options, fsoptions) < 0) { + fprintf (stderr, "error: %s\n", strerror(errno)); + return 1; + } + + printf ("mounted %s -> %s\n", source, target); + + return 0; +} + +rtems_shell_cmd_t rtems_shell_MOUNT_Command = { + "mount", /* name */ + "mount [-t type] [-r] [-L] source target", /* usage */ + "files", /* topic */ + rtems_shell_main_mount, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_mount_nfs.c b/cpukit/libmisc/shell/main_mount_nfs.c new file mode 100644 index 0000000000..121d0ca6c2 --- /dev/null +++ b/cpukit/libmisc/shell/main_mount_nfs.c @@ -0,0 +1,70 @@ +/* + * Shell Command Implmentation + * + * Author: Fernando RUIZ CASAS + * Work: fernando.ruiz@ctv.es + * Home: correo@fernando-ruiz.com + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include "internal.h" + +#include <librtemsNfs.h> + +static int +rtems_shell_nfs_mounter ( + const char* device, + const char* mntpoint, + rtems_shell_filesystems_t* fs __attribute__((unused)), + rtems_filesystem_options_t options __attribute__((unused))) +{ + char* uidhost; + char* path; + int ret; + + if (strchr (device, ':') == NULL) { + fprintf (stderr, "error: nfs mount device is [uid.gid@]host:path\n"); + return -1; + } + + if (rpcUdpInit () < 0) { + fprintf (stderr, "error: initialising RPC\n"); + return -1; + } + + nfsInit (0, 0); + + uidhost = strdup (device); + path = strchr (uidhost, ':'); + *path = '\0'; + path++; + + ret = nfsMount(uidhost, path, (char*) mntpoint); + + free (uidhost); + + return ret; +} + +rtems_shell_filesystems_t rtems_shell_Mount_NFS = { + name: "nfs", + driver_needed: 1, + fs_ops: NULL, + mounter: rtems_shell_nfs_mounter +}; diff --git a/cpukit/libmisc/shell/main_msdosfmt.c b/cpukit/libmisc/shell/main_msdosfmt.c new file mode 100644 index 0000000000..c682e879eb --- /dev/null +++ b/cpukit/libmisc/shell/main_msdosfmt.c @@ -0,0 +1,185 @@ +/* + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <inttypes.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include <rtems/stringto.h> +#include <rtems/shellconfig.h> +#include <rtems/dosfs.h> +#include <rtems/fsmount.h> +#include "internal.h" + +int rtems_shell_main_msdos_format( + int argc, + char *argv[] +) +{ + msdos_format_request_param_t rqdata = { + OEMName: "RTEMS", + VolLabel: "RTEMSDisk", + sectors_per_cluster: 0, + fat_num: 0, + files_per_root_dir: 0, + fattype: MSDOS_FMT_FATANY, + media: 0, + quick_format: TRUE, + cluster_align: 0, + info_level: 0 + }; + + unsigned long tmp; + const char* driver = NULL; + int arg; + + for (arg = 1; arg < argc; arg++) { + if (argv[arg][0] == '-') { + switch (argv[arg][1]) { + case 'V': + arg++; + if (arg == argc) { + fprintf (stderr, "error: no volume label.\n"); + return 1; + } + rqdata.VolLabel = argv[arg]; + break; + + case 's': + arg++; + if (arg == argc) { + fprintf (stderr, "error: sectors per cluster count.\n"); + return 1; + } + + if ( rtems_string_to_unsigned_long(argv[arg], &tmp, NULL, 0) ) { + printf( + "sector per cluster argument (%s) is not a number\n", + argv[arg] + ); + return -1; + } + + rqdata.sectors_per_cluster = (uint32_t) tmp; + break; + + case 'r': + arg++; + if (arg == argc) { + fprintf (stderr, "error: no root directory size.\n"); + return 1; + } + + if ( rtems_string_to_unsigned_long(argv[arg], &tmp, NULL, 0) ) { + printf( + "root directory size argument (%s) is not a number\n", + argv[arg] + ); + return -1; + } + + rqdata.files_per_root_dir = (uint32_t) tmp; + break; + + case 't': + arg++; + if (arg == argc) { + fprintf (stderr, "error: no FAT type.\n"); + return 1; + } + + if (strcmp (argv[arg], "any") == 0) + rqdata.fattype = MSDOS_FMT_FATANY; + else if (strcmp (argv[arg], "12") == 0) + rqdata.fattype = MSDOS_FMT_FAT12; + else if (strcmp (argv[arg], "16") == 0) + rqdata.fattype = MSDOS_FMT_FAT16; + else if (strcmp (argv[arg], "32") == 0) + rqdata.fattype = MSDOS_FMT_FAT32; + else { + fprintf (stderr, "error: invalid type, can any, 12, 16, or 32\n"); + return 1; + } + break; + + case 'v': + rqdata.info_level++; + break; + + default: + fprintf (stderr, "error: invalid option: %s\n", argv[arg]); + return 1; + + } + } else { + if (!driver) + driver = argv[arg]; + else { + fprintf (stderr, "error: only one driver allowed: %s\n", argv[arg]); + return 1; + } + } + } + + if (!driver) { + fprintf (stderr, "error: no driver\n"); + return 1; + } + + printf ("msdos format: %s\n", driver); + + if (rqdata.info_level) + { + printf (" %-20s: %s\n", "OEMName", "RTEMS"); + printf (" %-20s: %s\n", "VolLabel", "RTEMSDisk"); + printf (" %-20s: %" PRIu32 "\n", "sectors per cluster", rqdata.sectors_per_cluster); + printf (" %-20s: %" PRIu32 "\n", "fats", rqdata.fat_num); + printf (" %-20s: %" PRIu32 "\n", "files per root dir", rqdata.files_per_root_dir); + printf (" %-20s: %i\n", "fat type", rqdata.fattype); + printf (" %-20s: %d\n", "media", rqdata.media); + printf (" %-20s: %d\n", "quick_format", rqdata.quick_format); + printf (" %-20s: %" PRIu32 "\n", "cluster align", rqdata.cluster_align); + } + + if (msdos_format (driver, &rqdata) < 0) { + fprintf (stderr, "error: format failed: %s\n", strerror (errno)); + return 1; + } + + printf ("msdos format successful\n"); + + return 0; +} + +#define OPTIONS "[-v label] [-r size] [-t any/12/16/32]" + +rtems_shell_cmd_t rtems_shell_MSDOSFMT_Command = { + "mkdos", /* name */ + "mkdos " OPTIONS " path # format disk", /* usage */ + "files", /* topic */ + rtems_shell_main_msdos_format, /* command */ + NULL, /* alias */ + NULL /* next */ +}; + +rtems_shell_cmd_t rtems_shell_MSDOSFMT_Alias = { + "msdosfmt", /* name */ + NULL, /* usage */ + "files", /* topic */ + NULL, /* command */ + &rtems_shell_MSDOSFMT_Command, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_mv.c b/cpukit/libmisc/shell/main_mv.c new file mode 100644 index 0000000000..644900bc17 --- /dev/null +++ b/cpukit/libmisc/shell/main_mv.c @@ -0,0 +1,491 @@ +/* $NetBSD: mv.c,v 1.41 2008/07/20 00:52:40 lukem Exp $ */ + +/* + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ken Smith of The State University of New York at Buffalo. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if 0 +#include <sys/cdefs.h> +#ifndef lint +__COPYRIGHT("@(#) Copyright (c) 1989, 1993, 1994\ + The Regents of the University of California. All rights reserved."); +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)mv.c 8.2 (Berkeley) 4/2/94"; +#else +__RCSID("$NetBSD: mv.c,v 1.41 2008/07/20 00:52:40 lukem Exp $"); +#endif +#endif /* not lint */ +#endif + +#include <rtems.h> +#include <rtems/shell.h> +#include <rtems/shellconfig.h> +#define __need_getopt_newlib +#include <getopt.h> + +#include <sys/param.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <sys/stat.h> + +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <grp.h> +#include <locale.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "pathnames-mv.h" + +/* RTEMS specific changes */ +typedef struct { + int fflg, iflg, vflg; + int stdin_ok; + int exit_code; + jmp_buf exit_jmp; +} rtems_shell_mv_globals; + +int copy(char *, char *); +int do_move(char *, char *); +int fastcopy(char *, char *, struct stat *); +void usage(void); +int main(int, char *[]); + +#define fflg globals->fflg +#define iflg globals->iflg +#define vflg globals->vflg +#define stdin_ok globals->stdin_ok +#define exit_jump &(globals->exit_jmp) + +#include <setjmp.h> + +#define exit(ec) rtems_shell_mv_exit(globals, ec) + +void +rtems_shell_mv_exit (rtems_shell_mv_globals* globals, int code) +{ + globals->exit_code = code; + longjmp (globals->exit_jmp, 1); +} + +void strmode(mode_t mode, char *p); +const char *user_from_uid(uid_t uid, int nouser); +char *group_from_gid(gid_t gid, int nogroup); + +static int main_mv(rtems_shell_mv_globals* globals, int argc, char *argv[]); + +int rtems_shell_main_cp(int argc, char *argv[]); +int rtems_shell_main_rm(int argc, char *argv[]); + +int +rtems_shell_main_mv(int argc, char *argv[]) +{ + rtems_shell_mv_globals mv_globals; + memset (&mv_globals, 0, sizeof (mv_globals)); + mv_globals.exit_code = 1; + if (setjmp (mv_globals.exit_jmp) == 0) + return main_mv (&mv_globals, argc, argv); + return mv_globals.exit_code; +} + +#define do_move(a1, a2) do_move_mv(globals, a1, a2) +#define fastcopy(a1, a2, a3) fastcopy_mv(globals, a1, a2, a3) +#define copy(a1, a2) copy_mv(globals, a1, a2) +#define usage() usage_mv(globals) + +static int do_move_mv(rtems_shell_mv_globals* globals, char *from, char *to); +static int fastcopy_mv(rtems_shell_mv_globals* globals, + char *from, char *to, struct stat *sbp); +static int copy_mv(rtems_shell_mv_globals* globals, char *from, char *to); +static void usage_mv(rtems_shell_mv_globals* globals); + +/* RTEMS changes */ + +int +main_mv(rtems_shell_mv_globals* globals, int argc, char *argv[]) +{ + int ch, len, rval; + char *p, *endp; + struct stat sb; + char path[MAXPATHLEN + 1]; + size_t baselen; + + struct getopt_data getopt_reent; + memset(&getopt_reent, 0, sizeof(getopt_data)); + +/* setprogname(argv[0]); */ + + (void)setlocale(LC_ALL, ""); + + while ((ch = getopt_r(argc, argv, "ifv", &getopt_reent)) != -1) + switch (ch) { + case 'i': + fflg = 0; + iflg = 1; + break; + case 'f': + iflg = 0; + fflg = 1; + break; + case 'v': + vflg = 1; + break; + default: + usage(); + } + argc -= getopt_reent.optind; + argv += getopt_reent.optind; + + if (argc < 2) + usage(); + + stdin_ok = isatty(STDIN_FILENO); + + /* + * If the stat on the target fails or the target isn't a directory, + * try the move. More than 2 arguments is an error in this case. + */ + if (stat(argv[argc - 1], &sb) || !S_ISDIR(sb.st_mode)) { + if (argc > 2) + usage(); + exit(do_move(argv[0], argv[1])); + } + + /* It's a directory, move each file into it. */ + baselen = strlcpy(path, argv[argc - 1], sizeof(path)); + if (baselen >= sizeof(path)) + errx(exit_jump, 1, "%s: destination pathname too long", argv[argc - 1]); + endp = &path[baselen]; + if (!baselen || *(endp - 1) != '/') { + *endp++ = '/'; + ++baselen; + } + for (rval = 0; --argc; ++argv) { + p = *argv + strlen(*argv) - 1; + while (*p == '/' && p != *argv) + *p-- = '\0'; + if ((p = strrchr(*argv, '/')) == NULL) + p = *argv; + else + ++p; + + if ((baselen + (len = strlen(p))) >= MAXPATHLEN) { + warnx("%s: destination pathname too long", *argv); + rval = 1; + } else { + memmove(endp, p, len + 1); + if (do_move(*argv, path)) + rval = 1; + } + } + return rval; +} + +int +do_move_mv(rtems_shell_mv_globals* globals, char *from, char *to) +{ + struct stat sb; + char modep[15]; + + /* + * (1) If the destination path exists, the -f option is not specified + * and either of the following conditions are true: + * + * (a) The permissions of the destination path do not permit + * writing and the standard input is a terminal. + * (b) The -i option is specified. + * + * the mv utility shall write a prompt to standard error and + * read a line from standard input. If the response is not + * affirmative, mv shall do nothing more with the current + * source file... + */ + if (!fflg && !access(to, F_OK)) { + int ask = 1; + int ch; + + if (iflg) { + if (access(from, F_OK)) { + warn("rename %s", from); + return (1); + } + (void)fprintf(stderr, "overwrite %s? ", to); + } else if (stdin_ok && access(to, W_OK) && !stat(to, &sb)) { + if (access(from, F_OK)) { + warn("rename %s", from); + return (1); + } + strmode(sb.st_mode, modep); + (void)fprintf(stderr, "override %s%s%s/%s for %s? ", + modep + 1, modep[9] == ' ' ? "" : " ", + user_from_uid(sb.st_uid, 0), + group_from_gid(sb.st_gid, 0), to); + } else + ask = 0; + if (ask) { + if ((ch = getchar()) != EOF && ch != '\n') { + int ch2; + while ((ch2 = getchar()) != EOF && ch2 != '\n') + continue; + } + if (ch != 'y' && ch != 'Y') + return (0); + } + } + + /* + * (2) If rename() succeeds, mv shall do nothing more with the + * current source file. If it fails for any other reason than + * EXDEV, mv shall write a diagnostic message to the standard + * error and do nothing more with the current source file. + * + * (3) If the destination path exists, and it is a file of type + * directory and source_file is not a file of type directory, + * or it is a file not of type directory, and source file is + * a file of type directory, mv shall write a diagnostic + * message to standard error, and do nothing more with the + * current source file... + */ + if (!rename(from, to)) { + if (vflg) + printf("%s -> %s\n", from, to); + return (0); + } + + if (errno != EXDEV) { + warn("rename %s to %s", from, to); + return (1); + } + + /* + * (4) If the destination path exists, mv shall attempt to remove it. + * If this fails for any reason, mv shall write a diagnostic + * message to the standard error and do nothing more with the + * current source file... + */ + if (!lstat(to, &sb)) { + if ((S_ISDIR(sb.st_mode)) ? rmdir(to) : unlink(to)) { + warn("can't remove %s", to); + return (1); + } + } + + /* + * (5) The file hierarchy rooted in source_file shall be duplicated + * as a file hierarchy rooted in the destination path... + */ + if (lstat(from, &sb)) { + warn("%s", from); + return (1); + } + + return (S_ISREG(sb.st_mode) ? + fastcopy(from, to, &sb) : copy(from, to)); +} + +int +fastcopy_mv(rtems_shell_mv_globals* globals, char *from, char *to, struct stat *sbp) +{ + struct timeval tval[2]; + uint32_t blen; + static char *bp; + int nread, from_fd, to_fd; + + blen = 0; + + if ((from_fd = open(from, O_RDONLY, 0)) < 0) { + warn("%s", from); + return (1); + } + if ((to_fd = + open(to, O_CREAT | O_TRUNC | O_WRONLY, sbp->st_mode)) < 0) { + warn("%s", to); + (void)close(from_fd); + return (1); + } + if (!blen && !(bp = malloc(blen = sbp->st_blksize))) { + warn(NULL); + blen = 0; + (void)close(from_fd); + (void)close(to_fd); + return (1); + } + while ((nread = read(from_fd, bp, blen)) > 0) + if (write(to_fd, bp, nread) != nread) { + warn("%s", to); + goto err; + } + if (nread < 0) { + warn("%s", from); +err: if (unlink(to)) + warn("%s: remove", to); + (void)free(bp); + (void)close(from_fd); + (void)close(to_fd); + return (1); + } + + (void)free(bp); + (void)close(from_fd); +#ifdef xBSD4_4 + TIMESPEC_TO_TIMEVAL(&tval[0], &sbp->st_atimespec); + TIMESPEC_TO_TIMEVAL(&tval[1], &sbp->st_mtimespec); +#else + tval[0].tv_sec = sbp->st_atime; + tval[1].tv_sec = sbp->st_mtime; + tval[0].tv_usec = 0; + tval[1].tv_usec = 0; +#endif +#if 0 +#ifdef _SRV5 + if (utimes(to, tval)) +#else + if (futimes(to_fd, tval)) +#endif + warn("%s: set times", to); +#endif + if (fchown(to_fd, sbp->st_uid, sbp->st_gid)) { + if (errno != EPERM) + warn("%s: set owner/group", to); + sbp->st_mode &= ~(S_ISUID | S_ISGID); + } + if (fchmod(to_fd, sbp->st_mode)) + warn("%s: set mode", to); +#if 0 + if (fchflags(to_fd, sbp->st_flags) && (errno != EOPNOTSUPP)) + warn("%s: set flags (was: 0%07o)", to, sbp->st_flags); +#endif + if (close(to_fd)) { + warn("%s", to); + return (1); + } + + if (unlink(from)) { + warn("%s: remove", from); + return (1); + } + + if (vflg) + printf("%s -> %s\n", from, to); + + return (0); +} + +int +copy_mv(rtems_shell_mv_globals* globals, char *from, char *to) +{ + char* cp_argv[5] = { "mv", vflg ? "-PRpv" : "-PRp", "--", from, to }; + char* rm_argv[4] = { "mv", "-rf", "--", from }; + int result; + + result = rtems_shell_main_cp(5, cp_argv); + if (result) { + warnx("%s: did not terminate normally", _PATH_CP); + return (1); + } + result = rtems_shell_main_rm(4, rm_argv); + if (result) { + warnx("%s: did not terminate normally", _PATH_RM); + return (1); + } +#if 0 + pid_t pid; + int status; + + if ((pid = vfork()) == 0) { + execl(_PATH_CP, "mv", vflg ? "-PRpv" : "-PRp", "--", from, to, NULL); + warn("%s", _PATH_CP); + _exit(1); + } + if (waitpid(pid, &status, 0) == -1) { + warn("%s: waitpid", _PATH_CP); + return (1); + } + if (!WIFEXITED(status)) { + warnx("%s: did not terminate normally", _PATH_CP); + return (1); + } + if (WEXITSTATUS(status)) { + warnx("%s: terminated with %d (non-zero) status", + _PATH_CP, WEXITSTATUS(status)); + return (1); + } + if (!(pid = vfork())) { + execl(_PATH_RM, "mv", "-rf", "--", from, NULL); + warn("%s", _PATH_RM); + _exit(1); + } + if (waitpid(pid, &status, 0) == -1) { + warn("%s: waitpid", _PATH_RM); + return (1); + } + if (!WIFEXITED(status)) { + warnx("%s: did not terminate normally", _PATH_RM); + return (1); + } + if (WEXITSTATUS(status)) { + warnx("%s: terminated with %d (non-zero) status", + _PATH_RM, WEXITSTATUS(status)); + return (1); + } +#endif + return (0); +} + +void +usage_mv(rtems_shell_mv_globals* globals) +{ + (void)fprintf(stderr, "usage: %s [-fiv] source target\n" + " %s [-fiv] source ... directory\n", + "mv", "mv"); + exit(1); + /* NOTREACHED */ +} + +rtems_shell_cmd_t rtems_shell_MV_Command = { + "mv", /* name */ + "[-fiv] source target ...", /* usage */ + "files", /* topic */ + rtems_shell_main_mv, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_mwdump.c b/cpukit/libmisc/shell/main_mwdump.c new file mode 100644 index 0000000000..f3e3cfc27b --- /dev/null +++ b/cpukit/libmisc/shell/main_mwdump.c @@ -0,0 +1,95 @@ +/* + * MWDUMP Shell Command Implmentation + * + * Author: Fernando RUIZ CASAS + * Work: fernando.ruiz@ctv.es + * Home: correo@fernando-ruiz.com + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <inttypes.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include <rtems/stringto.h> +#include "internal.h" + +int rtems_shell_main_mwdump( + int argc, + char *argv[] +) +{ + unsigned char n; + unsigned char m; + int max; + int res; + void *addr = 0; + unsigned char *pb; + + if ( argc > 1 ) { + if ( rtems_string_to_pointer(argv[1], &addr, NULL) ) { + printf( "Address argument (%s) is not a number\n", argv[1] ); + return -1; + } + } + + if ( argc > 2 ) { + if ( rtems_string_to_int(argv[2], &max, NULL, 0) ) { + printf( "Address argument (%s) is not a number\n", argv[1] ); + return -1; + } + + if (max <= 0) { + max = 1; /* print 1 item if 0 or neg. */ + res = 0; + } else { + max--; + res = max & 0xf;/* num bytes in last row */ + max >>= 4; /* div by 16 */ + max++; /* num of rows to print */ + if (max > 20) { /* limit to 20 */ + max = 20; + res = 0xf; /* 16 bytes print in last row */ + } + } + } else { + max = 20; + res = 0xf; + } + + pb = addr; + for (m=0;m<max;m++) { + printf("%10p ", pb); + for (n=0;n<=(m==(max-1)?res:0xf);n+=2) + printf("%04X%c",*((unsigned short*)(pb+n)),n==6?'-':' '); + for (;n<=0xf;n+=2) + printf(" %c", n==6?'-':' '); + for (n=0;n<=(m==(max-1)?res:0xf);n++) { + printf("%c", isprint(pb[n]) ? pb[n] : '.'); + } + printf("\n"); + pb += 16; + } + return 0; +} + +rtems_shell_cmd_t rtems_shell_WDUMP_Command = { + "wdump", /* name */ + "wdump [address [length]]", /* usage */ + "mem", /* topic */ + rtems_shell_main_mwdump, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_netstats.c b/cpukit/libmisc/shell/main_netstats.c new file mode 100644 index 0000000000..cc9b95a52c --- /dev/null +++ b/cpukit/libmisc/shell/main_netstats.c @@ -0,0 +1,138 @@ +/* + * Network Statistics Shell Command Implmentation + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#define __need_getopt_newlib +#include <getopt.h> + +#include <rtems.h> +#include <rtems/rtems_bsdnet.h> +#include <rtems/shell.h> +#include "internal.h" + +static void netstats_usage(void) +{ + printf( + "netstats [-vAimfpcut] where:\n" + " -A print All statistics\n" + " -i print Inet Routes\n" + " -m print MBUF Statistics\n" + " -f print IF Statistics\n" + " -p print IP Statistics\n" + " -c print ICMP Statistics\n" + " -u print UDP Statistics\n" + " -t print TCP Statistics\n" + ); +} + +int rtems_shell_main_netstats( /* command */ + int argc, + char *argv[] +) +{ + int option; + int doAll = 0; + int doInetRoutes = 0; + int doMBUFStats = 0; + int doIFStats = 0; + int doIPStats = 0; + int doICMPStats = 0; + int doUDPStats = 0; + int doTCPStats = 0; + int verbose = 0; + struct getopt_data getopt_reent; + + memset(&getopt_reent, 0, sizeof(getopt_data)); + while ( (option = getopt_r( argc, argv, "Aimfpcutv", &getopt_reent)) != -1 ) { + + switch ((char)option) { + case 'A': doAll = 1; break; + case 'i': doInetRoutes = 1; break; + case 'm': doMBUFStats = 1; break; + case 'f': doIFStats = 1; break; + case 'p': doIPStats = 1; break; + case 'c': doICMPStats = 1; break; + case 'u': doUDPStats = 1; break; + case 't': doTCPStats = 1; break; + case 'v': verbose = 1; break; + case '?': + default: + netstats_usage(); + return -1; + } + } + + if ( verbose ) { + printf( + "doAll=%d\n" + "doInetRoutes=%d\n" + "doMBUFStats=%d\n" + "doIFStats=%d\n" + "doIPStats=%d\n" + "doICMPStats=%d\n" + "doUDPStats=%d\n" + "doTCPStats=%d\n", + doAll, + doInetRoutes, + doMBUFStats, + doIFStats, + doIPStats, + doICMPStats, + doUDPStats, + doTCPStats + ); + } + + if ( doInetRoutes == 1 || doAll == 1 ) { + rtems_bsdnet_show_inet_routes(); + } + + if ( doMBUFStats == 1 || doAll == 1 ) { + rtems_bsdnet_show_mbuf_stats(); + } + + if ( doIFStats == 1 || doAll == 1 ) { + rtems_bsdnet_show_if_stats(); + } + + if ( doIPStats == 1 || doAll == 1 ) { + rtems_bsdnet_show_ip_stats(); + } + + if ( doICMPStats == 1 || doAll == 1 ) { + rtems_bsdnet_show_icmp_stats(); + } + + if ( doUDPStats == 1 || doAll == 1 ) { + rtems_bsdnet_show_udp_stats(); + } + + if ( doTCPStats == 1 || doAll == 1 ) { + rtems_bsdnet_show_tcp_stats(); + } + + return 0; +} + +rtems_shell_cmd_t rtems_shell_NETSTATS_Command = { + "netstats", /* name */ + "netstats [-Aimfpcutv]", /* usage */ + "network", /* topic */ + rtems_shell_main_netstats, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_perioduse.c b/cpukit/libmisc/shell/main_perioduse.c new file mode 100644 index 0000000000..d0f123af1c --- /dev/null +++ b/cpukit/libmisc/shell/main_perioduse.c @@ -0,0 +1,63 @@ +/* + * perioduse Command Implementation + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include "internal.h" + +int rtems_shell_main_perioduse( + int argc, + char *argv[] +) +{ + /* + * When invoked with no arguments, print the report. + */ + if ( argc == 1 ) { + rtems_rate_monotonic_report_statistics_with_plugin( + stdout, + (rtems_printk_plugin_t)fprintf + ); + return 0; + } + + /* + * When invoked with the single argument -r, reset the statistics. + */ + if ( argc == 2 && !strcmp( argv[1], "-r" ) ) { + printf( "Resetting Period Usage information\n" ); + rtems_rate_monotonic_reset_all_statistics(); + return 0; + } + + /* + * OK. The user did something wrong. + */ + fprintf( stderr, "%s: [-r]\n", argv[0] ); + return -1; +} + +rtems_shell_cmd_t rtems_shell_PERIODUSE_Command = { + "perioduse", /* name */ + "[-r] print or reset per period usage", /* usage */ + "rtems", /* topic */ + rtems_shell_main_perioduse, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_pwd.c b/cpukit/libmisc/shell/main_pwd.c new file mode 100644 index 0000000000..3a298f8242 --- /dev/null +++ b/cpukit/libmisc/shell/main_pwd.c @@ -0,0 +1,45 @@ +/* + * PWD Shell Command Implmentation + * + * Author: Fernando RUIZ CASAS + * Work: fernando.ruiz@ctv.es + * Home: correo@fernando-ruiz.com + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <unistd.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include "internal.h" + +int rtems_shell_main_pwd( + int argc __attribute__((unused)), + char *argv[] __attribute__((unused)) +) +{ + char dir[1024]; + + getcwd(dir,1024); + puts(dir); + return 0; +} + +rtems_shell_cmd_t rtems_shell_PWD_Command = { + "pwd", /* name */ + "pwd # print work directory", /* usage */ + "files", /* topic */ + rtems_shell_main_pwd, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_rm.c b/cpukit/libmisc/shell/main_rm.c new file mode 100644 index 0000000000..465a0daf46 --- /dev/null +++ b/cpukit/libmisc/shell/main_rm.c @@ -0,0 +1,709 @@ +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if 0 +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1990, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)rm.c 8.5 (Berkeley) 4/18/94"; +#endif /* not lint */ +#endif +#if 0 +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/bin/rm/rm.c,v 1.58 2006/10/31 02:22:36 delphij Exp $"); +#endif + +#include <rtems.h> +#include <rtems/shell.h> +#include <rtems/shellconfig.h> +#define __need_getopt_newlib +#include <getopt.h> + +#include <sys/stat.h> +#include <sys/param.h> + +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <fts.h> +#include <grp.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#define rindex(s,c) strrchr(s,c) + +/* RTEMS specific changes */ +typedef struct { + int dflag, eval, fflag, iflag, Pflag, vflag, Wflag, stdin_ok; + int rflag, Iflag; + uid_t uid; + int exit_code; + jmp_buf exit_jmp; +} rtems_shell_rm_globals; + +#define dflag globals->dflag +#define eval globals->eval +#define fflag globals->fflag +#define iflag globals->iflag +#define Pflag globals->Pflag +#define vflag globals->vflag +#define Wflag globals->Wflag +#define stdin_ok globals->stdin_ok +#define rflag globals->rflag +#define Iflag globals->Iflag +#define xuid globals->uid +#define exit_jump &(globals->exit_jmp) + +#include <setjmp.h> + +#define exit(ec) rtems_shell_rm_exit(globals, ec) +void +rtems_shell_rm_exit (rtems_shell_rm_globals* globals, int code) +{ + globals->exit_code = code; + longjmp (globals->exit_jmp, 1); +} + +static int main_rm(rtems_shell_rm_globals* globals, int argc, char *argv[]); + +int +rtems_shell_main_rm(int argc, char *argv[]) +{ + rtems_shell_rm_globals rm_globals; + memset (&rm_globals, 0, sizeof (rm_globals)); + rm_globals.exit_code = 1; + if (setjmp (rm_globals.exit_jmp) == 0) + return main_rm (&rm_globals, argc, argv); + return rm_globals.exit_code; +} + +#define check(a1, a2, a3) check_rm(globals, a1, a2, a3) +#define check2(a1) check2_rm(globals, a1) +#define checkdot(a1) checkdot_rm(globals, a1) +#define checkslash(a1) checkslash_rm(globals, a1) +#define rm_file(a1) rm_file_rm(globals, a1) +#define rm_overwrite(a1, a2) rm_overwrite_rm(globals, a1, a2) +#define rm_tree(a1) rm_tree_rm(globals, a1) +#define usage() usage_rm(globals) + + +/* RTEMS changes */ + +static int check_rm(rtems_shell_rm_globals* globals, char *, char *, struct stat *); +static int check2_rm(rtems_shell_rm_globals* globals, char **); +static void checkdot_rm(rtems_shell_rm_globals* globals, char **); +static void checkslash_rm(rtems_shell_rm_globals* globals, char **); +static void rm_file_rm(rtems_shell_rm_globals* globals, char **); +static int rm_overwrite_rm(rtems_shell_rm_globals* globals, char *, struct stat *); +static void rm_tree_rm(rtems_shell_rm_globals* globals, char **); +static void usage_rm(rtems_shell_rm_globals* globals); + +/* + * rm -- + * This rm is different from historic rm's, but is expected to match + * POSIX 1003.2 behavior. The most visible difference is that -f + * has two specific effects now, ignore non-existent files and force + * file removal. + */ +int +main_rm(rtems_shell_rm_globals* globals, int argc, char *argv[]) +{ + int ch; + char *p; + + struct getopt_data getopt_reent; + memset(&getopt_reent, 0, sizeof(getopt_data)); + + /* + * Test for the special case where the utility is called as + * "unlink", for which the functionality provided is greatly + * simplified. + */ + if ((p = rindex(argv[0], '/')) == NULL) + p = argv[0]; + else + ++p; + if (strcmp(p, "unlink") == 0) { + while (getopt_r(argc, argv, "", &getopt_reent) != -1) + usage(); + argc -= getopt_reent.optind; + argv += getopt_reent.optind; + if (argc != 1) + usage(); + rm_file(&argv[0]); + exit(eval); + } + + Pflag = rflag = 0; + while ((ch = getopt_r(argc, argv, "dfiIPRrvW", &getopt_reent)) != -1) + switch(ch) { + case 'd': + dflag = 1; + break; + case 'f': + fflag = 1; + iflag = 0; + break; + case 'i': + fflag = 0; + iflag = 1; + break; + case 'I': + Iflag = 1; + break; + case 'P': + Pflag = 1; + break; + case 'R': + case 'r': /* Compatibility. */ + rflag = 1; + break; + case 'v': + vflag = 1; + break; + case 'W': + Wflag = 1; + break; + default: + usage(); + } + argc -= getopt_reent.optind; + argv += getopt_reent.optind; + + if (argc < 1) { + if (fflag) + return (0); + usage(); + } + + checkdot(argv); + if (getenv("POSIXLY_CORRECT") == NULL) + checkslash(argv); + xuid = geteuid(); + + if (*argv) { + stdin_ok = isatty(STDIN_FILENO); + + if (Iflag) { + if (check2(argv) == 0) + exit (1); + } + if (rflag) + rm_tree(argv); + else + rm_file(argv); + } + + exit (eval); + return 0; +} + +void +rm_tree_rm(rtems_shell_rm_globals* globals, char **argv) +{ + FTS *fts; + FTSENT *p; + int needstat; + int flags; + int rval; + + /* + * Remove a file hierarchy. If forcing removal (-f), or interactive + * (-i) or can't ask anyway (stdin_ok), don't stat the file. + */ + needstat = !xuid || (!fflag && !iflag && stdin_ok); + + /* + * If the -i option is specified, the user can skip on the pre-order + * visit. The fts_number field flags skipped directories. + */ +#define SKIPPED 1 + + flags = FTS_PHYSICAL; + if (!needstat) + flags |= FTS_NOSTAT; + if (Wflag) + flags |= FTS_WHITEOUT; + if (!(fts = fts_open(argv, flags, NULL))) { + if (fflag && errno == ENOENT) + return; + err(exit_jump, 1, "fts_open"); + } + while ((p = fts_read(fts)) != NULL) { + switch (p->fts_info) { + case FTS_DNR: + if (!fflag || p->fts_errno != ENOENT) { + warnx("%s: %s", + p->fts_path, strerror(p->fts_errno)); + eval = 1; + } + continue; + case FTS_ERR: + errx(exit_jump, 1, "%s: %s", p->fts_path, strerror(p->fts_errno)); + case FTS_NS: + /* + * Assume that since fts_read() couldn't stat the + * file, it can't be unlinked. + */ + if (!needstat) + break; + if (!fflag || p->fts_errno != ENOENT) { + warnx("%s: %s", + p->fts_path, strerror(p->fts_errno)); + eval = 1; + } + continue; + case FTS_D: + /* Pre-order: give user chance to skip. */ + if (!fflag && !check(p->fts_path, p->fts_accpath, + p->fts_statp)) { + (void)fts_set(fts, p, FTS_SKIP); + p->fts_number = SKIPPED; + } +#if RTEMS_REMOVED + else if (!xuid && + (p->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) && + !(p->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)) && + chflags(p->fts_accpath, + p->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE)) < 0) + goto err; +#endif + continue; + case FTS_DP: + /* Post-order: see if user skipped. */ + if (p->fts_number == SKIPPED) + continue; + break; + default: + if (!fflag && + !check(p->fts_path, p->fts_accpath, p->fts_statp)) + continue; + } + + rval = 0; +#if RTEMS_REMOVED + if (!xuid && + (p->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) && + !(p->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE))) + rval = chflags(p->fts_accpath, + p->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE)); +#endif + if (rval == 0) { + /* + * If we can't read or search the directory, may still be + * able to remove it. Don't print out the un{read,search}able + * message unless the remove fails. + */ + switch (p->fts_info) { + case FTS_DP: + case FTS_DNR: + rval = rmdir(p->fts_accpath); + if (rval == 0 || (fflag && errno == ENOENT)) { + if (rval == 0 && vflag) + (void)printf("%s\n", + p->fts_path); + continue; + } + break; + +#if RTEMS_REMOVED + case FTS_W: + rval = undelete(p->fts_accpath); + if (rval == 0 && (fflag && errno == ENOENT)) { + if (vflag) + (void)printf("%s\n", + p->fts_path); + continue; + } + break; +#endif + + case FTS_NS: + /* + * Assume that since fts_read() couldn't stat + * the file, it can't be unlinked. + */ + if (fflag) + continue; + /* FALLTHROUGH */ + default: + if (Pflag) + if (!rm_overwrite(p->fts_accpath, NULL)) + continue; + rval = unlink(p->fts_accpath); + if (rval == 0 || (fflag && errno == ENOENT)) { + if (rval == 0 && vflag) + (void)printf("%s\n", + p->fts_path); + continue; + } + } + } +#if RTEMS_REMOVED +err: +#endif + warn("%s", p->fts_path); + eval = 1; + } + if (errno) + err(exit_jump, 1, "fts_read"); + fts_close(fts); +} + +#define S_ISWHT(m) (0) + +void +rm_file_rm(rtems_shell_rm_globals* globals, char **argv) +{ + struct stat sb; + int rval; + char *f; + + /* + * Remove a file. POSIX 1003.2 states that, by default, attempting + * to remove a directory is an error, so must always stat the file. + */ + while ((f = *argv++) != NULL) { + /* Assume if can't stat the file, can't unlink it. */ + if (lstat(f, &sb)) { +#if RTEMS_REMOVED + if (Wflag) { + sb.st_mode = S_IFWHT|S_IWUSR|S_IRUSR; + } else { +#endif + if (!fflag || errno != ENOENT) { + warn("%s", f); + eval = 1; + } + continue; +#if RTEMS_REMOVED + } +#endif + } else if (Wflag) { + warnx("%s: %s", f, strerror(EEXIST)); + eval = 1; + continue; + } + + if (S_ISDIR(sb.st_mode) && !dflag) { + warnx("%s: is a directory", f); + eval = 1; + continue; + } + if (!fflag && !S_ISWHT(sb.st_mode) && !check(f, f, &sb)) + continue; + rval = 0; +#if RTEMS_REMOVED + if (!xuid && !S_ISWHT(sb.st_mode) && + (sb.st_flags & (UF_APPEND|UF_IMMUTABLE)) && + !(sb.st_flags & (SF_APPEND|SF_IMMUTABLE))) + rval = chflags(f, sb.st_flags & ~(UF_APPEND|UF_IMMUTABLE)); +#endif + if (rval == 0) { + if (S_ISWHT(sb.st_mode)) +#if RTEMS_REMOVED + rval = undelete(f); +#endif + ; + else if (S_ISDIR(sb.st_mode)) + rval = rmdir(f); + else { + if (Pflag) + if (!rm_overwrite(f, &sb)) + continue; + rval = unlink(f); + } + } + if (rval && (!fflag || errno != ENOENT)) { + warn("%s", f); + eval = 1; + } + if (vflag && rval == 0) + (void)printf("%s\n", f); + } +} + +/* + * rm_overwrite -- + * Overwrite the file 3 times with varying bit patterns. + * + * XXX + * This is a cheap way to *really* delete files. Note that only regular + * files are deleted, directories (and therefore names) will remain. + * Also, this assumes a fixed-block file system (like FFS, or a V7 or a + * System V file system). In a logging file system, you'll have to have + * kernel support. + */ +int +rm_overwrite_rm(rtems_shell_rm_globals* globals, char *file, struct stat *sbp) +{ + struct stat sb; +#if RTEMS_REMOVED + struct statfs fsb; +#endif + off_t len; + int bsize, fd, wlen; + char *buf = NULL; + + fd = -1; + if (sbp == NULL) { + if (lstat(file, &sb)) + goto err; + sbp = &sb; + } + if (!S_ISREG(sbp->st_mode)) + return (1); + if (sbp->st_nlink > 1 && !fflag) { + warnx("%s (inode %lu): not overwritten due to multiple links", + file, sbp->st_ino); + return (0); + } + if ((fd = open(file, O_WRONLY, 0)) == -1) + goto err; +#if RTEMS_REMOVED + if (fstatfs(fd, &fsb) == -1) + goto err; + bsize = MAX(fsb.f_iosize, 1024); +#endif + bsize = 1024; + if ((buf = malloc(bsize)) == NULL) + err(exit_jump, 1, "%s: malloc", file); + +#define PASS(byte) { \ + memset(buf, byte, bsize); \ + for (len = sbp->st_size; len > 0; len -= wlen) { \ + wlen = len < bsize ? len : bsize; \ + if (write(fd, buf, wlen) != wlen) \ + goto err; \ + } \ +} + PASS(0xff); + if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET)) + goto err; + PASS(0x00); + if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET)) + goto err; + PASS(0xff); + if (!fsync(fd) && !close(fd)) { + free(buf); + return (1); + } + +err: eval = 1; + if (buf) + free(buf); + if (fd != -1) + close(fd); + warn("%s", file); + return (0); +} + +void strmode(mode_t mode, char *p); +char *fflagstostr(u_long flags); +const char *user_from_uid(uid_t uid, int nouser); + +int +check_rm(rtems_shell_rm_globals* globals, char *path, char *name, struct stat *sp) +{ + int ch, first; + char modep[15], *flagsp; + + /* Check -i first. */ + if (iflag) + (void)fprintf(stderr, "remove %s? ", path); + else { + /* + * If it's not a symbolic link and it's unwritable and we're + * talking to a terminal, ask. Symbolic links are excluded + * because their permissions are meaningless. Check stdin_ok + * first because we may not have stat'ed the file. + */ +#if RTEMS_REMOVED + if (!stdin_ok || S_ISLNK(sp->st_mode) || + (!access(name, W_OK) && + !(sp->st_flags & (SF_APPEND|SF_IMMUTABLE)) && + (!(sp->st_flags & (UF_APPEND|UF_IMMUTABLE)) || !xuid))) +#endif + if (!stdin_ok || S_ISLNK(sp->st_mode) || + (!access(name, W_OK))) + return (1); + strmode(sp->st_mode, modep); +#if RTEMS_REMOVED + if ((flagsp = fflagstostr(sp->st_flags)) == NULL) + err(exit_jump, 1, "fflagstostr"); +#else + flagsp = "no supported"; +#endif + if (Pflag) + errx(exit_jump, 1, + "%s: -P was specified, but file is not writable", + path); + (void)fprintf(stderr, "override %s%s%s/%s %s%sfor %s? ", + modep + 1, modep[9] == ' ' ? "" : " ", + user_from_uid(sp->st_uid, 0), + group_from_gid(sp->st_gid, 0), + *flagsp ? flagsp : "", *flagsp ? " " : "", + path); +#if RTEMS_REMOVED + free(flagsp); +#endif + } + (void)fflush(stderr); + + first = ch = getchar(); + while (ch != '\n' && ch != EOF) + ch = getchar(); + return (first == 'y' || first == 'Y'); +} + +#define ISSLASH(a) ((a)[0] == '/' && (a)[1] == '\0') +void +checkslash_rm(rtems_shell_rm_globals* globals, char **argv) +{ + char **t, **u; + int complained; + + complained = 0; + for (t = argv; *t;) { + if (ISSLASH(*t)) { + if (!complained++) + warnx("\"/\" may not be removed"); + eval = 1; + for (u = t; u[0] != NULL; ++u) + u[0] = u[1]; + } else { + ++t; + } + } +} + +int +check2_rm(rtems_shell_rm_globals* globals, char **argv) +{ + struct stat st; + int first; + int ch; + int fcount = 0; + int dcount = 0; + int i; + const char *dname = NULL; + + for (i = 0; argv[i]; ++i) { + if (lstat(argv[i], &st) == 0) { + if (S_ISDIR(st.st_mode)) { + ++dcount; + dname = argv[i]; /* only used if 1 dir */ + } else { + ++fcount; + } + } + } + first = 0; + while (first != 'n' && first != 'N' && first != 'y' && first != 'Y') { + if (dcount && rflag) { + fprintf(stderr, "recursively remove"); + if (dcount == 1) + fprintf(stderr, " %s", dname); + else + fprintf(stderr, " %d dirs", dcount); + if (fcount == 1) + fprintf(stderr, " and 1 file"); + else if (fcount > 1) + fprintf(stderr, " and %d files", fcount); + } else if (dcount + fcount > 3) { + fprintf(stderr, "remove %d files", dcount + fcount); + } else { + return(1); + } + fprintf(stderr, "? "); + fflush(stderr); + + first = ch = getchar(); + while (ch != '\n' && ch != EOF) + ch = getchar(); + if (ch == EOF) + break; + } + return (first == 'y' || first == 'Y'); +} + +#define ISDOT(a) ((a)[0] == '.' && (!(a)[1] || ((a)[1] == '.' && !(a)[2]))) +void +checkdot_rm(rtems_shell_rm_globals* globals, char **argv) +{ + char *p, **save, **t; + int complained; + + complained = 0; + for (t = argv; *t;) { + if ((p = strrchr(*t, '/')) != NULL) + ++p; + else + p = *t; + if (ISDOT(p)) { + if (!complained++) + warnx("\".\" and \"..\" may not be removed"); + eval = 1; + for (save = t; (t[0] = t[1]) != NULL; ++t) + continue; + t = save; + } else + ++t; + } +} + +void +usage_rm(rtems_shell_rm_globals* globals) +{ + + (void)fprintf(stderr, "%s\n%s\n", + "usage: rm [-f | -i] [-dIPRrvW] file ...", + " unlink file"); + exit(1); +} + +rtems_shell_cmd_t rtems_shell_RM_Command = { + "rm", /* name */ + "[-f | -i] [-dIPRrvW] file ...", /* usage */ + "files", /* topic */ + rtems_shell_main_rm, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_rmdir.c b/cpukit/libmisc/shell/main_rmdir.c new file mode 100644 index 0000000000..df94a7efbf --- /dev/null +++ b/cpukit/libmisc/shell/main_rmdir.c @@ -0,0 +1,51 @@ +/* + * RMDIR Shell Command Implmentation + * + * Author: Fernando RUIZ CASAS + * Work: fernando.ruiz@ctv.es + * Home: correo@fernando-ruiz.com + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include "internal.h" + +int rtems_shell_main_rmdir (int argc, char *argv[]) +{ + char *dir; + int n; + + n = 1; + while (n < argc) { + dir = argv[n++]; + if (rmdir(dir)) { + fprintf(stderr,"%s: %s: %s\n", argv[0], dir, strerror(errno)); + return -1; + } + } + return 0; +} + +rtems_shell_cmd_t rtems_shell_RMDIR_Command = { + "rmdir", /* name */ + "rmdir dir # remove directory", /* usage */ + "files", /* topic */ + rtems_shell_main_rmdir, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_route.c b/cpukit/libmisc/shell/main_route.c new file mode 100644 index 0000000000..ea503b4ef2 --- /dev/null +++ b/cpukit/libmisc/shell/main_route.c @@ -0,0 +1,153 @@ +/* + * ROUTE Command Implmentation + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <string.h> +#include <ctype.h> + +#include <netinet/in.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <net/route.h> + +#include <rtems.h> +#include <rtems/rtems_bsdnet.h> +#include <rtems/shell.h> +#include "internal.h" + +int rtems_shell_main_route( + int argc, + char *argv[] +) +{ + int cmd; + struct sockaddr_in dst; + struct sockaddr_in gw; + struct sockaddr_in netmask; + int f_host; + int f_gw = 0; + int cur_idx; + int flags; + int rc; + + memset(&dst, 0, sizeof(dst)); + memset(&gw, 0, sizeof(gw)); + memset(&netmask, 0, sizeof(netmask)); + + dst.sin_len = sizeof(dst); + dst.sin_family = AF_INET; + dst.sin_addr.s_addr = inet_addr("0.0.0.0"); + + gw.sin_len = sizeof(gw); + gw.sin_family = AF_INET; + gw.sin_addr.s_addr = inet_addr("0.0.0.0"); + + netmask.sin_len = sizeof(netmask); + netmask.sin_family = AF_INET; + netmask.sin_addr.s_addr = inet_addr("255.255.255.0"); + + if (argc < 2) { + rtems_bsdnet_show_inet_routes(); + return 0; + } + + if (strcmp(argv[1], "add") == 0) { + cmd = RTM_ADD; + } else if (strcmp(argv[1], "del") == 0) { + cmd = RTM_DELETE; + } else { + printf("invalid command: %s\n", argv[1]); + printf("\tit should be 'add' or 'del'\n"); + return -1; + } + + if (argc < 3) { + printf("not enough arguments\n"); + return -1; + } + + if (strcmp(argv[2], "-host") == 0) { + f_host = 1; + } else if (strcmp(argv[2], "-net") == 0) { + f_host = 0; + } else { + printf("Invalid type: %s\n", argv[1]); + printf("\tit should be '-host' or '-net'\n"); + return -1; + } + + if (argc < 4) { + printf("not enough arguments\n"); + return -1; + } + + inet_pton(AF_INET, argv[3], &dst.sin_addr); + + cur_idx = 4; + while(cur_idx < argc) { + if (strcmp(argv[cur_idx], "gw") == 0) { + if ((cur_idx +1) >= argc) { + printf("no gateway address\n"); + return -1; + } + f_gw = 1; + inet_pton(AF_INET, argv[cur_idx + 1], &gw.sin_addr); + cur_idx += 1; + } else if(strcmp(argv[cur_idx], "netmask") == 0) { + if ((cur_idx +1) >= argc) { + printf("no netmask address\n"); + return -1; + } + f_gw = 1; + inet_pton(AF_INET, argv[cur_idx + 1], &netmask.sin_addr); + cur_idx += 1; + } else { + printf("Unknown argument\n"); + return -1; + } + cur_idx += 1; + } + + flags = RTF_STATIC; + if (f_gw != 0) { + flags |= RTF_GATEWAY; + } + if (f_host != 0) { + flags |= RTF_HOST; + } + + rc = rtems_bsdnet_rtrequest( + cmd, + (struct sockaddr *)&dst, + (struct sockaddr *)&gw, + (struct sockaddr *)&netmask, + flags, + NULL + ); + if (rc < 0) { + printf("Error adding route\n"); + } + + return 0; +} + +rtems_shell_cmd_t rtems_shell_ROUTE_Command = { + "route", /* name */ + "TBD", /* usage */ + "network", /* topic */ + rtems_shell_main_route, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_rtc.c b/cpukit/libmisc/shell/main_rtc.c new file mode 100644 index 0000000000..139018eb13 --- /dev/null +++ b/cpukit/libmisc/shell/main_rtc.c @@ -0,0 +1,173 @@ +/** + * @file + * + * Real time clock shell command. + */ + +/* + * Copyright (c) 2009 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <inttypes.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include <rtems.h> +#include <rtems/rtc.h> +#include <rtems/error.h> +#include <rtems/shell.h> + +#define RTEMS_RTC_SHELL_ERROR( fmt, ...) \ + do { \ + printf( "error: " fmt "\n", ##__VA_ARGS__); \ + return -1; \ + } while (0) + +#define RTEMS_RTC_SHELL_ERROR_SC( sc, fmt, ...) \ + if ((sc) != RTEMS_SUCCESSFUL) { \ + printf( "error: " fmt ": %s\n", ##__VA_ARGS__, rtems_status_text( sc)); \ + return -1; \ + } + +static const char rtems_rtc_shell_usage [] = + "real time clock read and set\n" + "\n" + "rtc\n" + "\tprints the current time of day\n" + "\n" + "rtc YYYY-MM-DD [HH:MM:SS [TICKS]]\n" + "\tsets the time of day and real time clock"; + +static int rtems_rtc_shell_main( int argc, char **argv) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + rtems_time_of_day tod = { + .year = 1988, + .month = 1, + .day = 1, + .hour = 0, + .minute = 0, + .second = 0, + .ticks = 0 + }; + + if (argc == 1) { + sc = rtems_clock_get_tod( &tod); + RTEMS_RTC_SHELL_ERROR_SC( sc, "get time of day"); + + printf( + "%04" PRIu32 "-%02" PRIu32 "-%02" PRIu32 + " %02" PRIu32 ":%02" PRIu32 ":%02" PRIu32 + " %02" PRIu32 "\n", + tod.year, + tod.month, + tod.day, + tod.hour, + tod.minute, + tod.second, + tod.ticks + ); + } else if (argc > 1 && argc < 5) { + int rv = 0; + int fd = 0; + ssize_t n = 0; + uint32_t v [3]; + + if (argc > 1) { + rv = sscanf( + argv [1], + "%04" PRIu32 "-%02" PRIu32 "-%02" PRIu32, + v, + v + 1, + v + 2 + ); + + if (rv == 3) { + tod.year = v [0]; + tod.month = v [1]; + tod.day = v [2]; + } else { + RTEMS_RTC_SHELL_ERROR( "unexpected YYYY-MM-DD input: %s", argv [1]); + } + } + + if (argc > 2) { + rv = sscanf( + argv [2], + "%04" PRIu32 ":%02" PRIu32 ":%02" PRIu32, + v, + v + 1, + v + 2 + ); + + if (rv == 3) { + tod.hour = v [0]; + tod.minute = v [1]; + tod.second = v [2]; + } else { + RTEMS_RTC_SHELL_ERROR( "unexpected HH:MM:SS input: %s", argv [2]); + } + } + + if (argc > 3) { + rv = sscanf( argv [3], "%5" PRIu32, v); + + if (rv == 1) { + tod.ticks = v [0]; + } else { + RTEMS_RTC_SHELL_ERROR( "unexpected TICKS input: %s", argv [3]); + } + } + + sc = rtems_clock_set( &tod); + RTEMS_RTC_SHELL_ERROR_SC( sc, "set time of day"); + + fd = open( RTC_DEVICE_NAME, O_WRONLY); + if (fd < 0) { + perror( "error: open " RTC_DEVICE_NAME); + return -1; + } + + n = write( fd, &tod, sizeof( tod)); + if (n != (ssize_t) sizeof( tod)) { + perror( "error: write to " RTC_DEVICE_NAME); + close( fd); + return -1; + } + + rv = close( fd); + if (rv != 0) { + perror( "error: close " RTC_DEVICE_NAME); + return -1; + } + } else { + puts( rtems_rtc_shell_usage); + return -1; + } + + return 0; +} + +struct rtems_shell_cmd_tt rtems_shell_RTC_Command = { + .name = "rtc", + .usage = rtems_rtc_shell_usage, + .topic = "misc", + .command = rtems_rtc_shell_main, + .alias = NULL, + .next = NULL +}; diff --git a/cpukit/libmisc/shell/main_setenv.c b/cpukit/libmisc/shell/main_setenv.c new file mode 100644 index 0000000000..5b7c92920f --- /dev/null +++ b/cpukit/libmisc/shell/main_setenv.c @@ -0,0 +1,72 @@ +/* + * Set an environment vairable. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include "internal.h" + +int rtems_shell_main_setenv(int argc, char *argv[]) +{ + char* env = NULL; + char* string = NULL; + int len = 0; + int arg; + char* p; + + if (argc <= 2) { + printf("error: no variable or string\n"); + return 1; + } + + env = argv[1]; + + for (arg = 2; arg < argc; arg++) + len += strlen(argv[arg]); + + len += argc - 2 - 1; + + string = malloc(len + 1); + + if (!string) { + printf("error: no memory\n"); + return 1; + } + + for (arg = 2, p = string; arg < argc; arg++) { + strcpy(p, argv[arg]); + p += strlen(argv[arg]); + if (arg < (argc - 1)) { + *p = ' '; + p++; + } + } + + if (setenv(env, string, 1) < 0) { + printf( "error: %s\n", strerror(errno) ); + free( string ); + return 1; + } + + free( string ); + return 0; +} + +rtems_shell_cmd_t rtems_shell_SETENV_Command = { + "setenv", /* name */ + "setenv [var] [string]", /* usage */ + "misc", /* topic */ + rtems_shell_main_setenv, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_sleep.c b/cpukit/libmisc/shell/main_sleep.c new file mode 100644 index 0000000000..2dbb66a996 --- /dev/null +++ b/cpukit/libmisc/shell/main_sleep.c @@ -0,0 +1,74 @@ +/* + * Sleep Shell Command Implmentation + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <time.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include <rtems/stringto.h> +#include "internal.h" + +int rtems_shell_main_sleep( + int argc, + char *argv[] +) +{ + struct timespec delay; + unsigned long tmp; + + if ((argc != 2) && (argc != 3)) { + fprintf( stderr, "%s: Usage seconds [nanoseconds]\n", argv[0] ); + return -1; + } + + /* + * Convert the seconds argument to a number + */ + if ( rtems_string_to_unsigned_long(argv[1], &tmp, NULL, 0) ) { + printf( "Seconds argument (%s) is not a number\n", argv[1] ); + return -1; + } + delay.tv_sec = (time_t) tmp; + + /* + * If the user specified a nanoseconds argument, convert it + */ + delay.tv_nsec = 0; + if (argc == 3) { + if ( rtems_string_to_unsigned_long(argv[2], &tmp, NULL, 0) ) { + printf( "Seconds argument (%s) is not a number\n", argv[1] ); + return -1; + } + delay.tv_nsec = tmp; + } + + /* + * Now sleep as requested. + */ + nanosleep( &delay, NULL ); + return 0; +} + +rtems_shell_cmd_t rtems_shell_SLEEP_Command = { + "sleep", /* name */ + "sleep seconds [nanoseconds]", /* usage */ + "misc", /* topic */ + rtems_shell_main_sleep, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_stackuse.c b/cpukit/libmisc/shell/main_stackuse.c new file mode 100644 index 0000000000..4d1d944ceb --- /dev/null +++ b/cpukit/libmisc/shell/main_stackuse.c @@ -0,0 +1,44 @@ +/* + * stackuse Command Implementation + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> + +#include <rtems.h> +#include <rtems/stackchk.h> +#include <rtems/shell.h> +#include "internal.h" + +int rtems_shell_main_stackuse( + int argc __attribute__((unused)), + char *argv[] __attribute__((unused)) +) +{ + rtems_stack_checker_report_usage_with_plugin( + stdout, + (rtems_printk_plugin_t)fprintf + ); + return 0; +} + +rtems_shell_cmd_t rtems_shell_STACKUSE_Command = { + "stackuse", /* name */ + "print per thread stack usage", /* usage */ + "rtems", /* topic */ + rtems_shell_main_stackuse, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_time.c b/cpukit/libmisc/shell/main_time.c new file mode 100644 index 0000000000..7d6cf557ee --- /dev/null +++ b/cpukit/libmisc/shell/main_time.c @@ -0,0 +1,84 @@ +/* + * Time Shell Command Implmentation + * + * Author: Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include "internal.h" + +int rtems_shell_main_time( + int argc, + char *argv[] +) +{ + rtems_shell_cmd_t* shell_cmd; + int errorlevel = 0; + struct timespec start; + struct timespec end; + struct timespec period; + rtems_status_code sc; + + argc--; + + sc = rtems_clock_get_uptime(&start); + if (sc != RTEMS_SUCCESSFUL) + printf("error: cannot read time\n"); + + if (argc) { + shell_cmd = rtems_shell_lookup_cmd(argv[1]); + if ( argv[1] == NULL ) { + errorlevel = -1; + } else if ( shell_cmd == NULL ) { + errorlevel = rtems_shell_script_file(argc, &argv[1]); + } else { + errorlevel = shell_cmd->command(argc, &argv[1]); + } + } + + sc = rtems_clock_get_uptime(&end); + if (sc != RTEMS_SUCCESSFUL) + printf("error: cannot read time\n"); + + period.tv_sec = end.tv_sec - start.tv_sec; + period.tv_nsec = end.tv_nsec - start.tv_nsec; + if (period.tv_nsec < 0) + { + --period.tv_sec; + period.tv_nsec += 1000000000UL; + } + + printf("time: %li:%02li:%02li.%03li\n", + period.tv_sec / 3600, + period.tv_sec / 60, period.tv_sec % 60, + period.tv_nsec / 1000000); + + return errorlevel; +} + +rtems_shell_cmd_t rtems_shell_TIME_Command = { + "time", /* name */ + "time command [arguments...]", /* usage */ + "misc", /* topic */ + rtems_shell_main_time, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_tty.c b/cpukit/libmisc/shell/main_tty.c new file mode 100644 index 0000000000..f8313b55f8 --- /dev/null +++ b/cpukit/libmisc/shell/main_tty.c @@ -0,0 +1,44 @@ +/* + * TTY Shell Command Implmentation + * + * Author: Fernando RUIZ CASAS + * Work: fernando.ruiz@ctv.es + * Home: correo@fernando-ruiz.com + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include "internal.h" + +int rtems_shell_main_tty( + int argc __attribute__((unused)), + char *argv[] __attribute__((unused)) +) +{ + printf("%s\n", ttyname(fileno(stdin))); + return 0; +} + +rtems_shell_cmd_t rtems_shell_TTY_Command = { + "tty", /* name */ + "show ttyname", /* usage */ + "misc", /* topic */ + rtems_shell_main_tty, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_umask.c b/cpukit/libmisc/shell/main_umask.c new file mode 100644 index 0000000000..8bfbe7e443 --- /dev/null +++ b/cpukit/libmisc/shell/main_umask.c @@ -0,0 +1,62 @@ +/* + * UMASK Shell Command Implmentation + * + * Author: Fernando RUIZ CASAS + * Work: fernando.ruiz@ctv.es + * Home: correo@fernando-ruiz.com + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include <rtems/stringto.h> +#include "internal.h" + +int rtems_shell_main_umask( + int argc, + char *argv[] +) +{ + unsigned long tmp; + mode_t msk = umask(0); + + if (argc == 2) { + if ( rtems_string_to_unsigned_long(argv[1], &tmp, NULL, 0) ) { + printf( "Mask argument (%s) is not a number\n", argv[1] ); + return -1; + } + msk = (mode_t) tmp; + + } + umask(msk); + + msk = umask(0); + printf("0%o\n", (unsigned int) msk); + umask(msk); + return 0; +} + +rtems_shell_cmd_t rtems_shell_UMASK_Command = { + "umask", /* name */ + "umask [new_umask]", /* usage */ + "misc", /* topic */ + rtems_shell_main_umask, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_unmount.c b/cpukit/libmisc/shell/main_unmount.c new file mode 100644 index 0000000000..ba101dc014 --- /dev/null +++ b/cpukit/libmisc/shell/main_unmount.c @@ -0,0 +1,74 @@ +/* + * Shell Command Implmentation + * + * Author: Fernando RUIZ CASAS + * Work: fernando.ruiz@ctv.es + * Home: correo@fernando-ruiz.com + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include <rtems/shellconfig.h> +#include <rtems/fsmount.h> +#include "internal.h" + +int rtems_shell_main_unmount( + int argc, + char *argv[] +) +{ + char* mount_point = NULL; + int arg; + + for (arg = 1; arg < argc; arg++) { + if (!mount_point) + mount_point = argv[arg]; + else { + fprintf (stderr, "error: only one mount path require: %s\n", argv[arg]); + return 1; + } + } + + if (!mount_point) { + fprintf (stderr, "error: no mount point\n"); + return 1; + } + + /* + * Unmount the disk. + */ + + if (unmount (mount_point) < 0) { + fprintf (stderr, "error: unmount failed: %s: %s\n", + mount_point, strerror (errno)); + return 1; + } + + printf ("unmounted %s\n", mount_point); + + return 0; +} + +rtems_shell_cmd_t rtems_shell_UNMOUNT_Command = { + "unmount", /* name */ + "unmount path # unmount disk", /* usage */ + "files", /* topic */ + rtems_shell_main_unmount, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_unsetenv.c b/cpukit/libmisc/shell/main_unsetenv.c new file mode 100644 index 0000000000..8805ba4341 --- /dev/null +++ b/cpukit/libmisc/shell/main_unsetenv.c @@ -0,0 +1,43 @@ +/* + * Unset an environment vairable. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include "internal.h" + +int rtems_shell_main_unsetenv(int argc, char *argv[]) +{ + if (argc != 2) + { + printf ("error: only argument is the variable name\n"); + return 1; + } + + if (unsetenv (argv[1]) < 0) + { + printf ("error: %s\n", strerror (errno)); + return 1; + } + + return 0; +} + +rtems_shell_cmd_t rtems_shell_UNSETENV_Command = { + "unsetenv", /* name */ + "unsetenv [var]", /* usage */ + "misc", /* topic */ + rtems_shell_main_unsetenv, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_whoami.c b/cpukit/libmisc/shell/main_whoami.c new file mode 100644 index 0000000000..ce34ed95ca --- /dev/null +++ b/cpukit/libmisc/shell/main_whoami.c @@ -0,0 +1,48 @@ +/* + * WHOAMI Shell Command Implmentation + * + * Author: Fernando RUIZ CASAS + * Work: fernando.ruiz@ctv.es + * Home: correo@fernando-ruiz.com + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <pwd.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include "internal.h" + +int rtems_shell_main_whoami( + int argc __attribute__((unused)), + char *argv[] __attribute__((unused)) +) +{ + struct passwd *pwd; + + pwd = getpwuid(geteuid()); + printf( "%s\n", (pwd) ? pwd->pw_name : "nobody"); + return 0; +} + +rtems_shell_cmd_t rtems_shell_WHOAMI_Command = { + "whoami", /* name */ + "show current user", /* usage */ + "misc", /* topic */ + rtems_shell_main_whoami, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/main_wkspaceinfo.c b/cpukit/libmisc/shell/main_wkspaceinfo.c new file mode 100644 index 0000000000..fd7c531854 --- /dev/null +++ b/cpukit/libmisc/shell/main_wkspaceinfo.c @@ -0,0 +1,59 @@ +/* + * MALLOC_INFO Shell Command Implmentation + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <inttypes.h> + +#include <rtems.h> +#include <rtems/malloc.h> +#include <rtems/shell.h> +#include <rtems/score/protectedheap.h> +#include "internal.h" + +extern bool rtems_unified_work_area; + +void rtems_shell_print_unified_work_area_message(void) +{ + printf( "\nC Program Heap and RTEMS Workspace are %s.\n", + ((rtems_unified_work_area) ? "the same" : "separate") + ); +} + +int rtems_shell_main_wkspace_info( + int argc __attribute__((unused)), + char *argv[] __attribute__((unused)) +) +{ + Heap_Information_block info; + + rtems_shell_print_unified_work_area_message(); + + _Protected_heap_Get_information( &_Workspace_Area, &info ); + rtems_shell_print_heap_info( "free", &info.Free ); + rtems_shell_print_heap_info( "used", &info.Used ); + + return 0; +} + +rtems_shell_cmd_t rtems_shell_WKSPACE_INFO_Command = { + "wkspace", /* name */ + "Report on RTEMS Executive Workspace", /* usage */ + "rtems", /* topic */ + rtems_shell_main_wkspace_info, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/mknod-pack_dev.c b/cpukit/libmisc/shell/mknod-pack_dev.c new file mode 100644 index 0000000000..043019ad5a --- /dev/null +++ b/cpukit/libmisc/shell/mknod-pack_dev.c @@ -0,0 +1,300 @@ +/* $NetBSD: pack_dev.c,v 1.10 2009/02/13 01:37:23 lukem Exp $ */ + +/*- + * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#if 0 +#include <sys/cdefs.h> +#if !defined(lint) +__RCSID("$NetBSD: pack_dev.c,v 1.10 2009/02/13 01:37:23 lukem Exp $"); +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/stat.h> + +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "pack_dev.h" +#endif + +static pack_t pack_netbsd; +static pack_t pack_freebsd; +static pack_t pack_8_8; +static pack_t pack_12_20; +static pack_t pack_14_18; +static pack_t pack_8_24; +static pack_t pack_bsdos; +static int compare_format(const void *, const void *); + +static const char iMajorError[] = "invalid major number"; +static const char iMinorError[] = "invalid minor number"; +static const char tooManyFields[] = "too many fields for format"; + +#define makedev(x,y) rtems_filesystem_make_dev_t(x,y) +#define major(d) rtems_filesystem_dev_major_t(d) +#define minor(d) rtems_filesystem_dev_minor_t(d) + + /* exported */ +portdev_t +pack_native(int n, u_long numbers[], const char **error) +{ + portdev_t dev = 0; + + if (n == 2) { + dev = makedev(numbers[0], numbers[1]); + if ((u_long)major(dev) != numbers[0]) + *error = iMajorError; + else if ((u_long)minor(dev) != numbers[1]) + *error = iMinorError; + } else + *error = tooManyFields; + return (dev); +} + + +static portdev_t +pack_netbsd(int n, u_long numbers[], const char **error) +{ + portdev_t dev = 0; + + if (n == 2) { + dev = makedev_netbsd(numbers[0], numbers[1]); + if ((u_long)major_netbsd(dev) != numbers[0]) + *error = iMajorError; + else if ((u_long)minor_netbsd(dev) != numbers[1]) + *error = iMinorError; + } else + *error = tooManyFields; + return (dev); +} + + +#define major_freebsd(x) ((int32_t)(((x) & 0x0000ff00) >> 8)) +#define minor_freebsd(x) ((int32_t)(((x) & 0xffff00ff) >> 0)) +#define makedev_freebsd(x,y) ((portdev_t)((((x) << 8) & 0x0000ff00) | \ + (((y) << 0) & 0xffff00ff))) + +static portdev_t +pack_freebsd(int n, u_long numbers[], const char **error) +{ + portdev_t dev = 0; + + if (n == 2) { + dev = makedev_freebsd(numbers[0], numbers[1]); + if ((u_long)major_freebsd(dev) != numbers[0]) + *error = iMajorError; + if ((u_long)minor_freebsd(dev) != numbers[1]) + *error = iMinorError; + } else + *error = tooManyFields; + return (dev); +} + + +#define major_8_8(x) ((int32_t)(((x) & 0x0000ff00) >> 8)) +#define minor_8_8(x) ((int32_t)(((x) & 0x000000ff) >> 0)) +#define makedev_8_8(x,y) ((portdev_t)((((x) << 8) & 0x0000ff00) | \ + (((y) << 0) & 0x000000ff))) + +static portdev_t +pack_8_8(int n, u_long numbers[], const char **error) +{ + portdev_t dev = 0; + + if (n == 2) { + dev = makedev_8_8(numbers[0], numbers[1]); + if ((u_long)major_8_8(dev) != numbers[0]) + *error = iMajorError; + if ((u_long)minor_8_8(dev) != numbers[1]) + *error = iMinorError; + } else + *error = tooManyFields; + return (dev); +} + + +#define major_12_20(x) ((int32_t)(((x) & 0xfff00000) >> 20)) +#define minor_12_20(x) ((int32_t)(((x) & 0x000fffff) >> 0)) +#define makedev_12_20(x,y) ((portdev_t)((((x) << 20) & 0xfff00000) | \ + (((y) << 0) & 0x000fffff))) + +static portdev_t +pack_12_20(int n, u_long numbers[], const char **error) +{ + portdev_t dev = 0; + + if (n == 2) { + dev = makedev_12_20(numbers[0], numbers[1]); + if ((u_long)major_12_20(dev) != numbers[0]) + *error = iMajorError; + if ((u_long)minor_12_20(dev) != numbers[1]) + *error = iMinorError; + } else + *error = tooManyFields; + return (dev); +} + + +#define major_14_18(x) ((int32_t)(((x) & 0xfffc0000) >> 18)) +#define minor_14_18(x) ((int32_t)(((x) & 0x0003ffff) >> 0)) +#define makedev_14_18(x,y) ((portdev_t)((((x) << 18) & 0xfffc0000) | \ + (((y) << 0) & 0x0003ffff))) + +static portdev_t +pack_14_18(int n, u_long numbers[], const char **error) +{ + portdev_t dev = 0; + + if (n == 2) { + dev = makedev_14_18(numbers[0], numbers[1]); + if ((u_long)major_14_18(dev) != numbers[0]) + *error = iMajorError; + if ((u_long)minor_14_18(dev) != numbers[1]) + *error = iMinorError; + } else + *error = tooManyFields; + return (dev); +} + + +#define major_8_24(x) ((int32_t)(((x) & 0xff000000) >> 24)) +#define minor_8_24(x) ((int32_t)(((x) & 0x00ffffff) >> 0)) +#define makedev_8_24(x,y) ((portdev_t)((((x) << 24) & 0xff000000) | \ + (((y) << 0) & 0x00ffffff))) + +static portdev_t +pack_8_24(int n, u_long numbers[], const char **error) +{ + portdev_t dev = 0; + + if (n == 2) { + dev = makedev_8_24(numbers[0], numbers[1]); + if ((u_long)major_8_24(dev) != numbers[0]) + *error = iMajorError; + if ((u_long)minor_8_24(dev) != numbers[1]) + *error = iMinorError; + } else + *error = tooManyFields; + return (dev); +} + + +#define major_12_12_8(x) ((int32_t)(((x) & 0xfff00000) >> 20)) +#define unit_12_12_8(x) ((int32_t)(((x) & 0x000fff00) >> 8)) +#define subunit_12_12_8(x) ((int32_t)(((x) & 0x000000ff) >> 0)) +#define makedev_12_12_8(x,y,z) ((portdev_t)((((x) << 20) & 0xfff00000) | \ + (((y) << 8) & 0x000fff00) | \ + (((z) << 0) & 0x000000ff))) + +static portdev_t +pack_bsdos(int n, u_long numbers[], const char **error) +{ + portdev_t dev = 0; + + if (n == 2) { + dev = makedev_12_20(numbers[0], numbers[1]); + if ((u_long)major_12_20(dev) != numbers[0]) + *error = iMajorError; + if ((u_long)minor_12_20(dev) != numbers[1]) + *error = iMinorError; + } else if (n == 3) { + dev = makedev_12_12_8(numbers[0], numbers[1], numbers[2]); + if ((u_long)major_12_12_8(dev) != numbers[0]) + *error = iMajorError; + if ((u_long)unit_12_12_8(dev) != numbers[1]) + *error = "invalid unit number"; + if ((u_long)subunit_12_12_8(dev) != numbers[2]) + *error = "invalid subunit number"; + } else + *error = tooManyFields; + return (dev); +} + + + /* list of formats and pack functions */ + /* this list must be sorted lexically */ +struct format { + const char *name; + pack_t *pack; +} formats[] = { + {"386bsd", pack_8_8}, + {"4bsd", pack_8_8}, + {"bsdos", pack_bsdos}, + {"freebsd", pack_freebsd}, + {"hpux", pack_8_24}, + {"isc", pack_8_8}, + {"linux", pack_8_8}, + {"native", pack_native}, + {"netbsd", pack_netbsd}, + {"osf1", pack_12_20}, + {"sco", pack_8_8}, + {"solaris", pack_14_18}, + {"sunos", pack_8_8}, + {"svr3", pack_8_8}, + {"svr4", pack_14_18}, + {"ultrix", pack_8_8}, +}; + +static int +compare_format(const void *key, const void *element) +{ + const char *name; + const struct format *format; + + name = key; + format = element; + + return (strcmp(name, format->name)); +} + + +pack_t * +pack_find(const char *name) +{ + struct format *format; + + format = bsearch(name, formats, + sizeof(formats)/sizeof(formats[0]), + sizeof(formats[0]), compare_format); + if (format == 0) + return (NULL); + return (format->pack); +} diff --git a/cpukit/libmisc/shell/mknod-pack_dev.h b/cpukit/libmisc/shell/mknod-pack_dev.h new file mode 100644 index 0000000000..5c6d78af8b --- /dev/null +++ b/cpukit/libmisc/shell/mknod-pack_dev.h @@ -0,0 +1,52 @@ +/* $NetBSD: pack_dev.h,v 1.7 2008/04/28 20:23:09 martin Exp $ */ + +/*- + * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PACK_DEV_H +#define _PACK_DEV_H + +#ifdef __CYGWIN__ +typedef __dev32_t portdev_t; +#else +typedef dev_t portdev_t; +#endif +typedef portdev_t pack_t(int, u_long [], const char **); + +static pack_t *pack_find(const char *); +static pack_t pack_native; + +#define major_netbsd(x) ((int32_t)((((x) & 0x000fff00) >> 8))) +#define minor_netbsd(x) ((int32_t)((((x) & 0xfff00000) >> 12) | \ + (((x) & 0x000000ff) >> 0))) +#define makedev_netbsd(x,y) ((dev_t)((((x) << 8) & 0x000fff00) | \ + (((y) << 12) & 0xfff00000) | \ + (((y) << 0) & 0x000000ff))) + +#endif /* _PACK_DEV_H */ diff --git a/cpukit/libmisc/shell/pathnames-mv.h b/cpukit/libmisc/shell/pathnames-mv.h new file mode 100644 index 0000000000..a38e4e9450 --- /dev/null +++ b/cpukit/libmisc/shell/pathnames-mv.h @@ -0,0 +1,40 @@ +/* $NetBSD: pathnames.h,v 1.8 2004/08/19 22:26:07 christos Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)pathnames.h 8.1 (Berkeley) 5/31/93 + */ + +#ifdef RESCUEDIR +#define _PATH_RM RESCUEDIR "/rm" +#define _PATH_CP RESCUEDIR "/cp" +#else +#define _PATH_RM "/bin/rm" +#define _PATH_CP "/bin/cp" +#endif diff --git a/cpukit/libmisc/shell/print-ls.c b/cpukit/libmisc/shell/print-ls.c new file mode 100644 index 0000000000..c19ce9009c --- /dev/null +++ b/cpukit/libmisc/shell/print-ls.c @@ -0,0 +1,492 @@ +/* $NetBSD: print.c,v 1.40 2004/11/17 17:00:00 mycroft Exp $ */ + +/* + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Michael Fischbein. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if 0 +#include <sys/cdefs.h> +#ifndef lint +#if 0 +static char sccsid[] = "@(#)print.c 8.5 (Berkeley) 7/28/94"; +#else +__RCSID("$NetBSD: print.c,v 1.40 2004/11/17 17:00:00 mycroft Exp $"); +#endif +#endif /* not lint */ +#endif + +#include <inttypes.h> + +#include <rtems.h> +#include <rtems/libio.h> + +#include <sys/param.h> +#include <sys/stat.h> + +#include <err.h> +#include <errno.h> +#include <fts.h> +#include <grp.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +//#include <tzfile.h> +#include <unistd.h> +//#include <util.h> + +#include "extern-ls.h" + +#define DAYSPERNYEAR ((time_t)365) +#define SECSPERDAY ((time_t)60 * (time_t)60 * (time_t)24) + + +#if RTEMS_REMOVED +extern int termwidth; +#endif + +static int printaname(rtems_shell_ls_globals* globals, FTSENT *, int, int); +static void printlink(rtems_shell_ls_globals* globals, FTSENT *); +static void printtime(rtems_shell_ls_globals* globals, time_t); +static int printtype(u_int); + +#if RTEMS_REMOVED +static time_t now; +#endif + +#define IS_NOPRINT(p) ((p)->fts_number == NO_PRINT) + +void +printscol(rtems_shell_ls_globals* globals, DISPLAY *dp) +{ + FTSENT *p; + + for (p = dp->list; p; p = p->fts_link) { + if (IS_NOPRINT(p)) + continue; + (void)printaname(globals, p, dp->s_inode, dp->s_block); + (void)putchar('\n'); + } +} + +void +printlong(rtems_shell_ls_globals* globals, DISPLAY *dp) +{ + struct stat *sp; + FTSENT *p; + NAMES *np; + char buf[20]; //, szbuf[5]; + + now = time(NULL); + + if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) { +#if RTEMS_REMOVED + if (f_humanize) { + if ((humanize_number(szbuf, sizeof(szbuf), dp->stotal, + "", HN_AUTOSCALE, + (HN_DECIMAL | HN_B | HN_NOSPACE))) == -1) + err(exit_jump, 1, "humanize_number"); + (void)printf("total %s\n", szbuf); + } else { +#endif + (void)printf("total %llu\n", + (long long)(howmany(dp->btotal, blocksize))); +#if RTEMS_REMOVED + } +#endif + } + + for (p = dp->list; p; p = p->fts_link) { + if (IS_NOPRINT(p)) + continue; + sp = p->fts_statp; + if (f_inode) + (void)printf("%*lu ", dp->s_inode, sp->st_ino); + if (f_size && !f_humanize) { + (void)printf("%*llu ", dp->s_block, + (long long)howmany(sp->st_blocks, blocksize)); + } + (void)strmode(sp->st_mode, buf); + np = p->fts_pointer; + (void)printf("%s %*lu ", buf, dp->s_nlink, + (unsigned long)sp->st_nlink); + if (!f_grouponly) + (void)printf("%-*s ", dp->s_user, np->user); + (void)printf("%-*s ", dp->s_group, np->group); + if (f_flags) + (void)printf("%-*s ", dp->s_flags, np->flags); + if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode)) + (void)printf("%*"PRIu32", %*"PRIu32" ", + dp->s_major, major(sp->st_rdev), dp->s_minor, + minor(sp->st_rdev)); + else +#if RTEMS_REMOVED + if (f_humanize) { + if ((humanize_number(szbuf, sizeof(szbuf), + sp->st_size, "", HN_AUTOSCALE, + (HN_DECIMAL | HN_B | HN_NOSPACE))) == -1) + err(1, "humanize_number"); + (void)printf("%*s ", dp->s_size, szbuf); + } else { +#endif + { + unsigned long long size; + if (sp->st_size < 0) + size = sp->st_size * -1; + else + size = sp->st_size; + (void)printf("%*llu ", dp->s_size, size); + } + if (f_accesstime) + printtime(globals, sp->st_atime); + else if (f_statustime) + printtime(globals, sp->st_ctime); + else + printtime(globals, sp->st_mtime); + if (f_octal || f_octal_escape) + (void)safe_print(globals, p->fts_name); + else if (f_nonprint) + (void)printescaped(globals, p->fts_name); + else + (void)printf("%s", p->fts_name); + + if (f_type || (f_typedir && S_ISDIR(sp->st_mode))) + (void)printtype(sp->st_mode); + if (S_ISLNK(sp->st_mode)) + printlink(globals, p); + (void)putchar('\n'); + } +} + +void +printcol(rtems_shell_ls_globals* globals, DISPLAY *dp) +{ + static FTSENT **array; + static int lastentries = -1; + FTSENT *p; + int base, chcnt, col, colwidth, num; + int numcols, numrows, row; + //char szbuf[5]; + + colwidth = dp->maxlen; + if (f_inode) + colwidth += dp->s_inode + 1; + if (f_size) { + if (f_humanize) + colwidth += dp->s_size + 1; + else + colwidth += dp->s_block + 1; + } + if (f_type || f_typedir) + colwidth += 1; + + colwidth += 1; + + if (termwidth < 2 * colwidth) { + printscol(globals, dp); + return; + } + + /* + * Have to do random access in the linked list -- build a table + * of pointers. + */ + if (dp->entries > lastentries) { + lastentries = dp->entries; + if ((array = + realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) { + warn(NULL); + printscol(globals, dp); + } + } + for (p = dp->list, num = 0; p; p = p->fts_link) + if (p->fts_number != NO_PRINT) + array[num++] = p; + + numcols = termwidth / colwidth; + colwidth = termwidth / numcols; /* spread out if possible */ + numrows = num / numcols; + if (num % numcols) + ++numrows; + + if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) { +#if RTEMS_REMOVED + if (f_humanize) { + if ((humanize_number(szbuf, sizeof(szbuf), dp->stotal, + "", HN_AUTOSCALE, + (HN_DECIMAL | HN_B | HN_NOSPACE))) == -1) + err(1, "humanize_number"); + (void)printf("total %s\n", szbuf); + } else { +#endif + (void)printf("total %llu\n", + (long long)(howmany(dp->btotal, blocksize))); +#if RTEMS_REMOVED + } +#endif + } + for (row = 0; row < numrows; ++row) { + for (base = row, chcnt = col = 0; col < numcols; ++col) { + chcnt = printaname(globals, array[base], dp->s_inode, + f_humanize && 0 ? dp->s_size : dp->s_block); + if ((base += numrows) >= num) + break; + while (chcnt++ < colwidth) + (void)putchar(' '); + } + (void)putchar('\n'); + } +} + +void +printacol(rtems_shell_ls_globals* globals, DISPLAY *dp) +{ + FTSENT *p; + int chcnt, col, colwidth; + int numcols; + //char szbuf[5]; + + colwidth = dp->maxlen; + if (f_inode) + colwidth += dp->s_inode + 1; + if (f_size) { + if (f_humanize) + colwidth += dp->s_size + 1; + else + colwidth += dp->s_block + 1; + } + if (f_type || f_typedir) + colwidth += 1; + + colwidth += 1; + + if (termwidth < 2 * colwidth) { + printscol(globals, dp); + return; + } + + numcols = termwidth / colwidth; + colwidth = termwidth / numcols; /* spread out if possible */ + + if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) { +#if RTEMS_REMOVED + if (f_humanize) { + if ((humanize_number(szbuf, sizeof(szbuf), dp->stotal, + "", HN_AUTOSCALE, + (HN_DECIMAL | HN_B | HN_NOSPACE))) == -1) + err(1, "humanize_number"); + (void)printf("total %s\n", szbuf); + } else { +#endif + (void)printf("total %llu\n", + (long long)(howmany(dp->btotal, blocksize))); +#if RTEMS_REMOVED + } +#endif + } + chcnt = col = 0; + for (p = dp->list; p; p = p->fts_link) { + if (IS_NOPRINT(p)) + continue; + if (col >= numcols) { + chcnt = col = 0; + (void)putchar('\n'); + } + chcnt = printaname(globals, p, dp->s_inode, + f_humanize && 0 ? dp->s_size : dp->s_block); + while (chcnt++ < colwidth) + (void)putchar(' '); + col++; + } + (void)putchar('\n'); +} + +void +printstream(rtems_shell_ls_globals* globals, DISPLAY *dp) +{ + FTSENT *p; + int col; + int extwidth; + + extwidth = 0; + if (f_inode) + extwidth += dp->s_inode + 1; + if (f_size) { + if (f_humanize) + extwidth += dp->s_size + 1; + else + extwidth += dp->s_block + 1; + } + if (f_type) + extwidth += 1; + + for (col = 0, p = dp->list; p != NULL; p = p->fts_link) { + if (IS_NOPRINT(p)) + continue; + if (col > 0) { + (void)putchar(','), col++; + if (col + 1 + extwidth + p->fts_namelen >= termwidth) + (void)putchar('\n'), col = 0; + else + (void)putchar(' '), col++; + } + col += printaname(globals, p, dp->s_inode, + f_humanize && 0 ? dp->s_size : dp->s_block); + } + (void)putchar('\n'); +} + +/* + * print [inode] [size] name + * return # of characters printed, no trailing characters. + */ +static int +printaname(rtems_shell_ls_globals* globals, + FTSENT *p, int inodefield, int sizefield) +{ + struct stat *sp; + int chcnt; + //char szbuf[5]; + + sp = p->fts_statp; + chcnt = 0; + if (f_inode) + chcnt += printf("%*lu ", inodefield, sp->st_ino); + if (f_size) { +#if RTEMS_REMOVED + if (f_humanize) { + if ((humanize_number(szbuf, sizeof(szbuf), sp->st_size, + "", HN_AUTOSCALE, + (HN_DECIMAL | HN_B | HN_NOSPACE))) == -1) + err(1, "humanize_number"); + chcnt += printf("%*s ", sizefield, szbuf); + } else { +#endif + chcnt += printf("%*llu ", sizefield, + (long long)howmany(sp->st_blocks, blocksize)); +#if RTEMS_REMOVED + } +#endif + } + if (f_octal || f_octal_escape) + chcnt += safe_print(globals, p->fts_name); + else if (f_nonprint) + chcnt += printescaped(globals, p->fts_name); + else + chcnt += printf("%s", p->fts_name); + if (f_type || (f_typedir && S_ISDIR(sp->st_mode))) + chcnt += printtype(sp->st_mode); + return (chcnt); +} + +static void +printtime(rtems_shell_ls_globals* globals, time_t ftime) +{ + int i; + char *longstring; + + longstring = ctime(&ftime); + for (i = 4; i < 11; ++i) + (void)putchar(longstring[i]); + +#define SIXMONTHS ((DAYSPERNYEAR / 2) * SECSPERDAY) + if (f_sectime) + for (i = 11; i < 24; i++) + (void)putchar(longstring[i]); + else if (ftime + SIXMONTHS > now && ftime - SIXMONTHS < now) + for (i = 11; i < 16; ++i) + (void)putchar(longstring[i]); + else { + (void)putchar(' '); + for (i = 20; i < 24; ++i) + (void)putchar(longstring[i]); + } + (void)putchar(' '); +} + +static int +printtype(u_int mode) +{ + switch (mode & S_IFMT) { + case S_IFDIR: + (void)putchar('/'); + return (1); + case S_IFIFO: + (void)putchar('|'); + return (1); + case S_IFLNK: + (void)putchar('@'); + return (1); + case S_IFSOCK: + (void)putchar('='); + return (1); +#if RTEMS_REMOVED + case S_IFWHT: + (void)putchar('%'); + return (1); +#endif + } + if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { + (void)putchar('*'); + return (1); + } + return (0); +} + +static void +printlink(rtems_shell_ls_globals* globals, FTSENT *p) +{ + int lnklen; + char name[MAXPATHLEN + 1], path[MAXPATHLEN + 1]; + + if (p->fts_level == FTS_ROOTLEVEL) + (void)snprintf(name, sizeof(name), "%s", p->fts_name); + else + (void)snprintf(name, sizeof(name), + "%s/%s", p->fts_parent->fts_accpath, p->fts_name); + if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) { + (void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno)); + return; + } + path[lnklen] = '\0'; + (void)printf(" -> "); + if (f_octal || f_octal_escape) + (void)safe_print(globals, path); + else if (f_nonprint) + (void)printescaped(globals, path); + else + (void)printf("%s", path); +} diff --git a/cpukit/libmisc/shell/print_heapinfo.c b/cpukit/libmisc/shell/print_heapinfo.c new file mode 100644 index 0000000000..ad6db121d2 --- /dev/null +++ b/cpukit/libmisc/shell/print_heapinfo.c @@ -0,0 +1,37 @@ +/* + * Print Heap Information Structure + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <inttypes.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include "internal.h" + +void rtems_shell_print_heap_info( + const char *c, + Heap_Information *h +) +{ + printf( + "Number of %s blocks: %" PRId32 "\n" + "Largest %s block: %" PRId32 "\n" + "Total bytes %s: %" PRId32 "\n", + c, h->number, + c, h->largest, + c, h->total + ); +} diff --git a/cpukit/libmisc/shell/pwcache.c b/cpukit/libmisc/shell/pwcache.c new file mode 100644 index 0000000000..47b8e96fc6 --- /dev/null +++ b/cpukit/libmisc/shell/pwcache.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)pwcache.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/lib/libc/gen/pwcache.c,v 1.11 2007/01/09 00:27:55 imp Exp $"); + +#include <sys/types.h> + +#include <grp.h> +#include <pwd.h> +#include <stdio.h> +#include <string.h> +//#include <utmp.h> + +#define UT_NAMESIZE 64 + +#define NCACHE 64 /* power of 2 */ +#define MASK (NCACHE - 1) /* bits to store with */ + +const char * +user_from_uid(uid_t uid, int nouser) +{ + static struct ncache { + uid_t uid; + int found; + char name[UT_NAMESIZE + 1]; + } c_uid[NCACHE]; + static int pwopen; + struct passwd *pw; + struct ncache *cp; + + cp = c_uid + (uid & MASK); + if (cp->uid != uid || !*cp->name) { + if (pwopen == 0) { + //setpassent(1); + pwopen = 1; + } + pw = getpwuid(uid); + cp->uid = uid; + if (pw != NULL) { + cp->found = 1; + (void)strncpy(cp->name, pw->pw_name, UT_NAMESIZE); + cp->name[UT_NAMESIZE] = '\0'; + } else { + cp->found = 0; + (void)snprintf(cp->name, UT_NAMESIZE, "%u", uid); + if (nouser) + return (NULL); + } + } + return ((nouser && !cp->found) ? NULL : cp->name); +} + +char * +group_from_gid(gid_t gid, int nogroup) +{ + static struct ncache { + gid_t gid; + int found; + char name[UT_NAMESIZE + 1]; + } c_gid[NCACHE]; + static int gropen; + struct group *gr; + struct ncache *cp; + + cp = c_gid + (gid & MASK); + if (cp->gid != gid || !*cp->name) { + if (gropen == 0) { + //setgroupent(1); + gropen = 1; + } + gr = getgrgid(gid); + cp->gid = gid; + if (gr != NULL) { + cp->found = 1; + (void)strncpy(cp->name, gr->gr_name, UT_NAMESIZE); + cp->name[UT_NAMESIZE] = '\0'; + } else { + cp->found = 0; + (void)snprintf(cp->name, UT_NAMESIZE, "%u", gid); + if (nogroup) + return (NULL); + } + } + return ((nogroup && !cp->found) ? NULL : cp->name); +} + diff --git a/cpukit/libmisc/shell/shell.c b/cpukit/libmisc/shell/shell.c new file mode 100644 index 0000000000..bcc146731b --- /dev/null +++ b/cpukit/libmisc/shell/shell.c @@ -0,0 +1,987 @@ +/* + * + * Instantatiate a new terminal shell. + * + * Author: + * + * WORK: fernando.ruiz@ctv.es + * HOME: correo@fernando-ruiz.com + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <time.h> + +#include <rtems.h> +#include <rtems/error.h> +#include <rtems/libio.h> +#include <rtems/libio_.h> +#include <rtems/system.h> +#include <rtems/shell.h> +#include <rtems/shellconfig.h> +#include <rtems/console.h> +#include "internal.h" + +#include <termios.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <sys/stat.h> +#include <unistd.h> +#include <errno.h> +#include <pwd.h> + +rtems_shell_env_t rtems_global_shell_env = { + .magic = rtems_build_name('S', 'E', 'N', 'V'), + .devname = CONSOLE_DEVICE_NAME, + .taskname = "SHGL", + .exit_shell = false, + .forever = true, + .errorlevel = -1, + .echo = false, + .cwd = "/", + .input = NULL, + .output = NULL, + .output_append = false, + .wake_on_end = RTEMS_ID_NONE, + .login_check = NULL +}; + +rtems_shell_env_t *rtems_current_shell_env = &rtems_global_shell_env; + +/* + * Initialize the shell user/process environment information + */ +rtems_shell_env_t *rtems_shell_init_env( + rtems_shell_env_t *shell_env_p +) +{ + rtems_shell_env_t *shell_env; + + shell_env = malloc(sizeof(rtems_shell_env_t)); + if ( !shell_env ) + return NULL; + if ( !shell_env_p ) { + *shell_env = rtems_global_shell_env; + } else { + *shell_env = *shell_env_p; + } + shell_env->taskname = NULL; + + return shell_env; +} + +/* + * Completely free a shell_env_t and all associated memory + */ +void rtems_shell_env_free( + void *ptr +) +{ + rtems_shell_env_t *shell_env; + shell_env = (rtems_shell_env_t *) ptr; + + if ( !ptr ) + return; + + if ( shell_env->input ) + free((void *)shell_env->input); + if ( shell_env->output ) + free((void *)shell_env->output); + free( ptr ); +} + +/* + * Get a line of user input with modest features + */ +int rtems_shell_line_editor( + char *cmds[], + int count, + int size, + const char *prompt, + FILE *in, + FILE *out +) +{ + unsigned int extended_key; + int c; + int col; + int last_col; + int output; + char line[size]; + char new_line[size]; + int up; + int cmd = -1; + int inserting = 1; + + output = (out && isatty(fileno(in))); + + col = last_col = 0; + + tcdrain(fileno(in)); + if (out) + tcdrain(fileno(out)); + + if (output && prompt) + fprintf(out, "\r%s", prompt); + + line[0] = 0; + new_line[0] = 0; + + for (;;) { + + if (output) + fflush(out); + + extended_key = rtems_shell_getchar(in); + + if (extended_key == EOF) + return -2; + + c = extended_key & RTEMS_SHELL_KEYS_NORMAL_MASK; + + /* + * Make the extended_key usable as a boolean. + */ + extended_key &= ~RTEMS_SHELL_KEYS_NORMAL_MASK; + + up = 0; + + if (extended_key) + { + switch (c) + { + case RTEMS_SHELL_KEYS_END: + if (output) + fprintf(out, "%s", line + col); + col = (int) strlen (line); + break; + + case RTEMS_SHELL_KEYS_HOME: + if (output) { + if (prompt) + fprintf(out,"\r%s", prompt); + } + col = 0; + break; + + case RTEMS_SHELL_KEYS_LARROW: + if (col > 0) + { + col--; + if (output) + fputc('\b', out); + } + break; + + case RTEMS_SHELL_KEYS_RARROW: + if ((col < size) && (line[col] != '\0')) + { + if (output) + fprintf(out, "%c", line[col]); + col++; + } + break; + + case RTEMS_SHELL_KEYS_UARROW: + if ((cmd >= (count - 1)) || (strlen(cmds[cmd + 1]) == 0)) { + if (output) + fputc('\x7', out); + break; + } + + up = 1; + + /* drop through */ + case RTEMS_SHELL_KEYS_DARROW: + + { + int last_cmd = cmd; + int clen = strlen (line); + + if (prompt) + clen += strlen(prompt); + + if (up) { + cmd++; + } else { + if (cmd < 0) { + if (output) + fprintf(out, "\x7"); + break; + } + else + cmd--; + } + + if ((last_cmd < 0) || (strcmp(cmds[last_cmd], line) != 0)) + memcpy (new_line, line, size); + + if (cmd < 0) + memcpy (line, new_line, size); + else + memcpy (line, cmds[cmd], size); + + col = strlen (line); + + if (output) { + fprintf(out,"\r%*c", clen, ' '); + fprintf(out,"\r%s%s", prompt, line); + } + } + break; + + case RTEMS_SHELL_KEYS_DEL: + if (line[col] != '\0') + { + int end; + int bs; + strcpy (&line[col], &line[col + 1]); + if (output) { + fprintf(out,"\r%s%s ", prompt, line); + end = (int) strlen (line); + for (bs = 0; bs < ((end - col) + 1); bs++) + fputc('\b', out); + } + } + break; + + case RTEMS_SHELL_KEYS_INS: + inserting = inserting ? 0 : 1; + break; + } + } + else + { + switch (c) + { + case 1:/*Control-a*/ + if (output) { + if (prompt) + fprintf(out,"\r%s", prompt); + } + col = 0; + break; + + case 5:/*Control-e*/ + if (output) + fprintf(out, "%s", line + col); + col = (int) strlen (line); + break; + + case 11:/*Control-k*/ + if (line[col]) { + if (output) { + int end = strlen(line); + int bs; + fprintf(out,"%*c", end - col, ' '); + for (bs = 0; bs < (end - col); bs++) + fputc('\b', out); + } + line[col] = '\0'; + } + break; + + case 0x04:/*Control-d*/ + if (strlen(line)) + break; + case EOF: + if (output) + fputc('\n', out); + return -2; + + case '\f': + if (output) { + int end; + int bs; + fputc('\f',out); + fprintf(out,"\r%s%s", prompt, line); + end = (int) strlen (line); + for (bs = 0; bs < (end - col); bs++) + fputc('\b', out); + } + break; + + case '\b': + case '\x7f': + if (col > 0) + { + int bs; + col--; + strcpy (line + col, line + col + 1); + if (output) { + fprintf(out,"\b%s \b", line + col); + for (bs = 0; bs < ((int) strlen (line) - col); bs++) + fputc('\b', out); + } + } + break; + + case '\n': + case '\r': + { + /* + * Process the command. + */ + if (output) + fprintf(out,"\n"); + + /* + * Only process the command if we have a command and it is not + * repeated in the history. + */ + if (strlen(line) == 0) { + cmd = -1; + } else { + if ((cmd < 0) || (strcmp(line, cmds[cmd]) != 0)) { + if (count > 1) + memmove(cmds[1], cmds[0], (count - 1) * size); + memmove (cmds[0], line, size); + cmd = 0; + } + } + } + return cmd; + + default: + if ((col < (size - 1)) && (c >= ' ') && (c <= '~')) { + int end = strlen (line); + if (inserting && (col < end) && (end < size)) { + int ch, bs; + for (ch = end + 1; ch > col; ch--) + line[ch] = line[ch - 1]; + if (output) { + fprintf(out, "%s", line + col); + for (bs = 0; bs < (end - col + 1); bs++) + fputc('\b', out); + } + } + line[col++] = c; + if (col > end) + line[col] = '\0'; + if (output) + fputc(c, out); + } + break; + } + } + } + return -2; +} + +/* ----------------------------------------------- * + * - The shell TASK + * Poor but enough.. + * TODO: Redirection. Tty Signals. ENVVARs. Shell language. + * ----------------------------------------------- */ + +void rtems_shell_init_issue(void) +{ + static bool issue_inited=false; + struct stat buf; + + if (issue_inited) + return; + issue_inited = true; + + /* dummy call to init /etc dir */ + getpwnam("root"); + + if (stat("/etc/issue",&buf)) { + rtems_shell_write_file("/etc/issue", + "\n" + "Welcome to @V\\n" + "Login into @S\\n"); + } + + if (stat("/etc/issue.net",&buf)) { + rtems_shell_write_file("/etc/issue.net", + "\n" + "Welcome to %v\n" + "running on %m\n"); + } +} + +static bool rtems_shell_login(FILE * in,FILE * out) { + FILE *fd; + int c; + time_t t; + + rtems_shell_init_issue(); + setuid(0); + setgid(0); + rtems_current_user_env->euid = + rtems_current_user_env->egid =0; + + if (out) { + if ((rtems_current_shell_env->devname[5]!='p')|| + (rtems_current_shell_env->devname[6]!='t')|| + (rtems_current_shell_env->devname[7]!='y')) { + fd = fopen("/etc/issue","r"); + if (fd) { + while ((c=fgetc(fd))!=EOF) { + if (c=='@') { + switch(c=fgetc(fd)) { + case 'L': + fprintf(out,"%s",rtems_current_shell_env->devname); + break; + case 'B': + fprintf(out,"0"); + break; + case 'T': + case 'D': + time(&t); + fprintf(out,"%s",ctime(&t)); + break; + case 'S': + fprintf(out,"RTEMS"); + break; + case 'V': + fprintf(out,"%s\n%s",_RTEMS_version, _Copyright_Notice); + break; + case '@': + fprintf(out,"@"); + break; + default : + fprintf(out,"@%c",c); + break; + } + } else if (c=='\\') { + switch(c=fgetc(fd)) { + case '\\': fprintf(out,"\\"); break; + case 'b': fprintf(out,"\b"); break; + case 'f': fprintf(out,"\f"); break; + case 'n': fprintf(out,"\n"); break; + case 'r': fprintf(out,"\r"); break; + case 's': fprintf(out," "); break; + case 't': fprintf(out,"\t"); break; + case '@': fprintf(out,"@"); break; + } + } else { + fputc(c,out); + } + } + fclose(fd); + } + } else { + fd = fopen("/etc/issue.net","r"); + if (fd) { + while ((c=fgetc(fd))!=EOF) { + if (c=='%') { + switch(c=fgetc(fd)) { + case 't': + fprintf(out,"%s",rtems_current_shell_env->devname); + break; + case 'h': + fprintf(out,"0"); + break; + case 'D': + fprintf(out," "); + break; + case 'd': + time(&t); + fprintf(out,"%s",ctime(&t)); + break; + case 's': + fprintf(out,"RTEMS"); + break; + case 'm': + fprintf(out,"(" CPU_NAME "/" CPU_MODEL_NAME ")"); + break; + case 'r': + fprintf(out,_RTEMS_version); + break; + case 'v': + fprintf(out,"%s\n%s",_RTEMS_version,_Copyright_Notice); + break; + case '%':fprintf(out,"%%"); + break; + default: + fprintf(out,"%%%c",c); + break; + } + } else { + fputc(c,out); + } + } + fclose(fd); + } + } + } + + return rtems_shell_login_prompt( + in, + out, + rtems_current_shell_env->devname, + rtems_current_shell_env->login_check + ); +} + +#if defined(SHELL_DEBUG) +void rtems_shell_print_env( + rtems_shell_env_t * shell_env +) +{ + if ( !shell_env ) { + printk( "shell_env is NULL\n" ); + return; + } + printk( "shell_env=%p\n" + "shell_env->magic=0x%08x\t" + "shell_env->devname=%s\n" + "shell_env->taskname=%s\t" + "shell_env->exit_shell=%d\t" + "shell_env->forever=%d\n", + shell_env->magic, + shell_env->devname, + ((shell_env->taskname) ? shell_env->taskname : "NOT SET"), + shell_env->exit_shell, + shell_env->forever + ); +} +#endif + +rtems_task rtems_shell_task(rtems_task_argument task_argument) +{ + rtems_shell_env_t *shell_env = (rtems_shell_env_t*) task_argument; + rtems_id wake_on_end = shell_env->wake_on_end; + rtems_shell_main_loop( shell_env ); + if (wake_on_end != RTEMS_INVALID_ID) + rtems_event_send (wake_on_end, RTEMS_EVENT_1); + rtems_task_delete( RTEMS_SELF ); +} + +#define RTEMS_SHELL_MAXIMUM_ARGUMENTS (128) +#define RTEMS_SHELL_CMD_SIZE (128) +#define RTEMS_SHELL_CMD_COUNT (32) +#define RTEMS_SHELL_PROMPT_SIZE (128) + +bool rtems_shell_main_loop( + rtems_shell_env_t *shell_env_arg +) +{ + rtems_shell_env_t *shell_env; + rtems_shell_cmd_t *shell_cmd; + rtems_status_code sc; + struct termios term; + struct termios previous_term; + char *prompt = NULL; + int cmd; + int cmd_count = 1; /* assume a script and so only 1 command line */ + char *cmds[RTEMS_SHELL_CMD_COUNT]; + char *cmd_argv; + int argc; + char *argv[RTEMS_SHELL_MAXIMUM_ARGUMENTS]; + bool result = true; + bool input_file = false; + int line = 0; + FILE *stdinToClose = NULL; + FILE *stdoutToClose = NULL; + + rtems_shell_initialize_command_set(); + + shell_env = + rtems_current_shell_env = rtems_shell_init_env( shell_env_arg ); + + /* + * @todo chrisj + * Remove the use of task variables. Change to have a single + * allocation per shell and then set into a notepad register + * in the TCB. Provide a function to return the pointer. + * Task variables are a virus to embedded systems software. + */ + sc = rtems_task_variable_add( + RTEMS_SELF, + (void*)&rtems_current_shell_env, + rtems_shell_env_free + ); + if (sc != RTEMS_SUCCESSFUL) { + rtems_error(sc,"rtems_task_variable_add(current_shell_env):"); + return false; + } + + setuid(0); + setgid(0); + + rtems_current_user_env->euid = rtems_current_user_env->egid = 0; + + fileno(stdout); + + /* fprintf( stderr, + "-%s-%s-\n", shell_env->input, shell_env->output ); + */ + + if (shell_env->output && strcmp(shell_env->output, "stdout") != 0) { + if (strcmp(shell_env->output, "stderr") == 0) { + stdout = stderr; + } else if (strcmp(shell_env->output, "/dev/null") == 0) { + fclose (stdout); + } else { + FILE *output = fopen(shell_env_arg->output, + shell_env_arg->output_append ? "a" : "w"); + if (!output) { + fprintf(stderr, "shell: open output %s failed: %s\n", + shell_env_arg->output, strerror(errno)); + return false; + } + stdout = output; + stdoutToClose = output; + } + } + + if (shell_env->input && strcmp(shell_env_arg->input, "stdin") != 0) { + FILE *input = fopen(shell_env_arg->input, "r"); + if (!input) { + fprintf(stderr, "shell: open input %s failed: %s\n", + shell_env_arg->input, strerror(errno)); + return false; + } + stdin = input; + stdinToClose = input; + shell_env->forever = false; + input_file =true; + } + else { + /* make a raw terminal,Linux Manuals */ + if (tcgetattr(fileno(stdin), &previous_term) >= 0) { + term = previous_term; + term.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); + term.c_oflag &= ~OPOST; + term.c_oflag |= (OPOST|ONLCR); /* But with cr+nl on output */ + term.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); + term.c_cflag |= CLOCAL | CREAD; + term.c_cc[VMIN] = 1; + term.c_cc[VTIME] = 0; + if (tcsetattr (fileno(stdin), TCSADRAIN, &term) < 0) { + fprintf(stderr, + "shell:cannot set terminal attributes(%s)\n",shell_env->devname); + } + } + cmd_count = RTEMS_SHELL_CMD_COUNT; + prompt = malloc(RTEMS_SHELL_PROMPT_SIZE); + if (!prompt) + fprintf(stderr, + "shell:cannot allocate prompt memory\n"); + } + + setvbuf(stdin,NULL,_IONBF,0); /* Not buffered*/ + setvbuf(stdout,NULL,_IONBF,0); /* Not buffered*/ + + rtems_shell_initialize_command_set(); + + /* + * Allocate the command line buffers. + */ + cmd_argv = malloc (RTEMS_SHELL_CMD_SIZE); + if (!cmd_argv) { + fprintf(stderr, "no memory for command line buffers\n" ); + } + + cmds[0] = calloc (cmd_count, RTEMS_SHELL_CMD_SIZE); + if (!cmds[0]) { + fprintf(stderr, "no memory for command line buffers\n" ); + } + + if (cmd_argv && cmds[0]) { + + memset (cmds[0], 0, cmd_count * RTEMS_SHELL_CMD_SIZE); + + for (cmd = 1; cmd < cmd_count; cmd++) { + cmds[cmd] = cmds[cmd - 1] + RTEMS_SHELL_CMD_SIZE; + } + + do { + /* Set again root user and root filesystem, side effect of set_priv..*/ + sc = rtems_libio_set_private_env(); + if (sc != RTEMS_SUCCESSFUL) { + rtems_error(sc,"rtems_libio_set_private_env():"); + result = false; + break; + } + + /* + * By using result here, we can fall to the bottom of the + * loop when the connection is dropped during login and + * keep on trucking. + */ + if (shell_env->login_check != NULL) { + result = rtems_shell_login(stdin,stdout); + } else { + result = true; + } + + if (result) { + const char *c; + memset (cmds[0], 0, cmd_count * RTEMS_SHELL_CMD_SIZE); + if (!input_file) { + rtems_shell_cat_file(stdout,"/etc/motd"); + fprintf(stdout, "\n" + "RTEMS SHELL (Ver.1.0-FRC):%s. " \ + __DATE__". 'help' to list commands.\n", + shell_env->devname); + } + + if (input_file) + chdir(shell_env->cwd); + else + chdir("/"); /* XXX: chdir to getpwent homedir */ + + shell_env->exit_shell = false; + + for (;;) { + int cmd; + + /* Prompt section */ + if (prompt) { + rtems_shell_get_prompt(shell_env, prompt, + RTEMS_SHELL_PROMPT_SIZE); + } + + /* getcmd section */ + cmd = rtems_shell_line_editor(cmds, cmd_count, + RTEMS_SHELL_CMD_SIZE, prompt, + stdin, stdout); + + if (cmd == -1) + continue; /* empty line */ + + if (cmd == -2) + break; /*EOF*/ + + line++; + + if (shell_env->echo) + fprintf(stdout, "%d: %s\n", line, cmds[cmd]); + + /* evaluate cmd section */ + c = cmds[cmd]; + while (*c) { + if (!isblank((unsigned char)*c)) + break; + c++; + } + + if (*c == '\0') /* empty line */ + continue; + + if (*c == '#') { /* comment character */ + cmds[cmd][0] = 0; + continue; + } + + if (!strcmp(cmds[cmd],"bye") || !strcmp(cmds[cmd],"exit")) { + fprintf(stdout, "Shell exiting\n" ); + break; + } else if (!strcmp(cmds[cmd],"shutdown")) { /* exit application */ + fprintf(stdout, "System shutting down at user request\n" ); + exit(0); + } + + /* exec cmd section */ + /* TODO: + * To avoid user crash catch the signals. + * Open a new stdio files with posibility of redirection * + * Run in a new shell task background. (unix &) + * Resuming. A little bash. + */ + memcpy (cmd_argv, cmds[cmd], RTEMS_SHELL_CMD_SIZE); + if (!rtems_shell_make_args(cmd_argv, &argc, argv, + RTEMS_SHELL_MAXIMUM_ARGUMENTS)) { + shell_cmd = rtems_shell_lookup_cmd(argv[0]); + if ( argv[0] == NULL ) { + shell_env->errorlevel = -1; + } else if ( shell_cmd == NULL ) { + shell_env->errorlevel = rtems_shell_script_file(argc, argv); + } else { + shell_env->errorlevel = shell_cmd->command(argc, argv); + } + } + + /* end exec cmd section */ + if (shell_env->exit_shell) + break; + } + + fflush( stdout ); + fflush( stderr ); + } + } while (result && shell_env->forever); + + } + + if (cmds[0]) + free (cmds[0]); + if (cmd_argv) + free (cmd_argv); + if (prompt) + free (prompt); + + if (stdinToClose) { + fclose( stdinToClose ); + } else { + if (tcsetattr(fileno(stdin), TCSADRAIN, &previous_term) < 0) { + fprintf( + stderr, + "shell: cannot reset terminal attributes (%s)\n", + shell_env->devname + ); + } + } + if ( stdoutToClose ) + fclose( stdoutToClose ); + return result; +} + +/* ----------------------------------------------- */ +static rtems_status_code rtems_shell_run ( + const char *task_name, + size_t task_stacksize, + rtems_task_priority task_priority, + const char *devname, + bool forever, + bool wait, + const char *input, + const char *output, + bool output_append, + rtems_id wake_on_end, + bool echo, + rtems_shell_login_check_t login_check +) +{ + rtems_id task_id; + rtems_status_code sc; + rtems_shell_env_t *shell_env; + rtems_name name; + + if ( task_name && strlen(task_name) >= 4) + name = rtems_build_name( + task_name[0], task_name[1], task_name[2], task_name[3]); + else + name = rtems_build_name( 'S', 'E', 'N', 'V' ); + + sc = rtems_task_create( + name, + task_priority, + task_stacksize, + RTEMS_PREEMPT | RTEMS_TIMESLICE | RTEMS_NO_ASR, + RTEMS_LOCAL | RTEMS_FLOATING_POINT, + &task_id + ); + if (sc != RTEMS_SUCCESSFUL) { + rtems_error(sc,"creating task %s in shell_init()",task_name); + return sc; + } + + shell_env = rtems_shell_init_env( NULL ); + if ( !shell_env ) { + rtems_error(RTEMS_NO_MEMORY, + "allocating shell_env %s in shell_init()",task_name); + return RTEMS_NO_MEMORY; + } + shell_env->devname = devname; + shell_env->taskname = task_name; + shell_env->exit_shell = false; + shell_env->forever = forever; + shell_env->echo = echo; + shell_env->input = strdup (input); + shell_env->output = strdup (output); + shell_env->output_append = output_append; + shell_env->wake_on_end = wake_on_end; + shell_env->login_check = login_check; + + getcwd(shell_env->cwd, sizeof(shell_env->cwd)); + + sc = rtems_task_start(task_id, rtems_shell_task, + (rtems_task_argument) shell_env); + if (sc != RTEMS_SUCCESSFUL) { + rtems_error(sc,"starting task %s in shell_init()",task_name); + return sc; + } + + if (wait) { + rtems_event_set out; + sc = rtems_event_receive (RTEMS_EVENT_1, RTEMS_WAIT, 0, &out); + } + + return 0; +} + +rtems_status_code rtems_shell_init( + const char *task_name, + size_t task_stacksize, + rtems_task_priority task_priority, + const char *devname, + bool forever, + bool wait, + rtems_shell_login_check_t login_check +) +{ + rtems_id to_wake = RTEMS_ID_NONE; + + if ( wait ) + to_wake = rtems_task_self(); + + return rtems_shell_run( + task_name, /* task_name */ + task_stacksize, /* task_stacksize */ + task_priority, /* task_priority */ + devname, /* devname */ + forever, /* forever */ + wait, /* wait */ + "stdin", /* input */ + "stdout", /* output */ + false, /* output_append */ + to_wake, /* wake_on_end */ + false, /* echo */ + login_check /* login check */ + ); +} + +rtems_status_code rtems_shell_script ( + const char *task_name, + size_t task_stacksize, + rtems_task_priority task_priority, + const char* input, + const char* output, + bool output_append, + bool wait, + bool echo +) +{ + rtems_id current_task = RTEMS_INVALID_ID; + rtems_status_code sc; + + if (wait) { + sc = rtems_task_ident (RTEMS_SELF, RTEMS_LOCAL, ¤t_task); + if (sc != RTEMS_SUCCESSFUL) + return sc; + } + + sc = rtems_shell_run( + task_name, /* task_name */ + task_stacksize, /* task_stacksize */ + task_priority, /* task_priority */ + NULL, /* devname */ + 0, /* forever */ + wait, /* wait */ + input, /* input */ + output, /* output */ + output_append, /* output_append */ + current_task, /* wake_on_end */ + echo, /* echo */ + NULL /* login check */ + ); + if (sc != RTEMS_SUCCESSFUL) + return sc; + + return sc; +} diff --git a/cpukit/libmisc/shell/shell.h b/cpukit/libmisc/shell/shell.h new file mode 100644 index 0000000000..759bf71589 --- /dev/null +++ b/cpukit/libmisc/shell/shell.h @@ -0,0 +1,292 @@ +/** + * @file rtems/shell.h + * + * Instantatiate a new terminal shell. + */ + +/* + * Author: + * + * WORK: fernando.ruiz@ctv.es + * HOME: correo@fernando-ruiz.com + * + * Thanks at: + * Chris Johns + * + * $Id$ + */ + +#ifndef __RTEMS_SHELL_H__ +#define __RTEMS_SHELL_H__ + +#include <rtems.h> +#include <stdio.h> +#include <termios.h> +#include <rtems/fs.h> +#include <rtems/libio.h> +#include <rtems/chain.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Some key labels to define special keys. + */ + +#define RTEMS_SHELL_KEYS_EXTENDED (0x8000) +#define RTEMS_SHELL_KEYS_NORMAL_MASK (0x00ff) +#define RTEMS_SHELL_KEYS_INS (0) +#define RTEMS_SHELL_KEYS_DEL (1) +#define RTEMS_SHELL_KEYS_UARROW (2) +#define RTEMS_SHELL_KEYS_DARROW (3) +#define RTEMS_SHELL_KEYS_LARROW (4) +#define RTEMS_SHELL_KEYS_RARROW (5) +#define RTEMS_SHELL_KEYS_HOME (6) +#define RTEMS_SHELL_KEYS_END (7) +#define RTEMS_SHELL_KEYS_F1 (8) +#define RTEMS_SHELL_KEYS_F2 (9) +#define RTEMS_SHELL_KEYS_F3 (10) +#define RTEMS_SHELL_KEYS_F4 (11) +#define RTEMS_SHELL_KEYS_F5 (12) +#define RTEMS_SHELL_KEYS_F6 (13) +#define RTEMS_SHELL_KEYS_F7 (14) +#define RTEMS_SHELL_KEYS_F8 (15) +#define RTEMS_SHELL_KEYS_F9 (16) +#define RTEMS_SHELL_KEYS_F10 (17) + +typedef bool (*rtems_shell_login_check_t)( + const char * /* user */, + const char * /* passphrase */ +); + +bool rtems_shell_login_prompt( + FILE *in, + FILE *out, + const char *device, + rtems_shell_login_check_t check +); + +bool rtems_shell_login_check( + const char *user, + const char *passphrase +); + +typedef int (*rtems_shell_command_t)(int argc, char **argv); + +struct rtems_shell_cmd_tt; +typedef struct rtems_shell_cmd_tt rtems_shell_cmd_t; + +struct rtems_shell_cmd_tt { + const char *name; + const char *usage; + const char *topic; + rtems_shell_command_t command; + rtems_shell_cmd_t *alias; + rtems_shell_cmd_t *next; +}; + +typedef struct { + const char *name; + const char *alias; +} rtems_shell_alias_t; + +/* + * The return value has RTEMS_SHELL_KEYS_EXTENDED set if the key + * is extended, ie a special key. + */ +unsigned int rtems_shell_getchar(FILE *in); + +rtems_shell_cmd_t * rtems_shell_lookup_cmd(const char *cmd); + +rtems_shell_cmd_t *rtems_shell_add_cmd_struct( + rtems_shell_cmd_t *shell_cmd +); + +rtems_shell_cmd_t * rtems_shell_add_cmd( + const char *cmd, + const char *topic, + const char *usage, + rtems_shell_command_t command +); + +rtems_shell_cmd_t * rtems_shell_alias_cmd( + const char *cmd, + const char *alias +); + +int rtems_shell_make_args( + char *commandLine, + int *argc_p, + char **argv_p, + int max_args +); + +int rtems_shell_cat_file( + FILE *out, + const char *name +); + +void rtems_shell_write_file( + const char *name, + const char *content +); + +int rtems_shell_script_file( + int argc, + char **argv +); + +/** + * Initialise the shell creating tasks to login and run the shell + * sessions. + * + * @param task_name Name of the shell task. + * @param task_stacksize The size of the stack. If 0 the default size is used. + * @param task_priority The priority the shell runs at. + * @param forever Repeat logins. + * @param wait Caller should block until shell exits. + * @param login_check User login check function, NULL disables login checks. + * + */ +rtems_status_code rtems_shell_init( + const char *task_name, + size_t task_stacksize, + rtems_task_priority task_priority, + const char *devname, + bool forever, + bool wait, + rtems_shell_login_check_t login_check +); + +/** + * Run a shell script creating a shell tasks to execute the command under. + * + * @param task_name Name of the shell task. + * @param task_stacksize The size of the stack. If 0 the default size is used. + * @param task_priority The priority the shell runs at. + * @param input The file of commands. Can be 'stdin' to use stdin. + * @param output The output file to write commands to. Can be 'stdout', + * 'stderr' or '/dev/null'. + * @param output_append Append the output to the file or truncate the file. + * Create if it does not exist. + * @param wait Wait for the script to finish. + */ +rtems_status_code rtems_shell_script( + const char *task_name, + size_t task_stacksize, /* 0 default*/ + rtems_task_priority task_priority, + const char *input, + const char *output, + bool output_append, + bool wait, + bool echo +); + +/** + * Private environment associated with each shell instance. + */ +typedef struct { + /** 'S','E','N','V': Shell Environment */ + rtems_name magic; + const char *devname; + const char *taskname; + bool exit_shell; /* logout */ + bool forever; /* repeat login */ + int errorlevel; + bool echo; + char cwd[256]; + const char *input; + const char *output; + bool output_append; + rtems_id wake_on_end; + rtems_shell_login_check_t login_check; +} rtems_shell_env_t; + +bool rtems_shell_main_loop( + rtems_shell_env_t *rtems_shell_env +); + +extern rtems_shell_env_t rtems_global_shell_env; +extern rtems_shell_env_t *rtems_current_shell_env; + +/* + * The types of file systems we can mount. We have them broken out + * out like this so they can be configured by shellconfig.h. The + * mount command needs special treatment due to some file systems + * being dependent on the network stack and some not. If we had + * all possible file systems being included it would force the + * networking stack into the applcation and this may not be + * required. + */ +struct rtems_shell_filesystems_tt; +typedef struct rtems_shell_filesystems_tt rtems_shell_filesystems_t; + +typedef int (*rtems_shell_filesystems_mounter_t)( + const char* driver, + const char* path, + rtems_shell_filesystems_t* fs, + rtems_filesystem_options_t options +); + +struct rtems_shell_filesystems_tt { + rtems_chain_node link; + const char *name; + int driver_needed; + const rtems_filesystem_operations_table *fs_ops; + rtems_shell_filesystems_mounter_t mounter; +}; + +/** + * This method dynamically builds the command line prompt string + * and places it in @a prompt. + * + * @param[in] shell_env is the shell execution environment + * @param[in] prompt is a pointer to a string buffer area + * @param[in] size is length of the prompt buffer area + * + * @return This method fills in the memory pointed to by @a prompt. + * + * @note An application specific implementation can be provided + * by the user. + */ +void rtems_shell_get_prompt( + rtems_shell_env_t *shell_env, + char *prompt, + size_t size +); + +/** + * Helper for the mount command. + * + * @param[in] driver The path to the driver. + * @param[in] path The path to mount on. + * @param[in] fs The file system definition. + * @param[in] options Special file system options. + */ +int rtems_shell_libc_mounter( + const char* driver, + const char* path, + rtems_shell_filesystems_t* fs, + rtems_filesystem_options_t options +); + +/** + * Add a new file system mount configuration to the mount command. + * + * @param[in] fs The file system mount data. + */ +void rtems_shell_mount_add_fsys(rtems_shell_filesystems_t* fs); + +/** + * Delete file system mount configuration from the mount command. + * + * @param[in] fs The file system mount data to remove. + */ +void rtems_shell_mount_del_fsys(rtems_shell_filesystems_t* fs); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/cpukit/libmisc/shell/shell_cmdset.c b/cpukit/libmisc/shell/shell_cmdset.c new file mode 100644 index 0000000000..2abaed9242 --- /dev/null +++ b/cpukit/libmisc/shell/shell_cmdset.c @@ -0,0 +1,234 @@ +/* + * + * Shell Command Set Management + * + * Author: + * WORK: fernando.ruiz@ctv.es + * HOME: correo@fernando-ruiz.com + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <time.h> +#include <termios.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <sys/stat.h> +#include <unistd.h> +#include <errno.h> + + +#include <rtems.h> +#include <rtems/shell.h> +#include <rtems/shellconfig.h> +#include "internal.h" + +/* + * Common linked list of shell commands. + * + * Because the help report is very long, there is a topic for each command. + * + * Help list the topics + * help [topic] list the commands for the topic + * help [command] help for the command + * + */ + +rtems_shell_cmd_t * rtems_shell_first_cmd; +rtems_shell_topic_t * rtems_shell_first_topic; + +/* + * Find the topic from the set of topics registered. + */ +rtems_shell_topic_t * rtems_shell_lookup_topic(const char * topic) { + rtems_shell_topic_t * shell_topic; + shell_topic=rtems_shell_first_topic; + + while (shell_topic) { + if (!strcmp(shell_topic->topic,topic)) + return shell_topic; + shell_topic=shell_topic->next; + } + return (rtems_shell_topic_t *) NULL; +} + +/* + * Add a new topic to the list of topics + */ +rtems_shell_topic_t * rtems_shell_add_topic(const char * topic) { + rtems_shell_topic_t * current,*aux; + + if (!rtems_shell_first_topic) { + aux = malloc(sizeof(rtems_shell_topic_t)); + aux->topic = topic; + aux->next = (rtems_shell_topic_t*)NULL; + return rtems_shell_first_topic = aux; + } + current=rtems_shell_first_topic; + if (!strcmp(topic,current->topic)) + return current; + + while (current->next) { + if (!strcmp(topic,current->next->topic)) + return current->next; + current=current->next; + } + aux = malloc(sizeof(rtems_shell_topic_t)); + aux->topic = topic; + aux->next = (rtems_shell_topic_t*)NULL; + current->next = aux; + return aux; +} + +/* + * Find the command in the set + */ +rtems_shell_cmd_t * rtems_shell_lookup_cmd(const char * cmd) { + rtems_shell_cmd_t * shell_cmd; + shell_cmd=rtems_shell_first_cmd; + while (shell_cmd) { + if (!strcmp(shell_cmd->name,cmd)) return shell_cmd; + shell_cmd=shell_cmd->next; + }; + return (rtems_shell_cmd_t *) NULL; +} + +/* + * Add a command structure to the set of known commands + */ +rtems_shell_cmd_t *rtems_shell_add_cmd_struct( + rtems_shell_cmd_t *shell_cmd +) +{ + rtems_shell_cmd_t *shell_pvt; + + shell_pvt = rtems_shell_first_cmd; + while (shell_pvt) { + if (strcmp(shell_pvt->name, shell_cmd->name) == 0) + return NULL; + shell_pvt = shell_pvt->next; + } + + if ( !rtems_shell_first_cmd ) { + rtems_shell_first_cmd = shell_cmd; + } else { + shell_pvt = rtems_shell_first_cmd; + while (shell_pvt->next) + shell_pvt = shell_pvt->next; + shell_pvt->next = shell_cmd; + } + rtems_shell_add_topic( shell_cmd->topic ); + return shell_cmd; +} + +/* + * Add a command as a set of arguments to the set and + * allocate the command structure on the fly. + */ +rtems_shell_cmd_t * rtems_shell_add_cmd( + const char *name, + const char *topic, + const char *usage, + rtems_shell_command_t command +) +{ + rtems_shell_cmd_t *shell_cmd = NULL; + char *my_name = NULL; + char *my_topic = NULL; + char *my_usage = NULL; + + /* Reject empty commands */ + if (name == NULL || command == NULL) { + return NULL; + } + + /* Allocate command stucture */ + shell_cmd = (rtems_shell_cmd_t *) malloc(sizeof(rtems_shell_cmd_t)); + if (shell_cmd == NULL) { + return NULL; + } + + /* Allocate strings */ + my_name = strdup(name); + my_topic = strdup(topic); + my_usage = strdup(usage); + + /* Assign values */ + shell_cmd->name = my_name; + shell_cmd->topic = my_topic; + shell_cmd->usage = my_usage; + shell_cmd->command = command; + shell_cmd->alias = NULL; + shell_cmd->next = NULL; + + if (rtems_shell_add_cmd_struct(shell_cmd) == NULL) { + /* Something is wrong, free allocated resources */ + free(my_usage); + free(my_topic); + free(my_name); + free(shell_cmd); + + return NULL; + } + + return shell_cmd; +} + + +void rtems_shell_initialize_command_set(void) +{ + rtems_shell_cmd_t **c; + rtems_shell_alias_t **a; + + for ( c = rtems_shell_Initial_commands ; *c ; c++ ) { + rtems_shell_add_cmd_struct( *c ); + } + + for ( a = rtems_shell_Initial_aliases ; *a ; a++ ) { + rtems_shell_alias_cmd( (*a)->name, (*a)->alias ); + } + + rtems_shell_register_monitor_commands(); +} + +/* ----------------------------------------------- * + * you can make an alias for every command. + * ----------------------------------------------- */ +rtems_shell_cmd_t *rtems_shell_alias_cmd( + const char *cmd, + const char *alias +) +{ + rtems_shell_cmd_t *shell_cmd, *shell_aux; + + shell_aux = (rtems_shell_cmd_t *) NULL; + + if (alias) { + shell_aux = rtems_shell_lookup_cmd(alias); + if (shell_aux != NULL) { + return NULL; + } + shell_cmd = rtems_shell_lookup_cmd(cmd); + if (shell_cmd != NULL) { + shell_aux = rtems_shell_add_cmd( + alias, + shell_cmd->topic, + shell_cmd->usage, + shell_cmd->command + ); + if (shell_aux) + shell_aux->alias = shell_cmd; + } + } + return shell_aux; +} diff --git a/cpukit/libmisc/shell/shell_getchar.c b/cpukit/libmisc/shell/shell_getchar.c new file mode 100644 index 0000000000..b214a9511f --- /dev/null +++ b/cpukit/libmisc/shell/shell_getchar.c @@ -0,0 +1,176 @@ +/* + * + * Handle keys for the shell. + * + * Author: + * + * Chris Johns (chrisj@rtems.org) + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <time.h> + +#include <rtems.h> +#include <rtems/error.h> +#include <rtems/system.h> +#include <rtems/shell.h> +#include <rtems/shellconfig.h> +#include "internal.h" + +/* + * Taken from the monitor code. + */ + +/* + * Translation tables. Not sure if this is the best way to + * handle this, how-ever I wish to avoid the overhead of + * including a more complete and standard environment such + * as ncurses. + */ + +struct translation_table +{ + char expecting; + const struct translation_table *branch; + unsigned int key; +}; + +static const struct translation_table trans_one[] = +{ + { '\x7e', 0, RTEMS_SHELL_KEYS_HOME }, + { 0, 0, 0 } +}; + +static const struct translation_table trans_two[] = +{ + { '~', 0, RTEMS_SHELL_KEYS_INS }, + { 0, 0, 0 } +}; + +static const struct translation_table trans_three[] = +{ + { '~', 0, RTEMS_SHELL_KEYS_DEL }, + { 0, 0, 0 } +}; + +static const struct translation_table trans_tab_csi[] = +{ + { '1', trans_one, 0 }, + { '2', trans_two, 0 }, + { '3', trans_three, 0 }, + { 'A', 0, RTEMS_SHELL_KEYS_UARROW }, + { 'B', 0, RTEMS_SHELL_KEYS_DARROW }, + { 'D', 0, RTEMS_SHELL_KEYS_LARROW }, + { 'C', 0, RTEMS_SHELL_KEYS_RARROW }, + { 'F', 0, RTEMS_SHELL_KEYS_END }, + { 'H', 0, RTEMS_SHELL_KEYS_HOME }, + { 0, 0, 0 } +}; + +static const struct translation_table trans_tab_O[] = +{ + { '1', 0, RTEMS_SHELL_KEYS_F1 }, + { '2', 0, RTEMS_SHELL_KEYS_F2 }, + { '3', 0, RTEMS_SHELL_KEYS_F3 }, + { '4', 0, RTEMS_SHELL_KEYS_F4 }, + { '5', 0, RTEMS_SHELL_KEYS_F5 }, + { '6', 0, RTEMS_SHELL_KEYS_F6 }, + { '7', 0, RTEMS_SHELL_KEYS_F7 }, + { '8', 0, RTEMS_SHELL_KEYS_F8 }, + { '9', 0, RTEMS_SHELL_KEYS_F9 }, + { ':', 0, RTEMS_SHELL_KEYS_F10 }, + { 'F', 0, RTEMS_SHELL_KEYS_END }, + { 'P', 0, RTEMS_SHELL_KEYS_F1 }, + { 'Q', 0, RTEMS_SHELL_KEYS_F2 }, + { 'R', 0, RTEMS_SHELL_KEYS_F3 }, + { 'S', 0, RTEMS_SHELL_KEYS_F4 }, + { 'T', 0, RTEMS_SHELL_KEYS_F5 }, + { 'U', 0, RTEMS_SHELL_KEYS_F6 }, + { 'V', 0, RTEMS_SHELL_KEYS_F7 }, + { 'W', 0, RTEMS_SHELL_KEYS_F8 }, + { 'X', 0, RTEMS_SHELL_KEYS_F9 }, + { 'Y', 0, RTEMS_SHELL_KEYS_F10 }, + { 0, 0, 0 } +}; + +static const struct translation_table trans_tab[] = +{ + { '[', trans_tab_csi, 0 }, /* CSI command sequences */ + { 'O', trans_tab_O, 0 }, /* O are the fuction keys */ + { 0, 0, 0 } +}; + +/* + * Perform a basic tranlation for some ANSI/VT100 key codes. + * This code could do with a timeout on the ESC as it is + * now lost from the input stream. It is not* used by the + * line editor below so considiered not worth the effort. + */ + +unsigned int +rtems_shell_getchar (FILE *in) +{ + const struct translation_table *translation = 0; + for (;;) + { + int c = fgetc (in); + if (c == EOF) + return EOF; + if (c == 27) + translation = trans_tab; + else + { + /* + * If no translation happing just pass through + * and return the key. + */ + if (translation) + { + /* + * Scan the current table for the key, and if found + * see if this key is a fork. If so follow it and + * wait else return the extended key. + */ + int index = 0; + int branched = 0; + while ((translation[index].expecting != '\0') || + (translation[index].key != '\0')) + { + if (translation[index].expecting == c) + { + /* + * A branch is take if more keys are to come. + */ + if (translation[index].branch == 0) + return RTEMS_SHELL_KEYS_EXTENDED | translation[index].key; + else + { + translation = translation[index].branch; + branched = 1; + break; + } + } + index++; + } + /* + * Who knows what these keys are, just drop them. + */ + if (!branched) + translation = 0; + } + else + return c; + } + } +} + diff --git a/cpukit/libmisc/shell/shell_getprompt.c b/cpukit/libmisc/shell/shell_getprompt.c new file mode 100644 index 0000000000..08c628b219 --- /dev/null +++ b/cpukit/libmisc/shell/shell_getprompt.c @@ -0,0 +1,49 @@ +/* + * Dynamically build the shell prompt + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <time.h> + +#include <rtems.h> +#include <rtems/error.h> +#include <rtems/libio.h> +#include <rtems/libio_.h> +#include <rtems/system.h> +#include <rtems/shell.h> +#include "internal.h" + +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <sys/stat.h> +#include <unistd.h> +#include <errno.h> +#include <pwd.h> + +void rtems_shell_get_prompt( + rtems_shell_env_t *shell_env, + char *prompt, + size_t size +) +{ + char curdir[256]; + + /* XXX: show_prompt user adjustable */ + getcwd(curdir,sizeof(curdir)); + snprintf(prompt, size - 1, "%s%s[%s] %c ", + ((shell_env->taskname) ? shell_env->taskname : ""), + ((shell_env->taskname) ? " " : ""), + curdir, + geteuid()?'$':'#'); +} diff --git a/cpukit/libmisc/shell/shell_makeargs.c b/cpukit/libmisc/shell/shell_makeargs.c new file mode 100644 index 0000000000..727ea829c9 --- /dev/null +++ b/cpukit/libmisc/shell/shell_makeargs.c @@ -0,0 +1,68 @@ +/* + * Split string into argc/argv style argument list + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> +#include <ctype.h> + +int rtems_shell_make_args( + char *commandLine, + int *argc_p, + char **argv_p, + int max_args +) +{ + int argc; + char *ch; + int status = 0; + + argc = 0; + ch = commandLine; + + while ( *ch ) { + + while ( isspace((unsigned char)*ch) ) ch++; + + if ( *ch == '\0' ) + break; + + if ( *ch == '"' ) { + argv_p[ argc ] = ++ch; + while ( ( *ch != '\0' ) && ( *ch != '"' ) ) ch++; + } else { + argv_p[ argc ] = ch; + while ( ( *ch != '\0' ) && ( !isspace((unsigned char)*ch) ) ) ch++; + } + + argc++; + + if ( *ch == '\0' ) + break; + + *ch++ = '\0'; + + if ( argc == (max_args-1) ) { + status = -1; + break; + } + + + } + argv_p[ argc ] = NULL; + *argc_p = argc; + return status; +} + diff --git a/cpukit/libmisc/shell/shell_script.c b/cpukit/libmisc/shell/shell_script.c new file mode 100644 index 0000000000..8854f4af35 --- /dev/null +++ b/cpukit/libmisc/shell/shell_script.c @@ -0,0 +1,351 @@ +/* + * Shell Script Invocation + * + * Pseudo-code from Chris Johns, implemented and debugged + * by Joel Sherrill. + * + * COPYRIGHT (c) 1989-2009. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <inttypes.h> +#include <sys/types.h> +#include <unistd.h> +#define __need_getopt_newlib +#include <getopt.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include <rtems/stringto.h> +#include "internal.h" + +static void rtems_shell_joel_usage(void) +{ + printf( + "joel [args] where args may be:\n" + " -o FILE output file (default=stdout)\n" + " -p PRIORITY task priority\n" + " -s SIZE task stack size\n" + " -t NAME task name\n" + ); +} + +static int findOnPATH( + const char *userScriptName, + char *scriptFile, + size_t scriptFileLength +) +{ + int sc; + + /* + * If the user script name starts with a / assume it is a fully + * qualified path name and just use it. + */ + if ( userScriptName[0] == '/' ) { + strncpy( scriptFile, userScriptName, PATH_MAX ); + } else { + /* + * For now, the provided name is just turned into a fully + * qualified path name and used. There is no attempt to + * search along a path for it. + */ + + /* XXX should use strncat but what is the limit? */ + getcwd( scriptFile, PATH_MAX ); + strncat( scriptFile, "/", PATH_MAX ); + strncat( + scriptFile, + ( (userScriptName[0] == '.' && userScriptName[1] == '/') ? + &userScriptName[2] : userScriptName), + PATH_MAX + ); + } + + sc = access( scriptFile, R_OK ); + if ( sc ) { + return -1; + } + + return 0; + +#if 0 + /* + * Does the command (argv[0]) contain a path ?, i.e. starts with + * '.' or contains a '/'? + */ + /* TODO: Add concept of PATH */ + if (!contains_path) { + /* check PATH environment variable */ + for (path_part = PATH; path_part; skip to ':') + { + } + if (not found) + return -1; + } +#endif +} + +int rtems_shell_main_joel( + int argc, + char **argv +); + +int rtems_shell_main_joel( + int argc, + char **argv +) +{ + unsigned long tmp; + int option; + int sc; + int verbose = 0; + char *taskName = "JOEL"; + uint32_t stackSize = RTEMS_MINIMUM_STACK_SIZE * 10; + rtems_task_priority taskPriority = 20; + char *outputFile = "stdout"; + rtems_status_code result; + char scriptFile[PATH_MAX]; + struct getopt_data getopt_reent; + + memset(&getopt_reent, 0, sizeof(getopt_data)); + while ( (option = getopt_r( argc, argv, "o:p:s:t:v", &getopt_reent)) != -1 ) { + switch ((char)option) { + case 'o': + outputFile = getopt_reent.optarg; + break; + case 'p': { + const char *s = getopt_reent.optarg; + + if ( rtems_string_to_unsigned_long( s, &tmp, NULL, 0) ) { + printf( "Task Priority argument (%s) is not a number\n", s ); + return -1; + } + taskPriority = (rtems_task_priority) tmp; + break; + } + case 's': { + const char *s = getopt_reent.optarg; + + if ( rtems_string_to_unsigned_long( s, &tmp, NULL, 0) ) { + printf( "Stack size argument (%s) is not a number\n", s ); + return -1; + } + stackSize = (uint32_t) tmp; + break; + } + case 't': + taskName = getopt_reent.optarg; + break; + case 'v': + verbose = 1; + break; + case '?': + default: + rtems_shell_joel_usage(); + return -1; + } + } + + if ( verbose ) { + fprintf( stderr, + "outputFile: %s\n" + "taskPriority: %" PRId32 "\n" + "stackSize: %" PRId32 "\n" + "taskName: %s\n", + outputFile, + taskPriority, + stackSize, + taskName + ); + } + + /* + * Verify there is a script name past the end of the arguments. + * Preincrement to skip program name. + */ + if ( getopt_reent.optind >= argc ) { + fprintf( stderr, "Shell: No script to execute\n" ); + return -1; + } + + /* + * Find script on the path. + * + * NOTE: It is terrible that this is done twice but it + * seems to be the most expedient thing. + */ + sc = findOnPATH( argv[getopt_reent.optind], scriptFile, PATH_MAX ); + if ( sc ) { + fprintf( stderr, "%s: command not found\n", argv[0] ); + return -1; + } + + /* fprintf( stderr, "SCRIPT: -%s-\n", scriptFile ); */ + + /* + * I assume that argv[optind...] will have the arguments to + * the shell script. But that remains to be implemented. + */ + + /* + * Run the script + */ + result = rtems_shell_script( + taskName, /* the name of the task */ + stackSize, /* stack size */ + taskPriority, /* task priority */ + scriptFile, /* the script file */ + outputFile, /* where to redirect the script */ + 0, /* run once and exit */ + 1, /* we will wait */ + verbose /* do we echo */ + ); + if (result) + return -1; + return 0; +} + +rtems_shell_cmd_t rtems_shell_JOEL_Command = { + "joel", /* name */ + "joel [args] SCRIPT", /* usage */ + "misc", /* topic */ + rtems_shell_main_joel, /* command */ + NULL, /* alias */ + NULL /* next */ +}; + +/* + * This is a helper function which takes a command as arguments + * which has not been located as a built-in command and attempts + * to find something in the filesystem with the same name that + * appears to be a shell script. + */ +int rtems_shell_script_file( + int argc __attribute__((unused)), + char *argv[] +) +{ + #define FIRST_LINE_LENGTH 128 + #define SCRIPT_ARGV_LIMIT 32 + char scriptFile[PATH_MAX]; + char *scriptHead; + char scriptHeadBuffer[FIRST_LINE_LENGTH]; + int sc; + FILE *script; + size_t length; + int scriptArgc; + char *scriptArgv[SCRIPT_ARGV_LIMIT]; + + /* + * Clear argv pointer array + */ + for ( scriptArgc=0 ; scriptArgc<SCRIPT_ARGV_LIMIT ; scriptArgc++ ) + scriptArgv[scriptArgc] = NULL; + + /* + * Find argv[0] on the path + */ + sc = findOnPATH( argv[0], scriptFile, PATH_MAX ); + if ( sc ) { + fprintf( stderr, "%s: command not found\n", argv[0] ); + return -1; + } + + /* + * Open the file so we can see if it looks like a script. + */ + script = fopen( scriptFile, "r" ); + if ( !script ) { + fprintf( stderr, "%s: Unable to open %s\n", argv[0], scriptFile ); + return -1; + } + + /* + * Is the script OK to run? + * Verify the current user has permission to execute it. + * + * NOTE: May not work on all file systems + */ + sc = access( scriptFile, X_OK ); + if ( sc ) { + fprintf( stderr, "Unable to execute %s\n", scriptFile ); + fclose( script ); + return -1; + } + + /* + * Try to read the first line from the potential script file + */ + scriptHead = fgets(scriptHeadBuffer, FIRST_LINE_LENGTH, script); + if ( !scriptHead ) { + fprintf( + stderr, "%s: Unable to read first line of %s\n", argv[0], scriptFile ); + fclose( script ); + return -1; + } + + fclose(script); + + length = strnlen(scriptHead, FIRST_LINE_LENGTH); + scriptHead[length - 1] = '\0'; + + /* fprintf( stderr, "FIRST LINE: -%s-\n", scriptHead ); */ + + /* + * Verify the name of the "shell" is joel. This means + * the line starts with "#! joel". + */ + if (strncmp("#! joel", scriptHead, 7) != 0) { + fprintf( stderr, "%s: Not a joel script %s\n", argv[0], scriptFile ); + return -1; + } + + /* + * Do not worry about search path further. We have found the + * script, it is executable, and we have successfully read the + * first line and found out it is a script. + */ + + /* + * Check for arguments in the first line of the script. This changes + * how the shell task is run. + */ + + sc = rtems_shell_make_args( + &scriptHead[3], + &scriptArgc, + scriptArgv, + SCRIPT_ARGV_LIMIT - 1 + ); + if ( sc ) { + fprintf( + stderr, "%s: Error parsing joel arguments %s\n", argv[0], scriptFile ); + return -1; + } + + scriptArgv[ scriptArgc++ ] = scriptFile; + + /* + * TODO: How do we pass arguments from here to the script? + * At this point, it doesn't matter because we don't + * have any way for a shell script to access them. + */ + return rtems_shell_main_joel( scriptArgc, scriptArgv ); + + return 0; +} diff --git a/cpukit/libmisc/shell/shellconfig.c b/cpukit/libmisc/shell/shellconfig.c new file mode 100644 index 0000000000..0cb0de0b30 --- /dev/null +++ b/cpukit/libmisc/shell/shellconfig.c @@ -0,0 +1,21 @@ +/* + * RTEMS Shell Command Set -- DEFAULT Configuration + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define CONFIGURE_SHELL_COMMANDS_INIT +#define CONFIGURE_SHELL_COMMANDS_ALL + +#include <rtems/shellconfig.h> diff --git a/cpukit/libmisc/shell/shellconfig.h b/cpukit/libmisc/shell/shellconfig.h new file mode 100644 index 0000000000..cfc475095e --- /dev/null +++ b/cpukit/libmisc/shell/shellconfig.h @@ -0,0 +1,438 @@ +/* + * RTEMS Shell Command Set Configuration + * + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifndef _RTEMS_SHELL_CONFIG_h +#define _RTEMS_SHELL_CONFIG_h + +#include <rtems/shell.h> + +/* + * Externs for all command definition structures + */ +extern rtems_shell_cmd_t rtems_shell_HELP_Command; +extern rtems_shell_cmd_t rtems_shell_ALIAS_Command; +extern rtems_shell_cmd_t rtems_shell_TIME_Command; +extern rtems_shell_cmd_t rtems_shell_LOGOFF_Command; +extern rtems_shell_cmd_t rtems_shell_SETENV_Command; +extern rtems_shell_cmd_t rtems_shell_GETENV_Command; +extern rtems_shell_cmd_t rtems_shell_UNSETENV_Command; + +extern rtems_shell_cmd_t rtems_shell_MDUMP_Command; +extern rtems_shell_cmd_t rtems_shell_WDUMP_Command; +extern rtems_shell_cmd_t rtems_shell_MEDIT_Command; +extern rtems_shell_cmd_t rtems_shell_MFILL_Command; +extern rtems_shell_cmd_t rtems_shell_MMOVE_Command; + +extern rtems_shell_cmd_t rtems_shell_JOEL_Command; +extern rtems_shell_cmd_t rtems_shell_DATE_Command; +extern rtems_shell_cmd_t rtems_shell_ECHO_Command; +extern rtems_shell_cmd_t rtems_shell_SLEEP_Command; +extern rtems_shell_cmd_t rtems_shell_ID_Command; +extern rtems_shell_cmd_t rtems_shell_TTY_Command; +extern rtems_shell_cmd_t rtems_shell_WHOAMI_Command; + +extern rtems_shell_cmd_t rtems_shell_CP_Command; +extern rtems_shell_cmd_t rtems_shell_PWD_Command; +extern rtems_shell_cmd_t rtems_shell_LS_Command; +extern rtems_shell_cmd_t rtems_shell_CHDIR_Command; +extern rtems_shell_cmd_t rtems_shell_MKDIR_Command; +extern rtems_shell_cmd_t rtems_shell_RMDIR_Command; +extern rtems_shell_cmd_t rtems_shell_CHROOT_Command; +extern rtems_shell_cmd_t rtems_shell_CHMOD_Command; +extern rtems_shell_cmd_t rtems_shell_CAT_Command; +extern rtems_shell_cmd_t rtems_shell_MKRFS_Command; +extern rtems_shell_cmd_t rtems_shell_MSDOSFMT_Command; +extern rtems_shell_cmd_t rtems_shell_MSDOSFMT_Alias; +extern rtems_shell_cmd_t rtems_shell_MV_Command; +extern rtems_shell_cmd_t rtems_shell_RM_Command; +extern rtems_shell_cmd_t rtems_shell_LN_Command; +extern rtems_shell_cmd_t rtems_shell_MKNOD_Command; +extern rtems_shell_cmd_t rtems_shell_UMASK_Command; +extern rtems_shell_cmd_t rtems_shell_MOUNT_Command; +extern rtems_shell_cmd_t rtems_shell_UNMOUNT_Command; +extern rtems_shell_cmd_t rtems_shell_BLKSYNC_Command; +extern rtems_shell_cmd_t rtems_shell_FDISK_Command; +extern rtems_shell_cmd_t rtems_shell_DD_Command; +extern rtems_shell_cmd_t rtems_shell_HEXDUMP_Command; +extern rtems_shell_cmd_t rtems_shell_DEBUGRFS_Command; + +extern rtems_shell_cmd_t rtems_shell_RTC_Command; + +extern rtems_shell_cmd_t rtems_shell_HALT_Command; +extern rtems_shell_cmd_t rtems_shell_CPUUSE_Command; +extern rtems_shell_cmd_t rtems_shell_STACKUSE_Command; +extern rtems_shell_cmd_t rtems_shell_PERIODUSE_Command; +extern rtems_shell_cmd_t rtems_shell_WKSPACE_INFO_Command; +extern rtems_shell_cmd_t rtems_shell_MALLOC_INFO_Command; +#if RTEMS_NETWORKING + extern rtems_shell_cmd_t rtems_shell_IFCONFIG_Command; + extern rtems_shell_cmd_t rtems_shell_ROUTE_Command; + extern rtems_shell_cmd_t rtems_shell_NETSTATS_Command; +#endif + +extern rtems_shell_cmd_t *rtems_shell_Initial_commands[]; + +/* + * Extern for alias commands + */ +extern rtems_shell_alias_t rtems_shell_DIR_Alias; +extern rtems_shell_alias_t rtems_shell_CD_Alias; +extern rtems_shell_alias_t rtems_shell_EXIT_Alias; + +extern rtems_shell_alias_t *rtems_shell_Initial_aliases[]; + +/* + * If we are configured to alias a command, then make sure the underlying + * command is configured. + */ + +#if !defined(CONFIGURE_SHELL_COMMANDS_ALL) + #if defined(CONFIGURE_SHELL_COMMANDS_DIR) && \ + !defined(CONFIGURE_SHELL_COMMANDS_LS) + #define CONFIGURE_SHELL_COMMAND_LS + #endif + + #if defined(CONFIGURE_SHELL_COMMANDS_CD) && \ + !defined(CONFIGURE_SHELL_COMMANDS_CHDIR) + #define CONFIGURE_SHELL_COMMAND_CHDIR + #endif + + #if defined(CONFIGURE_SHELL_COMMANDS_EXIT) && \ + !defined(CONFIGURE_SHELL_COMMANDS_LOGOFF) + #define CONFIGURE_SHELL_COMMAND_LOGOFF + #endif +#endif + +#if defined(CONFIGURE_SHELL_COMMANDS_INIT) + rtems_shell_alias_t *rtems_shell_Initial_aliases[] = { + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_DIR)) || \ + defined(CONFIGURE_SHELL_COMMAND_DIR) + &rtems_shell_DIR_Alias, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_CD)) || \ + defined(CONFIGURE_SHELL_COMMAND_CD) + &rtems_shell_CD_Alias, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_EXIT)) || \ + defined(CONFIGURE_SHELL_COMMAND_EXIT) + &rtems_shell_EXIT_Alias, + #endif + + /* + * User defined shell aliases + */ + #if defined(CONFIGURE_SHELL_USER_ALIASES) + CONFIGURE_SHELL_USER_ALIASES, + #endif + NULL + }; + + rtems_shell_cmd_t *rtems_shell_Initial_commands[] = { + /* + * General comamnds that should be present + */ + &rtems_shell_HELP_Command, + &rtems_shell_ALIAS_Command, + &rtems_shell_TIME_Command, + + /* + * Common commands that can be optional + */ + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_JOEL)) || \ + defined(CONFIGURE_SHELL_COMMAND_JOEL) + &rtems_shell_JOEL_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_DATE)) || \ + defined(CONFIGURE_SHELL_COMMAND_DATE) + &rtems_shell_DATE_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_ECHO)) || \ + defined(CONFIGURE_SHELL_COMMAND_ECHO) + &rtems_shell_ECHO_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_SLEEP)) || \ + defined(CONFIGURE_SHELL_COMMAND_SLEEP) + &rtems_shell_SLEEP_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_ID)) || \ + defined(CONFIGURE_SHELL_COMMAND_ID) + &rtems_shell_ID_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_TTY)) || \ + defined(CONFIGURE_SHELL_COMMAND_TTY) + &rtems_shell_TTY_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_WHOAMI)) || \ + defined(CONFIGURE_SHELL_COMMAND_WHOAMI) + &rtems_shell_WHOAMI_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_LOGOFF)) || \ + defined(CONFIGURE_SHELL_COMMAND_LOGOFF) + &rtems_shell_LOGOFF_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_SETENV)) || \ + defined(CONFIGURE_SHELL_COMMAND_SETENV) + &rtems_shell_SETENV_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_GETENV)) || \ + defined(CONFIGURE_SHELL_COMMAND_GETENV) + &rtems_shell_GETENV_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_CRLENV)) || \ + defined(CONFIGURE_SHELL_COMMAND_UNSETENV) + &rtems_shell_UNSETENV_Command, + #endif + + /* + * Memory printing/modification family commands + */ + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_MDUMP)) || \ + defined(CONFIGURE_SHELL_COMMAND_MDUMP) + &rtems_shell_MDUMP_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_WDUMP)) || \ + defined(CONFIGURE_SHELL_COMMAND_WDUMP) + &rtems_shell_WDUMP_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_MEDIT)) || \ + defined(CONFIGURE_SHELL_COMMAND_MEDIT) + &rtems_shell_MEDIT_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_MFILL)) || \ + defined(CONFIGURE_SHELL_COMMAND_MFILL) + &rtems_shell_MFILL_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_MMOVE)) || \ + defined(CONFIGURE_SHELL_COMMAND_MMOVE) + &rtems_shell_MMOVE_Command, + #endif + + /* + * File and directory commands + */ + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_CP)) || \ + defined(CONFIGURE_SHELL_COMMAND_CP) + &rtems_shell_CP_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_PWD)) || \ + defined(CONFIGURE_SHELL_COMMAND_PWD) + &rtems_shell_PWD_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_LS)) || \ + defined(CONFIGURE_SHELL_COMMAND_LS) + &rtems_shell_LS_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_CHDIR)) || \ + defined(CONFIGURE_SHELL_COMMAND_CHDIR) + &rtems_shell_CHDIR_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_MKDIR)) || \ + defined(CONFIGURE_SHELL_COMMAND_MKDIR) + &rtems_shell_MKDIR_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_RMDIR)) || \ + defined(CONFIGURE_SHELL_COMMAND_RMDIR) + &rtems_shell_RMDIR_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_CHROOT)) || \ + defined(CONFIGURE_SHELL_COMMAND_CHROOT) + &rtems_shell_CHROOT_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_CHMOD)) || \ + defined(CONFIGURE_SHELL_COMMAND_CHMOD) + &rtems_shell_CHMOD_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_CAT)) || \ + defined(CONFIGURE_SHELL_COMMAND_CAT) + &rtems_shell_CAT_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_MKRFS)) || \ + defined(CONFIGURE_SHELL_COMMAND_MKRFS) + &rtems_shell_MKRFS_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_MSDOSFMT)) || \ + defined(CONFIGURE_SHELL_COMMAND_MSDOSFMT) + &rtems_shell_MSDOSFMT_Command, + &rtems_shell_MSDOSFMT_Alias, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_MV)) || \ + defined(CONFIGURE_SHELL_COMMAND_MV) + &rtems_shell_MV_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_RM)) || \ + defined(CONFIGURE_SHELL_COMMAND_RM) + &rtems_shell_RM_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_LN)) || \ + defined(CONFIGURE_SHELL_COMMAND_LN) + &rtems_shell_LN_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_MKNOD)) || \ + defined(CONFIGURE_SHELL_COMMAND_MKNOD) + &rtems_shell_MKNOD_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_UMASK)) || \ + defined(CONFIGURE_SHELL_COMMAND_UMASK) + &rtems_shell_UMASK_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_MOUNT)) || \ + defined(CONFIGURE_SHELL_COMMAND_MOUNT) + &rtems_shell_MOUNT_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_UNMOUNT)) || \ + defined(CONFIGURE_SHELL_COMMAND_UNMOUNT) + &rtems_shell_UNMOUNT_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_BLKSYNC)) || \ + defined(CONFIGURE_SHELL_COMMAND_BLKSYNC) + &rtems_shell_BLKSYNC_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_FDISK)) || \ + defined(CONFIGURE_SHELL_COMMAND_FDISK) + &rtems_shell_FDISK_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_DD)) || \ + defined(CONFIGURE_SHELL_COMMAND_DD) + &rtems_shell_DD_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_HEXDUMP)) || \ + defined(CONFIGURE_SHELL_COMMAND_HEXDUMP) + &rtems_shell_HEXDUMP_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_DEBUGRFS)) || \ + defined(CONFIGURE_SHELL_COMMAND_DEBUGRFS) + &rtems_shell_DEBUGRFS_Command, + #endif + + /* + * RTEMS Related commands + */ + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_HALT)) || \ + defined(CONFIGURE_SHELL_COMMAND_HALT) + &rtems_shell_HALT_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_CPUUSE)) || \ + defined(CONFIGURE_SHELL_COMMAND_CPUUSE) + &rtems_shell_CPUUSE_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_STACKUSE)) || \ + defined(CONFIGURE_SHELL_COMMAND_STACKUSE) + &rtems_shell_STACKUSE_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_PERIODUSE)) || \ + defined(CONFIGURE_SHELL_COMMAND_PERIODUSE) + &rtems_shell_PERIODUSE_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_WKSPACE_INFO)) || \ + defined(CONFIGURE_SHELL_COMMAND_WKSPACE_INFO) + &rtems_shell_WKSPACE_INFO_Command, + #endif + + /* + * Malloc family commands + */ + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_MALLOC_INFO)) || \ + defined(CONFIGURE_SHELL_COMMAND_MALLOC_INFO) + &rtems_shell_MALLOC_INFO_Command, + #endif + + /* + * Network related commands + */ + #if RTEMS_NETWORKING + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL_NETWORKING) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_IFCONFIG)) || \ + defined(CONFIGURE_SHELL_COMMAND_IFCONFIG) + &rtems_shell_IFCONFIG_Command, + #endif + + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL_NETWORKING) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_ROUTE)) || \ + defined(CONFIGURE_SHELL_COMMAND_ROUTE) + &rtems_shell_ROUTE_Command, + #endif + + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL_NETWORKING) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_NETSTATS)) || \ + defined(CONFIGURE_SHELL_COMMAND_NETSTATS) + &rtems_shell_NETSTATS_Command, + #endif + #endif + + /* Miscanellous shell commands */ + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) \ + && !defined(CONFIGURE_SHELL_NO_COMMAND_RTC)) \ + || defined(CONFIGURE_SHELL_COMMAND_RTC) + &rtems_shell_RTC_Command, + #endif + + /* + * User defined shell commands + */ + #if defined(CONFIGURE_SHELL_USER_COMMANDS) + CONFIGURE_SHELL_USER_COMMANDS, + #endif + NULL + }; + +#endif + +#endif diff --git a/cpukit/libmisc/shell/utils-cp.c b/cpukit/libmisc/shell/utils-cp.c new file mode 100644 index 0000000000..7b7c7fc771 --- /dev/null +++ b/cpukit/libmisc/shell/utils-cp.c @@ -0,0 +1,496 @@ +/* $NetBSD: utils.c,v 1.29 2005/10/15 18:22:18 christos Exp $ */ + +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/cdefs.h> +#if 0 +#ifndef lint +#if 0 +static char sccsid[] = "@(#)utils.c 8.3 (Berkeley) 4/1/94"; +#else +__RCSID("$NetBSD: utils.c,v 1.29 2005/10/15 18:22:18 christos Exp $"); +#endif +#endif /* not lint */ +#endif + +#if 0 +#include <sys/mman.h> +#endif +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <utime.h> + +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <fts.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "extern-cp.h" + +#define lchmod chmod +#define lchown chown + +#define cp_pct(x, y) ((y == 0) ? 0 : (int)(100.0 * (x) / (y))) + +int +set_utimes(const char *file, struct stat *fs) +{ + struct utimbuf tv; + + tv.actime = fs->st_atime; + tv.modtime = fs->st_mtime; + + if (utime(file, &tv)) { + warn("lutimes: %s", file); + return (1); + } + return (0); +} + +int +copy_file(rtems_shell_cp_globals* cp_globals __attribute__((unused)), FTSENT *entp, int dne) +{ +#define MAX_READ max_read + int max_read; + char* buf; + struct stat *fs; + ssize_t wcount; + size_t wresid; + off_t wtotal; + int ch, checkch, from_fd = 0, rcount, rval, to_fd = 0; + char *bufp; +#ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED + char *p; +#endif + + fs = entp->fts_statp; + + max_read = fs->st_blksize; + if (max_read < (8 * 1024)) + max_read = 8 * 1024; + buf = malloc (max_read); + if (!buf) + { + warn("no memory"); + return (1); + } + + if ((from_fd = open(entp->fts_path, O_RDONLY, 0)) == -1) { + warn("%s", entp->fts_path); + (void)free(buf); + return (1); + } + + /* + * If the file exists and we're interactive, verify with the user. + * If the file DNE, set the mode to be the from file, minus setuid + * bits, modified by the umask; arguably wrong, but it makes copying + * executables work right and it's been that way forever. (The + * other choice is 666 or'ed with the execute bits on the from file + * modified by the umask.) + */ + if (!dne) { +#define YESNO "(y/n [n]) " + if (nflag) { + if (vflag) + printf("%s not overwritten\n", to.p_path); + (void)close(from_fd); + (void)free(buf); + return (0); + } else if (iflag) { + (void)fprintf(stderr, "overwrite %s? %s", + to.p_path, YESNO); + checkch = ch = getchar(); + while (ch != '\n' && ch != EOF) + ch = getchar(); + if (checkch != 'y' && checkch != 'Y') { + (void)close(from_fd); + (void)free(buf); + (void)fprintf(stderr, "not overwritten\n"); + return (1); + } + } + + if (fflag) { + /* remove existing destination file name, + * create a new file */ + (void)unlink(to.p_path); + if (!lflag) + to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT, + fs->st_mode & ~(S_ISUID | S_ISGID)); + } else { + if (!lflag) + /* overwrite existing destination file name */ + to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0); + } + } else { + if (!lflag) + to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT, + fs->st_mode & ~(S_ISUID | S_ISGID)); + } + + if (to_fd == -1) { + warn("%s", to.p_path); + (void)close(from_fd); + (void)free(buf); + return (1); + } + + rval = 0; + + if (!lflag) { + /* + * Mmap and write if less than 8M (the limit is so we don't totally + * trash memory on big files. This is really a minor hack, but it + * wins some CPU back. + */ +#ifdef CCJ_REMOVED_VM_AND_BUFFER_CACHE_SYNCHRONIZED + if (S_ISREG(fs->st_mode) && fs->st_size > 0 && + fs->st_size <= 8 * 1048576) { + if ((p = mmap(NULL, (size_t)fs->st_size, PROT_READ, + MAP_SHARED, from_fd, (off_t)0)) == MAP_FAILED) { + warn("%s", entp->fts_path); + rval = 1; + } else { + wtotal = 0; + for (bufp = p, wresid = fs->st_size; ; + bufp += wcount, wresid -= (size_t)wcount) { + wcount = write(to_fd, bufp, wresid); + if (wcount <= 0) + break; + wtotal += wcount; + if (info) { + info = 0; + (void)fprintf(stderr, + "%s -> %s %3d%%\n", + entp->fts_path, to.p_path, + cp_pct(wtotal, fs->st_size)); + } + if (wcount >= (ssize_t)wresid) + break; + } + if (wcount != (ssize_t)wresid) { + warn("%s", to.p_path); + rval = 1; + } + /* Some systems don't unmap on close(2). */ + if (munmap(p, fs->st_size) < 0) { + warn("%s", entp->fts_path); + rval = 1; + } + } + } else +#endif + { + wtotal = 0; + while ((rcount = read(from_fd, buf, MAX_READ)) > 0) { + for (bufp = buf, wresid = rcount; ; + bufp += wcount, wresid -= wcount) { + wcount = write(to_fd, bufp, wresid); + if (wcount <= 0) + break; + wtotal += wcount; + if (info) { + info = 0; + (void)fprintf(stderr, + "%s -> %s %3d%%\n", + entp->fts_path, to.p_path, + cp_pct(wtotal, fs->st_size)); + } + if (wcount >= (ssize_t)wresid) + break; + } + if (wcount != (ssize_t)wresid) { + warn("%s", to.p_path); + rval = 1; + break; + } + } + if (rcount < 0) { + warn("%s", entp->fts_path); + rval = 1; + } + } + } else { + if (link(entp->fts_path, to.p_path)) { + warn("%s", to.p_path); + rval = 1; + } + } + (void)close(from_fd); + + /* + * Don't remove the target even after an error. The target might + * not be a regular file, or its attributes might be important, + * or its contents might be irreplaceable. It would only be safe + * to remove it if we created it and its length is 0. + */ + + if (!lflag) { + if (pflag && setfile(cp_globals, fs, to_fd)) + rval = 1; + if (pflag && preserve_fd_acls(from_fd, to_fd) != 0) + rval = 1; + (void)close(from_fd); + if (close(to_fd)) { + warn("%s", to.p_path); + rval = 1; + } + } + (void)free(buf); + return (rval); +} + +int +copy_link(rtems_shell_cp_globals* cp_globals, FTSENT *p, int exists) +{ + ssize_t len; + char llink[PATH_MAX]; + + if ((len = readlink(p->fts_path, llink, sizeof(llink) - 1)) == -1) { + warn("readlink: %s", p->fts_path); + return (1); + } + llink[len] = '\0'; + if (exists && unlink(to.p_path)) { + warn("unlink: %s", to.p_path); + return (1); + } + if (symlink(llink, to.p_path)) { + warn("symlink: %s", llink); + return (1); + } + return (pflag ? setfile(cp_globals, p->fts_statp, -1) : 0); +} + +int +copy_fifo(rtems_shell_cp_globals* cp_globals, struct stat *from_stat, int exists) +{ + if (exists && unlink(to.p_path)) { + warn("unlink: %s", to.p_path); + return (1); + } + if (mkfifo(to.p_path, from_stat->st_mode)) { + warn("mkfifo: %s", to.p_path); + return (1); + } + return (pflag ? setfile(cp_globals, from_stat, -1) : 0); +} + +int +copy_special(rtems_shell_cp_globals* cp_globals, struct stat *from_stat, int exists) +{ + if (exists && unlink(to.p_path)) { + warn("unlink: %s", to.p_path); + return (1); + } + if (mknod(to.p_path, from_stat->st_mode, from_stat->st_rdev)) { + warn("mknod: %s", to.p_path); + return (1); + } + return (pflag ? setfile(cp_globals, from_stat, -1) : 0); +} + +#define TIMESPEC_TO_TIMEVAL(tv, ts) { \ + (tv)->tv_sec = *(ts); \ + (tv)->tv_usec = 0; \ +} + +#define st_atimespec st_atime +#define st_mtimespec st_mtime +#define lutimes utimes + +int +setfile(rtems_shell_cp_globals* cp_globals, struct stat *fs, int fd) +{ + static struct timeval tv[2]; + struct stat ts; + int rval, gotstat, islink, fdval; + + rval = 0; + fdval = fd != -1; + islink = !fdval && S_ISLNK(fs->st_mode); + fs->st_mode &= S_ISUID | S_ISGID | S_ISVTX | + S_IRWXU | S_IRWXG | S_IRWXO; + + TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec); + TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec); +#if 0 + if (islink ? lutimes(to.p_path, tv) : utimes(to.p_path, tv)) { + warn("%sutimes: %s", islink ? "l" : "", to.p_path); + rval = 1; + } +#endif + if (fdval ? fstat(fd, &ts) : + (islink ? lstat(to.p_path, &ts) : stat(to.p_path, &ts))) + gotstat = 0; + else { + gotstat = 1; + ts.st_mode &= S_ISUID | S_ISGID | S_ISVTX | + S_IRWXU | S_IRWXG | S_IRWXO; + } + /* + * Changing the ownership probably won't succeed, unless we're root + * or POSIX_CHOWN_RESTRICTED is not set. Set uid/gid before setting + * the mode; current BSD behavior is to remove all setuid bits on + * chown. If chown fails, lose setuid/setgid bits. + */ + if (!gotstat || fs->st_uid != ts.st_uid || fs->st_gid != ts.st_gid) + if (fdval ? fchown(fd, fs->st_uid, fs->st_gid) : + (islink ? lchown(to.p_path, fs->st_uid, fs->st_gid) : + chown(to.p_path, fs->st_uid, fs->st_gid))) { + if (errno != EPERM) { + warn("chown: %s", to.p_path); + rval = 1; + } + fs->st_mode &= ~(S_ISUID | S_ISGID); + } + + if (!gotstat || fs->st_mode != ts.st_mode) + if (fdval ? fchmod(fd, fs->st_mode) : + (islink ? lchmod(to.p_path, fs->st_mode) : + chmod(to.p_path, fs->st_mode))) { + warn("chmod: %s", to.p_path); + rval = 1; + } + +#if 0 + if (!gotstat || fs->st_flags != ts.st_flags) + if (fdval ? + fchflags(fd, fs->st_flags) : + (islink ? (errno = ENOSYS) : + chflags(to.p_path, fs->st_flags))) { + warn("chflags: %s", to.p_path); + rval = 1; + } +#endif + + return (rval); +} + +int +preserve_fd_acls(int source_fd __attribute__((unused)), int dest_fd __attribute__((unused))) +{ +#if 0 + struct acl *aclp; + acl_t acl; + + if (fpathconf(source_fd, _PC_ACL_EXTENDED) != 1 || + fpathconf(dest_fd, _PC_ACL_EXTENDED) != 1) + return (0); + acl = acl_get_fd(source_fd); + if (acl == NULL) { + warn("failed to get acl entries while setting %s", to.p_path); + return (1); + } + aclp = &acl->ats_acl; + if (aclp->acl_cnt == 3) + return (0); + if (acl_set_fd(dest_fd, acl) < 0) { + warn("failed to set acl entries for %s", to.p_path); + return (1); + } +#endif + return (0); +} + +int +preserve_dir_acls(struct stat *fs __attribute__((unused)), char *source_dir __attribute__((unused)), char *dest_dir __attribute__((unused))) +{ +#if 0 + acl_t (*aclgetf)(const char *, acl_type_t); + int (*aclsetf)(const char *, acl_type_t, acl_t); + struct acl *aclp; + acl_t acl; + + if (pathconf(source_dir, _PC_ACL_EXTENDED) != 1 || + pathconf(dest_dir, _PC_ACL_EXTENDED) != 1) + return (0); + /* + * If the file is a link we will not follow it + */ + if (S_ISLNK(fs->st_mode)) { + aclgetf = acl_get_link_np; + aclsetf = acl_set_link_np; + } else { + aclgetf = acl_get_file; + aclsetf = acl_set_file; + } + /* + * Even if there is no ACL_TYPE_DEFAULT entry here, a zero + * size ACL will be returned. So it is not safe to simply + * check the pointer to see if the default ACL is present. + */ + acl = aclgetf(source_dir, ACL_TYPE_DEFAULT); + if (acl == NULL) { + warn("failed to get default acl entries on %s", + source_dir); + return (1); + } + aclp = &acl->ats_acl; + if (aclp->acl_cnt != 0 && aclsetf(dest_dir, + ACL_TYPE_DEFAULT, acl) < 0) { + warn("failed to set default acl entries on %s", + dest_dir); + return (1); + } + acl = aclgetf(source_dir, ACL_TYPE_ACCESS); + if (acl == NULL) { + warn("failed to get acl entries on %s", source_dir); + return (1); + } + aclp = &acl->ats_acl; + if (aclsetf(dest_dir, ACL_TYPE_ACCESS, acl) < 0) { + warn("failed to set acl entries on %s", dest_dir); + return (1); + } +#endif + return (0); +} + +void +usage(rtems_shell_cp_globals* cp_globals) +{ + (void)fprintf(stderr, "%s\n%s\n", +"usage: cp [-R [-H | -L | -P]] [-f | -i | -n] [-alpv] source_file target_file", +" cp [-R [-H | -L | -P]] [-f | -i | -n] [-alpv] source_file ... " +"target_directory"); + longjmp (cp_globals->exit_jmp, 1); +} diff --git a/cpukit/libmisc/shell/utils-ls.c b/cpukit/libmisc/shell/utils-ls.c new file mode 100644 index 0000000000..7ff0d1b4bd --- /dev/null +++ b/cpukit/libmisc/shell/utils-ls.c @@ -0,0 +1,117 @@ +/* $NetBSD: util.c,v 1.28 2005/06/17 14:36:16 hira Exp $ */ + +/* + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Michael Fischbein. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if 0 +#include <sys/cdefs.h> +#ifndef lint +#if 0 +static char sccsid[] = "@(#)util.c 8.5 (Berkeley) 4/28/95"; +#else +__RCSID("$NetBSD: util.c,v 1.28 2005/06/17 14:36:16 hira Exp $"); +#endif +#endif /* not lint */ +#endif + +#include <sys/types.h> +#include <sys/stat.h> + +#include <ctype.h> +#include <err.h> +#include <fts.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <vis.h> + +#include "extern-ls.h" + +#define SIZE_T_MAX 255 + +int +safe_print(rtems_shell_ls_globals* globals, const char *src) +{ + size_t len; + char *name; + int flags; + + flags = VIS_NL | VIS_OCTAL; + if (f_octal_escape) + flags |= VIS_CSTYLE; + + len = strlen(src); + if (len != 0 && SIZE_T_MAX/len <= 4) { + errx(exit_jump, EXIT_FAILURE, "%s: name too long", src); + /* NOTREACHED */ + } + + name = (char *)malloc(4*len+1); + if (name != NULL) { + len = strvis(name, src, flags); + printf("%s", name); + free(name); + return len; + } else + errx(exit_jump, EXIT_FAILURE, "out of memory!"); + /* NOTREACHED */ +} + +int +printescaped(rtems_shell_ls_globals* globals __attribute__((unused)), const char *src) +{ + unsigned char c; + int n; + + for (n = 0; (c = *src) != '\0'; ++src, ++n) + if (isprint(c)) + (void)putchar(c); + else + (void)putchar('?'); + return n; +} + +void +usage(rtems_shell_ls_globals* globals) +{ + + (void)fprintf(stderr, + "usage: %s [-AaBbCcdFfghikLlmnopqRrSsTtuWwx1] [file ...]\n", + "ls"); + exit(EXIT_FAILURE); + /* NOTREACHED */ +} diff --git a/cpukit/libmisc/shell/verr.c b/cpukit/libmisc/shell/verr.c new file mode 100644 index 0000000000..301e229a1c --- /dev/null +++ b/cpukit/libmisc/shell/verr.c @@ -0,0 +1,75 @@ +/* $NetBSD: verr.c,v 1.13 2005/09/13 01:44:09 christos Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)err.c 8.1 (Berkeley) 6/4/93"; +#else +__RCSID("$NetBSD: verr.c,v 1.13 2005/09/13 01:44:09 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#include <err.h> +#include <errno.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef __weak_alias +__weak_alias(verr, _verr) +#endif + +__dead void +verr(jmp_buf* exit_jmp, int eval __attribute__((unused)), const char *fmt, _BSD_VA_LIST_ ap) +{ + int sverrno; + + sverrno = errno; +#if 0 + (void)fprintf(stderr, "%s: ", getprogname()); +#endif + if (fmt != NULL) { + (void)vfprintf(stdout, fmt, ap); + (void)fprintf(stdout, ": "); + } + (void)fprintf(stdout, "%s\n", strerror(sverrno)); + longjmp (*exit_jmp, 1); +} diff --git a/cpukit/libmisc/shell/verrx.c b/cpukit/libmisc/shell/verrx.c new file mode 100644 index 0000000000..30355dd31c --- /dev/null +++ b/cpukit/libmisc/shell/verrx.c @@ -0,0 +1,68 @@ +/* $NetBSD: verrx.c,v 1.13 2005/09/13 01:44:09 christos Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)err.c 8.1 (Berkeley) 6/4/93"; +#else +__RCSID("$NetBSD: verrx.c,v 1.13 2005/09/13 01:44:09 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#include <err.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> + +#ifdef __weak_alias +__weak_alias(verrx, _verrx) +#endif + +__dead void +verrx(jmp_buf* exit_jmp, int eval __attribute__((unused)), const char *fmt, _BSD_VA_LIST_ ap) +{ +#if 0 + (void)fprintf(stderr, "%s: ", getprogname()); +#endif + if (fmt != NULL) + (void)vfprintf(stdout, fmt, ap); + (void)fprintf(stdout, "\n"); + longjmp (*exit_jmp, 1); +} diff --git a/cpukit/libmisc/shell/vis.c b/cpukit/libmisc/shell/vis.c new file mode 100644 index 0000000000..6316555279 --- /dev/null +++ b/cpukit/libmisc/shell/vis.c @@ -0,0 +1,387 @@ +/* $NetBSD: vis.c,v 1.33 2005/05/28 13:11:14 lukem Exp $ */ + +/*- + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/*- + * Copyright (c) 1999, 2005 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define _DIAGASSERT(a) + +#if 0 +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: vis.c,v 1.33 2005/05/28 13:11:14 lukem Exp $"); +#endif /* LIBC_SCCS and not lint */ +#endif + +#include <sys/types.h> + +#include <vis.h> +#include <stdlib.h> + +#if !HAVE_VIS || !HAVE_SVIS +#include <ctype.h> +#include <limits.h> +#include <stdio.h> +#include <string.h> + +#undef BELL +#define BELL '\a' + +#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') +#define iswhite(c) (c == ' ' || c == '\t' || c == '\n') +#define issafe(c) (c == '\b' || c == BELL || c == '\r') +#define xtoa(c) "0123456789abcdef"[c] + +#define MAXEXTRAS 5 + + +#define MAKEEXTRALIST(flag, extra, orig) \ +do { \ + const char *o = orig; \ + char *e; \ + while (*o++) \ + continue; \ + extra = malloc((size_t)((o - orig) + MAXEXTRAS)); \ + if (!extra) break; \ + for (o = orig, e = extra; (*e++ = *o++) != '\0';) \ + continue; \ + e--; \ + if (flag & VIS_SP) *e++ = ' '; \ + if (flag & VIS_TAB) *e++ = '\t'; \ + if (flag & VIS_NL) *e++ = '\n'; \ + if ((flag & VIS_NOSLASH) == 0) *e++ = '\\'; \ + *e = '\0'; \ +} while (/*CONSTCOND*/0) + + +/* + * This is HVIS, the macro of vis used to HTTP style (RFC 1808) + */ +#define HVIS(dst, c, flag, nextc, extra) \ +do \ + if (!isascii(c) || !isalnum(c) || strchr("$-_.+!*'(),", c) != NULL) { \ + *dst++ = '%'; \ + *dst++ = xtoa(((unsigned int)c >> 4) & 0xf); \ + *dst++ = xtoa((unsigned int)c & 0xf); \ + } else { \ + SVIS(dst, c, flag, nextc, extra); \ + } \ +while (/*CONSTCOND*/0) + +/* + * This is SVIS, the central macro of vis. + * dst: Pointer to the destination buffer + * c: Character to encode + * flag: Flag word + * nextc: The character following 'c' + * extra: Pointer to the list of extra characters to be + * backslash-protected. + */ +#define SVIS(dst, c, flag, nextc, extra) \ +do { \ + int isextra; \ + isextra = strchr(extra, c) != NULL; \ + if (!isextra && isascii(c) && (isgraph(c) || iswhite(c) || \ + ((flag & VIS_SAFE) && issafe(c)))) { \ + *dst++ = c; \ + break; \ + } \ + if (flag & VIS_CSTYLE) { \ + switch (c) { \ + case '\n': \ + *dst++ = '\\'; *dst++ = 'n'; \ + continue; \ + case '\r': \ + *dst++ = '\\'; *dst++ = 'r'; \ + continue; \ + case '\b': \ + *dst++ = '\\'; *dst++ = 'b'; \ + continue; \ + case BELL: \ + *dst++ = '\\'; *dst++ = 'a'; \ + continue; \ + case '\v': \ + *dst++ = '\\'; *dst++ = 'v'; \ + continue; \ + case '\t': \ + *dst++ = '\\'; *dst++ = 't'; \ + continue; \ + case '\f': \ + *dst++ = '\\'; *dst++ = 'f'; \ + continue; \ + case ' ': \ + *dst++ = '\\'; *dst++ = 's'; \ + continue; \ + case '\0': \ + *dst++ = '\\'; *dst++ = '0'; \ + if (isoctal(nextc)) { \ + *dst++ = '0'; \ + *dst++ = '0'; \ + } \ + continue; \ + default: \ + if (isgraph(c)) { \ + *dst++ = '\\'; *dst++ = c; \ + continue; \ + } \ + } \ + } \ + if (isextra || ((c & 0177) == ' ') || (flag & VIS_OCTAL)) { \ + *dst++ = '\\'; \ + *dst++ = (u_char)(((u_int32_t)(u_char)c >> 6) & 03) + '0'; \ + *dst++ = (u_char)(((u_int32_t)(u_char)c >> 3) & 07) + '0'; \ + *dst++ = (c & 07) + '0'; \ + } else { \ + if ((flag & VIS_NOSLASH) == 0) *dst++ = '\\'; \ + if (c & 0200) { \ + c &= 0177; *dst++ = 'M'; \ + } \ + if (iscntrl(c)) { \ + *dst++ = '^'; \ + if (c == 0177) \ + *dst++ = '?'; \ + else \ + *dst++ = c + '@'; \ + } else { \ + *dst++ = '-'; *dst++ = c; \ + } \ + } \ +} while (/*CONSTCOND*/0) + + +/* + * svis - visually encode characters, also encoding the characters + * pointed to by `extra' + */ +char * +svis(char *dst, int c, int flag, int nextc, const char *extra) +{ + char *nextra = NULL; + + _DIAGASSERT(dst != NULL); + _DIAGASSERT(extra != NULL); + MAKEEXTRALIST(flag, nextra, extra); + if (!nextra) { + *dst = '\0'; /* can't create nextra, return "" */ + return dst; + } + if (flag & VIS_HTTPSTYLE) + HVIS(dst, c, flag, nextc, nextra); + else + SVIS(dst, c, flag, nextc, nextra); + free(nextra); + *dst = '\0'; + return dst; +} + + +/* + * strsvis, strsvisx - visually encode characters from src into dst + * + * Extra is a pointer to a \0-terminated list of characters to + * be encoded, too. These functions are useful e. g. to + * encode strings in such a way so that they are not interpreted + * by a shell. + * + * Dst must be 4 times the size of src to account for possible + * expansion. The length of dst, not including the trailing NULL, + * is returned. + * + * Strsvisx encodes exactly len bytes from src into dst. + * This is useful for encoding a block of data. + */ +int +strsvis(char *dst, const char *csrc, int flag, const char *extra) +{ + int c; + char *start; + char *nextra = NULL; + const unsigned char *src = (const unsigned char *)csrc; + + _DIAGASSERT(dst != NULL); + _DIAGASSERT(src != NULL); + _DIAGASSERT(extra != NULL); + MAKEEXTRALIST(flag, nextra, extra); + if (!nextra) { + *dst = '\0'; /* can't create nextra, return "" */ + return 0; + } + if (flag & VIS_HTTPSTYLE) { + for (start = dst; (c = *src++) != '\0'; /* empty */) + HVIS(dst, c, flag, *src, nextra); + } else { + for (start = dst; (c = *src++) != '\0'; /* empty */) + SVIS(dst, c, flag, *src, nextra); + } + free(nextra); + *dst = '\0'; + return (dst - start); +} + + +int +strsvisx(char *dst, const char *csrc, size_t len, int flag, const char *extra) +{ + unsigned char c; + char *start; + char *nextra = NULL; + const unsigned char *src = (const unsigned char *)csrc; + + _DIAGASSERT(dst != NULL); + _DIAGASSERT(src != NULL); + _DIAGASSERT(extra != NULL); + MAKEEXTRALIST(flag, nextra, extra); + if (! nextra) { + *dst = '\0'; /* can't create nextra, return "" */ + return 0; + } + + if (flag & VIS_HTTPSTYLE) { + for (start = dst; len > 0; len--) { + c = *src++; + HVIS(dst, c, flag, len ? *src : '\0', nextra); + } + } else { + for (start = dst; len > 0; len--) { + c = *src++; + SVIS(dst, c, flag, len ? *src : '\0', nextra); + } + } + free(nextra); + *dst = '\0'; + return (dst - start); +} +#endif + +#if !HAVE_VIS +/* + * vis - visually encode characters + */ +char * +vis(char *dst, int c, int flag, int nextc) +{ + char *extra = NULL; + unsigned char uc = (unsigned char)c; + + _DIAGASSERT(dst != NULL); + + MAKEEXTRALIST(flag, extra, ""); + if (! extra) { + *dst = '\0'; /* can't create extra, return "" */ + return dst; + } + if (flag & VIS_HTTPSTYLE) + HVIS(dst, uc, flag, nextc, extra); + else + SVIS(dst, uc, flag, nextc, extra); + free(extra); + *dst = '\0'; + return dst; +} + + +/* + * strvis, strvisx - visually encode characters from src into dst + * + * Dst must be 4 times the size of src to account for possible + * expansion. The length of dst, not including the trailing NULL, + * is returned. + * + * Strvisx encodes exactly len bytes from src into dst. + * This is useful for encoding a block of data. + */ +int +strvis(char *dst, const char *src, int flag) +{ + char *extra = NULL; + int rv; + + MAKEEXTRALIST(flag, extra, ""); + if (!extra) { + *dst = '\0'; /* can't create extra, return "" */ + return 0; + } + rv = strsvis(dst, src, flag, extra); + free(extra); + return rv; +} + + +int +strvisx(char *dst, const char *src, size_t len, int flag) +{ + char *extra = NULL; + int rv; + + MAKEEXTRALIST(flag, extra, ""); + if (!extra) { + *dst = '\0'; /* can't create extra, return "" */ + return 0; + } + rv = strsvisx(dst, src, len, flag, extra); + free(extra); + return rv; +} +#endif diff --git a/cpukit/libmisc/shell/vis.h b/cpukit/libmisc/shell/vis.h new file mode 100644 index 0000000000..fb0aa6dc2a --- /dev/null +++ b/cpukit/libmisc/shell/vis.h @@ -0,0 +1,91 @@ +/* $NetBSD: vis.h,v 1.16 2005/09/13 01:44:32 christos Exp $ */ + +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)vis.h 8.1 (Berkeley) 6/2/93 + */ + +#ifndef _VIS_H_ +#define _VIS_H_ + +#include <sys/types.h> + +/* + * to select alternate encoding format + */ +#define VIS_OCTAL 0x01 /* use octal \ddd format */ +#define VIS_CSTYLE 0x02 /* use \[nrft0..] where appropiate */ + +/* + * to alter set of characters encoded (default is to encode all + * non-graphic except space, tab, and newline). + */ +#define VIS_SP 0x04 /* also encode space */ +#define VIS_TAB 0x08 /* also encode tab */ +#define VIS_NL 0x10 /* also encode newline */ +#define VIS_WHITE (VIS_SP | VIS_TAB | VIS_NL) +#define VIS_SAFE 0x20 /* only encode "unsafe" characters */ + +/* + * other + */ +#define VIS_NOSLASH 0x40 /* inhibit printing '\' */ +#define VIS_HTTPSTYLE 0x80 /* http-style escape % HEX HEX */ + +/* + * unvis return codes + */ +#define UNVIS_VALID 1 /* character valid */ +#define UNVIS_VALIDPUSH 2 /* character valid, push back passed char */ +#define UNVIS_NOCHAR 3 /* valid sequence, no character produced */ +#define UNVIS_SYNBAD -1 /* unrecognized escape sequence */ +#define UNVIS_ERROR -2 /* decoder in unknown state (unrecoverable) */ + +/* + * unvis flags + */ +#define UNVIS_END 1 /* no more characters */ + +#include <sys/cdefs.h> + +__BEGIN_DECLS +char *vis(char *, int, int, int); +char *svis(char *, int, int, int, const char *); +int strvis(char *, const char *, int); +int strsvis(char *, const char *, int, const char *); +int strvisx(char *, const char *, size_t, int); +int strsvisx(char *, const char *, size_t, int, const char *); +int strunvis(char *, const char *); +int strunvisx(char *, const char *, int); +#ifndef __LIBC12_SOURCE__ +//int unvis(char *, int, int *, int) __RENAME(__unvis13); +#endif +__END_DECLS + +#endif /* !_VIS_H_ */ diff --git a/cpukit/libmisc/shell/vwarn.c b/cpukit/libmisc/shell/vwarn.c new file mode 100644 index 0000000000..df214c5db9 --- /dev/null +++ b/cpukit/libmisc/shell/vwarn.c @@ -0,0 +1,74 @@ +/* $NetBSD: vwarn.c,v 1.13 2005/09/13 01:44:09 christos Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)err.c 8.1 (Berkeley) 6/4/93"; +#else +__RCSID("$NetBSD: vwarn.c,v 1.13 2005/09/13 01:44:09 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#include <err.h> +#include <errno.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef __weak_alias +__weak_alias(vwarn, _vwarn) +#endif + +void +vwarn(const char *fmt, _BSD_VA_LIST_ ap) +{ + int sverrno; + + sverrno = errno; +#if 0 + (void)fprintf(stderr, "%s: ", getprogname()); +#endif + if (fmt != NULL) { + (void)vfprintf(stdout, fmt, ap); + (void)fprintf(stdout, ": "); + } + (void)fprintf(stdout, "%s\n", strerror(sverrno)); +} diff --git a/cpukit/libmisc/shell/vwarnx.c b/cpukit/libmisc/shell/vwarnx.c new file mode 100644 index 0000000000..34737a17f1 --- /dev/null +++ b/cpukit/libmisc/shell/vwarnx.c @@ -0,0 +1,67 @@ +/* $NetBSD: vwarnx.c,v 1.13 2005/09/13 01:44:09 christos Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)err.c 8.1 (Berkeley) 6/4/93"; +#else +__RCSID("$NetBSD: vwarnx.c,v 1.13 2005/09/13 01:44:09 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#include <err.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> + +#ifdef __weak_alias +__weak_alias(vwarnx, _vwarnx) +#endif + +void +vwarnx(const char *fmt, _BSD_VA_LIST_ ap) +{ +#if 0 + (void)fprintf(stderr, "%s: ", getprogname()); +#endif + if (fmt != NULL) + (void)vfprintf(stdout, fmt, ap); + (void)fprintf(stdout, "\n"); +} diff --git a/cpukit/libmisc/shell/warn.c b/cpukit/libmisc/shell/warn.c new file mode 100644 index 0000000000..f32edfb630 --- /dev/null +++ b/cpukit/libmisc/shell/warn.c @@ -0,0 +1,64 @@ +/* $NetBSD: warn.c,v 1.13 2005/09/13 13:51:50 christos Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)err.c 8.1 (Berkeley) 6/4/93"; +#else +__RCSID("$NetBSD: warn.c,v 1.13 2005/09/13 13:51:50 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#include <err.h> +#include <stdarg.h> + +#ifdef __weak_alias +__weak_alias(warn, _warn) +#endif + +void +warn(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vwarn(fmt, ap); + va_end(ap); +} diff --git a/cpukit/libmisc/shell/warnx.c b/cpukit/libmisc/shell/warnx.c new file mode 100644 index 0000000000..efcbd8b0f1 --- /dev/null +++ b/cpukit/libmisc/shell/warnx.c @@ -0,0 +1,64 @@ +/* $NetBSD: warnx.c,v 1.13 2005/09/13 13:51:50 christos Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)err.c 8.1 (Berkeley) 6/4/93"; +#else +__RCSID("$NetBSD: warnx.c,v 1.13 2005/09/13 13:51:50 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#include <err.h> +#include <stdarg.h> + +#ifdef __weak_alias +__weak_alias(warnx, _warnx) +#endif + +void +warnx(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vwarnx(fmt, ap); + va_end(ap); +} diff --git a/cpukit/libmisc/shell/write_file.c b/cpukit/libmisc/shell/write_file.c new file mode 100644 index 0000000000..f9e72f4645 --- /dev/null +++ b/cpukit/libmisc/shell/write_file.c @@ -0,0 +1,43 @@ +/* + * + * Write buffer to a file + * + * Author: + * + * WORK: fernando.ruiz@ctv.es + * HOME: correo@fernando-ruiz.com + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <unistd.h> +#include <string.h> + +void rtems_shell_write_file( + const char *name, + const char *content +) +{ + FILE * fd; + + fd = fopen(name,"w"); + if ( !fd ) { + fprintf( stderr, "Unable to write %s\n", name ); + } + + if (fd) { + fwrite(content,1,strlen(content),fd); + fclose(fd); + } +} + + |