1 // Copyright (C) 2024 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 pub(crate) static DEFAULT_IO_DEPTH: u16 = 2;
16 pub(crate) static DEFAULT_MAX_FDS: u16 = 128;
17 pub(crate) static DEFAULT_EXIT_ON_ERROR: bool = false;
18
19 mod args_argh;
20 use args_argh as args_internal;
21
22 use std::path::Path;
23 use std::path::PathBuf;
24 use std::process::exit;
25
26 pub use args_internal::OutputFormat;
27 pub use args_internal::ReplayArgs;
28 #[cfg(target_os = "android")]
29 pub use args_internal::StartArgs;
30 pub use args_internal::TracerType;
31 pub use args_internal::{DumpArgs, MainArgs, RecordArgs, SubCommands};
32 use serde::Deserialize;
33 use serde::Serialize;
34
35 use crate::Error;
36 use log::error;
37
38 // Deserialized form of the config file
39 #[derive(Clone, Debug, Default, Deserialize, Serialize, Eq, PartialEq)]
40 pub struct ConfigFile {
41 // Files to be excluded in prefetch. These files might have been
42 // added in the record file while recording,but we do not want to
43 // replay these files. These can be two types of files:
44 // 1) installation-specific files (e.g. files in /data) and
45 // 2) large files which we do not want to load in replay (e.g. APK files).
46 pub files_to_exclude_regex: Vec<String>,
47 // Files that are not in the record file, but need to be loaded during replay
48 pub additional_replay_files: Vec<String>,
49 }
50
verify_and_fix(args: &mut MainArgs) -> Result<(), Error>51 fn verify_and_fix(args: &mut MainArgs) -> Result<(), Error> {
52 match &mut args.nested {
53 SubCommands::Record(arg) => {
54 if arg.debug && arg.int_path.is_none() {
55 arg.int_path = Some(PathBuf::from(format!("{}.int", arg.path.to_str().unwrap())));
56 }
57
58 if let Some(p) = &arg.int_path {
59 ensure_path_doesnt_exist(p)?;
60 }
61 }
62 SubCommands::Replay(arg) => {
63 ensure_path_exists(&arg.path)?;
64 if !arg.config_path.as_os_str().is_empty() {
65 ensure_path_exists(&arg.config_path)?;
66 }
67 }
68 SubCommands::Dump(arg) => {
69 ensure_path_exists(&arg.path)?;
70 }
71 #[cfg(target_os = "android")]
72 SubCommands::Start(_arg) => return Ok(()),
73 }
74 Ok(())
75 }
76
77 /// Returns error if the given path at `p` exist.
ensure_path_doesnt_exist(p: &Path) -> Result<(), Error>78 pub(crate) fn ensure_path_doesnt_exist(p: &Path) -> Result<(), Error> {
79 if p.exists() {
80 Err(Error::InvalidArgs {
81 arg_name: "path".to_string(),
82 arg_value: p.display().to_string(),
83 error: "Path already exists".to_string(),
84 })
85 } else {
86 Ok(())
87 }
88 }
89
90 /// Returns error if the given path at `p` doesn't exist.
ensure_path_exists(p: &Path) -> Result<(), Error>91 pub(crate) fn ensure_path_exists(p: &Path) -> Result<(), Error> {
92 if p.is_file() {
93 Ok(())
94 } else {
95 Err(Error::InvalidArgs {
96 arg_name: "path".to_string(),
97 arg_value: p.display().to_string(),
98 error: "Path does not exist".to_string(),
99 })
100 }
101 }
102
103 /// Builds `MainArgs` from command line arguments. On error prints error/help message
104 /// and exits.
args_from_env() -> MainArgs105 pub fn args_from_env() -> MainArgs {
106 let mut args = args_internal::args_from_env();
107 if let Err(e) = verify_and_fix(&mut args) {
108 error!("failed to verify args: {}", e);
109 exit(1);
110 }
111 args
112 }
113