blob: 90c54b1990064475e8d7f180149883ab912ad10c [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
Nico Huber24c09772024-11-02 13:46:21 +0100216void print_generic_options(void)
217{
218 fprintf(stderr, "\n"
219 "Where generic <options> are\n"
220 " -p | --programmer <name>[:<params>] specify the programmer device. One of\n");
221 list_programmers_linebreak(12, 80, 0);
222 fprintf(stderr, "\n"
223 " -c | --chip <chipname> probe only for specified flash chip\n"
224 " -V | --verbose more verbose output\n"
225 " -o | --output <logfile> log output to <logfile>\n"
226 " -h | --help print help text\n");
227}
228
Stefan Tauner9b32de92014-08-08 23:52:33 +0000229void print_chip_support_status(const struct flashchip *chip)
230{
231 if (chip->feature_bits & FEATURE_OTP) {
Nico Huberc3b02dc2023-08-12 01:13:45 +0200232 msg_cdbg("This chip may contain one-time programmable memory. flashprog cannot read\n"
Stefan Tauner9b32de92014-08-08 23:52:33 +0000233 "and may never be able to write it, hence it may not be able to completely\n"
234 "clone the contents of this chip (see man page for details).\n");
235 }
236
237 if ((chip->tested.erase == NA) && (chip->tested.write == NA)) {
238 msg_cdbg("This chip's main memory can not be erased/written by design.\n");
239 }
240
241 if ((chip->tested.probe == BAD) || (chip->tested.probe == NT) ||
242 (chip->tested.read == BAD) || (chip->tested.read == NT) ||
243 (chip->tested.erase == BAD) || (chip->tested.erase == NT) ||
Nico Huberbb4f3b02022-12-30 14:28:06 +0100244 (chip->tested.write == BAD) || (chip->tested.write == NT)) {
Stefan Tauner9b32de92014-08-08 23:52:33 +0000245 msg_cinfo("===\n");
246 if ((chip->tested.probe == BAD) ||
247 (chip->tested.read == BAD) ||
248 (chip->tested.erase == BAD) ||
Nico Huberbb4f3b02022-12-30 14:28:06 +0100249 (chip->tested.write == BAD)) {
Stefan Tauner9b32de92014-08-08 23:52:33 +0000250 msg_cinfo("This flash part has status NOT WORKING for operations:");
251 if (chip->tested.probe == BAD)
252 msg_cinfo(" PROBE");
253 if (chip->tested.read == BAD)
254 msg_cinfo(" READ");
255 if (chip->tested.erase == BAD)
256 msg_cinfo(" ERASE");
257 if (chip->tested.write == BAD)
258 msg_cinfo(" WRITE");
259 msg_cinfo("\n");
260 }
261 if ((chip->tested.probe == NT) ||
262 (chip->tested.read == NT) ||
263 (chip->tested.erase == NT) ||
Nico Huberbb4f3b02022-12-30 14:28:06 +0100264 (chip->tested.write == NT)) {
Stefan Tauner9b32de92014-08-08 23:52:33 +0000265 msg_cinfo("This flash part has status UNTESTED for operations:");
266 if (chip->tested.probe == NT)
267 msg_cinfo(" PROBE");
268 if (chip->tested.read == NT)
269 msg_cinfo(" READ");
270 if (chip->tested.erase == NT)
271 msg_cinfo(" ERASE");
272 if (chip->tested.write == NT)
273 msg_cinfo(" WRITE");
274 msg_cinfo("\n");
275 }
276 msg_cinfo("The test status of this chip may have been updated in the latest development\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200277 "version of flashprog. If you are running the latest development version,\n"
278 "please email a report to flashprog@flashprog.org if any of the above\n"
Nico Huberac90af62022-12-18 00:22:47 +0000279 "operations work correctly for you with this flash chip. Please include the\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200280 "flashprog log file for all operations you tested (see the man page for details),\n"
Nico Huberac90af62022-12-18 00:22:47 +0000281 "and mention which mainboard or programmer you tested in the subject line.\n"
Stefan Tauner9b32de92014-08-08 23:52:33 +0000282 "Thanks for your help!\n");
283 }
284}