1 #!/usr/bin/env python3 1 #!/usr/bin/env python3 2 # SPDX-License-Identifier: GPL-2.0 2 # SPDX-License-Identifier: GPL-2.0 3 # 3 # 4 # Program to allow users to fuzz test Hyper-V 4 # Program to allow users to fuzz test Hyper-V drivers 5 # by interfacing with Hyper-V debugfs attribut 5 # by interfacing with Hyper-V debugfs attributes. 6 # Current test methods available: 6 # Current test methods available: 7 # 1. delay testing 7 # 1. delay testing 8 # 8 # 9 # Current file/directory structure of hyper-V 9 # Current file/directory structure of hyper-V debugfs: 10 # /sys/kernel/debug/hyperv/UUID 10 # /sys/kernel/debug/hyperv/UUID 11 # /sys/kernel/debug/hyperv/UUID/<test-st 11 # /sys/kernel/debug/hyperv/UUID/<test-state filename> 12 # /sys/kernel/debug/hyperv/UUID/<test-me 12 # /sys/kernel/debug/hyperv/UUID/<test-method sub-directory> 13 # 13 # 14 # author: Branden Bonaby <brandonbonaby94@gmail 14 # author: Branden Bonaby <brandonbonaby94@gmail.com> 15 15 16 import os 16 import os 17 import cmd 17 import cmd 18 import argparse 18 import argparse 19 import glob 19 import glob 20 from argparse import RawDescriptionHelpFormatt 20 from argparse import RawDescriptionHelpFormatter 21 from argparse import RawTextHelpFormatter 21 from argparse import RawTextHelpFormatter 22 from enum import Enum 22 from enum import Enum 23 23 24 # Do not change unless, you change the debugfs 24 # Do not change unless, you change the debugfs attributes 25 # in /drivers/hv/debugfs.c. All fuzz testing 25 # in /drivers/hv/debugfs.c. All fuzz testing 26 # attributes will start with "fuzz_test". 26 # attributes will start with "fuzz_test". 27 27 28 # debugfs path for hyperv must exist before pr 28 # debugfs path for hyperv must exist before proceeding 29 debugfs_hyperv_path = "/sys/kernel/debug/hyper 29 debugfs_hyperv_path = "/sys/kernel/debug/hyperv" 30 if not os.path.isdir(debugfs_hyperv_path): 30 if not os.path.isdir(debugfs_hyperv_path): 31 print("{} doesn't exist/check permissi 31 print("{} doesn't exist/check permissions".format(debugfs_hyperv_path)) 32 exit(-1) 32 exit(-1) 33 33 34 class dev_state(Enum): 34 class dev_state(Enum): 35 off = 0 35 off = 0 36 on = 1 36 on = 1 37 37 38 # File names, that correspond to the files cre 38 # File names, that correspond to the files created in 39 # /drivers/hv/debugfs.c 39 # /drivers/hv/debugfs.c 40 class f_names(Enum): 40 class f_names(Enum): 41 state_f = "fuzz_test_state" 41 state_f = "fuzz_test_state" 42 buff_f = "fuzz_test_buffer_interrupt_ 42 buff_f = "fuzz_test_buffer_interrupt_delay" 43 mess_f = "fuzz_test_message_delay" 43 mess_f = "fuzz_test_message_delay" 44 44 45 # Both single_actions and all_actions are used 45 # Both single_actions and all_actions are used 46 # for error checking and to allow for some sub 46 # for error checking and to allow for some subparser 47 # names to be abbreviated. Do not abbreviate t 47 # names to be abbreviated. Do not abbreviate the 48 # test method names, as it will become less in 48 # test method names, as it will become less intuitive 49 # as to what the user can do. If you do decide 49 # as to what the user can do. If you do decide to 50 # abbreviate the test method name, make sure t 50 # abbreviate the test method name, make sure the main 51 # function reflects this change. 51 # function reflects this change. 52 52 53 all_actions = [ 53 all_actions = [ 54 "disable_all", 54 "disable_all", 55 "D", 55 "D", 56 "enable_all", 56 "enable_all", 57 "view_all", 57 "view_all", 58 "V" 58 "V" 59 ] 59 ] 60 60 61 single_actions = [ 61 single_actions = [ 62 "disable_single", 62 "disable_single", 63 "d", 63 "d", 64 "enable_single", 64 "enable_single", 65 "view_single", 65 "view_single", 66 "v" 66 "v" 67 ] 67 ] 68 68 69 def main(): 69 def main(): 70 70 71 file_map = recursive_file_lookup(debug 71 file_map = recursive_file_lookup(debugfs_hyperv_path, dict()) 72 args = parse_args() 72 args = parse_args() 73 if (not args.action): 73 if (not args.action): 74 print ("Error, no options sele 74 print ("Error, no options selected...exiting") 75 exit(-1) 75 exit(-1) 76 arg_set = { k for (k,v) in vars(args). 76 arg_set = { k for (k,v) in vars(args).items() if v and k != "action" } 77 arg_set.add(args.action) 77 arg_set.add(args.action) 78 path = args.path if "path" in arg_set 78 path = args.path if "path" in arg_set else None 79 if (path and path[-1] == "/"): 79 if (path and path[-1] == "/"): 80 path = path[:-1] 80 path = path[:-1] 81 validate_args_path(path, arg_set, file 81 validate_args_path(path, arg_set, file_map) 82 if (path and "enable_single" in arg_se 82 if (path and "enable_single" in arg_set): 83 state_path = locate_state(path, fi 83 state_path = locate_state(path, file_map) 84 set_test_state(state_path, dev_sta 84 set_test_state(state_path, dev_state.on.value, args.quiet) 85 85 86 # Use subparsers as the key for differ 86 # Use subparsers as the key for different actions 87 if ("delay" in arg_set): 87 if ("delay" in arg_set): 88 validate_delay_values(args.del 88 validate_delay_values(args.delay_time) 89 if (args.enable_all): 89 if (args.enable_all): 90 set_delay_all_devices( 90 set_delay_all_devices(file_map, args.delay_time, 91 91 args.quiet) 92 else: 92 else: 93 set_delay_values(path, 93 set_delay_values(path, file_map, args.delay_time, 94 args. 94 args.quiet) 95 elif ("disable_all" in arg_set or "D" 95 elif ("disable_all" in arg_set or "D" in arg_set): 96 disable_all_testing(file_map) 96 disable_all_testing(file_map) 97 elif ("disable_single" in arg_set or " 97 elif ("disable_single" in arg_set or "d" in arg_set): 98 disable_testing_single_device( 98 disable_testing_single_device(path, file_map) 99 elif ("view_all" in arg_set or "V" in 99 elif ("view_all" in arg_set or "V" in arg_set): 100 get_all_devices_test_status(fi 100 get_all_devices_test_status(file_map) 101 elif ("view_single" in arg_set or "v" 101 elif ("view_single" in arg_set or "v" in arg_set): 102 get_device_test_values(path, f 102 get_device_test_values(path, file_map) 103 103 104 # Get the state location 104 # Get the state location 105 def locate_state(device, file_map): 105 def locate_state(device, file_map): 106 return file_map[device][f_names.state_ 106 return file_map[device][f_names.state_f.value] 107 107 108 # Validate delay values to make sure they are 108 # Validate delay values to make sure they are acceptable to 109 # enable delays on a device 109 # enable delays on a device 110 def validate_delay_values(delay): 110 def validate_delay_values(delay): 111 111 112 if (delay[0] == -1 and delay[1] == -1 112 if (delay[0] == -1 and delay[1] == -1): 113 print("\nError, At least 1 val 113 print("\nError, At least 1 value must be greater than 0") 114 exit(-1) 114 exit(-1) 115 for i in delay: 115 for i in delay: 116 if (i < -1 or i == 0 or i > 10 116 if (i < -1 or i == 0 or i > 1000): 117 print("\nError, Values 117 print("\nError, Values must be equal to -1 " 118 "or be > 0 and < 118 "or be > 0 and <= 1000") 119 exit(-1) 119 exit(-1) 120 120 121 # Validate argument path 121 # Validate argument path 122 def validate_args_path(path, arg_set, file_map 122 def validate_args_path(path, arg_set, file_map): 123 123 124 if (not path and any(element in arg_se 124 if (not path and any(element in arg_set for element in single_actions)): 125 print("Error, path (-p) REQUIR 125 print("Error, path (-p) REQUIRED for the specified option. " 126 "Use (-h) to check usage 126 "Use (-h) to check usage.") 127 exit(-1) 127 exit(-1) 128 elif (path and any(item in arg_set for 128 elif (path and any(item in arg_set for item in all_actions)): 129 print("Error, path (-p) NOT RE 129 print("Error, path (-p) NOT REQUIRED for the specified option. " 130 "Use (-h) to check usage 130 "Use (-h) to check usage." ) 131 exit(-1) 131 exit(-1) 132 elif (path not in file_map and any(ite 132 elif (path not in file_map and any(item in arg_set 133 for 133 for item in single_actions)): 134 print("Error, path '{}' not a 134 print("Error, path '{}' not a valid vmbus device".format(path)) 135 exit(-1) 135 exit(-1) 136 136 137 # display Testing status of single device 137 # display Testing status of single device 138 def get_device_test_values(path, file_map): 138 def get_device_test_values(path, file_map): 139 139 140 for name in file_map[path]: 140 for name in file_map[path]: 141 file_location = file_map[path] 141 file_location = file_map[path][name] 142 print( name + " = " + str(read 142 print( name + " = " + str(read_test_files(file_location))) 143 143 144 # Create a map of the vmbus devices and their 144 # Create a map of the vmbus devices and their associated files 145 # [key=device, value = [key = filename, value 145 # [key=device, value = [key = filename, value = file path]] 146 def recursive_file_lookup(path, file_map): 146 def recursive_file_lookup(path, file_map): 147 147 148 for f_path in glob.iglob(path + '**/*' 148 for f_path in glob.iglob(path + '**/*'): 149 if (os.path.isfile(f_path)): 149 if (os.path.isfile(f_path)): 150 if (f_path.rsplit("/", 150 if (f_path.rsplit("/",2)[0] == debugfs_hyperv_path): 151 directory = f_ 151 directory = f_path.rsplit("/",1)[0] 152 else: 152 else: 153 directory = f_ 153 directory = f_path.rsplit("/",2)[0] 154 f_name = f_path.split( 154 f_name = f_path.split("/")[-1] 155 if (file_map.get(direc 155 if (file_map.get(directory)): 156 file_map[direc 156 file_map[directory].update({f_name:f_path}) 157 else: 157 else: 158 file_map[direc 158 file_map[directory] = {f_name:f_path} 159 elif (os.path.isdir(f_path)): 159 elif (os.path.isdir(f_path)): 160 recursive_file_lookup( 160 recursive_file_lookup(f_path,file_map) 161 return file_map 161 return file_map 162 162 163 # display Testing state of devices 163 # display Testing state of devices 164 def get_all_devices_test_status(file_map): 164 def get_all_devices_test_status(file_map): 165 165 166 for device in file_map: 166 for device in file_map: 167 if (get_test_state(locate_stat !! 167 if (get_test_state(locate_state(device, file_map)) is 1): 168 print("Testing = ON fo 168 print("Testing = ON for: {}" 169 .format(device.s 169 .format(device.split("/")[5])) 170 else: 170 else: 171 print("Testing = OFF f 171 print("Testing = OFF for: {}" 172 .format(device.s 172 .format(device.split("/")[5])) 173 173 174 # read the vmbus device files, path must be ab 174 # read the vmbus device files, path must be absolute path before calling 175 def read_test_files(path): 175 def read_test_files(path): 176 try: 176 try: 177 with open(path,"r") as f: 177 with open(path,"r") as f: 178 file_value = f.readlin 178 file_value = f.readline().strip() 179 return int(file_value) 179 return int(file_value) 180 180 181 except IOError as e: 181 except IOError as e: 182 errno, strerror = e.args 182 errno, strerror = e.args 183 print("I/O error({0}): {1} on 183 print("I/O error({0}): {1} on file {2}" 184 .format(errno, strerror, 184 .format(errno, strerror, path)) 185 exit(-1) 185 exit(-1) 186 except ValueError: 186 except ValueError: 187 print ("Element to int convers 187 print ("Element to int conversion error in: \n{}".format(path)) 188 exit(-1) 188 exit(-1) 189 189 190 # writing to vmbus device files, path must be 190 # writing to vmbus device files, path must be absolute path before calling 191 def write_test_files(path, value): 191 def write_test_files(path, value): 192 192 193 try: 193 try: 194 with open(path,"w") as f: 194 with open(path,"w") as f: 195 f.write("{}".format(va 195 f.write("{}".format(value)) 196 except IOError as e: 196 except IOError as e: 197 errno, strerror = e.args 197 errno, strerror = e.args 198 print("I/O error({0}): {1} on 198 print("I/O error({0}): {1} on file {2}" 199 .format(errno, strerror, 199 .format(errno, strerror, path)) 200 exit(-1) 200 exit(-1) 201 201 202 # set testing state of device 202 # set testing state of device 203 def set_test_state(state_path, state_value, qu 203 def set_test_state(state_path, state_value, quiet): 204 204 205 write_test_files(state_path, state_val 205 write_test_files(state_path, state_value) 206 if (get_test_state(state_path) == 1): !! 206 if (get_test_state(state_path) is 1): 207 if (not quiet): 207 if (not quiet): 208 print("Testing = ON fo 208 print("Testing = ON for device: {}" 209 .format(state_pa 209 .format(state_path.split("/")[5])) 210 else: 210 else: 211 if (not quiet): 211 if (not quiet): 212 print("Testing = OFF f 212 print("Testing = OFF for device: {}" 213 .format(state_pa 213 .format(state_path.split("/")[5])) 214 214 215 # get testing state of device 215 # get testing state of device 216 def get_test_state(state_path): 216 def get_test_state(state_path): 217 #state == 1 - test = ON 217 #state == 1 - test = ON 218 #state == 0 - test = OFF 218 #state == 0 - test = OFF 219 return read_test_files(state_path) 219 return read_test_files(state_path) 220 220 221 # write 1 - 1000 microseconds, into a single d 221 # write 1 - 1000 microseconds, into a single device using the 222 # fuzz_test_buffer_interrupt_delay and fuzz_te 222 # fuzz_test_buffer_interrupt_delay and fuzz_test_message_delay 223 # debugfs attributes 223 # debugfs attributes 224 def set_delay_values(device, file_map, delay_l 224 def set_delay_values(device, file_map, delay_length, quiet): 225 225 226 try: 226 try: 227 interrupt = file_map[device][f 227 interrupt = file_map[device][f_names.buff_f.value] 228 message = file_map[device][f_n 228 message = file_map[device][f_names.mess_f.value] 229 229 230 # delay[0]- buffer interrupt d 230 # delay[0]- buffer interrupt delay, delay[1]- message delay 231 if (delay_length[0] >= 0 and d 231 if (delay_length[0] >= 0 and delay_length[0] <= 1000): 232 write_test_files(inter 232 write_test_files(interrupt, delay_length[0]) 233 if (delay_length[1] >= 0 and d 233 if (delay_length[1] >= 0 and delay_length[1] <= 1000): 234 write_test_files(messa 234 write_test_files(message, delay_length[1]) 235 if (not quiet): 235 if (not quiet): 236 print("Buffer delay te 236 print("Buffer delay testing = {} for: {}" 237 .format(read_tes 237 .format(read_test_files(interrupt), 238 interrup 238 interrupt.split("/")[5])) 239 print("Message delay t 239 print("Message delay testing = {} for: {}" 240 .format(read_tes 240 .format(read_test_files(message), 241 message. 241 message.split("/")[5])) 242 except IOError as e: 242 except IOError as e: 243 errno, strerror = e.args 243 errno, strerror = e.args 244 print("I/O error({0}): {1} on 244 print("I/O error({0}): {1} on files {2}{3}" 245 .format(errno, strerror, 245 .format(errno, strerror, interrupt, message)) 246 exit(-1) 246 exit(-1) 247 247 248 # enabling delay testing on all devices 248 # enabling delay testing on all devices 249 def set_delay_all_devices(file_map, delay, qui 249 def set_delay_all_devices(file_map, delay, quiet): 250 250 251 for device in (file_map): 251 for device in (file_map): 252 set_test_state(locate_state(de 252 set_test_state(locate_state(device, file_map), 253 dev_state.on.va 253 dev_state.on.value, 254 quiet) 254 quiet) 255 set_delay_values(device, file_ 255 set_delay_values(device, file_map, delay, quiet) 256 256 257 # disable all testing on a SINGLE device. 257 # disable all testing on a SINGLE device. 258 def disable_testing_single_device(device, file 258 def disable_testing_single_device(device, file_map): 259 259 260 for name in file_map[device]: 260 for name in file_map[device]: 261 file_location = file_map[devic 261 file_location = file_map[device][name] 262 write_test_files(file_location 262 write_test_files(file_location, dev_state.off.value) 263 print("ALL testing now OFF for {}".for 263 print("ALL testing now OFF for {}".format(device.split("/")[-1])) 264 264 265 # disable all testing on ALL devices 265 # disable all testing on ALL devices 266 def disable_all_testing(file_map): 266 def disable_all_testing(file_map): 267 267 268 for device in file_map: 268 for device in file_map: 269 disable_testing_single_device( 269 disable_testing_single_device(device, file_map) 270 270 271 def parse_args(): 271 def parse_args(): 272 parser = argparse.ArgumentParser(prog 272 parser = argparse.ArgumentParser(prog = "vmbus_testing",usage ="\n" 273 "%(prog)s [delay] [-h] [-e|- 273 "%(prog)s [delay] [-h] [-e|-E] -t [-p]\n" 274 "%(prog)s [view_all | V] 274 "%(prog)s [view_all | V] [-h]\n" 275 "%(prog)s [disable_all | D] 275 "%(prog)s [disable_all | D] [-h]\n" 276 "%(prog)s [disable_single | d] 276 "%(prog)s [disable_single | d] [-h|-p]\n" 277 "%(prog)s [view_single | v] 277 "%(prog)s [view_single | v] [-h|-p]\n" 278 "%(prog)s --version\n", 278 "%(prog)s --version\n", 279 description = "\nUse lsvmbus t 279 description = "\nUse lsvmbus to get vmbus device type " 280 "information.\n" "\nThe debugf 280 "information.\n" "\nThe debugfs root path is " 281 "/sys/kernel/debug/hyperv", 281 "/sys/kernel/debug/hyperv", 282 formatter_class = RawDescripti 282 formatter_class = RawDescriptionHelpFormatter) 283 subparsers = parser.add_subparsers(des 283 subparsers = parser.add_subparsers(dest = "action") 284 parser.add_argument("--version", actio 284 parser.add_argument("--version", action = "version", 285 version = '%(prog)s 0.1.0') 285 version = '%(prog)s 0.1.0') 286 parser.add_argument("-q","--quiet", ac 286 parser.add_argument("-q","--quiet", action = "store_true", 287 help = "silence none important 287 help = "silence none important test messages." 288 " This will only work w 288 " This will only work when enabling testing" 289 " on a device.") 289 " on a device.") 290 # Use the path parser to hold the --pa 290 # Use the path parser to hold the --path attribute so it can 291 # be shared between subparsers. Also d 291 # be shared between subparsers. Also do the same for the state 292 # parser, as all testing methods will 292 # parser, as all testing methods will use --enable_all and 293 # enable_single. 293 # enable_single. 294 path_parser = argparse.ArgumentParser( 294 path_parser = argparse.ArgumentParser(add_help=False) 295 path_parser.add_argument("-p","--path" 295 path_parser.add_argument("-p","--path", metavar = "", 296 help = "Debugfs path to a vmbu 296 help = "Debugfs path to a vmbus device. The path " 297 "must be the absolute path to 297 "must be the absolute path to the device.") 298 state_parser = argparse.ArgumentParser 298 state_parser = argparse.ArgumentParser(add_help=False) 299 state_group = state_parser.add_mutuall 299 state_group = state_parser.add_mutually_exclusive_group(required = True) 300 state_group.add_argument("-E", "--enab 300 state_group.add_argument("-E", "--enable_all", action = "store_const", 301 const = "enab 301 const = "enable_all", 302 help = "Enabl 302 help = "Enable the specified test type " 303 "on ALL vmbus 303 "on ALL vmbus devices.") 304 state_group.add_argument("-e", "--enab 304 state_group.add_argument("-e", "--enable_single", 305 action = "sto 305 action = "store_const", 306 const = "enab 306 const = "enable_single", 307 help = "Enabl 307 help = "Enable the specified test type on a " 308 "SINGLE vmbus 308 "SINGLE vmbus device.") 309 parser_delay = subparsers.add_parser(" 309 parser_delay = subparsers.add_parser("delay", 310 parents = [state_parse 310 parents = [state_parser, path_parser], 311 help = "Delay the ring 311 help = "Delay the ring buffer interrupt or the " 312 "ring buffer message r 312 "ring buffer message reads in microseconds.", 313 prog = "vmbus_testing" 313 prog = "vmbus_testing", 314 usage = "%(prog)s [-h] 314 usage = "%(prog)s [-h]\n" 315 "%(prog)s -E -t [value 315 "%(prog)s -E -t [value] [value]\n" 316 "%(prog)s -e -t [value 316 "%(prog)s -e -t [value] [value] -p", 317 description = "Delay t 317 description = "Delay the ring buffer interrupt for " 318 "vmbus devices, or del 318 "vmbus devices, or delay the ring buffer message " 319 "reads for vmbus devic 319 "reads for vmbus devices (both in microseconds). This " 320 "is only on the host t 320 "is only on the host to guest channel.") 321 parser_delay.add_argument("-t", "--del 321 parser_delay.add_argument("-t", "--delay_time", metavar = "", nargs = 2, 322 type = check_range, de 322 type = check_range, default =[0,0], required = (True), 323 help = "Set [buffer] & 323 help = "Set [buffer] & [message] delay time. " 324 "Value constraints: -1 324 "Value constraints: -1 == value " 325 "or 0 < value <= 1000. 325 "or 0 < value <= 1000.\n" 326 "Use -1 to keep the pr 326 "Use -1 to keep the previous value for that delay " 327 "type, or a value > 0 327 "type, or a value > 0 <= 1000 to change the delay " 328 "time.") 328 "time.") 329 parser_dis_all = subparsers.add_parser 329 parser_dis_all = subparsers.add_parser("disable_all", 330 aliases = ['D'], prog 330 aliases = ['D'], prog = "vmbus_testing", 331 usage = "%(prog)s [dis 331 usage = "%(prog)s [disable_all | D] -h\n" 332 "%(prog)s [disable_all 332 "%(prog)s [disable_all | D]\n", 333 help = "Disable ALL te 333 help = "Disable ALL testing on ALL vmbus devices.", 334 description = "Disable 334 description = "Disable ALL testing on ALL vmbus " 335 "devices.") 335 "devices.") 336 parser_dis_single = subparsers.add_par 336 parser_dis_single = subparsers.add_parser("disable_single", 337 aliases = ['d'], 337 aliases = ['d'], 338 parents = [path_parser 338 parents = [path_parser], prog = "vmbus_testing", 339 usage = "%(prog)s [dis 339 usage = "%(prog)s [disable_single | d] -h\n" 340 "%(prog)s [disable_sin 340 "%(prog)s [disable_single | d] -p\n", 341 help = "Disable ALL te 341 help = "Disable ALL testing on a SINGLE vmbus device.", 342 description = "Disable 342 description = "Disable ALL testing on a SINGLE vmbus " 343 "device.") 343 "device.") 344 parser_view_all = subparsers.add_parse 344 parser_view_all = subparsers.add_parser("view_all", aliases = ['V'], 345 help = "View the test 345 help = "View the test state for ALL vmbus devices.", 346 prog = "vmbus_testing" 346 prog = "vmbus_testing", 347 usage = "%(prog)s [vie 347 usage = "%(prog)s [view_all | V] -h\n" 348 "%(prog)s [view_all | 348 "%(prog)s [view_all | V]\n", 349 description = "This sh 349 description = "This shows the test state for ALL the " 350 "vmbus devices.") 350 "vmbus devices.") 351 parser_view_single = subparsers.add_pa 351 parser_view_single = subparsers.add_parser("view_single", 352 aliases = ['v'],parent 352 aliases = ['v'],parents = [path_parser], 353 help = "View the test 353 help = "View the test values for a SINGLE vmbus " 354 "device.", 354 "device.", 355 description = "This sh 355 description = "This shows the test values for a SINGLE " 356 "vmbus device.", prog 356 "vmbus device.", prog = "vmbus_testing", 357 usage = "%(prog)s [vie 357 usage = "%(prog)s [view_single | v] -h\n" 358 "%(prog)s [view_single 358 "%(prog)s [view_single | v] -p") 359 359 360 return parser.parse_args() 360 return parser.parse_args() 361 361 362 # value checking for range checking input in p 362 # value checking for range checking input in parser 363 def check_range(arg1): 363 def check_range(arg1): 364 364 365 try: 365 try: 366 val = int(arg1) 366 val = int(arg1) 367 except ValueError as err: 367 except ValueError as err: 368 raise argparse.ArgumentTypeErr 368 raise argparse.ArgumentTypeError(str(err)) 369 if val < -1 or val > 1000: 369 if val < -1 or val > 1000: 370 message = ("\n\nvalue must be 370 message = ("\n\nvalue must be -1 or 0 < value <= 1000. " 371 "Value program rece 371 "Value program received: {}\n").format(val) 372 raise argparse.ArgumentTypeErr 372 raise argparse.ArgumentTypeError(message) 373 return val 373 return val 374 374 375 if __name__ == "__main__": 375 if __name__ == "__main__": 376 main() 376 main()
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.