Useless Shell
A shell written in C with no purpose. However, it was fun to write.
Welcome, Guest. Today is Fri Oct 11 09:54:10 2024. > help - exit - help (cmd) -b - clear - history Display the session command history - clear - login <username> Login to an existing account - logout Logout of the currect account - users - info (username) - list - create <username> <password> (super) - delete <username> - uninstall - time -d -w Shows system time > users list 1 [@] admin > time -d _ _ __ __ __ _ | | |_| ' |_ |_ ' _| | |_| __| . __| __| . |__ _|_ >
Features
- Command auto completion (Tab)
- Command syntax hints (Ctrl+Tab)
- List commands with
help
- Colorful!
-
Users
- Saved to file
- Password hashing using the RSA Data Security, Inc. MD5 Message Digest Algorithm
- Superusers
-
History
- Saved to file per user (& guest)
- View with
history
- Clear with
history clear
- Navigation (↑ & ↓)
- Easy command declaration (see cmd_defs.c)
- Command verification and unit testing
-
Input buffer editing
- Cursor navigation (← & →)
- Word navigation (Ctrl+← & Ctrl+→)
- Backspace & Back word (Ctrl+Backspace)
- Delete & Delete word (Ctrl+Del)
- Clear (escape)
-
Easy uninstallation: login as admin and run
uninstall
. - Portable (ish): Single executable file and config directory.
Installation
Download the latest release or build from source with CMake.
Note that a config directory is placed at:
(Linux) | ~/.config/useless_shell |
---|---|
(Windows) | ~/AppData/Roaming/.useless-shell |
Run the executable and enter a password for the new admin user.
Adding a new command
-
Add definition to
cmd_defs.c
Use the CMD
macro with named-member-initalization style for
name
, description
, type
, optional
, impl
, and auto_complete
.
name
and type
are required, while the others are optional.
Valid types must be prefixed with USCommandArgType
and are as follows:
Number
, String
, Secret
, Boolean
, and Flag
.
When type is Flag
, optional
and auto_complete
are ignored.
impl
describes the implementation. Set it to the CMD_IMPL
macro
Example
CMD(
.name = "history",
.description = "Display the session command history",
.impl = CMD_IMPL(history),
SUB_CMDS(
CMD(
.name = "clear",
.impl = CMD_IMPL(history_clear)
)
)
)
-
Add implementation declaration to
cmd_impl.h
Call the CMD_IMPL_PROTO
with the implementation name you chose in the previous step.
Example
CMD_IMPL_PROTO(history);
-
Add implementation to
cmd_impl.c
Example
CMD_IMPL_PROTO(history)
{
// Information about the shell can be accessed via `us` parameter
if (fseek(us->history.read, 0, SEEK_SET) == 0)
{
...
}
else
{
puts(STYLE_ERROR("Failed to read history"));
return USCommandReturnError;
}
return USCommandReturnNormal;
}
cmd_defs.c
Use the CMD
macro with named-member-initalization style for
name
, description
, type
, optional
, impl
, and auto_complete
.
name
and type
are required, while the others are optional.
Valid types must be prefixed with USCommandArgType
and are as follows:
Number
, String
, Secret
, Boolean
, and Flag
.
When type is Flag
, optional
and auto_complete
are ignored.
impl
describes the implementation. Set it to the CMD_IMPL
macro
Example
CMD(
.name = "history",
.description = "Display the session command history",
.impl = CMD_IMPL(history),
SUB_CMDS(
CMD(
.name = "clear",
.impl = CMD_IMPL(history_clear)
)
)
)
cmd_impl.h
Call the CMD_IMPL_PROTO
with the implementation name you chose in the previous step.
Example
CMD_IMPL_PROTO(history);
cmd_impl.c
Example
CMD_IMPL_PROTO(history)
{
// Information about the shell can be accessed via `us` parameter
if (fseek(us->history.read, 0, SEEK_SET) == 0)
{
...
}
else
{
puts(STYLE_ERROR("Failed to read history"));
return USCommandReturnError;
}
return USCommandReturnNormal;
}
Adding a new auto complete function is very similar, but uses the AC_IMPL
and AC_IMPL_PROTO
macros instead.