/*
* Copyright 1998,2001-2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Copyright (c) 1985 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <setjmp.h>
#include <euc.h>
#include <widec.h>
#include "restore.h"
#include <ctype.h>
#include <limits.h>
extern eucwidth_t wp;
/*
* Things to handle interruptions.
*/
static int reset_OK;
#ifdef __STDC__
static void setpagercmd(void);
static uint_t setpagerargs(char **);
#else
static void getcmd();
static void expandarg();
static void printlist();
static void formatf();
static char *copynext();
static int fcmp();
static char *fmtentry();
static void setpagercmd();
static uint_t setpagerargs();
#endif
/*
* Read and execute commands from the terminal.
*/
void
#ifdef __STDC__
runcmdshell(void)
#else
#endif
{
#ifdef lint
curdir[0] = '\0';
#endif /* lint */
loop:
volno = 0;
goto loop; /* make sure jmpbuf is up-to-date */
}
reset_OK = 1;
/*
* Using strncmp() to catch unique prefixes.
*/
switch (cmd[0]) {
/*
* Add elements to the extraction list.
*/
case 'a':
goto bad;
if (name[0] == '\0')
break;
if (ino == 0)
break;
if (mflag)
break;
/*
* Change working directory.
*/
case 'c':
goto bad;
if (name[0] == '\0')
break;
if (ino == 0)
break;
break;
}
/* No need to canon(name), getcmd() did it for us */
break;
/*
* Delete elements from the extraction list.
*/
case 'd':
goto bad;
if (name[0] == '\0')
break;
break;
}
break;
/*
* Extract the requested list.
*/
case 'e':
goto bad;
createfiles();
createlinks();
setdirmodes();
if (dflag)
checkrestore();
volno = 0;
break;
/*
* List available commands.
*/
case 'h':
goto bad;
/*FALLTHROUGH*/
case '?':
/* ANSI string catenation, to shut cstyle up */
gettext("Available commands are:\n"
"\tls [arg] - list directory\n"
"\tmarked [arg] - list items marked for extraction from directory\n"
"\tcd arg - change directory\n"
"\tpwd - print current directory\n"
"\tadd [arg] - add `arg' to list of files to be extracted\n"
"\tdelete [arg] - delete `arg' from list of files to be extracted\n"
"\textract - extract requested files\n"
"\tsetmodes - set modes of requested directories\n"
"\tquit - immediately exit program\n"
"\twhat - list dump header information\n"
"\tverbose - toggle verbose flag (useful with ``ls'')\n"
"\tpaginate - toggle pagination flag (affects ``ls'' and ``marked'')\n"
"\tsetpager - set pagination command and arguments\n"
"\thelp or `?' - print this list\n"
"If no `arg' is supplied, the current directory is used\n"));
break;
/*
* List a directory.
*/
case 'l':
case 'm':
goto bad;
if (name[0] == '\0')
break;
if (ino == 0)
break;
break;
/*
* Print current directory or enable pagination.
*/
case 'p':
goto ambiguous;
} else {
}
if (paginating) {
gettext("paging disabled\n"));
paginating = 0;
break;
}
if (vflag) {
gettext("paging enabled (%s)\n"),
} else {
gettext("paging enabled\n"));
}
if (dflag) {
int index = 0;
">>>pager_vector[%d] = `%s'\n",
index += 1;
}
}
paginating = 1;
} else {
goto bad;
}
break;
/*
* Quit.
*/
case 'q':
goto bad;
reset_OK = 0;
return;
case 'x':
goto bad;
reset_OK = 0;
return;
/*
* Toggle verbose mode.
*/
case 'v':
goto bad;
if (vflag) {
vflag = 0;
break;
}
vflag = 1;
break;
/*
* Just restore requested directory modes, or set pagination command.
*/
case 's':
goto ambiguous;
setdirmodes();
setpagercmd();
} else {
goto bad;
}
break;
/*
* Print out dump header information.
*/
case 'w':
goto bad;
break;
/*
* Turn on debugging.
*/
case 'D':
goto bad;
if (dflag) {
dflag = 0;
break;
}
dflag++;
break;
/*
* Unknown command.
*/
default:
bad:
break;
break;
}
goto loop;
}
/*
* Read and parse an interactive command.
* The first word on the line is assigned to "cmd". If
* there are no arguments on the command line, then "curdir"
* is returned as the argument. If there are arguments
* on the line they are returned one at a time on each
* successive call to getcmd. Each argument is first assigned
* to "name". If it does not start with "/" the pathname in
* "curdir" is prepended to it. Finally "canon" is called to
* eliminate any embedded ".." components.
*/
/* ARGSUSED */
static void
{
char *cp;
/*
* Check to see if still processing arguments.
*/
/* double null terminate string */
} else {
}
return;
}
goto getnext;
/*
* Read a command line and trim off trailing white space.
*/
do {
return;
}
/* trim off trailing white space and newline */
cp--) {
continue;
/*LINTED [empty loop body]*/
}
*++cp = '\0';
goto readagain;
} else {
/* double null terminate string */
}
goto readagain;
/*
* Copy the command into "cmd".
*/
/*
* If no argument, use curdir as the default.
*/
if (*cp == '\0') {
/* double null terminate string */
} else {
}
return;
}
/*
* Find the next argument.
*/
if (*cp == '\0')
else
/*
* If it an absolute pathname, canonicalize it and return it.
*/
if (rawname[0] == '/') {
} else {
/*
* For relative pathnames, prepend the current directory to
* it then canonicalize and return it.
*/
}
/*
* ap->head->fname guaranteed to be double null-terminated and
* no more than MAXCOMPLEXLEN characters long.
*/
/* double null terminate string */
}
/*
* Strip off the next token of the input.
*/
static char *
{
char quote;
dontexpand = 0;
/* skip to argument */
continue;
/*LINTED [empty loop body]*/
}
/*
* Handle back slashes.
*/
if (*cp == '\\') {
if (*++cp == '\0') {
"command lines cannot be continued\n"));
continue;
}
continue;
}
/*
* The usual unquoted case.
*/
continue;
}
/*
* Handle single and double quotes.
*/
dontexpand = 1;
if (*cp++ == '\0') {
cp--;
continue;
}
}
*bp = '\0';
"name is too long, ignoring"));
} else {
/* double null terminate string */
}
return (cp);
}
/*
* Canonicalize file names to always start with ``./'' and
* remove any imbedded "." and ".." components.
*
* The pathname "canonname" is returned double null terminated.
*/
void
{
prefix = "";
else if (rawname[0] == '/')
prefix = ".";
else
prefix = "./";
/*
* Eliminate multiple and trailing '/'s
*/
np++;
}
*cp = '\0';
gettext("canonical name is too long, ignoring name\n"));
} else {
/* double null terminate string */
}
if (*--cp == '/')
*cp = '\0';
/*
* Eliminate extraneous "." and ".." from pathnames. Uses
* memmove(), as strcpy() might do the wrong thing for these
* small overlaps.
*/
while (*np != '\0') {
np++;
np++;
cp--;
/* double null terminate string */
}
cp--;
/* find beginning of name */
continue;
/*LINTED [empty loop body]*/
}
/* double null terminate string */
}
}
}
/*
* globals (file name generation)
*
* "*" in params matches r.e ".*"
* "?" in params matches r.e. "."
* "[...]" in params matches character class
* "[...a-z...]" in params matches a through z.
*/
static void
char *arg;
{
int size;
if (dontexpand)
size = 0;
else
if (size == 0) {
return;
}
gettext("Argument expansion too large to sort\n"));
} else {
/* LINTED pointer arith just range-checked */
(int (*)(const void *, const void *)) fcmp);
}
}
/*
* Do an "ls" style listing of a directory
*/
static void
char *name;
char *basename;
int marked_only;
{
int list_entry;
else
}
} else {
break;
}
continue;
if (vflag == 0 &&
continue;
list_entry = 1;
if (marked_only) {
list_entry = 0;
}
if (list_entry) {
return;
}
}
}
}
gettext("Directory too large to sort\n"));
} else {
/* LINTED range-checked */
(int (*)(const void *, const void *)) fcmp);
}
/*
* Don't free alist.base, as we'll probably be called
* again, and might as well re-use what we've got.
*/
}
}
}
/*
* Print out a pretty listing of a directory
*/
static void
{
/* LINTED: result fits into an int */
int i, j;
char *cp;
return;
if (paginating) {
goto no_page;
}
switch (fork()) {
case -1:
goto no_page;
case 0:
/*
* Make sure final output still ends up in
* the same place.
*/
exit(1);
/*NOTREACHED*/
default:
break;
}
gettext("pagination disabled\n"));
paginating = 0;
}
}
else
}
width += 2;
if (columns == 0)
columns = 1;
break;
}
while (w < width) {
w++;
break;
}
}
}
if (paginating) {
}
}
/*
* Comparison routine for qsort.
*/
static int
{
}
/*
* Format a directory entry.
*/
static char *
{
static int precision = 0;
ino_t i;
if (!vflag) {
/* MAXCOMPLEXLEN assumed to be >= 1 */
fmtres[0] = '\0';
} else {
if (precision == 0) {
for (i = maxino; i != 0; i /= 10)
precision++;
"\nInternal check failed, minimum width %d exceeds available size %d\n"),
done(1);
}
}
}
*dp++ = '^';
*dp++ = '*';
else
*dp++ = ' ';
/* LINTED: precedence ok, can't fix system macro */
*dp++ = '?';
else
*dp++ = '/';
*dp++ = 0;
return (fmtres);
}
/*
* respond to interrupts
*/
/* ARGSUSED */
void
int sig;
{
done(1);
}
/*
* Set up pager_catenated and pager_vector.
*/
void
#ifdef __STDC__
initpagercmd(void)
#else
#endif
{
char *cp;
if (pager_catenated != NULL)
}
if (pager_catenated == NULL) {
done(1);
}
pager_vector = (char **)malloc(sizeof (char *));
if (pager_vector == NULL) {
done(1);
}
pager_len = 1;
(void) setpagerargs(&cp);
}
/*
* Resets pager_catenated and pager_vector from user input.
*/
void
#ifdef __STDC__
setpagercmd(void)
#else
#endif
{
int index;
/*
* We'll get called immediately after setting a pager, due to
* our interaction with getcmd()'s internal state. Don't do
* anything when that happens.
*/
if (*input == '\0')
return;
if (pager_len > 0) {
}
if (pager_vector == NULL) {
done(1);
}
pager_len = 2;
if (pager_vector[0] == NULL) {
done(1);
}
if (dflag)
(size_t)sizeof (char));
if (pager_catenated == (char *)NULL) {
done(1);
}
if (index > 0)
}
}
/*
* Extract arguments for the pager command from getcmd()'s input buffer.
*/
static uint_t
char **source;
{
if (dflag)
if (pager_vector == (char **)NULL) {
done(1);
}
done(1);
}
pager_len += 1;
}
return (length);
}