539 lines
20 KiB
Go
539 lines
20 KiB
Go
package handler
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/bytedream/sshoneypot/sshoneypot/info"
|
|
"math/rand"
|
|
"os"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
func basicFileCommandParser(info *info.Info, help string, availableOptions... string) (options []string, files []string, ok bool) {
|
|
if len(info.Args) == 0 {
|
|
info.Errorln(missingOperand(info))
|
|
return nil, nil, false
|
|
} else {
|
|
for _, arg := range info.Args {
|
|
if strings.HasPrefix(arg, "-") {
|
|
hasArg := len(availableOptions) == 0
|
|
|
|
if arg == "--help" {
|
|
info.Writeln(help)
|
|
return nil, nil, false
|
|
}
|
|
for _, option := range availableOptions {
|
|
if arg == option {
|
|
hasArg = true
|
|
break
|
|
}
|
|
}
|
|
options = append(options, arg)
|
|
|
|
if !hasArg{
|
|
info.Errorlnf("%s: unrecognized option '%s'", info.Command, arg)
|
|
info.Errorlnf("Try '%s --help' for more information.", info.Command)
|
|
return nil, nil, false
|
|
}
|
|
} else {
|
|
files = append(files, arg)
|
|
}
|
|
}
|
|
}
|
|
return options, files, true
|
|
}
|
|
|
|
type Cat struct {
|
|
info.SimpleHandler
|
|
}
|
|
|
|
func (cat Cat) Handle(cmdInfo *info.Info) {
|
|
if multipleArgs(cmdInfo) {
|
|
var paths []string
|
|
for _, arg := range cmdInfo.Args {
|
|
if strings.HasPrefix(arg, "-") {
|
|
switch arg {
|
|
case "--help":
|
|
cmdInfo.Writeln(cat.help())
|
|
return
|
|
}
|
|
} else {
|
|
paths = append(paths, arg)
|
|
}
|
|
}
|
|
|
|
for _, path := range paths {
|
|
if file, ok := cmdInfo.FS.GetFile(path, false); ok {
|
|
if file.IsDir() {
|
|
cmdInfo.Writelnf("%s:%s: Is a directory", cmdInfo.Command, path)
|
|
} else {
|
|
realFile := file.(info.File)
|
|
bytes := make([]byte, realFile.Size)
|
|
// this will make the file content always the same
|
|
rand.Seed(realFile.Size + realFile.CreationTimestamp)
|
|
|
|
rand.Read(bytes)
|
|
cmdInfo.Writeln(string(bytes))
|
|
}
|
|
} else {
|
|
cmdInfo.Writeln(noSuchFileOrDirectory(path, cmdInfo))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (cat Cat) help() string {
|
|
return `
|
|
Usage: cat [OPTION]... [FILE]...
|
|
Concatenate FILE(s) to standard output.
|
|
|
|
With no FILE, or when FILE is -, read standard input.
|
|
|
|
-A, --show-all equivalent to -vET
|
|
-b, --number-nonblank number nonempty output lines, overrides -n
|
|
-e equivalent to -vE
|
|
-E, --show-ends display $ at end of each line
|
|
-n, --number number all output lines
|
|
-s, --squeeze-blank suppress repeated empty output lines
|
|
-t equivalent to -vT
|
|
-T, --show-tabs display TAB characters as ^I
|
|
-u (ignored)
|
|
-v, --show-nonprinting use ^ and M- notation, except for LFD and TAB
|
|
--help display this help and exit
|
|
--version output version information and exit
|
|
|
|
Examples:
|
|
cat f - g Output f's contents, then standard input, then g's contents.
|
|
cat Copy standard input to standard output.
|
|
|
|
GNU coreutils online help: <https://www.gnu.org/software/coreutils/>
|
|
Report cat translation bugs to <https://translationproject.org/team/>
|
|
Full documentation at: <https://www.gnu.org/software/coreutils/cat>
|
|
or available locally via: info '(coreutils) cat invocation'`
|
|
}
|
|
|
|
type CD struct {
|
|
info.SimpleHandler
|
|
}
|
|
|
|
func (cd CD) Handle(cmdInfo *info.Info) {
|
|
if _, files, ok := basicFileCommandParser(cmdInfo, cd.help()); ok {
|
|
if len(files) != 1 {
|
|
return
|
|
} else {
|
|
path := files[0]
|
|
if _, ok := cmdInfo.FS.GetExplicitDirectory(path, true); ok {
|
|
if cmdInfo.Terminal != nil {
|
|
cmdInfo.Terminal.SetPrompt(fmt.Sprintf("%s:%s $ ", cmdInfo.User.User(), cmdInfo.FS.Cwd().Name))
|
|
}
|
|
} else {
|
|
cmdInfo.Writelnf("-bash: cd: %s: No such file or directory", path)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (cd CD) help() string {
|
|
return `cd: cd [-L|[-P [-e]] [-@]] [dir]
|
|
Change the shell working directory.
|
|
|
|
Change the current directory to DIR. The default DIR is the value of the
|
|
HOME shell variable.
|
|
|
|
The variable CDPATH defines the search path for the directory containing
|
|
DIR. Alternative directory names in CDPATH are separated by a colon (:).
|
|
A null directory name is the same as the current directory. If DIR begins
|
|
with a slash (/), then CDPATH is not used.
|
|
|
|
If the directory is not found, and the shell option 'cdable_vars' is set,
|
|
the word is assumed to be a variable name. If that variable has a value,
|
|
its value is used for DIR.
|
|
|
|
Options:
|
|
-L force symbolic links to be followed: resolve symbolic
|
|
links in DIR after processing instances of '..'
|
|
-P use the physical directory structure without following
|
|
symbolic links: resolve symbolic links in DIR before
|
|
processing instances of '..'
|
|
-e if the -P option is supplied, and the current working
|
|
directory cannot be determined successfully, exit with
|
|
a non-zero status
|
|
-@ on systems that support it, present a file with extended
|
|
attributes as a directory containing the file attributes
|
|
|
|
The default is to follow symbolic links, as if '-L' were specified.
|
|
'..' is processed by removing the immediately previous pathname component
|
|
back to a slash or the beginning of DIR.
|
|
|
|
Exit Status:
|
|
Returns 0 if the directory is changed, and if $PWD is set successfully when
|
|
-P is used; non-zero otherwise.`
|
|
}
|
|
|
|
type LS struct {
|
|
info.SimpleHandler
|
|
}
|
|
|
|
func (ls LS) Handle(cmdInfo *info.Info) {
|
|
if len(cmdInfo.Args) == 0 {
|
|
cmdInfo.Args = []string{""}
|
|
}
|
|
|
|
if _, files, ok := basicFileCommandParser(cmdInfo, ls.help()); ok {
|
|
var errors []string
|
|
dirs := map[string]string{}
|
|
|
|
for _, dir := range files {
|
|
f, ok := cmdInfo.FS.GetFile(dir, false)
|
|
if !ok {
|
|
errors = append(errors, fmt.Sprintf("ls: cannot access '%s': No such file or directory", dir))
|
|
continue
|
|
}
|
|
switch f.(type) {
|
|
case info.Directory:
|
|
var length int
|
|
var files []string
|
|
for _, file := range f.(info.Directory).Files {
|
|
if l := len(file.Name); length < l {
|
|
length = l
|
|
}
|
|
files = append(files, file.Name)
|
|
}
|
|
length++
|
|
|
|
sort.Strings(files)
|
|
|
|
var builder strings.Builder
|
|
var perline int
|
|
if cmdInfo.Terminal.Width > 0 {
|
|
perline = int(cmdInfo.Terminal.Width) / length
|
|
} else {
|
|
perline = 80 / length
|
|
}
|
|
|
|
for i, file := range files {
|
|
if i % perline == 0 && i != 0 {
|
|
builder.WriteString("\n")
|
|
}
|
|
builder.WriteString(file + strings.Repeat(" ", length - len(file)))
|
|
}
|
|
|
|
dirs[dir] = builder.String()
|
|
case info.File:
|
|
dirs[dir] = dir
|
|
}
|
|
}
|
|
|
|
if len(dirs) == 1 && len(errors) == 0 {
|
|
for _, v := range dirs {
|
|
cmdInfo.Writeln(v)
|
|
}
|
|
} else {
|
|
var builder strings.Builder
|
|
for _, err := range errors {
|
|
builder.WriteString(err)
|
|
builder.WriteString("\n")
|
|
}
|
|
if len(errors) > 0 && len(dirs) > 0 {
|
|
builder.WriteString("\n")
|
|
}
|
|
for k, v := range dirs {
|
|
builder.WriteString(fmt.Sprintf("%s:\n", k))
|
|
builder.WriteString(v)
|
|
builder.WriteString("\n")
|
|
}
|
|
cmdInfo.Write(builder.String())
|
|
}
|
|
}
|
|
}
|
|
|
|
func (ls LS) help() string {
|
|
return `Usage: ls [OPTION]... [FILE]...
|
|
List information about the FILEs (the current directory by default).
|
|
Sort entries alphabetically if none of -cftuvSUX nor --sort is specified.
|
|
|
|
Mandatory arguments to long options are mandatory for short options too.
|
|
-a, --all do not ignore entries starting with .
|
|
-A, --almost-all do not list implied . and ..
|
|
--author with -l, print the author of each file
|
|
-b, --escape print C-style escapes for nongraphic characters
|
|
--block-size=SIZE with -l, scale sizes by SIZE when printing them;
|
|
e.g., '--block-size=M'; see SIZE format below
|
|
-B, --ignore-backups do not list implied entries ending with ~
|
|
-c with -lt: sort by, and show, ctime (time of last
|
|
modification of file status information);
|
|
with -l: show ctime and sort by name;
|
|
otherwise: sort by ctime, newest first
|
|
-C list entries by columns
|
|
--color[=WHEN] colorize the output; WHEN can be 'always' (default
|
|
if omitted), 'auto', or 'never'; more info below
|
|
-d, --directory list directories themselves, not their contents
|
|
-D, --dired generate output designed for Emacs' dired mode
|
|
-f do not sort, enable -aU, disable -ls --color
|
|
-F, --classify append indicator (one of */=>@|) to entries
|
|
--file-type likewise, except do not append '*'
|
|
--format=WORD across -x, commas -m, horizontal -x, long -l,
|
|
single-column -1, verbose -l, vertical -C
|
|
--full-time like -l --time-style=full-iso
|
|
-g like -l, but do not list owner
|
|
--group-directories-first
|
|
group directories before files;
|
|
can be augmented with a --sort option, but any
|
|
use of --sort=none (-U) disables grouping
|
|
-G, --no-group in a long listing, don't print group names
|
|
-h, --human-readable with -l and -s, print sizes like 1K 234M 2G etc.
|
|
--si likewise, but use powers of 1000 not 1024
|
|
-H, --dereference-command-line
|
|
follow symbolic links listed on the command line
|
|
--dereference-command-line-symlink-to-dir
|
|
follow each command line symbolic link
|
|
that points to a directory
|
|
--hide=PATTERN do not list implied entries matching shell PATTERN
|
|
(overridden by -a or -A)
|
|
--hyperlink[=WHEN] hyperlink file names; WHEN can be 'always'
|
|
(default if omitted), 'auto', or 'never'
|
|
--indicator-style=WORD append indicator with style WORD to entry names:
|
|
none (default), slash (-p),
|
|
file-type (--file-type), classify (-F)
|
|
-i, --inode print the index number of each file
|
|
-I, --ignore=PATTERN do not list implied entries matching shell PATTERN
|
|
-k, --kibibytes default to 1024-byte blocks for disk usage;
|
|
used only with -s and per directory totals
|
|
-l use a long listing format
|
|
-L, --dereference when showing file information for a symbolic
|
|
link, show information for the file the link
|
|
references rather than for the link itself
|
|
-m fill width with a comma separated list of entries
|
|
-n, --numeric-uid-gid like -l, but list numeric user and group IDs
|
|
-N, --literal print entry names without quoting
|
|
-o like -l, but do not list group information
|
|
-p, --indicator-style=slash
|
|
append / indicator to directories
|
|
-q, --hide-control-chars print ? instead of nongraphic characters
|
|
--show-control-chars show nongraphic characters as-is (the default,
|
|
unless program is 'ls' and output is a terminal)
|
|
-Q, --quote-name enclose entry names in double quotes
|
|
--quoting-style=WORD use quoting style WORD for entry names:
|
|
literal, locale, shell, shell-always,
|
|
shell-escape, shell-escape-always, c, escape
|
|
(overrides QUOTING_STYLE environment variable)
|
|
-r, --reverse reverse order while sorting
|
|
-R, --recursive list subdirectories recursively
|
|
-s, --size print the allocated size of each file, in blocks
|
|
-S sort by file size, largest first
|
|
--sort=WORD sort by WORD instead of name: none (-U), size (-S),
|
|
time (-t), version (-v), extension (-X)
|
|
--time=WORD with -l, show time as WORD instead of default
|
|
modification time: atime or access or use (-u);
|
|
ctime or status (-c); also use specified time
|
|
as sort key if --sort=time (newest first)
|
|
--time-style=TIME_STYLE time/date format with -l; see TIME_STYLE below
|
|
-t sort by modification time, newest first
|
|
-T, --tabsize=COLS assume tab stops at each COLS instead of 8
|
|
-u with -lt: sort by, and show, access time;
|
|
with -l: show access time and sort by name;
|
|
otherwise: sort by access time, newest first
|
|
-U do not sort; list entries in directory order
|
|
-v natural sort of (version) numbers within text
|
|
-w, --width=COLS set output width to COLS. 0 means no limit
|
|
-x list entries by lines instead of by columns
|
|
-X sort alphabetically by entry extension
|
|
-Z, --context print any security context of each file
|
|
-1 list one file per line. Avoid '\n' with -q or -b
|
|
--help display this help and exit
|
|
--version output version information and exit
|
|
|
|
The SIZE argument is an integer and optional unit (example: 10K is 10*1024).
|
|
Units are K,M,G,T,P,E,Z,Y (powers of 1024) or KB,MB,... (powers of 1000).
|
|
|
|
The TIME_STYLE argument can be full-iso, long-iso, iso, locale, or +FORMAT.
|
|
FORMAT is interpreted like in date(1). If FORMAT is FORMAT1<newline>FORMAT2,
|
|
then FORMAT1 applies to non-recent files and FORMAT2 to recent files.
|
|
TIME_STYLE prefixed with 'posix-' takes effect only outside the POSIX locale.
|
|
Also the TIME_STYLE environment variable sets the default style to use.
|
|
|
|
Using color to distinguish file types is disabled both by default and
|
|
with --color=never. With --color=auto, ls emits color codes only when
|
|
standard output is connected to a terminal. The LS_COLORS environment
|
|
variable can change the settings. Use the dircolors command to set it.
|
|
|
|
Exit status:
|
|
0 if OK,
|
|
1 if minor problems (e.g., cannot access subdirectory),
|
|
2 if serious trouble (e.g., cannot access command-line argument).
|
|
|
|
GNU coreutils online help: <https://www.gnu.org/software/coreutils/>
|
|
Report ls translation bugs to <https://translationproject.org/team/>
|
|
Full documentation at: <https://www.gnu.org/software/coreutils/ls>
|
|
or available locally via: info '(coreutils) ls invocation'`
|
|
}
|
|
|
|
type Mkdir struct {
|
|
info.SimpleHandler
|
|
}
|
|
|
|
func (mkdir Mkdir) Handle(cmdInfo *info.Info) {
|
|
if _, files, ok := basicFileCommandParser(cmdInfo, mkdir.help()); ok {
|
|
for _, file := range files {
|
|
switch _, err := cmdInfo.FS.CreateDirectory(file); err {
|
|
case os.ErrExist:
|
|
cmdInfo.Writelnf("%s: cannot create directory '%s': File exists", cmdInfo.Command, file)
|
|
case os.ErrPermission:
|
|
cmdInfo.Writelnf("%s: cannot create directory '%s': Permission denied", cmdInfo.Command, file)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (mkdir Mkdir) help() string {
|
|
return `
|
|
Usage: mkdir [OPTION]... DIRECTORY...
|
|
Create the DIRECTORY(ies), if they do not already exist.
|
|
|
|
Mandatory arguments to long options are mandatory for short options too.
|
|
-m, --mode=MODE set file mode (as in chmod), not a=rwx - umask
|
|
-p, --parents no error if existing, make parent directories as needed
|
|
-v, --verbose print a message for each created directory
|
|
-Z set SELinux security context of each created directory
|
|
to the default type
|
|
--context[=CTX] like -Z, or if CTX is specified then set the SELinux
|
|
or SMACK security context to CTX
|
|
--help display this help and exit
|
|
--version output version information and exit
|
|
|
|
GNU coreutils online help: <https://www.gnu.org/software/coreutils/>
|
|
Report mkdir translation bugs to <https://translationproject.org/team/>
|
|
Full documentation at: <https://www.gnu.org/software/coreutils/mkdir>
|
|
or available locally via: info '(coreutils) mkdir invocation'`
|
|
}
|
|
|
|
type RM struct {
|
|
info.SimpleHandler
|
|
}
|
|
|
|
func (rm RM) Handle(cmdInfo *info.Info) {
|
|
if options, files, ok := basicFileCommandParser(cmdInfo, rm.help()); ok {
|
|
var dir bool
|
|
for _, arg := range options {
|
|
switch arg {
|
|
case "-r", "-R", "--recursive":
|
|
dir = true
|
|
}
|
|
}
|
|
|
|
for _, fileName := range files {
|
|
if cmdInfo.FS.Manipulate {
|
|
if file, ok := cmdInfo.FS.GetFile(fileName, false); ok {
|
|
if file.IsDir() && !dir {
|
|
cmdInfo.Writelnf("rm: cannot remove '%s': Is a directory", fileName)
|
|
continue
|
|
}
|
|
file.Remove()
|
|
} else {
|
|
cmdInfo.Writelnf("rm: cannot remove '%s': No such file or directory", fileName)
|
|
}
|
|
} else {
|
|
cmdInfo.Writef("rm: remove write-protected file '%s'? ", fileName)
|
|
switch line, _ := cmdInfo.Read(); line {
|
|
case "y", "Y":
|
|
cmdInfo.Writelnf("rm: cannot remove '%s': Operation not permitted", fileName)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (rm RM) help() string {
|
|
return `
|
|
Usage: rm [OPTION]... [FILE]...
|
|
Remove (unlink) the FILE(s).
|
|
|
|
-f, --force ignore nonexistent files and arguments, never prompt
|
|
-i prompt before every removal
|
|
-I prompt once before removing more than three files, or
|
|
when removing recursively; less intrusive than -i,
|
|
while still giving protection against most mistakes
|
|
--interactive[=WHEN] prompt according to WHEN: never, once (-I), or
|
|
always (-i); without WHEN, prompt always
|
|
--one-file-system when removing a hierarchy recursively, skip any
|
|
directory that is on a file system different from
|
|
that of the corresponding command line argument
|
|
--no-preserve-root do not treat '/' specially
|
|
--preserve-root[=all] do not remove '/' (default);
|
|
with 'all', reject any command line argument
|
|
on a separate device from its parent
|
|
-r, -R, --recursive remove directories and their contents recursively
|
|
-d, --dir remove empty directories
|
|
-v, --verbose explain what is being done
|
|
--help display this help and exit
|
|
--version output version information and exit
|
|
|
|
By default, rm does not remove directories. Use the --recursive (-r or -R)
|
|
option to remove each listed directory, too, along with all of its contents.
|
|
|
|
To remove a file whose name starts with a '-', for example '-foo',
|
|
use one of these commands:
|
|
rm -- -foo
|
|
|
|
rm ./-foo
|
|
|
|
Note that if you use rm to remove a file, it might be possible to recover
|
|
some of its contents, given sufficient expertise and/or time. For greater
|
|
assurance that the contents are truly unrecoverable, consider using shred.
|
|
|
|
GNU coreutils online help: <https://www.gnu.org/software/coreutils/>
|
|
Report rm translation bugs to <https://translationproject.org/team/>
|
|
Full documentation at: <https://www.gnu.org/software/coreutils/rm>
|
|
or available locally via: info '(coreutils) rm invocation'
|
|
`
|
|
}
|
|
|
|
type Touch struct {
|
|
info.SimpleHandler
|
|
}
|
|
|
|
func (touch Touch) Handle(cmdInfo *info.Info) {
|
|
if _, files, ok := basicFileCommandParser(cmdInfo, touch.help()); ok {
|
|
for _, file := range files {
|
|
if _, err := cmdInfo.FS.CreateFile(file); err == os.ErrPermission {
|
|
cmdInfo.Writelnf("%s: cannot touch '%s': Permission denied", cmdInfo.Command, file)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (touch Touch) help() string {
|
|
return `Usage: touch [OPTION]... FILE...
|
|
Update the access and modification times of each FILE to the current time.
|
|
|
|
A FILE argument that does not exist is created empty, unless -c or -h
|
|
is supplied.
|
|
|
|
A FILE argument string of - is handled specially and causes touch to
|
|
change the times of the file associated with standard output.
|
|
|
|
Mandatory arguments to long options are mandatory for short options too.
|
|
-a change only the access time
|
|
-c, --no-create do not create any files
|
|
-d, --date=STRING parse STRING and use it instead of current time
|
|
-f (ignored)
|
|
-h, --no-dereference affect each symbolic link instead of any referenced
|
|
file (useful only on systems that can change the
|
|
timestamps of a symlink)
|
|
-m change only the modification time
|
|
-r, --reference=FILE use this file's times instead of current time
|
|
-t STAMP use [[CC]YY]MMDDhhmm[.ss] instead of current time
|
|
--time=WORD change the specified time:
|
|
WORD is access, atime, or use: equivalent to -a
|
|
WORD is modify or mtime: equivalent to -m
|
|
--help display this help and exit
|
|
--version output version information and exit
|
|
|
|
Note that the -d and -t options accept different time-date formats.
|
|
|
|
GNU coreutils online help: <https://www.gnu.org/software/coreutils/>
|
|
Report touch translation bugs to <https://translationproject.org/team/>
|
|
Full documentation at: <https://www.gnu.org/software/coreutils/touch>
|
|
or available locally via: info '(coreutils) touch invocation'`
|
|
}
|