buildgcc: Fix colors for dash
[coreboot.git] / util / nvramtool / input_file.c
1 /*****************************************************************************\
2  * input_file.c
3  *****************************************************************************
4  *  Copyright (C) 2002-2005 The Regents of the University of California.
5  *  Produced at the Lawrence Livermore National Laboratory.
6  *  Written by David S. Peterson <dsp@llnl.gov> <dave_peterson@pobox.com>.
7  *  UCRL-CODE-2003-012
8  *  All rights reserved.
9  *
10  *  This file is part of nvramtool, a utility for reading/writing coreboot
11  *  parameters and displaying information from the coreboot table.
12  *  For details, see http://coreboot.org/nvramtool.
13  *
14  *  Please also read the file DISCLAIMER which is included in this software
15  *  distribution.
16  *
17  *  This program is free software; you can redistribute it and/or modify it
18  *  under the terms of the GNU General Public License (as published by the
19  *  Free Software Foundation) version 2, dated June 1991.
20  *
21  *  This program is distributed in the hope that it will be useful, but
22  *  WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
23  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the terms and
24  *  conditions of the GNU General Public License for more details.
25  *
26  *  You should have received a copy of the GNU General Public License along
27  *  with this program; if not, write to the Free Software Foundation, Inc.,
28  *  51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
29 \*****************************************************************************/
30
31 #include "common.h"
32 #include "input_file.h"
33 #include "layout.h"
34 #include "cmos_ops.h"
35 #include "cmos_lowlevel.h"
36 #include "reg_expr.h"
37
38 static int get_input_file_line(FILE * f, char line[], int line_buf_size);
39 static unsigned long long try_prepare_cmos_write(const cmos_entry_t * e,
40                                                  const char value_str[]);
41
42 /* matches either a blank line or a comment line */
43 static const char blank_or_comment_regex[] =
44     /* a blank line */
45     "(^[[:space:]]+$)" "|"      /* or ... */
46     /* a line consisting of: optional whitespace followed by */
47     "(^[[:space:]]*"
48     /* a '#' character and optionally, additional characters */
49     "#.*$)";
50
51 /* matches an assignment line */
52 const char assignment_regex[] =
53     /* optional whitespace */
54     "^[[:space:]]*"
55     /* followed by a coreboot parameter name */
56     "([^[:space:]]+)"
57     /* followed by optional whitespace */
58     "[[:space:]]*"
59     /* followed by an '=' character */
60     "="
61     /* followed by optional whitespace */
62     "[[:space:]]*"
63     /* followed by a value that may contain embedded whitespace */
64     "([^[:space:]]+([[:space:]]+[^[:space:]]+)*)+"
65     /* followed by optional whitespace */
66     "[[:space:]]*$";
67
68 static int line_num;
69
70 /****************************************************************************
71  * process_input_file
72  *
73  * Read the contents of file 'f' and return a pointer to a list of pending
74  * write operations.  Perform sanity checking on all write operations and
75  * exit with an error message if there is a problem.
76  ****************************************************************************/
77 cmos_write_t *process_input_file(FILE * f)
78 {
79         static const int LINE_BUF_SIZE = 256;
80         static const size_t N_MATCHES = 4;
81         char line[LINE_BUF_SIZE];
82         const char *name, *value;
83         cmos_write_t *list, *item, **p;
84         regex_t blank_or_comment, assignment;
85         regmatch_t match[N_MATCHES];
86         const cmos_entry_t *e;
87
88         list = NULL;
89         p = &list;
90
91         compile_reg_expr(REG_EXTENDED | REG_NEWLINE, blank_or_comment_regex, &blank_or_comment);
92         compile_reg_expr(REG_EXTENDED | REG_NEWLINE, assignment_regex, &assignment);
93
94         /* each iteration processes one line from input file */
95         for (line_num = 1; get_input_file_line(f, line, LINE_BUF_SIZE) == OK; line_num++) {     /* skip comments and blank lines */
96                 if (!regexec(&blank_or_comment, line, 0, NULL, 0))
97                         continue;
98
99                 /* Is this a valid assignment line?  If not, then it's a syntax
100                  * error.
101                  */
102                 if (regexec(&assignment, line, N_MATCHES, match, 0)) {
103                         fprintf(stderr,
104                                 "%s: Syntax error on line %d of input file.\n",
105                                 prog_name, line_num);
106                         exit(1);
107                 }
108
109                 /* OK, we found an assignment.  Break the line into substrings
110                  * representing the lefthand and righthand sides of the assignment.
111                  */
112                 line[match[1].rm_eo] = '\0';
113                 line[match[2].rm_eo] = '\0';
114                 name = &line[match[1].rm_so];
115                 value = &line[match[2].rm_so];
116
117                 /* now look up the coreboot parameter name */
118                 if (is_checksum_name(name)
119                     || (e = find_cmos_entry(name)) == NULL) {
120                         fprintf(stderr,
121                                 "%s: Error on line %d of input file: CMOS parameter "
122                                 "%s not found.\n", prog_name, line_num, name);
123                         exit(1);
124                 }
125
126                 /* At this point, we figure out what numeric value needs to be written
127                  * to which location.  At the same time, we perform sanity checking on
128                  * the write operation.
129                  */
130
131                 if ((item = (cmos_write_t *) malloc(sizeof(*item))) == NULL)
132                         out_of_memory();
133
134                 item->bit = e->bit;
135                 item->length = e->length;
136                 item->config = e->config;
137                 item->value = try_prepare_cmos_write(e, value);
138
139                 /* Append write operation to pending write list. */
140                 item->next = NULL;
141                 *p = item;
142                 p = &item->next;
143         }
144
145         regfree(&blank_or_comment);
146         regfree(&assignment);
147         return list;
148 }
149
150 /****************************************************************************
151  * do_cmos_writes
152  *
153  * 'list' is a linked list of pending CMOS write operations that have passed
154  * all sanity checks.  Perform all write operations, destroying the list as
155  * we go.
156  ****************************************************************************/
157 void do_cmos_writes(cmos_write_t * list)
158 {
159         cmos_write_t *item;
160
161         set_iopl(3);
162
163         while (list != NULL) {
164                 cmos_entry_t e;
165                 item = list;
166                 e.bit = item->bit;
167                 e.length = item->length;
168                 e.config = item->config;
169                 list = item->next;
170                 cmos_write(&e, item->value);
171                 free(item);
172         }
173
174         cmos_checksum_write(cmos_checksum_compute());
175         set_iopl(0);
176 }
177
178 /****************************************************************************
179  * get_input_file_line
180  *
181  * Get a line of input from file 'f'.  Store result in 'line' which is an
182  * array of 'line_buf_size' bytes.  Return OK on success or an error code on
183  * error.
184  ****************************************************************************/
185 static int get_input_file_line(FILE * f, char line[], int line_buf_size)
186 {
187         switch (get_line_from_file(f, line, line_buf_size)) {
188         case OK:
189                 return OK;
190
191         case LINE_EOF:
192                 return LINE_EOF;
193
194         case LINE_TOO_LONG:
195                 fprintf(stderr,
196                         "%s: Error on line %d of input file: Maximum line "
197                         "length exceeded.  Max is %d characters.\n", prog_name,
198                         line_num, line_buf_size - 2);
199                 break;
200
201         default:
202                 BUG();
203         }
204
205         exit(1);
206         return 1;               /* keep compiler happy */
207 }
208
209 /****************************************************************************
210  * try_prepare_cmos_write
211  *
212  * Attempt to convert 'value_str' to an integer representation for storage in
213  * CMOS memory.  On success, return the converted value.  On error, exit with
214  * an error message.
215  ****************************************************************************/
216 static unsigned long long try_prepare_cmos_write(const cmos_entry_t * e,
217                                                  const char value_str[])
218 {
219         unsigned long long value;
220
221         switch (prepare_cmos_write(e, value_str, &value)) {
222         case OK:
223                 return value;
224
225         case CMOS_OP_BAD_ENUM_VALUE:
226                 fprintf(stderr,
227                         "%s: Error on line %d of input file: Bad value for "
228                         "parameter %s.", prog_name, line_num, e->name);
229                 break;
230
231         case CMOS_OP_NEGATIVE_INT:
232                 fprintf(stderr,
233                         "%s: Error on line %d of input file: This program "
234                         "does not support assignment of negative numbers to "
235                         "coreboot parameters.", prog_name, line_num);
236                 break;
237
238         case CMOS_OP_INVALID_INT:
239                 fprintf(stderr,
240                         "%s: Error on line %d of input file: %s is not a "
241                         "valid integer.", prog_name, line_num, value_str);
242                 break;
243
244         case CMOS_OP_RESERVED:
245                 fprintf(stderr,
246                         "%s: Error on line %d of input file: Can not modify "
247                         "reserved coreboot parameter %s.", prog_name, line_num,
248                         e->name);
249                 break;
250
251         case CMOS_OP_VALUE_TOO_WIDE:
252                 fprintf(stderr,
253                         "%s: Error on line %d of input file: Can not write "
254                         "value %s to CMOS parameter %s that is only %d bits wide.",
255                         prog_name, line_num, value_str, e->name, e->length);
256                 break;
257
258         case CMOS_OP_NO_MATCHING_ENUM:
259                 fprintf(stderr,
260                         "%s: coreboot parameter %s has no matching enums.",
261                         prog_name, e->name);
262                 break;
263
264         case CMOS_AREA_OUT_OF_RANGE:
265                 fprintf(stderr,
266                         "%s: The CMOS area specified by the layout info for "
267                         "coreboot parameter %s is out of range.", prog_name,
268                         e->name);
269                 break;
270
271         case CMOS_AREA_OVERLAPS_RTC:
272                 fprintf(stderr,
273                         "%s: The CMOS area specified by the layout info for "
274                         "coreboot parameter %s overlaps the realtime clock area.",
275                         prog_name, e->name);
276                 break;
277
278         case CMOS_AREA_TOO_WIDE:
279                 fprintf(stderr,
280                         "%s: The CMOS area specified by the layout info for "
281                         "coreboot parameter %s is too wide.", prog_name,
282                         e->name);
283                 break;
284
285         default:
286                 fprintf(stderr,
287                         "%s: Unknown error encountered while attempting to modify "
288                         "coreboot parameter %s.", prog_name, e->name);
289                 break;
290         }
291
292         fprintf(stderr, "  No CMOS writes performed.\n");
293         exit(1);
294         return 0;               /* keep compiler happy */
295 }