xref: /aosp_15_r20/external/flashrom/util/flashrom_tester/src/main.rs (revision 0d6140be3aa665ecc836e8907834fcd3e3b018fc)
1 //
2 // Copyright 2019, Google Inc.
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //    * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //    * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //    * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 //
31 // Alternatively, this software may be distributed under the terms of the
32 // GNU General Public License ("GPL") version 2 as published by the Free
33 // Software Foundation.
34 //
35 
36 #[macro_use]
37 extern crate log;
38 
39 mod logger;
40 
41 use clap::{App, Arg};
42 use flashrom::{FlashChip, Flashrom, FlashromCmd, FlashromLib};
43 use flashrom_tester::{tester, tests};
44 use std::sync::atomic::AtomicBool;
45 
46 pub mod built_info {
47     include!(concat!(env!("OUT_DIR"), "/built.rs"));
48 }
49 
main()50 fn main() {
51     let matches = App::new("flashrom_tester")
52         .long_version(&*format!(
53             "{}-{}\n\
54              Target: {}\n\
55              Profile: {}\n\
56              Features: {:?}\n\
57              Build time: {}\n\
58              Compiler: {}",
59             built_info::PKG_VERSION,
60             option_env!("VCSID").unwrap_or("<unknown>"),
61             built_info::TARGET,
62             built_info::PROFILE,
63             built_info::FEATURES,
64             built_info::BUILT_TIME_UTC,
65             built_info::RUSTC_VERSION,
66         ))
67         .arg(
68             Arg::with_name("libflashrom")
69                 .long("libflashrom")
70                 .takes_value(false)
71                 .help("Test the flashrom library instead of a binary"),
72         )
73         .arg(
74             Arg::with_name("flashrom_binary")
75                 .long("flashrom_binary")
76                 .short("b")
77                 .takes_value(true)
78                 .required_unless("libflashrom")
79                 .conflicts_with("libflashrom")
80                 .help("Path to flashrom binary to test"),
81         )
82         .arg(
83             Arg::with_name("ccd_target_type")
84                 .required(true)
85                 .possible_values(&["internal"]),
86         )
87         .arg(
88             Arg::with_name("print-layout")
89                 .short("l")
90                 .long("print-layout")
91                 .help("Print the layout file's contents before running tests"),
92         )
93         .arg(
94             Arg::with_name("log_debug")
95                 .short("d")
96                 .long("debug")
97                 .help("Write detailed logs, for debugging"),
98         )
99         .arg(
100             Arg::with_name("output-format")
101                 .short("f")
102                 .long("output-format")
103                 .help("Set the test report format")
104                 .takes_value(true)
105                 .case_insensitive(true)
106                 .possible_values(&["pretty", "json"])
107                 .default_value("pretty"),
108         )
109         .arg(
110             Arg::with_name("test_name")
111                 .multiple(true)
112                 .help("Names of individual tests to run (run all if unspecified)"),
113         )
114         .get_matches();
115 
116     logger::init(matches.is_present("log_debug"));
117     debug!("Args parsed and logging initialized OK");
118 
119     debug!("Collecting crossystem info");
120     let crossystem =
121         flashrom_tester::utils::collect_crosssystem(&[]).expect("could not run crossystem");
122 
123     let ccd_type = FlashChip::from(
124         matches
125             .value_of("ccd_target_type")
126             .expect("ccd_target_type should be required"),
127     )
128     .expect("ccd_target_type should admit only known types");
129 
130     let cmd: Box<dyn Flashrom> = if matches.is_present("libflashrom") {
131         Box::new(FlashromLib::new(
132             ccd_type,
133             if matches.is_present("log_debug") {
134                 flashrom::FLASHROM_MSG_DEBUG
135             } else {
136                 flashrom::FLASHROM_MSG_WARN
137             },
138         ))
139     } else {
140         Box::new(FlashromCmd {
141             path: matches
142                 .value_of("flashrom_binary")
143                 .expect("flashrom_binary is required")
144                 .to_string(),
145             fc: ccd_type,
146         })
147     };
148 
149     let print_layout = matches.is_present("print-layout");
150     let output_format = matches
151         .value_of("output-format")
152         .expect("output-format should have a default value")
153         .parse::<tester::OutputFormat>()
154         .expect("output-format is not a parseable OutputFormat");
155     let test_names = matches.values_of("test_name");
156 
157     if let Err(e) = tests::generic(
158         cmd.as_ref(),
159         ccd_type,
160         print_layout,
161         output_format,
162         test_names,
163         Some(handle_sigint()),
164         crossystem,
165     ) {
166         eprintln!("Failed to run tests: {:?}", e);
167         std::process::exit(1);
168     }
169 }
170 
171 /// Catch exactly one SIGINT, printing a message in response and setting a flag.
172 ///
173 /// The returned value is false by default, becoming true after a SIGINT is
174 /// trapped.
175 ///
176 /// Once a signal is trapped, the default behavior is restored (terminating
177 /// the process) for future signals.
handle_sigint() -> &'static AtomicBool178 fn handle_sigint() -> &'static AtomicBool {
179     use libc::c_int;
180     use std::sync::atomic::Ordering;
181 
182     unsafe {
183         let _ = libc::signal(libc::SIGINT, sigint_handler as libc::sighandler_t);
184     }
185     static TERMINATE_FLAG: AtomicBool = AtomicBool::new(false);
186 
187     extern "C" fn sigint_handler(_: c_int) {
188         const STDERR_FILENO: c_int = 2;
189         static MESSAGE: &[u8] = b"
190 WARNING: terminating tests prematurely may leave Flash in an inconsistent state,
191 rendering your machine unbootable. Testing will end on completion of the current
192 test, or press ^C again to exit immediately (possibly bricking your machine).
193 ";
194 
195         // Use raw write() because signal-safety is a very hard problem. Safe because this doesn't
196         // modify any memory.
197         let _ = unsafe {
198             libc::write(
199                 STDERR_FILENO,
200                 MESSAGE.as_ptr() as *const libc::c_void,
201                 MESSAGE.len() as libc::size_t,
202             )
203         };
204         unsafe {
205             let _ = libc::signal(libc::SIGINT, libc::SIG_DFL);
206         }
207         TERMINATE_FLAG.store(true, Ordering::Release);
208     }
209 
210     &TERMINATE_FLAG
211 }
212