1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include <cstdlib>
16 #include <getopt.h>
17 #include <iostream>
18 #include <iomanip>
19 #include <ctime>
20 #include <functional>
21 #include <string_ex.h>
22 #include <securec.h>
23 #include <list>
24
25 #include <hilog/log.h>
26 #include <hilog_common.h>
27 #include <log_utils.h>
28 #include <log_ioctl.h>
29 #include <log_print.h>
30 #include <properties.h>
31
32 #include "log_display.h"
33
34 namespace OHOS {
35 namespace HiviewDFX {
36 using namespace std;
FormatHelper()37 static void FormatHelper()
38 {
39 cout
40 << " -v <format>, --format=<format>" << endl
41 << " Show logs in different formats, options are:" << endl
42 << " color or colour display colorful logs by log level.i.e." << endl
43 << " \x1B[38;5;75mDEBUG \x1B[38;5;40mINFO \x1B[38;5;166mWARN"
44 << " \x1B[38;5;196mERROR \x1B[38;5;226mFATAL\x1B[0m" << endl
45 << " time format options are(single accepted):" << endl
46 << " time display local time, this is default." << endl
47 << " epoch display the time from 1970/1/1." << endl
48 << " monotonic display the cpu time from bootup." << endl
49 << " time accuracy format options are(single accepted):" << endl
50 << " msec display time by millisecond, this is default." << endl
51 << " usec display time by microsecond." << endl
52 << " nsec display time by nanosecond." << endl
53 << " year display the year when -v time is specified." << endl
54 << " zone display the time zone when -v time is specified." << endl
55 << " wrap display the log without prefix when a log line is wrapped." << endl
56 << " Different types of formats can be combined, such as:" << endl
57 << " -v color -v time -v msec -v year -v zone." << endl;
58 }
59
QueryHelper()60 static void QueryHelper()
61 {
62 cout
63 << "Querying logs options:" << endl
64 << " No option performs a blocking read and keeps printing." << endl
65 << " -x --exit" << endl
66 << " Performs a non-blocking read and exits when all logs in buffer are printed." << endl
67 << " -a <n>, --head=<n>" << endl
68 << " Show n lines logs on head of buffer." << endl
69 << " -z <n>, --tail=<n>" << endl
70 << " Show n lines logs on tail of buffer." << endl
71 << " -t <type>, --type=<type>" << endl
72 << " Show specific type/types logs with format: type1,type2,type3" << endl
73 << " Don't show specific type/types logs with format: ^type1,type2,type3" << endl
74 << " Type coule be: app/core/init/kmsg/only_prerelease, kmsg can't combine with others." << endl
75 << " Default types are: app,core,init,only_prerelease." << endl
76 << " -L <level>, --level=<level>" << endl
77 << " Show specific level/levels logs with format: level1,level2,level3" << endl
78 << " Don't show specific level/levels logs with format: ^level1,level2,level3" << endl
79 << " Long and short level string are both accepted" << endl
80 << " Long level string coule be: DEBUG/INFO/WARN/ERROR/FATAL." << endl
81 << " Short level string coule be: D/I/W/E/F." << endl
82 << " Default levels are all levels." << endl
83 << " -D <domain>, --domain=<domain>" << endl
84 << " Show specific domain/domains logs with format: domain1,domain2,doman3" << endl
85 << " Don't show specific domain/domains logs with format: ^domain1,domain2,doman3" << endl
86 << " Max domain count is " << MAX_DOMAINS << "." << endl
87 << " See domain description at the end of this message." << endl
88 << " -T <tag>, --tag=<tag>" << endl
89 << " Show specific tag/tags logs with format: tag1,tag2,tag3" << endl
90 << " Don't show specific tag/tags logs with format: ^tag1,tag2,tag3" << endl
91 << " Max tag count is " << MAX_TAGS << "." << endl
92 << " -P <pid>, --pid=<pid>" << endl
93 << " Show specific pid/pids logs with format: pid1,pid2,pid3" << endl
94 << " Don't show specific domain/domains logs with format: ^pid1,pid2,pid3" << endl
95 << " Max pid count is " << MAX_PIDS << "." << endl
96 << " -e <expr>, --regex=<expr>" << endl
97 << " Show the logs which match the regular expression <expr>." << endl;
98 FormatHelper();
99 }
100
ClearHelper()101 static void ClearHelper()
102 {
103 cout
104 << "-r" << endl
105 << " Remove all logs in hilogd buffer, advanced option:" << endl
106 << " -t <type>, --type=<type>" << endl
107 << " Remove specific type/types logs in buffer with format: type1,type2,type3" << endl
108 << " Type coule be: app/core/init/kmsg/only_prerelease." << endl
109 << " Default types are: app,core,only_prerelease" << endl;
110 }
111
BufferHelper()112 static void BufferHelper()
113 {
114 cout
115 << "-g" << endl
116 << " Query hilogd buffer size, advanced option:" << endl
117 << " -t <type>, --type=<type>" << endl
118 << " Query specific type/types buffer size with format: type1,type2,type3" << endl
119 << " Type coule be: app/core/init/kmsg/only_prerelease." << endl
120 << " Default types are: app,core,only_prerelease" << endl
121 << "-G <size>, --buffer-size=<size>" << endl
122 << " Set hilogd buffer size, <size> could be number or number with unit." << endl
123 << " Unit could be: B/K/M/G which represents Byte/Kilobyte/Megabyte/Gigabyte." << endl
124 << " <size> range: [" << Size2Str(MIN_BUFFER_SIZE) << "," << Size2Str(MAX_BUFFER_SIZE) << "]." << endl
125 << " Advanced option:" << endl
126 << " -t <type>, --type=<type>" << endl
127 << " Set specific type/types log buffer size with format: type1,type2,type3" << endl
128 << " Type coule be: app/core/init/kmsg/only_prerelease." << endl
129 << " Default types are: app,core,only_prerelease" << endl
130 << " **It's a persistant configuration**" << endl;
131 }
132
StatisticHelper()133 static void StatisticHelper()
134 {
135 cout
136 << "-s, --statistics" << endl
137 << " Query log statistic information." << endl
138 << " Set param persist.sys.hilog.stats true to enable statistic." << endl
139 << " Set param persist.sys.hilog.stats.tag true to enable statistic of log tag." << endl
140 << "-S" << endl
141 << " Clear hilogd statistic information." << endl;
142 }
143
PersistTaskHelper()144 static void PersistTaskHelper()
145 {
146 cout
147 << "-w <control>,--write=<control>" << endl
148 << " Log persistance task control, options are:" << endl
149 << " query query tasks informations" << endl
150 << " stop stop all tasks" << endl
151 << " start start one task" << endl
152 << " refresh refresh buffer content to file" << endl
153 << " clear clear /data/log/hilog/hilog*.gz" << endl
154 << " Persistance task is used for saving logs in files." << endl
155 << " The files are saved in directory: " << HILOG_FILE_DIR << endl
156 << " Advanced options:" << endl
157 << " -f <filename>, --filename=<filename>" << endl
158 << " Set log file name, name should be valid of Linux FS." << endl
159 << " -l <length>, --length=<length>" << endl
160 << " Set single log file size. <length> could be number or number with unit." << endl
161 << " Unit could be: B/K/M/G which represents Byte/Kilobyte/Megabyte/Gigabyte." << endl
162 << " <length> range: [" << Size2Str(MIN_LOG_FILE_SIZE) <<", " << Size2Str(MAX_LOG_FILE_SIZE) << "]." << endl
163 << " -n <number>, --number<number>" << endl
164 << " Set max log file numbers, log file rotate when files count over this number." << endl
165 << " <number> range: [" << MIN_LOG_FILE_NUM << ", " << MAX_LOG_FILE_NUM << "]." << endl
166 << " -m <compress algorithm>,--stream=<compress algorithm>" << endl
167 << " Set log file compressed algorithm, options are:" << endl
168 << " none write file with non-compressed logs." << endl
169 << " zlib write file with zlib compressed logs." << endl
170 << " -j <jobid>, --jobid<jobid>" << endl
171 << " Start/stop specific task of <jobid>." << endl
172 << " <jobid> range: [" << JOB_ID_MIN << ", 0x" << hex << JOB_ID_MAX << dec << ")." << endl
173 << " User can start task with options (t/L/D/T/P/e/v) as if using them when \"Query logs\" too." << endl
174 << " **It's a persistant configuration**" << endl;
175 }
176
PrivateHelper()177 static void PrivateHelper()
178 {
179 cout
180 << "-p <on/off>, --privacy <on/off>" << endl
181 << " Set HILOG api privacy formatter feature on or off." << endl
182 << " **It's a temporary configuration, will be lost after reboot**" << endl;
183 }
184
KmsgHelper()185 static void KmsgHelper()
186 {
187 cout
188 << "-k <on/off>, --kmsg <on/off>" << endl
189 << " Set hilogd storing kmsg log feature on or off" << endl
190 << " **It's a persistant configuration**" << endl;
191 }
192
FlowControlHelper()193 static void FlowControlHelper()
194 {
195 cout
196 << "-Q <control-type>" << endl
197 << " Set log flow-control feature on or off, options are:" << endl
198 << " pidon process flow control on" << endl
199 << " pidoff process flow control off" << endl
200 << " domainon domain flow control on" << endl
201 << " domainoff domain flow control off" << endl
202 << " **It's a temporary configuration, will be lost after reboot**" << endl;
203 }
204
BaseLevelHelper()205 static void BaseLevelHelper()
206 {
207 cout
208 << "-b <loglevel>, --baselevel=<loglevel>" << endl
209 << " Set global loggable level to <loglevel>" << endl
210 << " Long and short level string are both accepted." << endl
211 << " Long level string coule be: DEBUG/INFO/WARN/ERROR/FATAL/X." << endl
212 << " Short level string coule be: D/I/W/E/F/X." << endl
213 << " X means that loggable level is higher than the max level, no log could be printed." << endl
214 << " Advanced options:" << endl
215 << " -D <domain>, --domain=<domain>" << endl
216 << " Set specific domain loggable level." << endl
217 << " See domain description at the end of this message." << endl
218 << " -T <tag>, --tag=<tag>" << endl
219 << " Set specific tag loggable level." << endl
220 << " The priority is: tag level > domain level > global level." << endl
221 << " **It's a temporary configuration, will be lost after reboot**" << endl
222 << " --persist" << endl
223 << " Set persist configuration." << endl
224 << " The priority is: tag level > persist tag level > domain level > persist domain level > global level"
225 " > persist global level." << endl;
226 }
227
DomainHelper()228 static void DomainHelper()
229 {
230 cout
231 << endl << endl
232 << "Domain description:" << endl
233 << " Log type \"core\" & \"init\" & \"only_prerelease\" are used for OS subsystems, the range is"
234 << " [0x" << hex << DOMAIN_OS_MIN << ", 0x" << DOMAIN_OS_MAX << "]" << endl
235 << " Log type \"app\" is used for applications, the range is [0x" << DOMAIN_APP_MIN << ","
236 << " 0x" << DOMAIN_APP_MAX << "]" << dec << endl
237 << " To reduce redundant info when printing logs, only last five hex numbers of domain are printed" << endl
238 << " So if user wants to use -D option to filter OS logs, user should add 0xD0 as prefix to the printed domain:"
239 << endl
240 << " Exapmle: hilog -D 0xD0xxxxx" << endl
241 << " The xxxxx is the domain string printed in logs." << endl;
242 }
243
ComboHelper()244 static void ComboHelper()
245 {
246 cout
247 << "The first layer options can't be used in combination, ILLEGAL expamples:" << endl
248 << " hilog -S -s; hilog -w start -r; hilog -p on -k on -b D" << endl;
249 }
250
251 using HelperFunc = std::function<void()>;
252 static const std::list<pair<string, HelperFunc>> g_HelperList = {
253 {"query", QueryHelper},
254 {"clear", ClearHelper},
255 {"buffer", BufferHelper},
256 {"stats", StatisticHelper},
257 {"persist", PersistTaskHelper},
258 {"private", PrivateHelper},
259 {"kmsg", KmsgHelper},
260 {"flowcontrol", FlowControlHelper},
261 {"baselevel", BaseLevelHelper},
262 {"combo", ComboHelper},
263 {"domain", DomainHelper},
264 };
265
Helper(const string & arg)266 static void Helper(const string& arg)
267 {
268 cout << "Usage:" << endl
269 << "-h --help" << endl
270 << " Show all help information." << endl
271 << " Show single help information with option: " << endl
272 << " query/clear/buffer/stats/persist/private/kmsg/flowcontrol/baselevel/domain/combo" << endl;
273 for (auto &it : g_HelperList) {
274 if (arg == "" || arg == it.first) {
275 it.second();
276 }
277 }
278 return;
279 }
280
PrintErr(int error)281 static void PrintErr(int error)
282 {
283 cerr << ErrorCode2Str(error) << endl;
284 }
285
PrintResult(int ret,const string & msg)286 static void PrintResult(int ret, const string& msg)
287 {
288 cout << msg << ((ret == RET_SUCCESS) ? " successfully" : " failed") << endl;
289 }
290
291 enum class ControlCmd {
292 NOT_CMD = -1,
293 CMD_HELP = 0,
294 CMD_QUERY,
295 CMD_REMOVE,
296 CMD_BUFFER_SIZE_QUERY,
297 CMD_BUFFER_SIZE_SET,
298 CMD_STATS_INFO_QUERY,
299 CMD_STATS_INFO_CLEAR,
300 CMD_PERSIST_TASK,
301 CMD_PRIVATE_FEATURE_SET,
302 CMD_KMSG_FEATURE_SET,
303 CMD_FLOWCONTROL_FEATURE_SET,
304 CMD_LOGLEVEL_SET,
305 };
306
307 struct HilogArgs {
308 uint16_t headLines = 0;
309 uint16_t baseLevel = 0;
310 bool blackDomain = false;
311 int domainCount = 0;
312 uint32_t domains[MAX_DOMAINS] = {0};
313 string regex = "";
314 string fileName = "";
315 int32_t buffSize = 0;
316 uint32_t jobId = 0;
317 uint32_t fileSize = 0;
318 uint16_t levels = 0;
319 string stream = "";
320 uint16_t fileNum = 0;
321 bool persist = false;
322 bool blackPid = false;
323 int pidCount = 0;
324 uint32_t pids[MAX_PIDS] = {0};
325 uint16_t types = 0;
326 bool blackTag = false;
327 int tagCount = 0;
328 string tags[MAX_TAGS] = {""};
329 bool colorful = false;
330 FormatTime timeFormat = FormatTime::INVALID;
331 FormatTimeAccu timeAccuFormat = FormatTimeAccu::INVALID;
332 bool year = false;
333 bool zone = false;
334 bool wrap = false;
335 bool noBlock = false;
336 uint16_t tailLines = 0;
337
ToOutputRqstOHOS::HiviewDFX::HilogArgs338 void ToOutputRqst(OutputRqst& rqst)
339 {
340 rqst.headLines = headLines;
341 rqst.types = types;
342 rqst.levels = levels;
343 rqst.blackDomain = blackDomain;
344 rqst.domainCount = static_cast<uint8_t>(domainCount);
345 int i;
346 for (i = 0; i < domainCount; i++) {
347 rqst.domains[i] = domains[i];
348 }
349 rqst.blackTag = blackTag;
350 rqst.tagCount = tagCount;
351 for (i = 0; i < tagCount; i++) {
352 (void)strncpy_s(rqst.tags[i], MAX_TAG_LEN, tags[i].c_str(), tags[i].length());
353 }
354 rqst.blackPid = blackPid;
355 rqst.pidCount = pidCount;
356 for (i = 0; i < pidCount; i++) {
357 rqst.pids[i] = pids[i];
358 }
359 (void)strncpy_s(rqst.regex, MAX_REGEX_STR_LEN, regex.c_str(), regex.length());
360 rqst.noBlock = noBlock;
361 rqst.tailLines = tailLines;
362 }
363
ToPersistStartRqstOHOS::HiviewDFX::HilogArgs364 void ToPersistStartRqst(PersistStartRqst& rqst)
365 {
366 ToOutputRqst(rqst.outputFilter);
367 rqst.jobId = jobId;
368 rqst.fileNum = fileNum;
369 rqst.fileSize = fileSize;
370 (void)strncpy_s(rqst.fileName, MAX_FILE_NAME_LEN, fileName.c_str(), fileName.length());
371 (void)strncpy_s(rqst.stream, MAX_STREAM_NAME_LEN, stream.c_str(), stream.length());
372 }
373
ToPersistStopRqstOHOS::HiviewDFX::HilogArgs374 void ToPersistStopRqst(PersistStopRqst& rqst)
375 {
376 rqst.jobId = jobId;
377 }
378
ToBufferSizeSetRqstOHOS::HiviewDFX::HilogArgs379 void ToBufferSizeSetRqst(BufferSizeSetRqst& rqst)
380 {
381 rqst.types = types;
382 rqst.size = buffSize;
383 }
384
ToBufferSizeGetRqstOHOS::HiviewDFX::HilogArgs385 void ToBufferSizeGetRqst(BufferSizeGetRqst& rqst)
386 {
387 rqst.types = types;
388 }
389
ToStatsQueryRqstOHOS::HiviewDFX::HilogArgs390 void ToStatsQueryRqst(StatsQueryRqst& rqst)
391 {
392 rqst.types = types;
393 rqst.domainCount = static_cast<uint8_t>(domainCount);
394 int i;
395 for (i = 0; i < domainCount; i++) {
396 rqst.domains[i] = domains[i];
397 }
398 }
399
ToLogRemoveRqstOHOS::HiviewDFX::HilogArgs400 void ToLogRemoveRqst(LogRemoveRqst& rqst)
401 {
402 rqst.types = types;
403 }
404 };
405
406 using OptHandler = std::function<int(HilogArgs& context, const char *arg)>;
407
QueryLogHandler(HilogArgs & context,const char * arg)408 static int QueryLogHandler(HilogArgs& context, const char *arg)
409 {
410 OutputRqst rqst = { 0 };
411 context.ToOutputRqst(rqst);
412 LogIoctl ioctl(IoctlCmd::OUTPUT_RQST, IoctlCmd::OUTPUT_RSP);
413 int ret = ioctl.RequestOutput(rqst, [&context](const OutputRsp& rsp) {
414 if (rsp.end) {
415 return RET_SUCCESS;
416 }
417 LogContent content = {
418 .level = rsp.level,
419 .type = rsp.type,
420 .pid = rsp.pid,
421 .tid = rsp.tid,
422 .domain = rsp.domain,
423 .tv_sec = rsp.tv_sec,
424 .tv_nsec = rsp.tv_nsec,
425 .mono_sec = rsp.mono_sec,
426 .tag = rsp.data,
427 .log = (rsp.data + rsp.tagLen)
428 };
429 LogFormat format = {
430 .colorful = context.colorful,
431 .timeFormat = ((context.timeFormat == FormatTime::INVALID) ? FormatTime::TIME : context.timeFormat),
432 .timeAccuFormat =
433 ((context.timeAccuFormat == FormatTimeAccu::INVALID) ? FormatTimeAccu::MSEC : context.timeAccuFormat),
434 .year = context.year,
435 .zone = context.zone,
436 .wrap = context.wrap
437 };
438 LogPrintWithFormat(content, format);
439 return static_cast<int>(SUCCESS_CONTINUE);
440 });
441 if (ret != RET_SUCCESS) {
442 return ret;
443 }
444 return RET_SUCCESS;
445 }
446
HeadHandler(HilogArgs & context,const char * arg)447 static int HeadHandler(HilogArgs& context, const char *arg)
448 {
449 if (IsNumericStr(arg) == false) {
450 return ERR_NOT_NUMBER_STR;
451 }
452 int lines = 0;
453 (void)StrToInt(arg, lines);
454 context.headLines = static_cast<uint16_t>(lines);
455 context.noBlock = true; // don't block implicitly
456 return QueryLogHandler(context, arg);
457 }
458
BaseLogLevelHandler(HilogArgs & context,const char * arg)459 static int BaseLogLevelHandler(HilogArgs& context, const char *arg)
460 {
461 uint16_t baseLevel = PrettyStr2LogLevel(arg);
462 if (baseLevel == LOG_LEVEL_MIN) {
463 return ERR_LOG_LEVEL_INVALID;
464 }
465 context.baseLevel = baseLevel;
466 int ret;
467 if (context.domainCount == 0 && context.tagCount == 0) {
468 ret = SetGlobalLevel(context.baseLevel);
469 PrintResult(ret, (string("Set global log level to ") + arg));
470 if (context.persist) {
471 ret = SetPersistGlobalLevel(context.baseLevel);
472 PrintResult(ret, (string("Set persist global log level to ") + arg));
473 }
474 }
475 if (context.domainCount != 0) {
476 for (int i = 0; i < context.domainCount; i++) {
477 ret = SetDomainLevel(context.domains[i], context.baseLevel);
478 PrintResult(ret, (string("Set domain 0x") + Uint2HexStr(context.domains[i]) + " log level to " + arg));
479 if (context.persist) {
480 ret = SetPersistDomainLevel(context.domains[i], context.baseLevel);
481 PrintResult(ret, (string("Set persist domain 0x") +
482 Uint2HexStr(context.domains[i]) + " log level to " + arg));
483 }
484 }
485 }
486 if (context.tagCount != 0) {
487 for (int i = 0; i < context.tagCount; i++) {
488 ret = SetTagLevel(context.tags[i], context.baseLevel);
489 PrintResult(ret, (string("Set tag ") + context.tags[i] + " log level to " + arg));
490 if (context.persist) {
491 ret = SetPersistTagLevel(context.tags[i], context.baseLevel);
492 PrintResult(ret, (string("Set persist tag ") + context.tags[i] + " log level to " + arg));
493 }
494 }
495 }
496 return RET_SUCCESS;
497 }
498
499 static constexpr char BLACK_PREFIX = '^';
DomainHandler(HilogArgs & context,const char * arg)500 static int DomainHandler(HilogArgs& context, const char *arg)
501 {
502 context.blackDomain = (arg[0] == BLACK_PREFIX);
503 std::vector<std::string> domains;
504 Split(context.blackDomain ? arg + 1 : arg, domains);
505 if (domains.size() == 0) {
506 return ERR_INVALID_ARGUMENT;
507 }
508 int index = 0;
509 for (string d : domains) {
510 if (index >= MAX_DOMAINS) {
511 return ERR_TOO_MANY_DOMAINS;
512 }
513 bool success = false;
514 uint32_t domain = HexStr2Uint(d, success);
515 if (!success) {
516 return ERR_INVALID_DOMAIN_STR;
517 }
518 if (((domain >= DOMAIN_APP_MIN) && (domain <= DOMAIN_APP_MAX)) ||
519 ((domain >= DOMAIN_OS_MIN) && (domain <= DOMAIN_OS_MAX))) {
520 context.domains[index++] = domain;
521 } else {
522 return ERR_INVALID_DOMAIN_STR;
523 }
524 }
525 context.domainCount = index;
526 return RET_SUCCESS;
527 }
528
RegexHandler(HilogArgs & context,const char * arg)529 static int RegexHandler(HilogArgs& context, const char *arg)
530 {
531 context.regex = arg;
532 if (context.regex.length() >= MAX_REGEX_STR_LEN) {
533 return ERR_REGEX_STR_TOO_LONG;
534 }
535 return RET_SUCCESS;
536 }
537
PersistHandler(HilogArgs & context,const char * arg)538 static int PersistHandler(HilogArgs& context, const char *arg)
539 {
540 context.persist = true;
541 return RET_SUCCESS;
542 }
543
FileNameHandler(HilogArgs & context,const char * arg)544 static int FileNameHandler(HilogArgs& context, const char *arg)
545 {
546 context.fileName = arg;
547 if (context.fileName.length() >= MAX_FILE_NAME_LEN) {
548 return ERR_FILE_NAME_TOO_LONG;
549 }
550 return RET_SUCCESS;
551 }
552
BufferSizeGetHandler(HilogArgs & context,const char * arg)553 static int BufferSizeGetHandler(HilogArgs& context, const char *arg)
554 {
555 BufferSizeGetRqst rqst = { 0 };
556 context.ToBufferSizeGetRqst(rqst);
557 LogIoctl ioctl(IoctlCmd::BUFFERSIZE_GET_RQST, IoctlCmd::BUFFERSIZE_GET_RSP);
558 int ret = ioctl.Request<BufferSizeGetRqst, BufferSizeGetRsp>(rqst, [&rqst](const BufferSizeGetRsp& rsp) {
559 for (uint16_t i = 0; i < static_cast<uint16_t>(LOG_TYPE_MAX); i++) {
560 if (rsp.size[i] > 0) {
561 cout << "Log type " << LogType2Str(i) << " buffer size is " << Size2Str(rsp.size[i]) << endl;
562 }
563 }
564 return RET_SUCCESS;
565 });
566 if (ret != RET_SUCCESS) {
567 cout << "Get " << ComboLogType2Str(rqst.types) << " buffer size failed" << endl;
568 }
569 return ret;
570 }
571
BufferSizeSetHandler(HilogArgs & context,const char * arg)572 static int BufferSizeSetHandler(HilogArgs& context, const char *arg)
573 {
574 uint64_t size = Str2Size(arg);
575 if (size == 0) {
576 return ERR_INVALID_SIZE_STR;
577 }
578 context.buffSize = static_cast<int32_t>(size);
579 BufferSizeSetRqst rqst;
580 context.ToBufferSizeSetRqst(rqst);
581 LogIoctl ioctl(IoctlCmd::BUFFERSIZE_SET_RQST, IoctlCmd::BUFFERSIZE_SET_RSP);
582 int ret = ioctl.Request<BufferSizeSetRqst, BufferSizeSetRsp>(rqst, [&rqst](const BufferSizeSetRsp& rsp) {
583 for (uint16_t i = 0; i < static_cast<uint16_t>(LOG_TYPE_MAX); i++) {
584 if (rsp.size[i] > 0) {
585 cout << "Set log type " << LogType2Str(i) << " buffer size to "
586 << Size2Str(rsp.size[i]) << " successfully" << endl;
587 } else if (rsp.size[i] < 0) {
588 cout << "Set log type " << LogType2Str(i) << " buffer size to "
589 << Size2Str(rqst.size) << " failed" << endl;
590 PrintErr(rsp.size[i]);
591 }
592 }
593 return RET_SUCCESS;
594 });
595 if (ret != RET_SUCCESS) {
596 cout << "Set buffer size failed" << endl;
597 }
598 return ret;
599 }
600
HelpHandler(HilogArgs & context,const char * arg)601 static int HelpHandler(HilogArgs& context, const char *arg)
602 {
603 Helper("");
604 return RET_SUCCESS;
605 }
606
JobIdHandler(HilogArgs & context,const char * arg)607 static int JobIdHandler(HilogArgs& context, const char *arg)
608 {
609 if (IsNumericStr(arg) == false) {
610 return ERR_NOT_NUMBER_STR;
611 }
612 int jobId = 0;
613 (void)StrToInt(arg, jobId);
614 context.jobId = static_cast<uint32_t>(jobId);
615 return RET_SUCCESS;
616 }
617
618 static const string FEATURE_ON = "on";
619 static const string FEATURE_OFF = "off";
KmsgFeatureSetHandler(HilogArgs & context,const char * arg)620 static int KmsgFeatureSetHandler(HilogArgs& context, const char *arg)
621 {
622 string argStr = arg;
623 bool kmsgOn = true;
624 if (argStr == FEATURE_ON) {
625 kmsgOn = true;
626 } else if (argStr == FEATURE_OFF) {
627 kmsgOn = false;
628 } else {
629 return ERR_INVALID_ARGUMENT;
630 }
631 KmsgEnableRqst rqst = { kmsgOn };
632 LogIoctl ioctl(IoctlCmd::KMSG_ENABLE_RQST, IoctlCmd::KMSG_ENABLE_RSP);
633 int ret = ioctl.Request<KmsgEnableRqst, KmsgEnableRsp>(rqst, [&rqst](const KmsgEnableRsp& rsp) {
634 return RET_SUCCESS;
635 });
636 PrintResult(ret, (string("Set hilogd storing kmsg log ") + arg));
637 return ret;
638 }
639
FileLengthHandler(HilogArgs & context,const char * arg)640 static int FileLengthHandler(HilogArgs& context, const char *arg)
641 {
642 uint64_t size = Str2Size(arg);
643 if (size == 0) {
644 return ERR_INVALID_SIZE_STR;
645 }
646 context.fileSize = size;
647 return RET_SUCCESS;
648 }
649
LevelHandler(HilogArgs & context,const char * arg)650 static int LevelHandler(HilogArgs& context, const char *arg)
651 {
652 uint16_t levels = Str2ComboLogLevel(arg);
653 if (levels == 0) {
654 return ERR_LOG_LEVEL_INVALID;
655 }
656 context.levels = levels;
657 return RET_SUCCESS;
658 }
659
FileCompressHandler(HilogArgs & context,const char * arg)660 static int FileCompressHandler(HilogArgs& context, const char *arg)
661 {
662 context.stream = arg;
663 return RET_SUCCESS;
664 }
665
FileNumberHandler(HilogArgs & context,const char * arg)666 static int FileNumberHandler(HilogArgs& context, const char *arg)
667 {
668 if (IsNumericStr(arg) == false) {
669 return ERR_NOT_NUMBER_STR;
670 }
671 int fileNum = 0;
672 (void)StrToInt(arg, fileNum);
673 context.fileNum = static_cast<uint16_t>(fileNum);
674 return RET_SUCCESS;
675 }
676
PrivateFeatureSetHandler(HilogArgs & context,const char * arg)677 static int PrivateFeatureSetHandler(HilogArgs& context, const char *arg)
678 {
679 string argStr = arg;
680 bool privateOn = true;
681 if (argStr == FEATURE_ON) {
682 privateOn = true;
683 } else if (argStr == FEATURE_OFF) {
684 privateOn = false;
685 } else {
686 return ERR_INVALID_ARGUMENT;
687 }
688 int ret = SetPrivateSwitchOn(privateOn);
689 PrintResult(ret, (string("Set hilog privacy format ") + arg));
690 return RET_SUCCESS;
691 }
692
PidHandler(HilogArgs & context,const char * arg)693 static int PidHandler(HilogArgs& context, const char *arg)
694 {
695 context.blackPid = (arg[0] == BLACK_PREFIX);
696 std::vector<std::string> pids;
697 Split(context.blackPid ? arg + 1 : arg, pids);
698 if (pids.size() == 0) {
699 return ERR_INVALID_ARGUMENT;
700 }
701 int index = 0;
702 for (string p : pids) {
703 if (index >= MAX_PIDS) {
704 return ERR_TOO_MANY_PIDS;
705 }
706 if (IsNumericStr(p) == false) {
707 return ERR_NOT_NUMBER_STR;
708 }
709 int pid = 0;
710 (void)StrToInt(p, pid);
711 context.pids[index++] = static_cast<uint32_t>(pid);
712 }
713 context.pidCount = index;
714 return RET_SUCCESS;
715 }
716
SetDomainFlowCtrl(bool on)717 static int SetDomainFlowCtrl(bool on)
718 {
719 DomainFlowCtrlRqst rqst = { 0 };
720 rqst.on = on;
721 LogIoctl ioctl(IoctlCmd::DOMAIN_FLOWCTRL_RQST, IoctlCmd::DOMAIN_FLOWCTRL_RSP);
722 int ret = ioctl.Request<DomainFlowCtrlRqst, DomainFlowCtrlRsp>(rqst, [&rqst](const DomainFlowCtrlRsp& rsp) {
723 return RET_SUCCESS;
724 });
725 return ret;
726 }
FlowControlFeatureSetHandler(HilogArgs & context,const char * arg)727 static int FlowControlFeatureSetHandler(HilogArgs& context, const char *arg)
728 {
729 string pid = "pid";
730 string domain = "domain";
731 string argStr = arg;
732 int ret;
733 if (argStr == (pid + FEATURE_ON)) {
734 ret = SetProcessSwitchOn(true);
735 cout << "Set flow control by process to enabled, result: " << ErrorCode2Str(ret) << endl;
736 } else if (argStr == (pid + FEATURE_OFF)) {
737 ret = SetProcessSwitchOn(false);
738 cout << "Set flow control by process to disabled, result: " << ErrorCode2Str(ret) << endl;
739 } else if (argStr == (domain + FEATURE_ON)) {
740 ret = SetDomainFlowCtrl(true);
741 cout << "Set flow control by domain to enabled, result: " << ErrorCode2Str(ret) << endl;
742 } else if (argStr == (domain + FEATURE_OFF)) {
743 ret = SetDomainFlowCtrl(false);
744 cout << "Set flow control by domain to disabled, result: " << ErrorCode2Str(ret) << endl;
745 } else {
746 return ERR_INVALID_ARGUMENT;
747 }
748 return ret;
749 }
750
RemoveHandler(HilogArgs & context,const char * arg)751 static int RemoveHandler(HilogArgs& context, const char *arg)
752 {
753 LogRemoveRqst rqst = { 0 };
754 context.ToLogRemoveRqst(rqst);
755 LogIoctl ioctl(IoctlCmd::LOG_REMOVE_RQST, IoctlCmd::LOG_REMOVE_RSP);
756 int ret = ioctl.Request<LogRemoveRqst, LogRemoveRsp>(rqst, [&rqst](const LogRemoveRsp& rsp) {
757 cout << "Log type " << ComboLogType2Str(rsp.types) << " buffer clear successfully" << endl;
758 return RET_SUCCESS;
759 });
760 if (ret != RET_SUCCESS) {
761 cout << "Log buffer clear failed" << endl;
762 }
763 return ret;
764 }
765
StatsInfoQueryHandler(HilogArgs & context,const char * arg)766 static int StatsInfoQueryHandler(HilogArgs& context, const char *arg)
767 {
768 StatsQueryRqst rqst = { 0 };
769 context.ToStatsQueryRqst(rqst);
770 LogIoctl ioctl(IoctlCmd::STATS_QUERY_RQST, IoctlCmd::STATS_QUERY_RSP);
771 int ret = ioctl.RequestStatsQuery(rqst, [&rqst](const StatsQueryRsp& rsp) {
772 HilogShowLogStatsInfo(rsp);
773 return RET_SUCCESS;
774 });
775 if (ret != RET_SUCCESS) {
776 cout << "Statistic info query failed" << endl;
777 }
778 return ret;
779 }
780
StatsInfoClearHandler(HilogArgs & context,const char * arg)781 static int StatsInfoClearHandler(HilogArgs& context, const char *arg)
782 {
783 StatsClearRqst rqst = { 0 };
784 LogIoctl ioctl(IoctlCmd::STATS_CLEAR_RQST, IoctlCmd::STATS_CLEAR_RSP);
785 int ret = ioctl.Request<StatsClearRqst, StatsClearRsp>(rqst, [&rqst](const StatsClearRsp& rsp) {
786 cout << "Statistic info clear successfully" << endl;
787 return RET_SUCCESS;
788 });
789 if (ret != RET_SUCCESS) {
790 cout << "Statistic info clear failed" << endl;
791 }
792 return ret;
793 }
794
TypeHandler(HilogArgs & context,const char * arg)795 static int TypeHandler(HilogArgs& context, const char *arg)
796 {
797 uint16_t types = Str2ComboLogType(arg);
798 if (types == 0) {
799 return ERR_LOG_TYPE_INVALID;
800 }
801 context.types = types;
802 return RET_SUCCESS;
803 }
804
TagHandler(HilogArgs & context,const char * arg)805 static int TagHandler(HilogArgs& context, const char *arg)
806 {
807 context.blackTag = (arg[0] == BLACK_PREFIX);
808 std::vector<std::string> tags;
809 Split(context.blackTag ? arg + 1 : arg, tags);
810 int index = 0;
811 for (string t : tags) {
812 if (index >= MAX_TAGS) {
813 return ERR_TOO_MANY_TAGS;
814 }
815 if (t.length() >= MAX_TAG_LEN) {
816 return ERR_TAG_STR_TOO_LONG;
817 }
818 context.tags[index++] = t;
819 }
820 context.tagCount = index;
821 return RET_SUCCESS;
822 }
823
TimeHandler(HilogArgs & context,FormatTime value)824 static int TimeHandler(HilogArgs& context, FormatTime value)
825 {
826 if (context.timeFormat != FormatTime::INVALID) {
827 return ERR_DUPLICATE_OPTION;
828 }
829 context.timeFormat = value;
830 return RET_SUCCESS;
831 }
832
TimeAccuHandler(HilogArgs & context,FormatTimeAccu value)833 static int TimeAccuHandler(HilogArgs& context, FormatTimeAccu value)
834 {
835 if (context.timeAccuFormat != FormatTimeAccu::INVALID) {
836 return ERR_DUPLICATE_OPTION;
837 }
838 context.timeAccuFormat = value;
839 return RET_SUCCESS;
840 }
841
FormatHandler(HilogArgs & context,const char * arg)842 static int FormatHandler(HilogArgs& context, const char *arg)
843 {
844 static std::unordered_map<std::string, std::function<int(HilogArgs&, int)>> handlers = {
845 {"color", [] (HilogArgs& context, int value) {
846 context.colorful = true;
847 return RET_SUCCESS;
848 }},
849 {"colour", [] (HilogArgs& context, int value) {
850 context.colorful = true;
851 return RET_SUCCESS;
852 }},
853 {"time", [] (HilogArgs& context, int value) {
854 return TimeHandler(context, FormatTime::TIME);
855 }},
856 {"epoch", [] (HilogArgs& context, int value) {
857 return TimeHandler(context, FormatTime::EPOCH);
858 }},
859 {"monotonic", [] (HilogArgs& context, int value) {
860 return TimeHandler(context, FormatTime::MONOTONIC);
861 }},
862 {"msec", [] (HilogArgs& context, int value) {
863 return TimeAccuHandler(context, FormatTimeAccu::MSEC);
864 }},
865 {"usec", [] (HilogArgs& context, int value) {
866 return TimeAccuHandler(context, FormatTimeAccu::USEC);
867 }},
868 {"nsec", [] (HilogArgs& context, int value) {
869 return TimeAccuHandler(context, FormatTimeAccu::NSEC);
870 }},
871 {"year", [] (HilogArgs& context, int value) {
872 context.year = true;
873 return RET_SUCCESS;
874 }},
875 {"zone", [] (HilogArgs& context, int value) {
876 context.zone = true;
877 tzset();
878 return RET_SUCCESS;
879 }},
880 {"wrap", [] (HilogArgs& context, int value) {
881 context.wrap = true;
882 return RET_SUCCESS;
883 }},
884 };
885
886 auto handler = handlers.find(arg);
887 if (handler == handlers.end() || handler->second == nullptr) {
888 return ERR_INVALID_ARGUMENT;
889 }
890 return handler->second(context, 0);
891 }
892
PersistTaskStart(HilogArgs & context)893 static int PersistTaskStart(HilogArgs& context)
894 {
895 PersistStartRqst rqst = { { 0 }, 0 };
896 context.ToPersistStartRqst(rqst);
897 LogIoctl ioctl(IoctlCmd::PERSIST_START_RQST, IoctlCmd::PERSIST_START_RSP);
898 int ret = ioctl.Request<PersistStartRqst, PersistStartRsp>(rqst, [&rqst](const PersistStartRsp& rsp) {
899 cout << "Persist task [jobid:" << rsp.jobId << "] start successfully" << endl;
900 return RET_SUCCESS;
901 });
902 if (ret != RET_SUCCESS) {
903 cout << "Persist task start failed" << endl;
904 }
905 return ret;
906 }
907
PersistTaskStop(HilogArgs & context)908 static int PersistTaskStop(HilogArgs& context)
909 {
910 PersistStopRqst rqst = { 0 };
911 context.ToPersistStopRqst(rqst);
912 LogIoctl ioctl(IoctlCmd::PERSIST_STOP_RQST, IoctlCmd::PERSIST_STOP_RSP);
913 int ret = ioctl.Request<PersistStopRqst, PersistStopRsp>(rqst, [&rqst](const PersistStopRsp& rsp) {
914 for (int i = 0; i < rsp.jobNum; i++) {
915 cout << "Persist task [jobid:" << rsp.jobId[i] << "] stop successfully" << endl;
916 }
917 return RET_SUCCESS;
918 });
919 if (ret != RET_SUCCESS) {
920 cout << "Persist task stop failed" << endl;
921 }
922 return ret;
923 }
924
PrintTaskInfo(const PersistTaskInfo & task)925 static void PrintTaskInfo(const PersistTaskInfo& task)
926 {
927 cout << task.jobId << " " << ComboLogType2Str(task.outputFilter.types) << " " << task.stream << " ";
928 cout << task.fileName << " " << Size2Str(task.fileSize) << " " << to_string(task.fileNum) << endl;
929 }
930
PersistTaskQuery()931 static int PersistTaskQuery()
932 {
933 PersistQueryRqst rqst = { 0 };
934 LogIoctl ioctl(IoctlCmd::PERSIST_QUERY_RQST, IoctlCmd::PERSIST_QUERY_RSP);
935 int ret = ioctl.Request<PersistQueryRqst, PersistQueryRsp>(rqst, [&rqst](const PersistQueryRsp& rsp) {
936 for (int i = 0; i < rsp.jobNum; i++) {
937 PrintTaskInfo(rsp.taskInfo[i]);
938 }
939 return RET_SUCCESS;
940 });
941 if (ret != RET_SUCCESS) {
942 cout << "Persist task query failed" << endl;
943 }
944 return ret;
945 }
946
PersistTaskRefresh()947 static int PersistTaskRefresh()
948 {
949 PersistRefreshRqst rqst = { 0 };
950 LogIoctl ioctl(IoctlCmd::PERSIST_REFRESH_RQST, IoctlCmd::PERSIST_REFRESH_RSP);
951 int ret = ioctl.Request<PersistRefreshRqst, PersistRefreshRsp>(rqst, [&rqst](const PersistRefreshRsp& rsp) {
952 for (int i = 0; i < rsp.jobNum; i++) {
953 PrintResult(RET_SUCCESS, (string("Persist task [jobid:") + to_string(rsp.jobId[i]) + "] refresh"));
954 }
955 return RET_SUCCESS;
956 });
957 if (ret != RET_SUCCESS) {
958 PrintResult(RET_FAIL, (string("Persist task refresh")));
959 }
960 return ret;
961 }
962
ClearPersistLog()963 static int ClearPersistLog()
964 {
965 PersistClearRqst rqst = { 0 };
966 LogIoctl ioctl(IoctlCmd::PERSIST_CLEAR_RQST, IoctlCmd::PERSIST_CLEAR_RSP);
967 int ret = ioctl.Request<PersistClearRqst, PersistClearRsp>(rqst, [&rqst](const PersistClearRsp& rsp) {
968 PrintResult(RET_SUCCESS, (string("Persist log /data/log/hilog clear")));
969 return RET_SUCCESS;
970 });
971 if (ret != RET_SUCCESS) {
972 PrintResult(RET_FAIL, (string("Persist log /data/log/hilog clear")));
973 }
974 return ret;
975 }
976
PersistTaskHandler(HilogArgs & context,const char * arg)977 static int PersistTaskHandler(HilogArgs& context, const char *arg)
978 {
979 string strArg = arg;
980 if (strArg == "start") {
981 return PersistTaskStart(context);
982 } else if (strArg == "stop") {
983 return PersistTaskStop(context);
984 } else if (strArg == "query") {
985 return PersistTaskQuery();
986 } else if (strArg == "refresh") {
987 return PersistTaskRefresh();
988 } else if (strArg == "clear") {
989 return ClearPersistLog();
990 } else {
991 return ERR_INVALID_ARGUMENT;
992 }
993 return RET_SUCCESS;
994 }
995
NoBlockHandler(HilogArgs & context,const char * arg)996 static int NoBlockHandler(HilogArgs& context, const char *arg)
997 {
998 context.noBlock = true;
999 return QueryLogHandler(context, arg);
1000 }
1001
TailHandler(HilogArgs & context,const char * arg)1002 static int TailHandler(HilogArgs& context, const char *arg)
1003 {
1004 if (IsNumericStr(arg) == false) {
1005 return ERR_NOT_NUMBER_STR;
1006 }
1007 int tailLines = 0;
1008 (void)StrToInt(arg, tailLines);
1009 context.tailLines = static_cast<uint16_t>(tailLines);
1010 context.noBlock = true; // don't block implicitly
1011 return QueryLogHandler(context, arg);
1012 }
1013
1014 struct OptEntry {
1015 const char opt;
1016 const char *longOpt;
1017 const ControlCmd cmd;
1018 const OptHandler handler;
1019 const bool needArg;
1020 // how many times can this option be used, for example:
1021 // hilog -v msec -v color ...
1022 uint32_t count;
1023 };
1024 static OptEntry optEntries[] = {
1025 {'a', "head", ControlCmd::CMD_QUERY, HeadHandler, true, 1},
1026 {'b', "baselevel", ControlCmd::CMD_LOGLEVEL_SET, BaseLogLevelHandler, true, 1},
1027 {'D', "domain", ControlCmd::NOT_CMD, DomainHandler, true, 1},
1028 {'e', "regex", ControlCmd::NOT_CMD, RegexHandler, true, 1},
1029 {0, "persist", ControlCmd::NOT_CMD, PersistHandler, false, 1},
1030 {'f', "filename", ControlCmd::NOT_CMD, FileNameHandler, true, 1},
1031 {'g', nullptr, ControlCmd::CMD_BUFFER_SIZE_QUERY, BufferSizeGetHandler, false, 1},
1032 {'G', "buffer-size", ControlCmd::CMD_BUFFER_SIZE_SET, BufferSizeSetHandler, true, 1},
1033 {'h', "help", ControlCmd::CMD_HELP, HelpHandler, false, 1},
1034 {'j', "jobid", ControlCmd::NOT_CMD, JobIdHandler, true, 1},
1035 {'k', "kmsg", ControlCmd::CMD_KMSG_FEATURE_SET, KmsgFeatureSetHandler, true, 1},
1036 {'l', "length", ControlCmd::NOT_CMD, FileLengthHandler, true, 1},
1037 {'L', "level", ControlCmd::NOT_CMD, LevelHandler, true, 1},
1038 {'m', "stream", ControlCmd::NOT_CMD, FileCompressHandler, true, 1},
1039 {'n', "number", ControlCmd::NOT_CMD, FileNumberHandler, true, 1},
1040 {'p', "private", ControlCmd::CMD_PRIVATE_FEATURE_SET, PrivateFeatureSetHandler, true, 1},
1041 {'P', "pid", ControlCmd::NOT_CMD, PidHandler, true, 1},
1042 {'Q', "flowctrl", ControlCmd::CMD_FLOWCONTROL_FEATURE_SET, FlowControlFeatureSetHandler, true, 1},
1043 {'r', nullptr, ControlCmd::CMD_REMOVE, RemoveHandler, false, 1},
1044 {'s', "statistics", ControlCmd::CMD_STATS_INFO_QUERY, StatsInfoQueryHandler, false, 1},
1045 {'S', nullptr, ControlCmd::CMD_STATS_INFO_CLEAR, StatsInfoClearHandler, false, 1},
1046 {'t', "type", ControlCmd::NOT_CMD, TypeHandler, true, 1},
1047 {'T', "tag", ControlCmd::NOT_CMD, TagHandler, true, 1},
1048 {'v', "format", ControlCmd::NOT_CMD, FormatHandler, true, 5},
1049 {'w', "write", ControlCmd::CMD_PERSIST_TASK, PersistTaskHandler, true, 1},
1050 {'x', "exit", ControlCmd::CMD_QUERY, NoBlockHandler, false, 1},
1051 {'z', "tail", ControlCmd::CMD_QUERY, TailHandler, true, 1},
1052 {0, nullptr, ControlCmd::NOT_CMD, nullptr, false, 1}, // End default entry
1053 }; // "hxz:grsSa:v:e:t:L:G:f:l:n:j:w:p:k:D:T:b:Q:m:P:"
1054 static constexpr int OPT_ENTRY_CNT = sizeof(optEntries) / sizeof(OptEntry);
1055
GetOpts(string & opts,struct option (& longOptions)[OPT_ENTRY_CNT])1056 static void GetOpts(string& opts, struct option(&longOptions)[OPT_ENTRY_CNT])
1057 {
1058 int longOptcount = 0;
1059 opts = "";
1060 int i;
1061 for (i = 0; i < OPT_ENTRY_CNT; i++) {
1062 if (optEntries[i].opt != 0) {
1063 // opts
1064 opts += optEntries[i].opt;
1065 if (optEntries[i].needArg) {
1066 opts += ':';
1067 }
1068 }
1069 // long option
1070 if (optEntries[i].longOpt == nullptr) {
1071 continue;
1072 }
1073 longOptions[longOptcount].name = optEntries[i].longOpt;
1074 longOptions[longOptcount].has_arg = optEntries[i].needArg ? required_argument : no_argument;
1075 longOptions[longOptcount].flag = nullptr;
1076 longOptions[longOptcount].val = optEntries[i].opt;
1077 longOptcount++;
1078 }
1079 longOptions[longOptcount].name = nullptr;
1080 longOptions[longOptcount].has_arg = 0;
1081 longOptions[longOptcount].flag = nullptr;
1082 longOptions[longOptcount].val = 0;
1083 return;
1084 }
1085
GetOptEntry(int choice)1086 static OptEntry* GetOptEntry(int choice)
1087 {
1088 OptEntry *entry = &(optEntries[OPT_ENTRY_CNT - 1]);
1089 int i = 0;
1090 for (i = 0; i < OPT_ENTRY_CNT; i++) {
1091 if (optEntries[i].opt == static_cast<char>(choice)) {
1092 entry = &(optEntries[i]);
1093 break;
1094 }
1095 }
1096 return entry;
1097 }
1098
HilogEntry(int argc,char * argv[])1099 int HilogEntry(int argc, char* argv[])
1100 {
1101 struct option longOptions[OPT_ENTRY_CNT];
1102 string opts;
1103 GetOpts(opts, longOptions);
1104 HilogArgs context;
1105 int optIndex = 0;
1106
1107 // 0. help has special case
1108 static const int argCountHelp = 3;
1109 if (argc == argCountHelp) {
1110 string arg = argv[1];
1111 if (arg == "--help" || arg == "-h") {
1112 Helper(argv[argCountHelp - 1]);
1113 return RET_SUCCESS;
1114 }
1115 }
1116 // 1. Scan all options and process NOT_CMD options' arguments
1117 int cmdCount = 0;
1118 OptEntry queryEntry = {' ', "", ControlCmd::CMD_QUERY, QueryLogHandler, false, 0};
1119 OptEntry *cmdEntry = &queryEntry; // No cmd means CMD_QUERY cmd
1120 string cmdArgs = "";
1121 while (1) {
1122 int choice = getopt_long(argc, argv, opts.c_str(), longOptions, &optIndex);
1123 if (choice == -1) {
1124 break;
1125 }
1126 if (choice == '?') {
1127 return RET_FAIL;
1128 }
1129 OptEntry *entry = GetOptEntry(choice);
1130 if (optind < argc && argv[optind][0] != '-') { // all options need only 1 argument
1131 PrintErr(ERR_TOO_MANY_ARGUMENTS);
1132 return ERR_TOO_MANY_ARGUMENTS;
1133 }
1134 if (entry->count == 0) {
1135 PrintErr(ERR_DUPLICATE_OPTION);
1136 return ERR_DUPLICATE_OPTION;
1137 }
1138 entry->count--;
1139 if (entry->cmd == ControlCmd::NOT_CMD) {
1140 int ret = entry->handler(context, optarg);
1141 if (ret != RET_SUCCESS) {
1142 PrintErr(ret);
1143 return ret;
1144 } else {
1145 continue;
1146 }
1147 }
1148 cmdEntry = entry;
1149 cmdCount++;
1150 if (optarg != nullptr) {
1151 cmdArgs = optarg;
1152 }
1153 }
1154 if (cmdCount > 1) {
1155 cerr << ErrorCode2Str(ERR_COMMAND_INVALID) << endl;
1156 return ERR_COMMAND_INVALID;
1157 }
1158 // 2. Process CMD_XXX
1159 int ret = cmdEntry->handler(context, cmdArgs.c_str());
1160 if (ret != RET_SUCCESS) {
1161 PrintErr(ret);
1162 return ret;
1163 }
1164 return RET_SUCCESS;
1165 }
1166 } // namespace HiviewDFX
1167 } // namespace OHOS
1168
main(int argc,char * argv[])1169 int main(int argc, char* argv[])
1170 {
1171 (void)OHOS::HiviewDFX::HilogEntry(argc, argv);
1172 return 0;
1173 }
1174