xref: /openbmc/openbmc-test-automation/lib/valid.tcl (revision e17cf5fd0e4bff1169dab667fe0ce361ca76d857)
1#!/usr/bin/wish
2
3# This file provides many valuable validation procedures such as valid_value,
4# valid_integer, etc.
5
6my_source [list print.tcl call_stack.tcl]
7
8
9proc valid_value { var_name { invalid_values {}} { valid_values {}} } {
10
11  # If the value of the variable named in var_name is not valid, print an
12  # error message and exit the program with a non-zero return code.
13
14  # Description of arguments:
15  # var_name                        The name of the variable whose value is to
16  #                                 be validated.
17  # invalid_values                  A list of invalid values.  If the variable
18  #                                 value is equal to any value in the
19  #                                 invalid_values list, it is deemed to be
20  #                                 invalid.  Note that if you specify
21  #                                 anything for invalid_values (below), the
22  #                                 valid_values list is not even processed.
23  #                                 In other words, specify either
24  #                                 invalid_values or valid_values but not
25  #                                 both.  If no value is specified for either
26  #                                 invalid_values or valid_values,
27  #                                 invalid_values will default to a list with
28  #                                 one blank entry.  This is useful if you
29  #                                 simply want to ensure that your variable
30  #                                 is non blank.
31  # valid_values                    A list of invalid values.  The variable
32  #                                 value must be equal to one of the values
33  #                                 in this list to be considered valid.
34
35  # Call get_stack_var_level to relieve the caller of the need for declaring
36  # the variable as global.
37  set stack_level [get_stack_var_level $var_name]
38  # Access the variable value.
39  upvar $stack_level $var_name var_value
40
41  set len_invalid_values [llength $invalid_values]
42  set len_valid_values [llength $valid_values]
43
44  if { $len_valid_values > 0 &&  $len_invalid_values > 0 } {
45    append error_message "Programmer error - You must provide either an"
46    append error_message " invalid_values list or a valid_values"
47    append error_message " list but NOT both.\n"
48    append error_message [sprint_list invalid_values "" "" 1]
49    append error_message [sprint_list valid_values "" "" 1]
50    print_error_report $error_message
51    exit 1
52  }
53
54  if { $len_valid_values > 0 } {
55    # Processing the valid_values list.
56    if { [lsearch -exact $valid_values "${var_value}"] != -1 } { return }
57    append error_message "The following variable has an invalid value:\n"
58    append error_message [sprint_varx $var_name $var_value "" "" 1]
59    append error_message "\nIt must be one of the following values:\n"
60    append error_message [sprint_list valid_values "" "" 1]
61    print_error_report $error_message
62    exit 1
63  }
64
65  if { $len_invalid_values == 0 } {
66    # Assign default value.
67    set invalid_values [list ""]
68  }
69
70  # Assertion: We have an invalid_values list.  Processing it now.
71  if { [lsearch -exact $invalid_values "${var_value}"] == -1 } { return }
72
73  if { [lsearch -exact $valid_values "${var_value}"] != -1 } { return }
74  append error_message "The following variable has an invalid value:\n"
75  append error_message [sprint_varx $var_name $var_value "" "" 1]
76  append error_message "\nIt must NOT be one of the following values:\n"
77  append error_message [sprint_list invalid_values "" "" 1]
78  print_error_report $error_message
79  exit 1
80
81}
82
83
84proc valid_integer { var_name } {
85
86  # If the value of the variable named in var_name is not a valid integer,
87  # print an error message and exit the program with a non-zero return code.
88
89  # Description of arguments:
90  # var_name                        The name of the variable whose value is to
91  #                                 be validated.
92
93  # Call get_stack_var_level to relieve the caller of the need for declaring
94  # the variable as global.
95  set stack_level [get_stack_var_level $var_name]
96  # Access the variable value.
97  upvar $stack_level $var_name var_value
98
99  if { [catch {format "0x%08x" "$var_value"} result] } {
100    append error_message "Invalid integer value:\n"
101    append error_message [sprint_varx $var_name $var_value]
102    print_error_report $error_message
103    exit 1
104  }
105
106}
107
108
109proc valid_dir_path { var_name { add_slash 1 } } {
110
111  # If the value of the variable named in var_name is not a valid directory
112  # path, print an error message and exit the program with a non-zero return
113  # code.
114
115  # Description of arguments:
116  # var_name                        The name of the variable whose value is to
117  #                                 be validated.
118  # add_slash                       If set to 1, this procedure will add a
119  #                                 trailing slash to the directory path value.
120
121  # Call get_stack_var_level to relieve the caller of the need for declaring
122  # the variable as global.
123  set stack_level [get_stack_var_level $var_name]
124  # Access the variable value.
125  upvar $stack_level $var_name var_value
126
127  expand_shell_string var_value
128
129  if { ![file isdirectory $var_value] } {
130    append error_message "The following directory does not exist:\n"
131    append error_message [sprint_varx $var_name $var_value "" "" 1]
132    print_error_report $error_message
133    exit 1
134  }
135
136  if { $add_slash } { add_trailing_string var_value / }
137
138}
139
140
141proc valid_file_path { var_name } {
142
143  # If the value of the variable named in var_name is not a valid file path,
144  # print an error message and exit the program with a non-zero return code.
145
146  # Description of arguments:
147  # var_name                        The name of the variable whose value is to
148  #                                 be validated.
149
150  # Call get_stack_var_level to relieve the caller of the need for declaring
151  # the variable as global.
152  set stack_level [get_stack_var_level $var_name]
153  # Access the variable value.
154  upvar $stack_level $var_name var_value
155
156  expand_shell_string var_value
157
158  if { ![file isfile $var_value] } {
159    append error_message "The following file does not exist:\n"
160    append error_message [sprint_varx $var_name $var_value "" "" 1]
161    print_error_report $error_message
162    exit 1
163  }
164
165}
166
167
168proc get_password { {password_var_name password} } {
169
170  # Prompt user for password and return result.
171
172  # On error, print to stderr and terminate the program with non-zero return
173  # code.
174
175  set prompt\
176    [string trimright [sprint_varx "Please enter $password_var_name" ""] "\n"]
177  puts -nonewline $prompt
178  flush stdout
179  stty -echo
180  gets stdin password1
181  stty echo
182  puts ""
183
184  set prompt [string\
185    trimright [sprint_varx "Please re-enter $password_var_name" ""] "\n"]
186  puts -nonewline $prompt
187  flush stdout
188  stty -echo
189  gets stdin password2
190  stty echo
191  puts ""
192
193  if { $password1 != $password2 } {
194    print_error_report "Passwords do not match.\n"
195    gen_exit_proc 1
196  }
197
198  if { $password1 == "" } {
199    print_error_report "Need a non-blank value for $password_var_name.\n"
200    gen_exit_proc 1
201  }
202
203  return $password1
204
205}
206
207
208proc valid_password { var_name { prompt_user 1 } } {
209
210  # If the value of the variable named in var_name is not a valid password,
211  # print an error message and exit the program with a non-zero return code.
212
213  # Description of arguments:
214  # var_name                        The name of the variable whose value is to
215  #                                 be validated.
216  # prompt_user                     If the variable has a blank value, prompt
217  #                                 the user for a value.
218
219  # Call get_stack_var_level to relieve the caller of the need for declaring
220  # the variable as global.
221  set stack_level [get_stack_var_level $var_name]
222  # Access the variable value.
223  upvar $stack_level $var_name var_value
224
225  if { $var_value == "" && $prompt_user } {
226    global $var_name
227    set $var_name [get_password $var_name]
228  }
229
230  if { $var_value == "" } {
231    print_error_report "Need a non-blank value for $var_name.\n"
232    gen_exit_proc 1
233  }
234
235}
236
237
238proc process_pw_file_path {pw_file_path_var_name} {
239
240  # Process a password file path parameter by setting or validating the
241  # corresponding password variable.
242
243  # For example, let's say you have an os_pw_file_path parm defined.  This
244  # procedure will set the global os_password variable.
245
246  # If there is no os_password program parm defined, then the pw_file_path
247  # must exist and will be validated by this procedure.  If there is an
248  # os_password program parm defined, then either the os_pw_file_path must be
249  # valid or the os_password must be valid.  Again, this procedure will verify
250  # all of this.
251
252  # When a valid pw_file_path exists, this program will read the password
253  # from it and set the global password variable with the value.
254  # Finally, this procedure will call valid_password which will prompt user
255  # if password has not been obtained by this point.
256
257  # Description of argument(s):
258  # pw_file_path_var_name           The name of a global variable that
259  #                                 contains a file path which in turn
260  #                                 contains a password value.  The variable
261  #                                 name must end in "pw_file_path" (e.g.
262  #                                 "os_pw_file_path").
263
264  # Verify that $pw_file_path_var_name ends with "pw_file_path".
265  if { ! [regexp -expanded "pw_file_path$" $pw_file_path_var_name] } {
266    append message "Programming error - Proc [get_stack_proc_name] its"
267    append message " pw_file_path_var_name parameter to contain a value that"
268    append message "ends in \"pw_file_path\" instead of the current value:\n"
269    append message [sprint_var pw_file_path_var_name]
270    print_error $message
271    gen_exit_proc 1
272  }
273
274  global $pw_file_path_var_name
275  expand_shell_string $pw_file_path_var_name
276
277  # Get the prefix portion of pw_file_path_var_name which is obtained by
278  # stripping "pw_file_path" from the end.
279  regsub -expanded {pw_file_path$} $pw_file_path_var_name {} var_prefix
280
281  # Create password_var_name.
282  set password_var_name ${var_prefix}password
283  global $password_var_name
284
285  global longoptions pos_parms
286  regsub -all ":" "${longoptions} ${pos_parms}" {} parm_names
287  if { [lsearch -exact parm_names $password_var_name] == -1 } {
288    # If no corresponding password program parm has been defined, then the
289    # pw_file_path must be valid.
290    valid_file_path $pw_file_path_var_name
291  }
292
293  if { [file isfile [set $pw_file_path_var_name]] } {
294    # Read the entire password file into a list, filtering comments out.
295    set file_descriptor [open [set $pw_file_path_var_name] r]
296    set file_data [list_filter_comments [split [read $file_descriptor] "\n"]]
297    close $file_descriptor
298
299    # Assign the password value to the global password variable.
300    set $password_var_name [lindex $file_data 0]
301    # Register the password to prevent printing it.
302    register_passwords [set $password_var_name]
303  }
304
305  # Validate the password, which includes prompting the user if need be.
306  valid_password $password_var_name
307
308}
309