diff options
Diffstat (limited to 'lib/snmp/src')
-rw-r--r-- | lib/snmp/src/agent/snmp_generic.erl | 30 | ||||
-rw-r--r-- | lib/snmp/src/agent/snmpa_conf.erl | 16 | ||||
-rw-r--r-- | lib/snmp/src/app/snmp.app.src | 14 | ||||
-rw-r--r-- | lib/snmp/src/app/snmp.erl | 80 | ||||
-rw-r--r-- | lib/snmp/src/compile/snmpc.erl | 114 | ||||
-rw-r--r-- | lib/snmp/src/compile/snmpc_lib.erl | 43 | ||||
-rw-r--r-- | lib/snmp/src/compile/snmpc_mib_gram.yrl | 6 | ||||
-rw-r--r-- | lib/snmp/src/compile/snmpc_misc.erl | 20 | ||||
-rw-r--r-- | lib/snmp/src/manager/snmpm_net_if.erl | 4 |
9 files changed, 215 insertions, 112 deletions
diff --git a/lib/snmp/src/agent/snmp_generic.erl b/lib/snmp/src/agent/snmp_generic.erl index fc23e16ef1..e67a1b3c80 100644 --- a/lib/snmp/src/agent/snmp_generic.erl +++ b/lib/snmp/src/agent/snmp_generic.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -413,20 +413,21 @@ table_check_status(NameDb, Col, ?'RowStatus_createAndGo', RowIndex, Cols) -> false -> % it's ok to use snmpa_local_db:table_construct_row since it's % side effect free and we only use the result temporary. - case catch snmpa_local_db:table_construct_row( + try snmpa_local_db:table_construct_row( NameDb, RowIndex, ?'RowStatus_createAndGo', Cols) of - {'EXIT', _Reason} -> - ?vtrace( - "failed construct row (createAndGo): " - " n Reason: ~p" - " n Stack: ~p", - [_Reason, erlang:get_stacktrace()]), - {noCreation, Col}; % Bad RowIndex Row -> case lists:member(noinit, tuple_to_list(Row)) of false -> {noError, 0}; _Found -> {inconsistentValue, Col} end + catch + _:_Reason -> + ?vtrace( + "failed construct row (createAndGo): " + " n Reason: ~p" + " n Stack: ~p", + [_Reason, erlang:get_stacktrace()]), + {noCreation, Col} % Bad RowIndex end; true -> {inconsistentValue, Col} end; @@ -435,17 +436,18 @@ table_check_status(NameDb, Col, ?'RowStatus_createAndGo', RowIndex, Cols) -> table_check_status(NameDb, Col, ?'RowStatus_createAndWait', RowIndex, Cols) -> case table_row_exists(NameDb, RowIndex) of false -> - case catch snmpa_local_db:table_construct_row( + try snmpa_local_db:table_construct_row( NameDb, RowIndex, ?'RowStatus_createAndGo', Cols) of - {'EXIT', _Reason} -> + _Row -> + {noError, 0} + catch + _:_Reason -> ?vtrace( "failed construct row (createAndWait): " " n Reason: ~p" " n Stack: ~p", [_Reason, erlang:get_stacktrace()]), - {noCreation, Col}; % Bad RowIndex - _Row -> - {noError, 0} + {noCreation, Col} % Bad RowIndex end; true -> {inconsistentValue, Col} end; diff --git a/lib/snmp/src/agent/snmpa_conf.erl b/lib/snmp/src/agent/snmpa_conf.erl index 94325a8ed6..fc5116dac9 100644 --- a/lib/snmp/src/agent/snmpa_conf.erl +++ b/lib/snmp/src/agent/snmpa_conf.erl @@ -154,7 +154,7 @@ do_write_agent_conf(Fd, {intAgentMaxPacketSize = Tag, Val} ) -> do_write_agent_conf(Fd, {snmpEngineMaxMessageSize = Tag, Val} ) -> io:format(Fd, "{~w, ~w}.~n", [Tag, Val]); do_write_agent_conf(Fd, {snmpEngineID = Tag, Val} ) -> - io:format(Fd, "{~w, \"~s\"}.~n", [Tag, Val]); + io:format(Fd, "{~w, ~p}.~n", [Tag, Val]); do_write_agent_conf(_Fd, Crap) -> error({bad_agent_config, Crap}). @@ -758,9 +758,9 @@ do_write_usm_conf( PrivP, PrivKeyC, OwnPrivKeyC, Public, AuthKey, PrivKey}) -> io:format(Fd, "{", []), - io:format(Fd, "\"~s\", ", [EngineID]), - io:format(Fd, "\"~s\", ", [UserName]), - io:format(Fd, "\"~s\", ", [SecName]), + io:format(Fd, "~p, ", [EngineID]), + io:format(Fd, "~p, ", [UserName]), + io:format(Fd, "~p, ", [SecName]), io:format(Fd, "~w, ", [Clone]), io:format(Fd, "~w, ", [AuthP]), do_write_usm2(Fd, AuthKeyC, ", "), @@ -859,15 +859,15 @@ do_write_vacm_conf( {vacmSecurityToGroup, SecModel, SecName, GroupName}) -> io:format( - Fd, "{vacmSecurityToGroup, ~w, \"~s\", \"~s\"}.~n", + Fd, "{vacmSecurityToGroup, ~w, ~p, ~p}.~n", [SecModel, SecName, GroupName]); do_write_vacm_conf( Fd, {vacmAccess, GroupName, Prefix, SecModel, SecLevel, Match, RV, WV, NV}) -> io:format( - Fd, "{vacmAccess, \"~s\", \"~s\", ~w, ~w, ~w, " - "\"~s\", \"~s\", \"~s\"}.~n", + Fd, "{vacmAccess, ~p, ~p, ~w, ~w, ~w, " + "~p, ~p, ~p}.~n", [GroupName, Prefix, SecModel, SecLevel, Match, RV, WV, NV]); do_write_vacm_conf( @@ -875,7 +875,7 @@ do_write_vacm_conf( {vacmViewTreeFamily, ViewIndex, ViewSubtree, ViewStatus, ViewMask}) -> io:format( - Fd, "{vacmViewTreeFamily, \"~s\", ~w, ~w, ~w}.~n", + Fd, "{vacmViewTreeFamily, ~p, ~w, ~w, ~w}.~n", [ViewIndex, ViewSubtree, ViewStatus, ViewMask]); do_write_vacm_conf(_Fd, Crap) -> error({bad_vacm_config, Crap}). diff --git a/lib/snmp/src/app/snmp.app.src b/lib/snmp/src/app/snmp.app.src index b593e9ea84..d4bf0de61a 100644 --- a/lib/snmp/src/app/snmp.app.src +++ b/lib/snmp/src/app/snmp.app.src @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2015. All Rights Reserved. +%% Copyright Ericsson AB 1996-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -23,12 +23,12 @@ {vsn, "%VSN%"}, {modules, [ %% Compiler modules (not in the runtime part of the app) -% snmpc, -% snmpc_lib, -% snmpc_mib_gram, -% snmpc_mib_to_hrl, -% snmpc_misc, -% snmpc_tok, + snmpc, + snmpc_lib, + snmpc_mib_gram, + snmpc_mib_to_hrl, + snmpc_misc, + snmpc_tok, %% Application modules snmp, diff --git a/lib/snmp/src/app/snmp.erl b/lib/snmp/src/app/snmp.erl index df3933ea01..8a736f688b 100644 --- a/lib/snmp/src/app/snmp.erl +++ b/lib/snmp/src/app/snmp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -573,9 +573,16 @@ print_mod_info(Prefix, {Module, Info}) -> CompDate = case key1search(compile_time, Info) of {value, {Year, Month, Day, Hour, Min, Sec}} -> - lists:flatten( - io_lib:format("~w-~2..0w-~2..0w ~2..0w:~2..0w:~2..0w", - [Year, Month, Day, Hour, Min, Sec])); + io_lib:format( + "~w-~2..0w-~2..0w ~2..0w:~2..0w:~2..0w", + [Year, Month, Day, Hour, Min, Sec]); + _ -> + "Not found" + end, + Digest = + case key1search(md5, Info) of + {value, MD5} when is_binary(MD5) -> + [io_lib:format("~2.16.0b", [Byte]) || <<Byte>> <= MD5]; _ -> "Not found" end, @@ -583,12 +590,14 @@ print_mod_info(Prefix, {Module, Info}) -> "~s Vsn: ~s~n" "~s App vsn: ~s~n" "~s Compiler ver: ~s~n" - "~s Compile time: ~s~n", + "~s Compile time: ~s~n" + "~s MD5 digest: ~s~n", [Prefix, Module, Prefix, Vsn, Prefix, AppVsn, - Prefix, CompVer, - Prefix, CompDate]), + Prefix, CompVer, + Prefix, CompDate, + Prefix, Digest]), ok. key1search(Key, Vals) -> @@ -617,7 +626,7 @@ versions1() -> Error -> Error end. - + versions2() -> case ms2() of {ok, Mods} -> @@ -625,25 +634,56 @@ versions2() -> Error -> Error end. - + version_info(Mods) -> SysInfo = sys_info(), OsInfo = os_info(), ModInfo = [mod_version_info(Mod) || Mod <- Mods], [{sys_info, SysInfo}, {os_info, OsInfo}, {mod_info, ModInfo}]. - + mod_version_info(Mod) -> Info = Mod:module_info(), - {value, {attributes, Attr}} = lists:keysearch(attributes, 1, Info), - {value, {vsn, [Vsn]}} = lists:keysearch(vsn, 1, Attr), - {value, {app_vsn, AppVsn}} = lists:keysearch(app_vsn, 1, Attr), - {value, {compile, Comp}} = lists:keysearch(compile, 1, Info), - {value, {version, Ver}} = lists:keysearch(version, 1, Comp), - {value, {time, Time}} = lists:keysearch(time, 1, Comp), - {Mod, [{vsn, Vsn}, - {app_vsn, AppVsn}, - {compiler_version, Ver}, - {compile_time, Time}]}. + {Mod, + case key1search(attributes, Info) of + {value, Attr} -> + case key1search(vsn, Attr) of + {value, [Vsn]} -> + [{vsn, Vsn}]; + not_found -> + [] + end ++ + case key1search(app_vsn, Attr) of + {value, AppVsn} -> + [{app_vsn, AppVsn}]; + not_found -> + [] + end; + not_found -> + [] + end ++ + case key1search(compile, Info) of + {value, Comp} -> + case key1search(version, Comp) of + {value, Ver} -> + [{compiler_version, Ver}]; + not_found -> + [] + end ++ + case key1search(time, Comp) of + {value, Ver} -> + [{compile_time, Ver}]; + not_found -> + [] + end; + not_found -> + [] + end ++ + case key1search(md5, Info) of + {value, Bin} -> + [{md5, Bin}]; + not_found -> + [] + end}. sys_info() -> SysArch = string:strip(erlang:system_info(system_architecture),right,$\n), diff --git a/lib/snmp/src/compile/snmpc.erl b/lib/snmp/src/compile/snmpc.erl index db1f9ee61b..7f627d66d9 100644 --- a/lib/snmp/src/compile/snmpc.erl +++ b/lib/snmp/src/compile/snmpc.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2015. All Rights Reserved. +%% Copyright Ericsson AB 1997-2018. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -64,7 +64,7 @@ compile(Input, _Output, Options) -> {ok, _} -> ok; {error, Reason} -> - io:format("~p", [Reason]), + io:format("~tp", [Reason]), error end. @@ -126,7 +126,14 @@ compile(FileName) -> %%---------------------------------------------------------------------- compile(FileName, Options) when is_list(FileName) -> - true = snmpc_misc:is_string(FileName), + case snmpc_misc:check_file(FileName) of + true -> + compile_1(FileName, Options); + false -> + {error, {invalid_file, FileName}} + end. + +compile_1(FileName, Options) -> DefOpts = [{deprecated, true}, {group_check, true}, {i, ["./"]}, @@ -448,7 +455,9 @@ compile_parsed_data(#pdata{mib_name = MibName, Deprecated = get_deprecated(Opts), RelChk = get_relaxed_row_name_assign_check(Opts), Data = #dldata{deprecated = Deprecated, - relaxed_row_name_assign_check = RelChk}, + relaxed_row_name_assign_check = RelChk}, + mc_new_type_loop(Definitions), + put(augmentations, false), definitions_loop(Definitions, Data), MibName. @@ -473,7 +482,40 @@ do_update_imports([{{Mib, ImportsFromMib0},_Line}|Imports], Acc) -> update_status(Name, Status) -> #cdata{status_ets = Ets} = get(cdata), ets:insert(Ets, {Name, Status}). - + + +mc_new_type_loop( + [{#mc_new_type{ + name = NewTypeName, + macro = Macro, + syntax = OldType, + display_hint = DisplayHint},Line}|T]) -> + ?vlog2("typeloop -> new_type:" + "~n Macro: ~p" + "~n NewTypeName: ~p" + "~n OldType: ~p" + "~n DisplayHint: ~p", + [Macro, NewTypeName, OldType, DisplayHint], Line), + ensure_macro_imported(Macro,Line), + Types = (get(cdata))#cdata.asn1_types, + case lists:keysearch(NewTypeName, #asn1_type.aliasname, Types) of + {value,_} -> + snmpc_lib:print_error("Type ~w already defined.", + [NewTypeName],Line); + false -> + %% NameOfOldType = element(2,OldType), + ASN1 = snmpc_lib:make_ASN1type(OldType), + snmpc_lib:add_cdata(#cdata.asn1_types, + [ASN1#asn1_type{aliasname = NewTypeName, + imported = false, + display_hint = DisplayHint}]) + end, + mc_new_type_loop(T); +mc_new_type_loop([_|T]) -> + mc_new_type_loop(T); +mc_new_type_loop([]) -> + ok. + %% A deprecated object definitions_loop([{#mc_object_type{name = ObjName, status = deprecated}, @@ -737,32 +779,8 @@ definitions_loop([{#mc_object_type{name = NameOfTable, ColMEs]), definitions_loop(RestObjs, Data); -definitions_loop([{#mc_new_type{name = NewTypeName, - macro = Macro, - syntax = OldType, - display_hint = DisplayHint},Line}|T], - Data) -> - ?vlog2("defloop -> new_type:" - "~n Macro: ~p" - "~n NewTypeName: ~p" - "~n OldType: ~p" - "~n DisplayHint: ~p", - [Macro, NewTypeName, OldType, DisplayHint], Line), - ensure_macro_imported(Macro,Line), - Types = (get(cdata))#cdata.asn1_types, - case lists:keysearch(NewTypeName, #asn1_type.aliasname, Types) of - {value,_} -> - snmpc_lib:print_error("Type ~w already defined.", - [NewTypeName],Line); - false -> - %% NameOfOldType = element(2,OldType), - ASN1 = snmpc_lib:make_ASN1type(OldType), - snmpc_lib:add_cdata(#cdata.asn1_types, - [ASN1#asn1_type{aliasname = NewTypeName, - imported = false, - display_hint = DisplayHint}]) - end, - definitions_loop(T, Data); +definitions_loop([{#mc_new_type{},_}|T], Data) -> + definitions_loop(T, Data); %% Plain variable definitions_loop([{#mc_object_type{name = NewVarName, @@ -1204,7 +1222,39 @@ definitions_loop([{Obj,Line}|T], Data) -> definitions_loop([], _Data) -> ?vlog("defloop -> done", []), - ok. + case get(augmentations) of + true -> + CData = get(cdata), + put(cdata, CData#cdata{mes = augmentations(CData#cdata.mes)}), + ok; + false -> + ok + end. + +augmentations( + [#me{ + aliasname = AliasName, + assocList = + [{table_info, + #table_info{ + index_types = + {augments, SrcTableEntry, Line}} = TableInfo}|Ref]} = Me + |Mes]) -> + ?vlog("augmentations(~w) ->" + "~n NameOfTable: ~p" + "~n IndexingInfo: ~p" + "~n Sline: ~p", + [?LINE, AliasName, {augments, SrcTableEntry}, Line]), + NewTableInfo = snmpc_lib:fix_table_info_augmentation(TableInfo), + [Me#me{assocList = [{table_info,NewTableInfo}|Ref]} + |augmentations(Mes)]; +augmentations([Me | Mes]) -> + [Me|augmentations(Mes)]; +augmentations([]) -> + ?vlog("augmentations -> done", []), + []. + + safe_elem(N,T) -> case catch(element(N,T)) of diff --git a/lib/snmp/src/compile/snmpc_lib.erl b/lib/snmp/src/compile/snmpc_lib.erl index 51690b6e7e..19a6bc8851 100644 --- a/lib/snmp/src/compile/snmpc_lib.erl +++ b/lib/snmp/src/compile/snmpc_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2016. All Rights Reserved. +%% Copyright Ericsson AB 1997-2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -26,7 +26,7 @@ -export([test_father/4, make_ASN1type/1, import/1, makeInternalNode2/2, is_consistent/1, resolve_defval/1, make_variable_info/1, check_trap_name/3, make_table_info/5, get_final_mib/2, set_dir/2, - look_at/1, add_cdata/2, + fix_table_info_augmentation/1, look_at/1, add_cdata/2, check_object_group/4, check_notification_group/4, check_notification/3, register_oid/4, @@ -99,7 +99,7 @@ make_ASN1type({{type_with_size,Type,{range,Lo,Hi}},Line}) -> print_error("Undefined type '~w'",[Type],Line), guess_string_type() end; -make_ASN1type({{integer_with_enum,Type,Enums},Line}) -> +make_ASN1type({{type_with_enum,Type,Enums},Line}) -> case lookup_vartype(Type) of {value,ASN1type} -> ASN1type#asn1_type{assocList = [{enums, Enums}]}; false -> @@ -710,25 +710,34 @@ check_trap_name(EnterpriseName, Line, MEs) -> %% functions for tables. %%---------------------------------------------------------------------- +fix_table_info_augmentation( + #table_info{index_types = {augments, SrcTableEntry, Line}} = TableInfo) -> + MEs = (get(cdata))#cdata.mes, + Aug = + case lookup(SrcTableEntry, MEs) of + false -> + print_error( + "Cannot AUGMENT the non-existing table entry ~p", + [SrcTableEntry], Line), + {augments, error}; + {value, ME} -> + {augments, + {SrcTableEntry, translate_type(ME#me.asn1_type)}} + end, + TableInfo#table_info{index_types = Aug}. + + make_table_info(Line, TableName, {augments, SrcTableEntry}, _, ColumnMEs) -> ColMEs = lists:keysort(#me.oid, ColumnMEs), - Nbr_of_Cols = length(ColMEs), - MEs = ColMEs ++ (get(cdata))#cdata.mes, - Aug = case lookup(SrcTableEntry, MEs) of - false -> - print_error("Cannot AUGMENT the non-existing table entry ~p", - [SrcTableEntry], Line), - {augments, error}; - {value, ME} -> - {augments, {SrcTableEntry, translate_type(ME#me.asn1_type)}} - end, - FirstNonIdxCol = augments_first_non_index_column(ColMEs), + Nbr_of_Cols = length(ColMEs), + put(augmentations, true), + FirstNonIdxCol = augments_first_non_index_column(ColMEs), NoAccs = list_not_accessible(FirstNonIdxCol, ColMEs), FirstAcc = first_accessible(TableName, ColMEs), #table_info{nbr_of_cols = Nbr_of_Cols, - first_accessible = FirstAcc, - not_accessible = NoAccs, - index_types = Aug}; + first_accessible = FirstAcc, + not_accessible = NoAccs, + index_types = {augments, SrcTableEntry, Line}}; make_table_info(Line, TableName, {indexes, []}, _, _ColumnMEs) -> print_error("Table ~w lacks indexes.", [TableName],Line), #table_info{}; diff --git a/lib/snmp/src/compile/snmpc_mib_gram.yrl b/lib/snmp/src/compile/snmpc_mib_gram.yrl index 743c3a6550..14a668127e 100644 --- a/lib/snmp/src/compile/snmpc_mib_gram.yrl +++ b/lib/snmp/src/compile/snmpc_mib_gram.yrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -387,10 +387,12 @@ syntax -> type : {{type, cat('$1')},line_of('$1')}. syntax -> type size : {{type_with_size, cat('$1'), '$2'},line_of('$1')}. syntax -> usertype size : {{type_with_size,val('$1'), '$2'},line_of('$1')}. syntax -> 'INTEGER' '{' namedbits '}' : - {{integer_with_enum, 'INTEGER', '$3'}, line_of('$1')}. + {{type_with_enum, 'INTEGER', '$3'}, line_of('$1')}. syntax -> 'BITS' '{' namedbits '}' : ensure_ver(2,'$1'), {{bits, '$3'}, line_of('$1')}. +syntax -> usertype '{' namedbits '}' : + {{type_with_enum, 'INTEGER', '$3'}, line_of('$1')}. syntax -> 'SEQUENCE' 'OF' usertype : {{sequence_of,val('$3')},line_of('$1')}. diff --git a/lib/snmp/src/compile/snmpc_misc.erl b/lib/snmp/src/compile/snmpc_misc.erl index 933d629746..312074f2e7 100644 --- a/lib/snmp/src/compile/snmpc_misc.erl +++ b/lib/snmp/src/compile/snmpc_misc.erl @@ -29,7 +29,7 @@ bits_to_int/2, ensure_trailing_dir_delimiter/1, foreach/3, - is_string/1, + check_file/1, read_mib/1, read_noexit/2, strip_extension_from_filename/2, @@ -86,21 +86,21 @@ to_upper([C|Cs]) -> [C|to_upper(Cs)]; to_upper([]) -> []. -is_string([]) -> true; -is_string([Tkn | Str]) - when is_integer(Tkn) andalso (Tkn >= 0) andalso (Tkn =< 255) -> - is_string(Str); -is_string(_) -> false. - - +check_file(FileName) -> + case filename:extension(FileName) of + ".mib" -> + filelib:is_regular(FileName); + _ -> + filelib:is_regular(FileName ++ ".mib") + end. + + foreach(Function, ExtraArgs, [H | T]) -> apply(Function, [H | ExtraArgs]), foreach(Function, ExtraArgs, T); foreach(_Function, _ExtraArgs, []) -> true. - - %%---------------------------------------------------------------------- %% Returns: {ok, Mib}|{error, Reason} %% The reason for having the function if this module is: diff --git a/lib/snmp/src/manager/snmpm_net_if.erl b/lib/snmp/src/manager/snmpm_net_if.erl index 93c987eb0f..29216f9d6a 100644 --- a/lib/snmp/src/manager/snmpm_net_if.erl +++ b/lib/snmp/src/manager/snmpm_net_if.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2015. All Rights Reserved. +%% Copyright Ericsson AB 2004-2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -367,7 +367,7 @@ common_socket_opts(Opts) -> default -> []; Sz -> - [{sndbuf, Sz}] + [{recbuf, Sz}] end ++ case get_opt(Opts, no_reuse, false) of false -> |