tizen 2.4 release
[framework/security/key-manager.git] / tools / ckm_so_loader.cpp
1 /*
2  *  Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License
15  */
16 /*
17  * @file       ckm_so_loader.cpp
18  * @author     Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
19  * @version    1.0
20  */
21
22 #include <dlfcn.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <sys/types.h>
27 #include <sys/wait.h>
28
29 #include <iostream>
30 #include <fstream>
31 #include <string>
32 #include <chrono>
33
34 using namespace std;
35
36 enum {
37     CLEAR_CACHE = 1,
38     LAZY = 2
39 };
40
41 void clear_cache()
42 {
43     sync();
44     ofstream of("/proc/sys/vm/drop_caches");
45     if (of.bad()) {
46         cerr << "Cache clearing failed: " << strerror(errno) << endl;
47         return;
48     }
49     of << "3";
50 }
51
52 void test(int flags, const string& library, const string& symbol)
53 {
54     bool lazy = (flags & LAZY);
55     if (flags & CLEAR_CACHE)
56         clear_cache();
57
58     chrono::time_point<chrono::high_resolution_clock> tp[4];
59
60     tp[0] = chrono::high_resolution_clock::now();
61     void* handle = dlopen(library.c_str(), (lazy?RTLD_LAZY:RTLD_NOW));
62     tp[1] = chrono::high_resolution_clock::now();
63     if (!handle) {
64         cerr << "dlopen failed: " << dlerror() << endl;
65         exit(1);
66     }
67
68     if (!symbol.empty())
69     {
70         tp[2] = chrono::high_resolution_clock::now();
71         void* sym = dlsym(handle, symbol.c_str());
72         tp[3] = chrono::high_resolution_clock::now();
73         if (!sym) {
74             cerr << "dlsym failed: " << dlerror() << endl;
75             exit(1);
76         }
77     }
78     dlclose(handle);
79
80     cout << (tp[1] - tp[0]).count() << ";" << (tp[3] - tp[2]).count() << endl;
81 }
82
83 int main(int argc, char* argv[])
84 {
85     if (argc < 5) {
86         cerr << "Usage: ckm_so_loader [flags] [repeats] [library] [symbol]" << endl;
87         cerr << " flags: 1-clear cache, 2-lazy binding" << endl;
88         cerr << "Example: ckm_so_loader 3 100 /usr/lib/libkey-manager-client.so ckmc_save_key" << endl;
89         return -1;
90     }
91
92     int flags = stoi(argv[1]); // let it throw
93     int repeats = stoi(argv[2]); // let it throw
94     string so_path(argv[3]);
95     string symbol(argv[4]);
96
97     /*
98      *  perform sanity check of user input string
99      *  which will be used for dlopen
100      */
101     if (so_path.compare(so_path.size() - 3, 3, ".so")
102         && so_path.compare(so_path.size() - 5, 3, ".so")
103         && so_path.compare(so_path.size() - 9, 3, ".so")) {
104         cerr << "[" << so_path << "] doesn't has .so postfix." << endl;
105         return -1;
106     }
107     if (access(so_path.c_str(), R_OK)) {
108         cerr << "cannot read [" << so_path << "]" << endl;
109         return -1;
110     }
111
112     cout << "dlopen[us];dlsym[us]" << endl;
113     for (int cnt = 0 ; cnt < repeats; cnt++)
114     {
115         /*
116          *  It has to be a different process each time. Glibc somehow caches the library information
117          *  and consecutive calls are faster
118          */
119         pid_t pid = fork();
120         if (pid < 0) {
121             cerr << "fork failed: " << strerror(errno) << endl;
122             return -1;
123         }
124         if (pid == 0) {
125             test(flags, so_path, symbol);
126             exit(0);
127         }
128         else
129         {
130             int status;
131             pid_t ret = waitpid(pid,&status, 0);
132             if (ret != pid) {
133                 cerr << "waitpid failed: " << strerror(errno) << endl;
134                 exit(1);
135             }
136         }
137     }
138     return 0;
139 }