1 // Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved.
2 //
3 // StratoVirt is licensed under Mulan PSL v2.
4 // You can use this software according to the terms and conditions of the Mulan
5 // PSL v2.
6 // You may obtain a copy of Mulan PSL v2 at:
7 // http://license.coscl.org.cn/MulanPSL2
8 // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
9 // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
10 // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
11 // See the Mulan PSL v2 for more details.
12
13 mod commands;
14 mod container;
15 mod linux;
16 mod utils;
17
18 use std::{
19 fs::remove_dir_all,
20 path::{Path, PathBuf},
21 process::exit,
22 };
23
24 use anyhow::{anyhow, Context, Result};
25 use clap::{crate_description, Args, Parser, Subcommand};
26 use commands::{Delete, Exec, Kill, Start, State};
27 use log::info;
28 use nix::unistd::geteuid;
29
30 use crate::{commands::Create, utils::logger};
31
32 // Global options which are not binded to any specific command.
33 #[derive(Args, Debug)]
34 struct GlobalOpts {
35 /// Root directory to store container state.
36 #[arg(short, long)]
37 root: Option<PathBuf>,
38 /// Path of log file.
39 #[arg(short, long)]
40 log: Option<PathBuf>,
41 /// Enable debug log level.
42 #[arg(short, long)]
43 debug: bool,
44 }
45
46 // Standard commands supported by [OCI runtime-spec]
47 // (https://github.com/opencontainers/runtime-spec/blob/master/runtime.md)
48 // and [OCI Command Line Interface]
49 // (https://github.com/opencontainers/runtime-tools/blob/master/docs/command-line-interface.md).
50 #[derive(Subcommand, Debug)]
51 enum StandardCmd {
52 Create(Create),
53 Start(Start),
54 State(State),
55 Kill(Kill),
56 Delete(Delete),
57 }
58
59 // Extended commands not documented in [OCI Command Line Interface].
60 #[derive(Subcommand, Debug)]
61 enum ExtendCmd {
62 Exec(Exec),
63 }
64
65 #[derive(Subcommand, Debug)]
66 enum Command {
67 #[command(flatten)]
68 Standard(StandardCmd),
69 #[command(flatten)]
70 Extend(ExtendCmd),
71 }
72
73 #[derive(Parser, Debug)]
74 #[command(version, author, about = crate_description!())]
75 #[command(propagate_version = true)]
76 struct Cli {
77 #[command(flatten)]
78 global: GlobalOpts,
79 #[command(subcommand)]
80 cmd: Command,
81 }
82
cmd_run(command: Command, root: &Path) -> Result<()>83 fn cmd_run(command: Command, root: &Path) -> Result<()> {
84 match command {
85 Command::Standard(cmd) => match cmd {
86 StandardCmd::Create(create) => {
87 info!("Run command: {:?}", create);
88
89 let mut root_exist = false;
90 create.run(root, &mut root_exist).map_err(|e| {
91 if !root_exist {
92 let _ = remove_dir_all(root);
93 }
94 anyhow!(e)
95 })?
96 }
97 StandardCmd::Start(start) => {
98 info!("Run command: {:?}", start);
99 start.run(root)?
100 }
101 StandardCmd::Kill(kill) => {
102 info!("Run command: {:?}", kill);
103 kill.run(root)?
104 }
105 StandardCmd::Delete(delete) => {
106 info!("Run command: {:?}", delete);
107 delete.run(root)?
108 }
109 StandardCmd::State(state) => {
110 info!("Run command: {:?}", state);
111 state.run(root)?
112 }
113 },
114 Command::Extend(cmd) => match cmd {
115 ExtendCmd::Exec(exec) => {
116 info!("Run command: {:?}", exec);
117 exec.run(root)?
118 }
119 },
120 }
121 Ok(())
122 }
123
real_main() -> Result<()>124 fn real_main() -> Result<()> {
125 let cli = Cli::parse();
126
127 logger::init(&cli.global.log, cli.global.debug).with_context(|| "Failed to init logger")?;
128
129 let root_path = if let Some(root) = cli.global.root {
130 root
131 } else {
132 let euid = geteuid();
133 PathBuf::from(format!("/var/run/user/{}/ozonec", euid))
134 };
135 cmd_run(cli.cmd, &root_path)
136 }
137
main()138 fn main() {
139 if let Err(e) = real_main() {
140 eprintln!("ERROR: {:?}", e);
141 exit(1);
142 }
143 exit(0);
144 }
145