From c0edea3dedf01a678417419f71fa8b7bb155302b Mon Sep 17 00:00:00 2001 From: h7x4 Date: Fri, 2 Jan 2026 17:48:26 +0900 Subject: [PATCH] Initial commit --- .envrc | 1 + .gitignore | 12 +++ Cargo.lock | 202 +++++++++++++++++++++++++++++++++++ Cargo.toml | 63 +++++++++++ README.md | 23 ++++ flake.lock | 48 +++++++++ flake.nix | 73 +++++++++++++ nix/default.nix | 25 +++++ src/bin/finger.rs | 109 +++++++++++++++++++ src/bin/roowhod.rs | 4 + src/bin/rup.rs | 42 ++++++++ src/bin/ruptime.rs | 39 +++++++ src/bin/rusers.rs | 35 ++++++ src/bin/rwall.rs | 20 ++++ src/bin/rwho.rs | 26 +++++ src/lib.rs | 1 + src/proto.rs | 3 + src/proto/finger_protocol.rs | 0 src/proto/rusers_protocol.rs | 0 src/proto/write_protocol.rs | 0 20 files changed, 726 insertions(+) create mode 100644 .envrc create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 README.md create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 nix/default.nix create mode 100644 src/bin/finger.rs create mode 100644 src/bin/roowhod.rs create mode 100644 src/bin/rup.rs create mode 100644 src/bin/ruptime.rs create mode 100644 src/bin/rusers.rs create mode 100644 src/bin/rwall.rs create mode 100644 src/bin/rwho.rs create mode 100644 src/lib.rs create mode 100644 src/proto.rs create mode 100644 src/proto/finger_protocol.rs create mode 100644 src/proto/rusers_protocol.rs create mode 100644 src/proto/write_protocol.rs diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b3d8ad0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +/target +result +result-* + +Cargo.lock + + +# Added by cargo +# +# already existing elements were commented out + +#/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..16f1ff5 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,202 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys", +] + +[[package]] +name = "clap" +version = "4.5.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "libc" +version = "0.2.178" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "proc-macro2" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9695f8df41bb4f3d222c95a67532365f569318332d03d5f3f67f37b20e6ebdf0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "roowho2" +version = "0.1.0" +dependencies = [ + "clap", + "sd-notify", +] + +[[package]] +name = "sd-notify" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b943eadf71d8b69e661330cb0e2656e31040acf21ee7708e2c238a0ec6af2bf4" +dependencies = [ + "libc", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.112" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21f182278bf2d2bcb3c88b1b08a37df029d71ce3d3ae26168e3c653b213b99d4" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..ffc240a --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,63 @@ +[package] +name = "roowho2" +version = "0.1.0" +edition = "2024" +resolver = "2" +license = "BSD3" +authors = [ + "projects@pvv.ntnu.no", +] +description = "A modern reimplementation of netkit tools" +categories = ["command-line-interface", "command-line-utilities"] +readme = "README.md" +autobins = false +autolib = false + +[dependencies] +clap = { version = "4.5.53", features = ["derive"] } +sd-notify = "0.4.5" + +[lib] +name = "roowho2_lib" +path = "src/lib.rs" + +[[bin]] +name = "roowhod" +bench = false +path = "src/bin/roowhod.rs" + +[[bin]] +name = "finger" +bench = false +path = "src/bin/finger.rs" + +[[bin]] +name = "rup" +bench = false +path = "src/bin/rup.rs" + +[[bin]] +name = "ruptime" +bench = false +path = "src/bin/ruptime.rs" + +[[bin]] +name = "rusers" +bench = false +path = "src/bin/rusers.rs" + +[[bin]] +name = "rwall" +bench = false +path = "src/bin/rwall.rs" + +[[bin]] +name = "rwho" +bench = false +path = "src/bin/rwho.rs" + +[profile.releaselto] +inherits = "release" +strip = true +lto = true +codegen-units = 1 diff --git a/README.md b/README.md new file mode 100644 index 0000000..791d65c --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +# roowhoo2 + +Reimplementation of a subset of linux' netkit tools. + +## Programs reimplemented + +- [ ] finger +- [ ] rup +- [ ] ruptime +- [ ] rusers +- [ ] rwall +- [ ] rwho + +## Programs *not* reimplemented + +- `rsh`/`rexec`/`rcp`/`rlogin`: use `ssh` + `scp`/`rsync` +- `talk`: use a local irc server +- `ping`/`telnet`/`ftp`/`tftp`/`write`: all of these you can get from other packages +- `inetd`: either use a different distribution or use systemd socket activation +- `timed`: use an ntp client +- `biff`/`comsat`: nah +- `ripquery`/`routed`: nuh-uh +- `rpc*`: no need diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..66d0896 --- /dev/null +++ b/flake.lock @@ -0,0 +1,48 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1767116409, + "narHash": "sha256-5vKw92l1GyTnjoLzEagJy5V5mDFck72LiQWZSOnSicw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "cad22e7d996aea55ecab064e84834289143e44a0", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs", + "rust-overlay": "rust-overlay" + } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1767322002, + "narHash": "sha256-yHKXXw2OWfIFsyTjduB4EyFwR0SYYF0hK8xI9z4NIn0=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "03c6e38661c02a27ca006a284813afdc461e9f7e", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..57b1142 --- /dev/null +++ b/flake.nix @@ -0,0 +1,73 @@ +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + + rust-overlay.url = "github:oxalica/rust-overlay"; + rust-overlay.inputs.nixpkgs.follows = "nixpkgs"; + }; + + outputs = { self, nixpkgs, rust-overlay}: + let + inherit (nixpkgs) lib; + + systems = [ + "x86_64-linux" + "aarch64-linux" + "x86_64-darwin" + "aarch64-darwin" + "armv7l-linux" + ]; + + forAllSystems = f: nixpkgs.lib.genAttrs systems (system: let + pkgs = import nixpkgs { + inherit system; + overlays = [ + (import rust-overlay) + ]; + }; + + rust-bin = rust-overlay.lib.mkRustBin { } pkgs.buildPackages; + toolchain = rust-bin.stable.latest.default.override { + extensions = [ "rust-src" ]; + }; + in f system pkgs toolchain); + in { + devShell = forAllSystems (system: pkgs: toolchain: pkgs.mkShell { + nativeBuildInputs = with pkgs; [ + toolchain + cargo-edit + ]; + + RUST_SRC_PATH = "${toolchain}/lib/rustlib/src/rust/library"; + }); + + overlays = { + default = self.overlays.muscl; + roowho2 = final: prev: { + inherit (self.packages.${prev.stdenv.hostPlatform.system}) roowho2; + }; + }; + + packages = forAllSystems (system: pkgs: _: + let + cargoToml = builtins.fromTOML (builtins.readFile ./Cargo.toml); + cargoLock = ./Cargo.lock; + src = lib.fileset.toSource { + root = ./.; + fileset = lib.fileset.unions [ + ./src + ./Cargo.toml + ./Cargo.lock + ]; + }; + in { + default = self.packages.${system}.roowho2; + + roowho2 = pkgs.callPackage ./nix/default.nix { inherit cargoToml cargoLock src; }; + + filteredSource = pkgs.runCommandLocal "filtered-source" { } '' + ln -s ${src} $out + ''; + }); + }; +} diff --git a/nix/default.nix b/nix/default.nix new file mode 100644 index 0000000..dadf82a --- /dev/null +++ b/nix/default.nix @@ -0,0 +1,25 @@ +{ + lib +, rustPlatform +, stdenv +, installShellFiles +, versionCheckHook + +, cargoToml +, cargoLock +, src +}: +rustPlatform.buildRustPackage { + pname = "roowho2"; + inherit (cargoToml.package) version; + inherit src; + + cargoLock.lockFile = cargoLock; + + # buildType = "releaselto"; + + meta = with lib; { + license = licenses.mit; + platforms = platforms.linux ++ platforms.darwin; + }; +} diff --git a/src/bin/finger.rs b/src/bin/finger.rs new file mode 100644 index 0000000..badad26 --- /dev/null +++ b/src/bin/finger.rs @@ -0,0 +1,109 @@ +use clap::Parser; + +/// User information lookup program +/// +/// The `finger` utility displays information about the system users. +/// +/// +/// If no options are specified, finger defaults to the -l style output if operands are provided, otherwise to the -s style. +/// Note that some fields may be missing, in either format, if information is not available for them. +/// +/// If no arguments are specified, finger will print an entry for each user currently logged into the system. +/// +/// Finger may be used to look up users on a remote machine. +/// The format is to specify a user as “user@host”, or “@host”, +/// where the default output format for the former is the -l style, +/// and the default output format for the latter is the -s style. +/// The -l option is the only option that may be passed to a remote machine. +/// +/// If standard output is a socket, finger will emit a carriage return (^M) before every linefeed (^J). +/// This is for processing remote finger requests when invoked by the daemon. +#[derive(Debug, Parser)] +pub struct Args { + /// Forces finger to use IPv4 addresses only. + #[arg(long, short = '4', conflicts_with = "ipv6")] + ipv4: bool, + + /// Forces finger to use IPv6 addresses only. + #[arg(long, short = '6', conflicts_with = "ipv4")] + ipv6: bool, + + /// Display the user's login name, real name, terminal name and write status + /// (as a ``*'' before the terminal name if write permission is denied), + /// idle time, login time, and either office location and office phone number, + /// or the remote host. If -o is given, the office location and office phone number + /// is printed (the default). If -h is given, the remote host is printed instead. + /// + /// Idle time is in minutes if it is a single integer, hours and minutes if a ``:'' + /// is present, or days if a ``d'' is present. If it is an "*", the login time indicates + /// the time of last login. Login time is displayed as the day name if less than 6 days, + /// else month, day; hours and minutes, unless more than six months ago, in which case the year + /// is displayed rather than the hours and minutes. + /// + /// Unknown devices as well as nonexistent idle and login times are displayed as single asterisks. + #[arg(long, short, conflicts_with = "long")] + short: bool, + + /// When used in conjunction with the -s option, the name of the remote host + /// is displayed instead of the office location and office phone. + #[arg(long, short, requires = "short", conflicts_with = "office")] + host: bool, + + /// When used in conjunction with the -s option, the office location and + /// office phone information is displayed instead of the name of the remote host. + #[arg(long, short, requires = "short", conflicts_with = "host")] + office: bool, + + /// This option restricts the gecos output to only the users' real name. + /// It also has the side-effect of restricting the output of the remote host + /// when used in conjunction with the -h option. + #[arg(long, short, requires = "short")] + gecos: bool, + + /// Disable all use of the user accounting database. + #[arg(short = 'k')] + no_acct: bool, + + /// Produce a multi-line format displaying all of the information + /// described for the -s option as well as the user's home directory, + /// home phone number, login shell, mail status, and the contents of + /// the files .forward, .plan, .project and .pubkey from the user's home directory. + /// + /// If idle time is at least a minute and less than a day, it is presented in the form ``hh:mm''. + /// Idle times greater than a day are presented as ``d day[s]hh:mm'' + /// + /// Phone numbers specified as eleven digits are printed as ``+N-NNN-NNN-NNNN''. + /// Numbers specified as ten or seven digits are printed as the appropriate subset of that string. + /// Numbers specified as five digits are printed as ``xN-NNNN''. + /// Numbers specified as four digits are printed as ``xNNNN''. + /// + /// If write permission is denied to the device, the phrase ``(messages off)'' + /// is appended to the line containing the device name. One entry per user is displayed with the -l option; + /// if a user is logged on multiple times, terminal information is repeated once per login. + /// + /// Mail status is shown as ``No Mail.'' if there is no mail at all, + /// ``Mail last read DDD MMM ## HH:MM YYYY (TZ)'' if the person has looked at their mailbox since new mail arriving, + /// or ``New mail received ...'', ``Unread since ...'' if they have new mail. + #[arg(long, short, conflicts_with = "short")] + long: bool, + + /// Prevent the -l option of finger from displaying the contents of + /// the .forward, .plan, .project and .pubkey files. + #[arg(long, short, requires = "long")] + prevent_files: bool, + + /// Prevent matching of user names. User is usually a login name; + /// however, matching will also be done on the users' real names, + /// unless the -m option is supplied. All name matching performed by finger is case insensitive. + #[arg(long, short = 'm')] + no_name_match: bool, + + /// Output in JSON format + #[arg(long, short)] + json: bool, +} + +fn main() { + let _args = Args::parse(); + unimplemented!() +} diff --git a/src/bin/roowhod.rs b/src/bin/roowhod.rs new file mode 100644 index 0000000..16b04d5 --- /dev/null +++ b/src/bin/roowhod.rs @@ -0,0 +1,4 @@ +fn main() { + unimplemented!() +} + diff --git a/src/bin/rup.rs b/src/bin/rup.rs new file mode 100644 index 0000000..bc7fe1b --- /dev/null +++ b/src/bin/rup.rs @@ -0,0 +1,42 @@ +use clap::Parser; + +/// Remote status display. +/// +/// `rup` displays a summary of the current system status of a particular host or all hosts on the local network. +/// The output shows the current time of day, how long the system has been up, and the load averages. +/// The load average numbers give the number of jobs in the run queue averaged over 1, 5 and 15 minutes. +#[derive(Debug, Parser)] +pub struct Args { + /// The hosts to query. + hosts: Vec, + + /// For each host, report what its local time is. + /// This is useful for checking time syncronization on a network. + #[arg(long, short)] + date: bool, + + /// Print time data in seconds (seconds of uptime or seconds since the epoch), for scripts. + #[arg(long, short)] + seconds: bool, + + /// Sort the display alphabetically by host name. + #[arg(long, short)] + hostname: bool, + + /// Sort the display by load average. + #[arg(long, short)] + load: bool, + + /// Sort the display by uptime. + #[arg(long, short)] + uptime: bool, + + /// Output in JSON format + #[arg(long, short)] + json: bool, +} + +fn main() { + let _args = Args::parse(); + unimplemented!() +} diff --git a/src/bin/ruptime.rs b/src/bin/ruptime.rs new file mode 100644 index 0000000..87ca215 --- /dev/null +++ b/src/bin/ruptime.rs @@ -0,0 +1,39 @@ +use clap::Parser; + +/// Show host status of local machines. +/// +/// `ruptime` gives a status line like uptime for each machine on the local network; +/// these are formed from packets broadcast by each host on the network once a minute. +/// +/// Machines for which no status report has been received for 11 minutes are shown as being down. +#[derive(Debug, Parser)] +pub struct Args { + /// Users idle an hour or more are not counted unless the `-a` flag is given. + #[arg(long, short)] + all: bool, + + /// Sort by load average. + #[arg(long, short)] + load: bool, + + /// Reverses the sort order. + #[arg(long, short)] + reverse: bool, + + /// Sort by uptime. + #[arg(long, short)] + time: bool, + + /// Sort by number of users. + #[arg(long, short)] + users: bool, + + /// Output in JSON format + #[arg(long, short)] + json: bool, +} + +fn main() { + let _args = Args::parse(); + unimplemented!() +} diff --git a/src/bin/rusers.rs b/src/bin/rusers.rs new file mode 100644 index 0000000..e06c63e --- /dev/null +++ b/src/bin/rusers.rs @@ -0,0 +1,35 @@ +use clap::Parser; + +/// Check who is logged in to machines on local network. +/// +/// The `rusers` command produces output similar to `who`, +/// but for the list of hosts or all machines on the local network. +/// For each host responding to the rusers query, +/// the host‐name with the names of the users currently logged on is printed on each line. +/// The `rusers` command will wait for one minute to catch late responders. +#[derive(Debug, Parser)] +pub struct Args { + /// Print all machines responding even if no one is currently logged in + #[arg(long, short)] + all: bool, + + /// Print a long format listing. + /// This includes: + /// - the user name + /// - the host name + /// - the tty that the user is logged in to + /// - the date and time the user logged in + /// - the amount of time since the user typed on the keyboard + /// - the remote host they logged in from (if applicable) + #[arg(long, short)] + long: bool, + + /// Output in JSON format + #[arg(long, short)] + json: bool, +} + +fn main() { + let _args = Args::parse(); + unimplemented!() +} diff --git a/src/bin/rwall.rs b/src/bin/rwall.rs new file mode 100644 index 0000000..ed875fd --- /dev/null +++ b/src/bin/rwall.rs @@ -0,0 +1,20 @@ +use clap::Parser; + +/// Send a message to users logged on a host. +/// +/// The `rwall` command sends a message to the users logged into the specified host. +/// The message to be sent can be typed in and terminated with EOF or it can be in a file +#[derive(Debug, Parser)] +pub struct Args { + /// The host to send the message to + host: String, + + /// The file containing the message to be sent + #[arg(value_name = "PATH")] + file: Option, +} + +fn main() { + let _args = Args::parse(); + unimplemented!() +} diff --git a/src/bin/rwho.rs b/src/bin/rwho.rs new file mode 100644 index 0000000..fec79be --- /dev/null +++ b/src/bin/rwho.rs @@ -0,0 +1,26 @@ +use clap::Parser; + +/// Check who is logged in on local machines. +/// +/// The `rwho` command produces output similar to `who`, but for all machines on the local network. +/// If no report has been received from a machine for 11 minutes then rwho assumes the machine is down, +/// and does not report users last known to be logged into that machine. +/// +/// If a users hasn't typed to the system for a minute or more, then rwho reports this idle time. +/// If a user hasn't typed to the system for an hour or more, +/// then the user will be omitted from the output of `rwho` unless the `-a` flag is given. +#[derive(Debug, Parser)] +pub struct Args { + /// Print all machines responding even if no one is currently logged in + #[arg(long, short)] + all: bool, + + /// Output in JSON format + #[arg(long, short)] + json: bool, +} + +fn main() { + let _args = Args::parse(); + unimplemented!() +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..febacec --- /dev/null +++ b/src/lib.rs @@ -0,0 +1 @@ +pub mod proto; diff --git a/src/proto.rs b/src/proto.rs new file mode 100644 index 0000000..dee9cb9 --- /dev/null +++ b/src/proto.rs @@ -0,0 +1,3 @@ +pub mod finger_protocol; +pub mod rusers_protocol; +pub mod write_protocol; diff --git a/src/proto/finger_protocol.rs b/src/proto/finger_protocol.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/proto/rusers_protocol.rs b/src/proto/rusers_protocol.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/proto/write_protocol.rs b/src/proto/write_protocol.rs new file mode 100644 index 0000000..e69de29