~ubuntu-branches/ubuntu/trusty/erlang/trusty

« back to all changes in this revision

Viewing changes to lib/common_test/src/ct_util.erl

  • Committer: Bazaar Package Importer
  • Author(s): Clint Byrum
  • Date: 2011-05-05 15:48:43 UTC
  • mfrom: (3.5.13 sid)
  • Revision ID: james.westby@ubuntu.com-20110505154843-0om6ekzg6m7ugj27
Tags: 1:14.b.2-dfsg-3ubuntu1
* Merge from debian unstable.  Remaining changes:
  - Drop libwxgtk2.8-dev build dependency. Wx isn't in main, and not
    supposed to.
  - Drop erlang-wx binary.
  - Drop erlang-wx dependency from -megaco, -common-test, and -reltool, they
    do not really need wx. Also drop it from -debugger; the GUI needs wx,
    but it apparently has CLI bits as well, and is also needed by -megaco,
    so let's keep the package for now.
  - debian/patches/series: Do what I meant, and enable build-options.patch
    instead.
* Additional changes:
  - Drop erlang-wx from -et
* Dropped Changes:
  - patches/pcre-crash.patch: CVE-2008-2371: outer level option with
    alternatives caused crash. (Applied Upstream)
  - fix for ssl certificate verification in newSSL: 
    ssl_cacertfile_fix.patch (Applied Upstream)
  - debian/patches/series: Enable native.patch again, to get stripped beam
    files and reduce the package size again. (build-options is what
    actually accomplished this)
  - Remove build-options.patch on advice from upstream and because it caused
    odd build failures.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
%%
2
2
%% %CopyrightBegin%
3
 
%% 
4
 
%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
5
 
%% 
 
3
%%
 
4
%% Copyright Ericsson AB 2003-2011. All Rights Reserved.
 
5
%%
6
6
%% The contents of this file are subject to the Erlang Public License,
7
7
%% Version 1.1, (the "License"); you may not use this file except in
8
8
%% compliance with the License. You should have received a copy of the
9
9
%% Erlang Public License along with this software. If not, it can be
10
10
%% retrieved online at http://www.erlang.org/.
11
 
%% 
 
11
%%
12
12
%% Software distributed under the License is distributed on an "AS IS"
13
13
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
14
14
%% the License for the specific language governing rights and limitations
15
15
%% under the License.
16
 
%% 
 
16
%%
17
17
%% %CopyrightEnd%
18
18
%%
19
19
 
30
30
-export([register_connection/4,unregister_connection/1,
31
31
         does_connection_exist/3,get_key_from_name/1]).
32
32
 
33
 
-export([require/1, require/2, get_config/1, get_config/2, get_config/3,         
34
 
         set_default_config/2, set_default_config/3, delete_default_config/1,
35
 
         get_all_config/0, update_config/2, 
36
 
         release_allocated/0, close_connections/0]).
 
33
-export([close_connections/0]).
37
34
 
38
 
-export([save_suite_data/3, save_suite_data/2, read_suite_data/1, 
 
35
-export([save_suite_data/3, save_suite_data/2,
 
36
         save_suite_data_async/3, save_suite_data_async/2,
 
37
         read_suite_data/1, 
39
38
         delete_suite_data/0, delete_suite_data/1, match_delete_suite_data/1,
40
39
         delete_testdata/0, delete_testdata/1, set_testdata/1, get_testdata/1,
41
40
         update_testdata/2]).
46
45
         silence_all_connections/0, silence_connections/1, is_silenced/1, 
47
46
         reset_silent_connections/0]).
48
47
 
 
48
-export([get_mode/0, create_table/3, read_opts/0]).
 
49
 
49
50
-export([set_cwd/1, reset_cwd/0]).
50
51
 
51
52
-export([parse_table/1]).
56
57
 
57
58
-export([is_test_dir/1, get_testdir/2]).
58
59
 
59
 
-export([encrypt_config_file/2, encrypt_config_file/3,
60
 
         decrypt_config_file/2, decrypt_config_file/3]).
61
 
 
62
 
-export([kill_attached/2, get_attached/1]).
 
60
-export([kill_attached/2, get_attached/1, ct_make_ref/0]).
63
61
 
64
62
-export([warn_duplicates/1]).
65
63
 
66
64
-include("ct_event.hrl").
67
65
-include("ct_util.hrl").
68
66
 
69
 
-record(ct_conf,{key,value,ref,name='_UNDEF',default=false}).  
70
 
%% default = {true,suite} | {true,testcase} | false
71
 
 
72
67
-record(suite_data, {key,name,value}).
73
68
 
74
 
-define(cryptfile, ".ct_config.crypt").
75
 
 
76
69
%%%-----------------------------------------------------------------
77
70
%%% @spec start(Mode) -> Pid | exit(Error)
78
71
%%%       Mode = normal | interactive
119
112
do_start(Parent,Mode,LogDir) ->
120
113
    process_flag(trap_exit,true),
121
114
    register(ct_util_server,self()),
122
 
    create_table(?attr_table,bag,#ct_conf.key),
123
115
    create_table(?conn_table,#conn.handle),
124
116
    create_table(?board_table,2),
125
117
    create_table(?suite_table,#suite_data.key),
135
127
                   Parent ! {self(),Error},
136
128
                   exit(Error)
137
129
           end,
138
 
 
139
130
    %% start an event manager (if not already started by master)
140
131
    case ct_event:start_link() of
141
132
        {error,{already_started,_}} ->
148
139
                    ct_event:add_handler([{vts,VtsPid}])
149
140
            end
150
141
    end,
151
 
    case read_config_files(Opts) of
152
 
        ok ->
153
 
            %% add user handlers
154
 
            case lists:keysearch(event_handler,1,Opts) of
155
 
                {value,{_,Handlers}} ->
156
 
                    Add = fun({H,Args}) ->
157
 
                                  case catch gen_event:add_handler(?CT_EVMGR_REF,H,Args) of
158
 
                                      ok -> ok;
159
 
                                      {'EXIT',Why} -> exit(Why);
160
 
                                      Other -> exit({event_handler,Other})
161
 
                                  end
162
 
                          end,
163
 
                    case catch lists:foreach(Add,Handlers) of
164
 
                        {'EXIT',Reason} ->
165
 
                            Parent ! {self(),Reason};
166
 
                        _ ->
167
 
                            ok
168
 
                    end;
169
 
                false ->
 
142
    %% start ct_config server
 
143
    ct_config:start(Mode),
 
144
    %% add user event handlers
 
145
    case lists:keysearch(event_handler,1,Opts) of
 
146
        {value,{_,Handlers}} ->
 
147
            Add = fun({H,Args}) ->
 
148
                          case catch gen_event:add_handler(?CT_EVMGR_REF,H,Args) of
 
149
                              ok -> ok;
 
150
                              {'EXIT',Why} -> exit(Why);
 
151
                              Other -> exit({event_handler,Other})
 
152
                          end
 
153
                  end,
 
154
            case catch lists:foreach(Add,Handlers) of
 
155
                {'EXIT',Reason} ->
 
156
                    Parent ! {self(),Reason};
 
157
                _ ->
170
158
                    ok
171
 
            end,
172
 
            {StartTime,TestLogDir} = ct_logs:init(Mode),
173
 
            ct_event:notify(#event{name=test_start,
174
 
                                   node=node(),
175
 
                                   data={StartTime,
176
 
                                         lists:flatten(TestLogDir)}}),
177
 
            Parent ! {self(),started},
178
 
            loop(Mode,[],StartDir);
179
 
        ReadError ->
180
 
            Parent ! {self(),ReadError},
181
 
            exit(ReadError)
182
 
    end.
 
159
            end;
 
160
        false ->
 
161
            ok
 
162
    end,
 
163
    {StartTime,TestLogDir} = ct_logs:init(Mode),
 
164
 
 
165
    %% Initiate ct_hooks
 
166
    case catch ct_hooks:init(Opts) of
 
167
        ok ->
 
168
            ok;
 
169
        {_,CTHReason} ->
 
170
            ct_logs:tc_print('Suite Callback',CTHReason,[]),
 
171
            Parent ! {self(), CTHReason},
 
172
            self() ! {{stop,normal},{self(),make_ref()}}
 
173
    end,
 
174
 
 
175
    ct_event:notify(#event{name=test_start,
 
176
                           node=node(),
 
177
                           data={StartTime,
 
178
                                 lists:flatten(TestLogDir)}}),
 
179
    Parent ! {self(),started},
 
180
    loop(Mode,[],StartDir).
183
181
 
184
182
create_table(TableName,KeyPos) ->
185
183
    create_table(TableName,set,KeyPos).
197
195
            {error,{bad_installation,Error}}
198
196
    end.
199
197
 
200
 
read_config_files(Opts) ->
201
 
    ConfigFiles =
202
 
        lists:foldl(fun({config,Files},Acc) ->
203
 
                            Acc ++ Files;
204
 
                       (_,Acc) ->
205
 
                            Acc
206
 
                    end,[],Opts),
207
 
    read_config_files1(ConfigFiles).
208
 
 
209
 
read_config_files1([ConfigFile|Files]) ->
210
 
    case file:consult(ConfigFile) of
211
 
        {ok,Config} -> 
212
 
            set_config(Config),
213
 
            read_config_files1(Files);
214
 
        {error,enoent} ->
215
 
            {user_error,{config_file_error,ConfigFile,enoent}};
216
 
        {error,Reason} ->
217
 
            Key =
218
 
                case application:get_env(common_test, decrypt) of
219
 
                    {ok,KeyOrFile} ->
220
 
                        case KeyOrFile of
221
 
                            {key,K} ->
222
 
                                K;
223
 
                            {file,F} ->
224
 
                                get_crypt_key_from_file(F)
225
 
                        end;
226
 
                    _ ->
227
 
                        get_crypt_key_from_file()
228
 
                end,
229
 
            case Key of
230
 
                {error,no_crypt_file} ->
231
 
                    {user_error,{config_file_error,ConfigFile,Reason}};
232
 
                {error,CryptError} ->
233
 
                    {user_error,{decrypt_file_error,ConfigFile,CryptError}};
234
 
                _ when is_list(Key) ->
235
 
                    case decrypt_config_file(ConfigFile, undefined, {key,Key}) of
236
 
                        {ok,CfgBin} ->
237
 
                            case read_config_terms(CfgBin) of
238
 
                                {error,ReadFail} ->
239
 
                                    {user_error,{config_file_error,ConfigFile,ReadFail}};
240
 
                                Config ->
241
 
                                    set_config(Config),
242
 
                                    read_config_files1(Files)
243
 
                            end;
244
 
                        {error,DecryptFail} ->
245
 
                            {user_error,{decrypt_config_error,ConfigFile,DecryptFail}}
246
 
                    end;
247
 
                _ ->
248
 
                    {user_error,{bad_decrypt_key,ConfigFile,Key}}
249
 
            end
250
 
    end;
251
 
read_config_files1([]) ->
252
 
    ok.
253
 
 
254
 
read_config_terms(Bin) when is_binary(Bin) ->
255
 
    case catch binary_to_list(Bin) of
256
 
        {'EXIT',_} ->
257
 
            {error,invalid_textfile};
258
 
        Lines ->
259
 
            read_config_terms(Lines)
260
 
    end;
261
 
read_config_terms(Lines) when is_list(Lines) ->
262
 
    read_config_terms1(erl_scan:tokens([], Lines, 0), 1, [], []).
263
 
 
264
 
read_config_terms1({done,{ok,Ts,EL},Rest}, L, Terms, _) ->
265
 
    case erl_parse:parse_term(Ts) of
266
 
        {ok,Term} when Rest == [] ->
267
 
            lists:reverse([Term|Terms]);
268
 
        {ok,Term} ->
269
 
            read_config_terms1(erl_scan:tokens([], Rest, 0), 
270
 
                               EL+1, [Term|Terms], Rest);
271
 
        _ ->
272
 
            {error,{bad_term,{L,EL}}}
273
 
    end;
274
 
read_config_terms1({done,{eof,_},_}, _, Terms, Rest) when Rest == [] ->
275
 
    lists:reverse(Terms);
276
 
read_config_terms1({done,{eof,EL},_}, L, _, _) ->
277
 
    {error,{bad_term,{L,EL}}};
278
 
read_config_terms1({done,{error,Info,EL},_}, L, _, _) ->
279
 
    {error,{Info,{L,EL}}};
280
 
read_config_terms1({more,_}, L, Terms, Rest) ->
281
 
    case string:tokens(Rest, [$\n,$\r,$\t]) of
282
 
        [] ->
283
 
            lists:reverse(Terms);
284
 
        _ ->
285
 
            {error,{bad_term,L}}
286
 
    end.
287
 
 
288
 
set_default_config(NewConfig, Scope) ->
289
 
    call({set_default_config, {NewConfig, Scope}}).
290
 
 
291
 
set_default_config(Name, NewConfig, Scope) ->
292
 
    call({set_default_config, {Name, NewConfig, Scope}}).
293
 
 
294
 
delete_default_config(Scope) ->
295
 
    call({delete_default_config, Scope}).
296
 
 
297
 
update_config(Name, Config) ->
298
 
    call({update_config, {Name, Config}}).
299
198
 
300
199
save_suite_data(Key, Value) ->
301
200
    call({save_suite_data, {Key, undefined, Value}}).
303
202
save_suite_data(Key, Name, Value) ->
304
203
    call({save_suite_data, {Key, Name, Value}}).
305
204
 
 
205
save_suite_data_async(Key, Value) ->
 
206
    save_suite_data_async(Key, undefined, Value).
 
207
 
 
208
save_suite_data_async(Key, Name, Value) ->
 
209
    cast({save_suite_data, {Key, Name, Value}}).
 
210
 
306
211
read_suite_data(Key) ->
307
212
    call({read_suite_data, Key}).
308
213
 
342
247
            ct_logs:make_last_run_index(),
343
248
            return(From,ok),
344
249
            loop(Mode,TestData,StartDir);
345
 
        {{require,Name,Tag,SubTags},From} ->
346
 
            Result = do_require(Name,Tag,SubTags),
347
 
            return(From,Result),
348
 
            loop(Mode,TestData,StartDir);
349
 
        {{set_default_config,{Config,Scope}},From} ->
350
 
            set_config(Config,{true,Scope}),
351
 
            return(From,ok),
352
 
            loop(Mode,TestData,StartDir);
353
 
        {{set_default_config,{Name,Config,Scope}},From} ->
354
 
            set_config(Name,Config,{true,Scope}),
355
 
            return(From,ok),
356
 
            loop(Mode,TestData,StartDir);
357
 
        {{delete_default_config,Scope},From} ->
358
 
            delete_config({true,Scope}),
359
 
            return(From,ok),
360
 
            loop(Mode,TestData,StartDir);
361
 
        {{update_config,{Name,NewConfig}},From} ->
362
 
            update_conf(Name,NewConfig),
363
 
            return(From,ok),
364
 
            loop(Mode,TestData,StartDir);
365
250
        {{save_suite_data,{Key,Name,Value}},From} ->
366
251
            ets:insert(?suite_table, #suite_data{key=Key,
367
252
                                                 name=Name,
403
288
            TestData1 = lists:keydelete(Key,1,TestData),
404
289
            return(From,ok),
405
290
            loop(Mode,[New|TestData1],StartDir);
 
291
        {{get_testdata, all}, From} ->
 
292
            return(From, TestData),
 
293
            loop(From, TestData, StartDir);
406
294
        {{get_testdata,Key},From} ->
407
295
            case lists:keysearch(Key,1,TestData) of
408
296
                {value,{Key,Val}} ->
434
322
            ct_event:sync_notify(#event{name=test_done,
435
323
                                        node=node(),
436
324
                                        data=Time}),
437
 
            ets:delete(?attr_table),
 
325
            Callbacks = ets:lookup_element(?suite_table,
 
326
                                           ct_hooks,
 
327
                                           #suite_data.value),
 
328
            ct_hooks:terminate(Callbacks),
438
329
            close_connections(ets:tab2list(?conn_table)),
439
330
            ets:delete(?conn_table),
440
331
            ets:delete(?board_table),
441
332
            ets:delete(?suite_table),
442
333
            ct_logs:close(How),
443
 
            file:set_cwd(StartDir),
444
334
            ct_event:stop(),
 
335
            ct_config:stop(),
 
336
            file:set_cwd(StartDir),
445
337
            return(From,ok);
 
338
        {Ref, _Msg} when is_reference(Ref) ->
 
339
            %% This clause is used when doing cast operations.
 
340
            loop(Mode,TestData,StartDir);
446
341
        {get_mode,From} ->
447
342
            return(From,Mode),
448
343
            loop(Mode,TestData,StartDir);
463
358
close_connections([]) ->
464
359
    ok.
465
360
 
 
361
get_key_from_name(Name)->
 
362
    ct_config:get_key_from_name(Name).
466
363
 
467
364
%%%-----------------------------------------------------------------
468
365
%%% @spec register_connection(TargetName,Address,Callback,Handle) -> 
480
377
%%% test is finished by calling <code>Callback:close/1</code>.</p>
481
378
register_connection(TargetName,Address,Callback,Handle) ->
482
379
    TargetRef = 
483
 
        case get_ref_from_name(TargetName) of
 
380
        case ct_config:get_ref_from_name(TargetName) of
484
381
            {ok,Ref} ->
485
382
                Ref;
486
383
            _ ->
518
415
%%%
519
416
%%% @doc Check if a connection already exists.
520
417
does_connection_exist(TargetName,Address,Callback) ->
521
 
    case get_ref_from_name(TargetName) of
 
418
    case ct_config:get_ref_from_name(TargetName) of
522
419
        {ok,TargetRef} ->
523
420
            case ets:select(?conn_table,[{#conn{handle='$1',
524
421
                                                targetref=TargetRef,
548
445
%%% @doc Return all connections for the <code>Callback</code> on the
549
446
%%% given target (<code>TargetName</code>).
550
447
get_connections(TargetName,Callback) ->
551
 
    case get_ref_from_name(TargetName) of
 
448
    case ct_config:get_ref_from_name(TargetName) of
552
449
        {ok,Ref} ->
553
450
            {ok,ets:select(?conn_table,[{#conn{handle='$1',
554
451
                                               address='$2',
568
465
                                  [],
569
466
                                  ['$1']}]) of
570
467
        [TargetRef] ->
571
 
            get_name_from_ref(TargetRef);
 
468
            ct_config:get_name_from_ref(TargetRef);
572
469
        [] ->
573
470
            {error,{unknown_connection,ConnPid}}
574
471
    end.
575
472
 
576
 
 
577
 
%%%-----------------------------------------------------------------
578
 
%%% @hidden
579
 
%%% @equiv ct:require/1
580
 
require(Key) when is_atom(Key) ->
581
 
    require({Key,[]});
582
 
require({Key,SubKeys}) when is_atom(Key) ->
583
 
    allocate('_UNDEF',Key,to_list(SubKeys));
584
 
require(Key) ->
585
 
    {error,{invalid,Key}}.
586
 
 
587
 
 
588
 
%%%-----------------------------------------------------------------
589
 
%%% @hidden
590
 
%%% @equiv ct:require/2
591
 
require(Name,Key) when is_atom(Key) ->
592
 
    require(Name,{Key,[]});
593
 
require(Name,{Key,SubKeys}) when is_atom(Name), is_atom(Key) ->
594
 
    call({require,Name,Key,to_list(SubKeys)});
595
 
require(Name,Keys) ->
596
 
    {error,{invalid,{Name,Keys}}}.
597
 
 
598
 
to_list(X) when is_list(X) -> X;
599
 
to_list(X) -> [X].
600
 
 
601
 
do_require(Name,Key,SubKeys) when is_list(SubKeys) ->
602
 
    case get_key_from_name(Name) of
603
 
        {error,_} ->
604
 
            allocate(Name,Key,SubKeys);             
605
 
        {ok,Key} ->
606
 
            %% already allocated - check that it has all required subkeys
607
 
            Vals = [Val || {_Ref,Val} <- lookup_name(Name)],
608
 
            case get_subconfig(SubKeys,Vals) of
609
 
                {ok,_SubMapped} ->
610
 
                    ok;
611
 
                Error ->
612
 
                    Error
613
 
            end;
614
 
        {ok,OtherKey} ->
615
 
            {error,{name_in_use,Name,OtherKey}}
616
 
    end.
617
 
 
618
 
allocate(Name,Key,SubKeys) ->
619
 
    case ets:match_object(?attr_table,#ct_conf{key=Key,name='_UNDEF',_='_'}) of
620
 
        [] ->
621
 
            {error,{not_available,Key}};
622
 
        Available ->
623
 
            case allocate_subconfig(Name,SubKeys,Available,false) of
624
 
                ok ->
625
 
                    ok;
626
 
                Error ->
627
 
                    Error
628
 
            end
629
 
    end.
630
 
 
631
 
allocate_subconfig(Name,SubKeys,[C=#ct_conf{value=Value}|Rest],Found) ->
632
 
    case do_get_config(SubKeys,Value,[]) of
633
 
        {ok,_SubMapped} ->
634
 
            ets:insert(?attr_table,C#ct_conf{name=Name}),
635
 
            allocate_subconfig(Name,SubKeys,Rest,true);
636
 
        _Error ->
637
 
            allocate_subconfig(Name,SubKeys,Rest,Found)
638
 
    end;
639
 
allocate_subconfig(_Name,_SubKeys,[],true) ->
640
 
    ok;
641
 
allocate_subconfig(_Name,SubKeys,[],false) ->
642
 
    {error,{not_available,SubKeys}}.
643
 
 
644
 
 
645
 
 
646
 
 
647
 
%%%-----------------------------------------------------------------
648
 
%%% @hidden
649
 
%%% @equiv ct:get_config/1
650
 
get_config(KeyOrName) ->
651
 
    get_config(KeyOrName,undefined,[]).
652
 
 
653
 
%%%-----------------------------------------------------------------
654
 
%%% @hidden
655
 
%%% @equiv ct:get_config/2
656
 
get_config(KeyOrName,Default) ->
657
 
    get_config(KeyOrName,Default,[]).
658
 
 
659
 
%%%-----------------------------------------------------------------
660
 
%%% @hidden
661
 
%%% @equiv ct:get_config/3
662
 
get_config(KeyOrName,Default,Opts) when is_atom(KeyOrName) ->
663
 
    case lookup_config(KeyOrName) of
664
 
        [] ->
665
 
            Default;
666
 
        [{_Ref,Val}|_] = Vals ->
667
 
            case {lists:member(all,Opts),lists:member(element,Opts)} of
668
 
                {true,true} ->
669
 
                    [{KeyOrName,V} || {_R,V} <- lists:sort(Vals)];
670
 
                {true,false} ->
671
 
                    [V || {_R,V} <- lists:sort(Vals)];
672
 
                {false,true} ->
673
 
                    {KeyOrName,Val};
674
 
                {false,false} ->
675
 
                    Val
676
 
            end
677
 
    end;
678
 
                
679
 
get_config({KeyOrName,SubKey},Default,Opts) ->
680
 
    case lookup_config(KeyOrName) of
681
 
        [] ->
682
 
            Default;
683
 
        Vals ->
684
 
            Vals1 = case [Val || {_Ref,Val} <- lists:sort(Vals)] of
685
 
                        Result=[L|_] when is_list(L) ->
686
 
                            case L of
687
 
                                [{_,_}|_] ->
688
 
                                    Result;
689
 
                                _ ->
690
 
                                    []
691
 
                            end;
692
 
                        _ ->
693
 
                            []
694
 
                    end,                                    
695
 
            case get_subconfig([SubKey],Vals1,[],Opts) of
696
 
                {ok,[{_,SubVal}|_]=SubVals} ->
697
 
                    case {lists:member(all,Opts),lists:member(element,Opts)} of
698
 
                        {true,true} ->
699
 
                            [{{KeyOrName,SubKey},Val} || {_,Val} <- SubVals];
700
 
                        {true,false} ->
701
 
                            [Val || {_SubKey,Val} <- SubVals];
702
 
                        {false,true} ->
703
 
                            {{KeyOrName,SubKey},SubVal};
704
 
                        {false,false} ->
705
 
                            SubVal
706
 
                    end;
707
 
                _ ->
708
 
                    Default
709
 
            end
710
 
    end.
711
 
                    
712
 
 
713
 
get_subconfig(SubKeys,Values) ->
714
 
    get_subconfig(SubKeys,Values,[],[]).
715
 
 
716
 
get_subconfig(SubKeys,[Value|Rest],Mapped,Opts) ->
717
 
    case do_get_config(SubKeys,Value,[]) of
718
 
        {ok,SubMapped} ->
719
 
            case lists:member(all,Opts) of
720
 
                true ->
721
 
                    get_subconfig(SubKeys,Rest,Mapped++SubMapped,Opts);
722
 
                false ->
723
 
                    {ok,SubMapped}
724
 
            end;
725
 
        _Error ->
726
 
            get_subconfig(SubKeys,Rest,Mapped,Opts)
727
 
    end;
728
 
get_subconfig(SubKeys,[],[],_) ->
729
 
    {error,{not_available,SubKeys}};
730
 
get_subconfig(_SubKeys,[],Mapped,_) ->
731
 
    {ok,Mapped}.
732
 
 
733
 
do_get_config([Key|Required],Available,Mapped) ->
734
 
    case lists:keysearch(Key,1,Available) of
735
 
        {value,{Key,Value}} ->
736
 
            NewAvailable = lists:keydelete(Key,1,Available),
737
 
            NewMapped = [{Key,Value}|Mapped],
738
 
            do_get_config(Required,NewAvailable,NewMapped);
739
 
        false ->
740
 
            {error,{not_available,Key}}
741
 
    end;
742
 
do_get_config([],_Available,Mapped) ->
743
 
    {ok,lists:reverse(Mapped)}.
744
 
 
745
 
get_all_config() ->
746
 
    ets:select(?attr_table,[{#ct_conf{name='$1',key='$2',value='$3',
747
 
                                      default='$4',_='_'},
748
 
                             [],
749
 
                             [{{'$1','$2','$3','$4'}}]}]).
750
 
 
751
 
lookup_config(KeyOrName) ->
752
 
    case lookup_name(KeyOrName) of
753
 
        [] ->
754
 
            lookup_key(KeyOrName);
755
 
        Values ->
756
 
            Values
757
 
    end.
758
 
 
759
 
lookup_name(Name) ->
760
 
    ets:select(?attr_table,[{#ct_conf{ref='$1',value='$2',name=Name,_='_'},
761
 
                             [],
762
 
                             [{{'$1','$2'}}]}]).
763
 
lookup_key(Key) ->
764
 
    ets:select(?attr_table,[{#ct_conf{key=Key,ref='$1',value='$2',name='_UNDEF',_='_'},
765
 
                             [],
766
 
                             [{{'$1','$2'}}]}]).
767
 
 
768
 
set_config(Config) ->
769
 
    set_config('_UNDEF',Config,false).
770
 
 
771
 
set_config(Config,Default) ->
772
 
    set_config('_UNDEF',Config,Default).
773
 
 
774
 
set_config(Name,Config,Default) ->
775
 
    [ets:insert(?attr_table,
776
 
                #ct_conf{key=Key,value=Val,ref=ct_make_ref(),
777
 
                         name=Name,default=Default}) ||
778
 
        {Key,Val} <- Config].
779
 
 
780
 
delete_config(Default) ->
781
 
    ets:match_delete(?attr_table,#ct_conf{default=Default,_='_'}),
782
 
    ok.
783
 
 
784
 
 
785
 
%%%-----------------------------------------------------------------
786
 
%%% @spec release_allocated() -> ok
787
 
%%%
788
 
%%% @doc Release all allocated resources, but don't take down any
789
 
%%% connections.
790
 
release_allocated() ->
791
 
    Allocated = ets:select(?attr_table,[{#ct_conf{name='$1',_='_'},
792
 
                                         [{'=/=','$1','_UNDEF'}],
793
 
                                         ['$_']}]),
794
 
    release_allocated(Allocated).
795
 
release_allocated([H|T]) ->
796
 
    ets:delete_object(?attr_table,H),
797
 
    ets:insert(?attr_table,H#ct_conf{name='_UNDEF'}),
798
 
    release_allocated(T);
799
 
release_allocated([]) ->
800
 
    ok.
801
 
 
802
 
%%%-----------------------------------------------------------------
803
 
%%% @spec 
804
 
%%%
805
 
%%% @doc 
806
 
update_conf(Name, NewConfig) ->
807
 
    Old = ets:select(?attr_table,[{#ct_conf{name=Name,_='_'},[],['$_']}]),
808
 
    lists:foreach(fun(OldElem) ->
809
 
                          NewElem = OldElem#ct_conf{value=NewConfig},
810
 
                          ets:delete_object(?attr_table, OldElem),
811
 
                          ets:insert(?attr_table, NewElem)
812
 
                  end, Old),
813
 
    ok.
814
 
                                       
815
473
%%%-----------------------------------------------------------------
816
474
%%% @spec close_connections() -> ok
817
475
%%%
928
586
%%% @hidden
929
587
%%% @equiv ct:parse_table/1
930
588
parse_table(Data) ->
931
 
    [Heading|Lines]=
932
 
        [remove_space(string:tokens(L, "|"),[]) || L <- Data, hd(L)==$|],
 
589
    {Heading, Rest} = get_headings(Data),
 
590
    Lines = parse_row(Rest,[],size(Heading)),
933
591
    {Heading,Lines}.
934
592
 
 
593
get_headings(["|" ++ Headings | Rest]) ->
 
594
    {remove_space(string:tokens(Headings, "|"),[]), Rest};
 
595
get_headings([_ | Rest]) ->
 
596
    get_headings(Rest);
 
597
get_headings([]) ->
 
598
    {{},[]}.
 
599
 
 
600
parse_row(["|" ++ _ = Row | T], Rows, NumCols) when NumCols > 1 ->
 
601
    case string:tokens(Row, "|") of
 
602
        Values when length(Values) =:= NumCols ->
 
603
            parse_row(T,[remove_space(Values,[])|Rows], NumCols);
 
604
        Values when length(Values) < NumCols ->
 
605
            parse_row([Row ++"\n"++ hd(T) | tl(T)], Rows, NumCols)
 
606
    end;
 
607
parse_row(["|" ++ _ = Row | T], Rows, 1 = NumCols) ->
 
608
    case string:rchr(Row, $|) of
 
609
        1 ->
 
610
            parse_row([Row ++"\n"++hd(T) | tl(T)], Rows, NumCols);
 
611
        _Else ->
 
612
            parse_row(T, [remove_space(string:tokens(Row,"|"),[])|Rows],
 
613
                      NumCols)
 
614
    end;
 
615
parse_row([_Skip | T], Rows, NumCols) ->
 
616
    parse_row(T, Rows, NumCols);
 
617
parse_row([], Rows, _NumCols) ->
 
618
    lists:reverse(Rows).
 
619
 
935
620
remove_space([Str|Rest],Acc) ->
936
621
    remove_space(Rest,[string:strip(string:strip(Str),both,$')|Acc]);
937
622
remove_space([],Acc) ->
995
680
%%% @spec 
996
681
%%%
997
682
%%% @doc
998
 
encrypt_config_file(SrcFileName, EncryptFileName) ->
999
 
    case get_crypt_key_from_file() of
1000
 
        {error,_} = E ->
1001
 
            E;
1002
 
        Key ->
1003
 
            encrypt_config_file(SrcFileName, EncryptFileName, {key,Key})
1004
 
    end.
1005
 
 
1006
 
%%%-----------------------------------------------------------------
1007
 
%%% @spec 
1008
 
%%%
1009
 
%%% @doc
1010
 
encrypt_config_file(SrcFileName, EncryptFileName, {file,KeyFile}) ->
1011
 
    case get_crypt_key_from_file(KeyFile) of
1012
 
        {error,_} = E ->
1013
 
            E;
1014
 
        Key ->
1015
 
            encrypt_config_file(SrcFileName, EncryptFileName, {key,Key})
1016
 
    end;
1017
 
 
1018
 
encrypt_config_file(SrcFileName, EncryptFileName, {key,Key}) ->    
1019
 
    crypto:start(),
1020
 
    {K1,K2,K3,IVec} = make_crypto_key(Key),
1021
 
    case file:read_file(SrcFileName) of
1022
 
        {ok,Bin0} ->
1023
 
            Bin1 = term_to_binary({SrcFileName,Bin0}),
1024
 
            Bin2 = case byte_size(Bin1) rem 8 of
1025
 
                       0 -> Bin1;
1026
 
                       N -> list_to_binary([Bin1,random_bytes(8-N)])
1027
 
                   end,
1028
 
            EncBin = crypto:des3_cbc_encrypt(K1, K2, K3, IVec, Bin2),
1029
 
            case file:write_file(EncryptFileName, EncBin) of
1030
 
                ok ->
1031
 
                    io:format("~s --(encrypt)--> ~s~n", 
1032
 
                              [SrcFileName,EncryptFileName]),
1033
 
                    ok;
1034
 
                {error,Reason} ->
1035
 
                    {error,{Reason,EncryptFileName}}
1036
 
            end;
1037
 
        {error,Reason} ->
1038
 
            {error,{Reason,SrcFileName}}
1039
 
    end.                    
1040
 
 
1041
 
%%%-----------------------------------------------------------------
1042
 
%%% @spec 
1043
 
%%%
1044
 
%%% @doc
1045
 
decrypt_config_file(EncryptFileName, TargetFileName) ->
1046
 
    case get_crypt_key_from_file() of
1047
 
        {error,_} = E ->
1048
 
            E;
1049
 
        Key ->
1050
 
            decrypt_config_file(EncryptFileName, TargetFileName, {key,Key})
1051
 
    end.
1052
 
    
1053
 
 
1054
 
%%%-----------------------------------------------------------------
1055
 
%%% @spec 
1056
 
%%%
1057
 
%%% @doc
1058
 
decrypt_config_file(EncryptFileName, TargetFileName, {file,KeyFile}) ->
1059
 
    case get_crypt_key_from_file(KeyFile) of
1060
 
        {error,_} = E ->
1061
 
            E;
1062
 
        Key ->
1063
 
            decrypt_config_file(EncryptFileName, TargetFileName, {key,Key})
1064
 
    end;
1065
 
 
1066
 
decrypt_config_file(EncryptFileName, TargetFileName, {key,Key}) ->
1067
 
    crypto:start(),
1068
 
    {K1,K2,K3,IVec} = make_crypto_key(Key),
1069
 
    case file:read_file(EncryptFileName) of
1070
 
        {ok,Bin} ->
1071
 
            DecBin = crypto:des3_cbc_decrypt(K1, K2, K3, IVec, Bin),
1072
 
            case catch binary_to_term(DecBin) of
1073
 
                {'EXIT',_} ->
1074
 
                    {error,bad_file};
1075
 
                {_SrcFile,SrcBin} ->
1076
 
                    case TargetFileName of
1077
 
                        undefined ->
1078
 
                            {ok,SrcBin};
1079
 
                        _ ->                                      
1080
 
                            case file:write_file(TargetFileName, SrcBin) of
1081
 
                                ok ->
1082
 
                                    io:format("~s --(decrypt)--> ~s~n", 
1083
 
                                              [EncryptFileName,TargetFileName]),
1084
 
                                    ok;
1085
 
                                {error,Reason} ->
1086
 
                                    {error,{Reason,TargetFileName}}
1087
 
                            end
1088
 
                    end
1089
 
            end;
1090
 
        {error,Reason} ->
1091
 
            {error,{Reason,EncryptFileName}}
1092
 
    end.
1093
 
 
1094
 
 
1095
 
get_crypt_key_from_file(File) ->
1096
 
    case file:read_file(File) of
1097
 
        {ok,Bin} ->
1098
 
            case catch string:tokens(binary_to_list(Bin), [$\n,$\r]) of
1099
 
                [Key] ->
1100
 
                    Key;
1101
 
                _ ->
1102
 
                    {error,{bad_crypt_file,File}}
1103
 
            end;
1104
 
        {error,Reason} ->
1105
 
            {error,{Reason,File}}
1106
 
    end.
1107
 
 
1108
 
get_crypt_key_from_file() ->
1109
 
    CwdFile = filename:join(".",?cryptfile),
1110
 
    {Result,FullName} =
1111
 
        case file:read_file(CwdFile) of
1112
 
            {ok,Bin} ->
1113
 
                {Bin,CwdFile};
1114
 
            _ ->
1115
 
                case init:get_argument(home) of
1116
 
                    {ok,[[Home]]} ->
1117
 
                        HomeFile = filename:join(Home,?cryptfile),
1118
 
                        case file:read_file(HomeFile) of
1119
 
                            {ok,Bin} ->
1120
 
                                {Bin,HomeFile};
1121
 
                            _ ->
1122
 
                                {{error,no_crypt_file},noent}
1123
 
                        end;
1124
 
                    _ ->
1125
 
                        {{error,no_crypt_file},noent}
1126
 
                end
1127
 
        end,
1128
 
    case FullName of
1129
 
        noent ->
1130
 
            Result;
1131
 
        _ ->
1132
 
            case catch string:tokens(binary_to_list(Result), [$\n,$\r]) of
1133
 
                [Key] ->
1134
 
                    io:format("~nCrypt key file: ~s~n", [FullName]),
1135
 
                    Key;
1136
 
                _ ->
1137
 
                    {error,{bad_crypt_file,FullName}}
1138
 
            end
1139
 
    end.
1140
 
 
1141
 
make_crypto_key(String) ->
1142
 
    <<K1:8/binary,K2:8/binary>> = First = erlang:md5(String),
1143
 
    <<K3:8/binary,IVec:8/binary>> = erlang:md5([First|lists:reverse(String)]),
1144
 
    {K1,K2,K3,IVec}.
1145
 
 
1146
 
random_bytes(N) ->
1147
 
    {A,B,C} = now(),
1148
 
    random:seed(A, B, C),
1149
 
    random_bytes_1(N, []).
1150
 
 
1151
 
random_bytes_1(0, Acc) -> Acc;
1152
 
random_bytes_1(N, Acc) -> random_bytes_1(N-1, [random:uniform(255)|Acc]).
1153
 
 
1154
 
 
1155
 
%%%-----------------------------------------------------------------
1156
 
%%% @spec 
1157
 
%%%
1158
 
%%% @doc
1159
683
get_attached(TCPid) ->
1160
684
    case dbg_iserver:safe_call({get_attpid,TCPid}) of
1161
685
        {ok,AttPid} when is_pid(AttPid) ->
1210
734
    ct_util_server ! {Msg,{self(),Ref}},
1211
735
    receive
1212
736
        {Ref, Result} -> 
1213
 
            erlang:demonitor(MRef),
 
737
            erlang:demonitor(MRef, [flush]),
1214
738
            Result;
1215
739
        {'DOWN',MRef,process,_,Reason}  -> 
1216
740
            {error,{ct_util_server_down,Reason}}
1219
743
return({To,Ref},Result) ->
1220
744
    To ! {Ref, Result}.
1221
745
 
 
746
cast(Msg) ->
 
747
    ct_util_server ! {Msg, {ct_util_server, make_ref()}}.
 
748
 
1222
749
seconds(T) ->
1223
750
    test_server:seconds(T).
1224
751
 
1244
771
            From ! {self(),N},
1245
772
            ct_make_ref_loop(N+1)
1246
773
    end.
1247
 
 
1248
 
get_ref_from_name(Name) ->
1249
 
    case ets:select(?attr_table,[{#ct_conf{name=Name,ref='$1',_='_'},
1250
 
                                  [],
1251
 
                                  ['$1']}]) of
1252
 
        [Ref] ->
1253
 
            {ok,Ref};
1254
 
        _ ->
1255
 
            {error,{no_such_name,Name}}
1256
 
    end.
1257
 
    
1258
 
get_name_from_ref(Ref) ->
1259
 
    case ets:select(?attr_table,[{#ct_conf{name='$1',ref=Ref,_='_'},
1260
 
                                  [],
1261
 
                                  ['$1']}]) of
1262
 
        [Name] ->
1263
 
            {ok,Name};
1264
 
        _ ->
1265
 
            {error,{no_such_ref,Ref}}
1266
 
    end.
1267
 
    
1268
 
get_key_from_name(Name) ->
1269
 
    case ets:select(?attr_table,[{#ct_conf{name=Name,key='$1',_='_'},
1270
 
                                  [],
1271
 
                                  ['$1']}]) of
1272
 
        [Key|_] ->
1273
 
            {ok,Key};
1274
 
        _ ->
1275
 
            {error,{no_such_name,Name}}
1276
 
    end.
1277
 
 
1278
774
   
1279
775
abs_name(Dir0) ->
1280
776
    Abs = filename:absname(Dir0),