blob: 024881ccdc6258c41c0e7e21d339ba52f4d28e51 [file] [log] [blame]
Stefan Tauner9b32de92014-08-08 23:52:33 +00001/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
5 * Copyright (C) 2009 Carl-Daniel Hailfinger
6 * Copyright (C) 2011-2014 Stefan Tauner
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
Stefan Tauner9b32de92014-08-08 23:52:33 +000017 */
18
Nico Huberd39c7d62023-02-11 00:53:08 +010019#include <stdio.h>
Stefan Tauner9b32de92014-08-08 23:52:33 +000020#include <stdlib.h>
21#include <string.h>
Nico Huber0da839b2023-02-11 01:40:07 +010022#include <sys/stat.h>
Nico Huber34e783a2023-02-11 00:30:27 +010023
Stefan Tauner9b32de92014-08-08 23:52:33 +000024#include "flash.h"
Nico Huber34e783a2023-02-11 00:30:27 +010025#include "cli.h"
26
Nico Huberd91822a2023-02-11 00:43:54 +010027int cli_check_filename(const char *const filename, const char *const type)
28{
29 if (!filename || (filename[0] == '\0')) {
30 fprintf(stderr, "Error: No %s file specified.\n", type);
31 return 1;
32 }
33 /* Not an error, but maybe the user intended to specify a CLI option instead of a file name. */
34 if (filename[0] == '-' && filename[1] != '\0')
35 fprintf(stderr, "Warning: Supplied %s file name starts with -\n", type);
36 return 0;
37}
38
Nico Huberd39c7d62023-02-11 00:53:08 +010039/* Ensure a file is open by means of fstat */
40static bool cli_check_file(FILE *file)
41{
42 struct stat statbuf;
43
44 if (fstat(fileno(file), &statbuf) < 0)
45 return false;
46 return true;
47}
48
49int cli_init(void)
50{
51 /*
52 * Safety-guard against a user who has (mistakenly) closed
53 * stdout or stderr before exec'ing flashprog. We disable
54 * logging in this case to prevent writing log data to a flash
55 * chip when a flash device gets opened with fd 1 or 2.
56 */
57 if (cli_check_file(stdout) && cli_check_file(stderr)) {
58 flashprog_set_log_callback((flashprog_log_callback *)&flashprog_print_cb);
59 }
60
61 print_version();
62 print_banner();
63
64 return flashprog_init(/* perform_selfcheck => */1);
65}
66
Nico Huberdf6ce9f2023-02-11 16:16:04 +010067int cli_parse_log_args(struct log_args *const args, const int opt, const char *const optarg)
68{
69 switch (opt) {
70 case OPTION_VERBOSE:
71 args->screen_level++;
72 if (args->screen_level > args->logfile_level)
73 args->logfile_level = args->screen_level;
74 break;
75 case OPTION_LOGFILE:
76 if (cli_check_filename(optarg, "log"))
77 return 1;
78
79 if (args->logfile) {
80 fprintf(stderr, "Warning: -o/--output specified multiple times.\n");
81 free(args->logfile);
82 }
83
84 args->logfile = strdup(optarg);
85 if (!args->logfile) {
86 fprintf(stderr, "Out of memory!\n");
87 return 2;
88 }
89 break;
90 }
91
92 return 0;
93}
94
Nico Huber34e783a2023-02-11 00:30:27 +010095int cli_parse_flash_args(struct flash_args *const args, const int opt, const char *const optarg)
96{
97 switch (opt) {
98 case OPTION_PROGRAMMER:
99 if (args->prog_name) {
100 fprintf(stderr,
101 "Error: --programmer specified more than once. You can separate multiple\n"
102 "arguments for a programmer with ','. Please see the man page for details.\n");
103 return 1;
104 }
105 const char *const colon = strchr(optarg, ':');
106 if (colon) {
107 args->prog_name = strndup(optarg, colon - optarg);
108 args->prog_args = strdup(colon + 1);
109 } else {
110 args->prog_name = strdup(optarg);
111 }
112 if (!args->prog_name || (colon && !args->prog_args)) {
113 fprintf(stderr, "Out of memory!\n");
114 return 2;
115 }
116 break;
117 case OPTION_CHIP:
118 if (args->chip) {
119 fprintf(stderr, "Error: --chip specified more than once.\n");
120 return 1;
121 }
122 args->chip = strdup(optarg);
123 if (!args->chip) {
124 fprintf(stderr, "Out of memory!\n");
125 return 2;
126 }
127 break;
128 }
129
130 return 0;
131}
Stefan Tauner9b32de92014-08-08 23:52:33 +0000132
Nico Huberd91822a2023-02-11 00:43:54 +0100133int cli_parse_layout_args(struct layout_args *const args, const int opt, const char *const optarg)
134{
135 if (args->layoutfile || args->ifd || args->fmap || args->fmapfile) {
136 fprintf(stderr, "Error: Only one layout source may be specified.\n");
137 return 1;
138 }
139
140 switch (opt) {
141 case OPTION_LAYOUT:
142 if (cli_check_filename(optarg, "layout"))
143 return 1;
144
145 args->layoutfile = strdup(optarg);
146 if (!args->layoutfile) {
147 fprintf(stderr, "Out of memory!\n");
148 return 2;
149 }
150 break;
151 case OPTION_IFD:
152 args->ifd = true;
153 break;
154 case OPTION_FMAP:
155 args->fmap = true;
156 break;
157 case OPTION_FMAP_FILE:
158 if (cli_check_filename(optarg, "fmap"))
159 return 1;
160
161 args->fmapfile = strdup(optarg);
162 if (!args->fmapfile) {
163 fprintf(stderr, "Out of memory!\n");
164 return 2;
165 }
166 break;
167 }
168
169 return 0;
170}
171
Nico Huber0da839b2023-02-11 01:40:07 +0100172int cli_process_layout_args(struct flashprog_layout **const layout,
173 struct flashprog_flashctx *const flash,
174 const struct layout_args *const args)
175{
176 *layout = NULL;
177
178 if (args->layoutfile) {
179 if (layout_from_file(layout, args->layoutfile))
180 return 1;
181 } else if (args->ifd) {
182 if (flashprog_layout_read_from_ifd(layout, flash, NULL, 0))
183 return 1;
184 } else if (args->fmap) {
185 if (flashprog_layout_read_fmap_from_rom(layout, flash, 0, flashprog_flash_getsize(flash)))
186 return 1;
187 } else if (args->fmapfile) {
188 struct stat s;
189 if (stat(args->fmapfile, &s) != 0) {
190 msg_gerr("Failed to stat fmapfile \"%s\"\n", args->fmapfile);
191 return 1;
192 }
193
194 size_t fmapfile_size = s.st_size;
195 uint8_t *fmapfile_buffer = malloc(fmapfile_size);
196 if (!fmapfile_buffer) {
197 fprintf(stderr, "Out of memory!\n");
198 return 1;
199 }
200
201 if (read_buf_from_file(fmapfile_buffer, fmapfile_size, args->fmapfile)) {
202 free(fmapfile_buffer);
203 return 1;
204 }
205
206 if (flashprog_layout_read_fmap_from_buffer(layout, flash, fmapfile_buffer, fmapfile_size)) {
207 free(fmapfile_buffer);
208 return 1;
209 }
210 free(fmapfile_buffer);
211 }
212
213 return 0;
214}
215
Stefan Tauner9b32de92014-08-08 23:52:33 +0000216void print_chip_support_status(const struct flashchip *chip)
217{
218 if (chip->feature_bits & FEATURE_OTP) {
Nico Huberc3b02dc2023-08-12 01:13:45 +0200219 msg_cdbg("This chip may contain one-time programmable memory. flashprog cannot read\n"
Stefan Tauner9b32de92014-08-08 23:52:33 +0000220 "and may never be able to write it, hence it may not be able to completely\n"
221 "clone the contents of this chip (see man page for details).\n");
222 }
223
224 if ((chip->tested.erase == NA) && (chip->tested.write == NA)) {
225 msg_cdbg("This chip's main memory can not be erased/written by design.\n");
226 }
227
228 if ((chip->tested.probe == BAD) || (chip->tested.probe == NT) ||
229 (chip->tested.read == BAD) || (chip->tested.read == NT) ||
230 (chip->tested.erase == BAD) || (chip->tested.erase == NT) ||
Nico Huberbb4f3b02022-12-30 14:28:06 +0100231 (chip->tested.write == BAD) || (chip->tested.write == NT)) {
Stefan Tauner9b32de92014-08-08 23:52:33 +0000232 msg_cinfo("===\n");
233 if ((chip->tested.probe == BAD) ||
234 (chip->tested.read == BAD) ||
235 (chip->tested.erase == BAD) ||
Nico Huberbb4f3b02022-12-30 14:28:06 +0100236 (chip->tested.write == BAD)) {
Stefan Tauner9b32de92014-08-08 23:52:33 +0000237 msg_cinfo("This flash part has status NOT WORKING for operations:");
238 if (chip->tested.probe == BAD)
239 msg_cinfo(" PROBE");
240 if (chip->tested.read == BAD)
241 msg_cinfo(" READ");
242 if (chip->tested.erase == BAD)
243 msg_cinfo(" ERASE");
244 if (chip->tested.write == BAD)
245 msg_cinfo(" WRITE");
246 msg_cinfo("\n");
247 }
248 if ((chip->tested.probe == NT) ||
249 (chip->tested.read == NT) ||
250 (chip->tested.erase == NT) ||
Nico Huberbb4f3b02022-12-30 14:28:06 +0100251 (chip->tested.write == NT)) {
Stefan Tauner9b32de92014-08-08 23:52:33 +0000252 msg_cinfo("This flash part has status UNTESTED for operations:");
253 if (chip->tested.probe == NT)
254 msg_cinfo(" PROBE");
255 if (chip->tested.read == NT)
256 msg_cinfo(" READ");
257 if (chip->tested.erase == NT)
258 msg_cinfo(" ERASE");
259 if (chip->tested.write == NT)
260 msg_cinfo(" WRITE");
261 msg_cinfo("\n");
262 }
263 msg_cinfo("The test status of this chip may have been updated in the latest development\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200264 "version of flashprog. If you are running the latest development version,\n"
265 "please email a report to flashprog@flashprog.org if any of the above\n"
Nico Huberac90af62022-12-18 00:22:47 +0000266 "operations work correctly for you with this flash chip. Please include the\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200267 "flashprog log file for all operations you tested (see the man page for details),\n"
Nico Huberac90af62022-12-18 00:22:47 +0000268 "and mention which mainboard or programmer you tested in the subject line.\n"
Stefan Tauner9b32de92014-08-08 23:52:33 +0000269 "Thanks for your help!\n");
270 }
271}