• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     if (setvbuf(stdout, nullptr, _IOLBF, MAX_LOG_LEN) != 0) {
411         cout << "failed to setvbuf _IOLBF " << endl;
412     }
413     OutputRqst rqst = { 0 };
414     context.ToOutputRqst(rqst);
415     LogIoctl ioctl(IoctlCmd::OUTPUT_RQST, IoctlCmd::OUTPUT_RSP);
416     int ret = ioctl.RequestOutput(rqst, [&context](const OutputRsp& rsp) {
417         if (rsp.end) {
418             return RET_SUCCESS;
419         }
420         LogContent content = {
421             .level = rsp.level,
422             .type = rsp.type,
423             .pid = rsp.pid,
424             .tid = rsp.tid,
425             .domain = rsp.domain,
426             .tv_sec = rsp.tv_sec,
427             .tv_nsec = rsp.tv_nsec,
428             .mono_sec = rsp.mono_sec,
429             .tag = rsp.data,
430             .log = (rsp.data + rsp.tagLen)
431         };
432         LogFormat format = {
433             .colorful = context.colorful,
434             .timeFormat = ((context.timeFormat == FormatTime::INVALID) ? FormatTime::TIME : context.timeFormat),
435             .timeAccuFormat =
436                 ((context.timeAccuFormat == FormatTimeAccu::INVALID) ? FormatTimeAccu::MSEC : context.timeAccuFormat),
437             .year = context.year,
438             .zone = context.zone,
439             .wrap = context.wrap
440         };
441         LogPrintWithFormat(content, format);
442         return static_cast<int>(SUCCESS_CONTINUE);
443     });
444     if (ret != RET_SUCCESS) {
445         return ret;
446     }
447     return RET_SUCCESS;
448 }
449 
HeadHandler(HilogArgs & context,const char * arg)450 static int HeadHandler(HilogArgs& context, const char *arg)
451 {
452     if (IsNumericStr(arg) == false) {
453         return ERR_NOT_NUMBER_STR;
454     }
455     int lines = 0;
456     (void)StrToInt(arg, lines);
457     context.headLines = static_cast<uint16_t>(lines);
458     context.noBlock = true; // don't block implicitly
459     return QueryLogHandler(context, arg);
460 }
461 
BaseLogLevelHandler(HilogArgs & context,const char * arg)462 static int BaseLogLevelHandler(HilogArgs& context, const char *arg)
463 {
464     uint16_t baseLevel = PrettyStr2LogLevel(arg);
465     if (baseLevel == LOG_LEVEL_MIN) {
466         return ERR_LOG_LEVEL_INVALID;
467     }
468     context.baseLevel = baseLevel;
469     int ret;
470     if (context.domainCount == 0 && context.tagCount == 0) {
471         ret = SetGlobalLevel(context.baseLevel);
472         PrintResult(ret, (string("Set global log level to ") + arg));
473         if (context.persist) {
474             ret = SetPersistGlobalLevel(context.baseLevel);
475             PrintResult(ret, (string("Set persist global log level to ") + arg));
476         }
477     }
478     if (context.domainCount != 0) {
479         for (int i = 0; i < context.domainCount; i++) {
480             ret = SetDomainLevel(context.domains[i], context.baseLevel);
481             PrintResult(ret, (string("Set domain 0x") + Uint2HexStr(context.domains[i]) +  " log level to " + arg));
482             if (context.persist) {
483                 ret = SetPersistDomainLevel(context.domains[i], context.baseLevel);
484                 PrintResult(ret, (string("Set persist domain 0x") +
485                                   Uint2HexStr(context.domains[i]) +  " log level to " + arg));
486             }
487         }
488     }
489     if (context.tagCount != 0) {
490         for (int i = 0; i < context.tagCount; i++) {
491             ret = SetTagLevel(context.tags[i], context.baseLevel);
492             PrintResult(ret, (string("Set tag ") + context.tags[i] +  " log level to " + arg));
493             if (context.persist) {
494                 ret = SetPersistTagLevel(context.tags[i], context.baseLevel);
495                 PrintResult(ret, (string("Set persist tag ") + context.tags[i] +  " log level to " + arg));
496             }
497         }
498     }
499     return RET_SUCCESS;
500 }
501 
502 static constexpr char BLACK_PREFIX = '^';
DomainHandler(HilogArgs & context,const char * arg)503 static int DomainHandler(HilogArgs& context, const char *arg)
504 {
505     context.blackDomain = (arg[0] == BLACK_PREFIX);
506     std::vector<std::string> domains;
507     Split(context.blackDomain ? arg + 1 : arg, domains);
508     if (domains.size() == 0) {
509         return ERR_INVALID_ARGUMENT;
510     }
511     int index = 0;
512     for (string d : domains) {
513         if (index >= MAX_DOMAINS) {
514             return ERR_TOO_MANY_DOMAINS;
515         }
516         bool success = false;
517         uint32_t domain = HexStr2Uint(d, success);
518         if (!success) {
519             return ERR_INVALID_DOMAIN_STR;
520         }
521         if (((domain >= DOMAIN_APP_MIN) && (domain <= DOMAIN_APP_MAX)) ||
522             ((domain >= DOMAIN_OS_MIN) && (domain <= DOMAIN_OS_MAX))) {
523             context.domains[index++] = domain;
524         } else {
525             return ERR_INVALID_DOMAIN_STR;
526         }
527     }
528     context.domainCount = index;
529     return RET_SUCCESS;
530 }
531 
RegexHandler(HilogArgs & context,const char * arg)532 static int RegexHandler(HilogArgs& context, const char *arg)
533 {
534     context.regex = arg;
535     if (context.regex.length() >= MAX_REGEX_STR_LEN) {
536         return ERR_REGEX_STR_TOO_LONG;
537     }
538     return RET_SUCCESS;
539 }
540 
PersistHandler(HilogArgs & context,const char * arg)541 static int PersistHandler(HilogArgs& context, const char *arg)
542 {
543     context.persist = true;
544     return RET_SUCCESS;
545 }
546 
FileNameHandler(HilogArgs & context,const char * arg)547 static int FileNameHandler(HilogArgs& context, const char *arg)
548 {
549     context.fileName = arg;
550     if (context.fileName.length() >= MAX_FILE_NAME_LEN) {
551         return ERR_FILE_NAME_TOO_LONG;
552     }
553     return RET_SUCCESS;
554 }
555 
BufferSizeGetHandler(HilogArgs & context,const char * arg)556 static int BufferSizeGetHandler(HilogArgs& context, const char *arg)
557 {
558     BufferSizeGetRqst rqst = { 0 };
559     context.ToBufferSizeGetRqst(rqst);
560     LogIoctl ioctl(IoctlCmd::BUFFERSIZE_GET_RQST, IoctlCmd::BUFFERSIZE_GET_RSP);
561     int ret = ioctl.Request<BufferSizeGetRqst, BufferSizeGetRsp>(rqst, [&rqst](const BufferSizeGetRsp& rsp) {
562         for (uint16_t i = 0; i < static_cast<uint16_t>(LOG_TYPE_MAX); i++) {
563             if (rsp.size[i] > 0) {
564                 cout << "Log type " << LogType2Str(i) << " buffer size is " << Size2Str(rsp.size[i]) << endl;
565             }
566         }
567         return RET_SUCCESS;
568     });
569     if (ret != RET_SUCCESS) {
570         cout << "Get " << ComboLogType2Str(rqst.types) << " buffer size failed" << endl;
571     }
572     return ret;
573 }
574 
BufferSizeSetHandler(HilogArgs & context,const char * arg)575 static int BufferSizeSetHandler(HilogArgs& context, const char *arg)
576 {
577     uint64_t size = Str2Size(arg);
578     if (size == 0) {
579         return ERR_INVALID_SIZE_STR;
580     }
581     context.buffSize = static_cast<int32_t>(size);
582     BufferSizeSetRqst rqst;
583     context.ToBufferSizeSetRqst(rqst);
584     LogIoctl ioctl(IoctlCmd::BUFFERSIZE_SET_RQST, IoctlCmd::BUFFERSIZE_SET_RSP);
585     int ret = ioctl.Request<BufferSizeSetRqst, BufferSizeSetRsp>(rqst, [&rqst](const BufferSizeSetRsp& rsp) {
586         for (uint16_t i = 0; i < static_cast<uint16_t>(LOG_TYPE_MAX); i++) {
587             if (rsp.size[i] > 0) {
588                 cout << "Set log type " << LogType2Str(i) << " buffer size to "
589                 << Size2Str(rsp.size[i]) << " successfully" << endl;
590             } else if (rsp.size[i] < 0) {
591                 cout << "Set log type " << LogType2Str(i) << " buffer size to "
592                 << Size2Str(rqst.size) << " failed" << endl;
593                 PrintErr(rsp.size[i]);
594             }
595         }
596         return RET_SUCCESS;
597     });
598     if (ret != RET_SUCCESS) {
599         cout << "Set buffer size failed" << endl;
600     }
601     return ret;
602 }
603 
HelpHandler(HilogArgs & context,const char * arg)604 static int HelpHandler(HilogArgs& context, const char *arg)
605 {
606     Helper("");
607     return RET_SUCCESS;
608 }
609 
JobIdHandler(HilogArgs & context,const char * arg)610 static int JobIdHandler(HilogArgs& context, const char *arg)
611 {
612     if (IsNumericStr(arg) == false) {
613         return ERR_NOT_NUMBER_STR;
614     }
615     int jobId = 0;
616     (void)StrToInt(arg, jobId);
617     context.jobId = static_cast<uint32_t>(jobId);
618     return RET_SUCCESS;
619 }
620 
621 static const string FEATURE_ON = "on";
622 static const string FEATURE_OFF = "off";
KmsgFeatureSetHandler(HilogArgs & context,const char * arg)623 static int KmsgFeatureSetHandler(HilogArgs& context, const char *arg)
624 {
625     string argStr = arg;
626     bool kmsgOn = true;
627     if (argStr == FEATURE_ON) {
628         kmsgOn = true;
629     } else if (argStr == FEATURE_OFF) {
630         kmsgOn = false;
631     } else {
632         return ERR_INVALID_ARGUMENT;
633     }
634     KmsgEnableRqst rqst = { kmsgOn };
635     LogIoctl ioctl(IoctlCmd::KMSG_ENABLE_RQST, IoctlCmd::KMSG_ENABLE_RSP);
636     int ret = ioctl.Request<KmsgEnableRqst, KmsgEnableRsp>(rqst, [&rqst](const KmsgEnableRsp& rsp) {
637         return RET_SUCCESS;
638     });
639     PrintResult(ret, (string("Set hilogd storing kmsg log ") + arg));
640     return ret;
641 }
642 
FileLengthHandler(HilogArgs & context,const char * arg)643 static int FileLengthHandler(HilogArgs& context, const char *arg)
644 {
645     uint64_t size = Str2Size(arg);
646     if (size == 0) {
647         return ERR_INVALID_SIZE_STR;
648     }
649     context.fileSize = size;
650     return RET_SUCCESS;
651 }
652 
LevelHandler(HilogArgs & context,const char * arg)653 static int LevelHandler(HilogArgs& context, const char *arg)
654 {
655     uint16_t levels = Str2ComboLogLevel(arg);
656     if (levels == 0) {
657         return ERR_LOG_LEVEL_INVALID;
658     }
659     context.levels = levels;
660     return RET_SUCCESS;
661 }
662 
FileCompressHandler(HilogArgs & context,const char * arg)663 static int FileCompressHandler(HilogArgs& context, const char *arg)
664 {
665     context.stream = arg;
666     return RET_SUCCESS;
667 }
668 
FileNumberHandler(HilogArgs & context,const char * arg)669 static int FileNumberHandler(HilogArgs& context, const char *arg)
670 {
671     if (IsNumericStr(arg) == false) {
672         return ERR_NOT_NUMBER_STR;
673     }
674     int fileNum = 0;
675     (void)StrToInt(arg, fileNum);
676     context.fileNum = static_cast<uint16_t>(fileNum);
677     return RET_SUCCESS;
678 }
679 
PrivateFeatureSetHandler(HilogArgs & context,const char * arg)680 static int PrivateFeatureSetHandler(HilogArgs& context, const char *arg)
681 {
682     string argStr = arg;
683     bool privateOn = true;
684     if (argStr == FEATURE_ON) {
685         privateOn = true;
686     } else if (argStr == FEATURE_OFF) {
687         privateOn = false;
688     } else {
689         return ERR_INVALID_ARGUMENT;
690     }
691     int ret = SetPrivateSwitchOn(privateOn);
692     PrintResult(ret, (string("Set hilog privacy format ") + arg));
693     return RET_SUCCESS;
694 }
695 
PidHandler(HilogArgs & context,const char * arg)696 static int PidHandler(HilogArgs& context, const char *arg)
697 {
698     context.blackPid = (arg[0] == BLACK_PREFIX);
699     std::vector<std::string> pids;
700     Split(context.blackPid ? arg + 1 : arg, pids);
701     if (pids.size() == 0) {
702         return ERR_INVALID_ARGUMENT;
703     }
704     int index = 0;
705     for (string p : pids) {
706         if (index >= MAX_PIDS) {
707             return ERR_TOO_MANY_PIDS;
708         }
709         if (IsNumericStr(p) == false) {
710             return ERR_NOT_NUMBER_STR;
711         }
712         int pid = 0;
713         (void)StrToInt(p, pid);
714         context.pids[index++] = static_cast<uint32_t>(pid);
715     }
716     context.pidCount = index;
717     return RET_SUCCESS;
718 }
719 
SetDomainFlowCtrl(bool on)720 static int SetDomainFlowCtrl(bool on)
721 {
722     DomainFlowCtrlRqst rqst = { 0 };
723     rqst.on = on;
724     LogIoctl ioctl(IoctlCmd::DOMAIN_FLOWCTRL_RQST, IoctlCmd::DOMAIN_FLOWCTRL_RSP);
725     int ret = ioctl.Request<DomainFlowCtrlRqst, DomainFlowCtrlRsp>(rqst, [&rqst](const DomainFlowCtrlRsp& rsp) {
726         return RET_SUCCESS;
727     });
728     return ret;
729 }
FlowControlFeatureSetHandler(HilogArgs & context,const char * arg)730 static int FlowControlFeatureSetHandler(HilogArgs& context, const char *arg)
731 {
732     string pid = "pid";
733     string domain = "domain";
734     string argStr = arg;
735     int ret;
736     if (argStr == (pid + FEATURE_ON)) {
737         ret = SetProcessSwitchOn(true);
738         cout << "Set flow control by process to enabled, result: " << ErrorCode2Str(ret) << endl;
739     } else if (argStr == (pid + FEATURE_OFF)) {
740         ret = SetProcessSwitchOn(false);
741         cout << "Set flow control by process to disabled, result: " << ErrorCode2Str(ret) << endl;
742     } else if (argStr == (domain + FEATURE_ON)) {
743         ret = SetDomainFlowCtrl(true);
744         cout << "Set flow control by domain to enabled, result: " << ErrorCode2Str(ret) << endl;
745     } else if (argStr == (domain + FEATURE_OFF)) {
746         ret = SetDomainFlowCtrl(false);
747         cout << "Set flow control by domain to disabled, result: " << ErrorCode2Str(ret) << endl;
748     } else {
749         return ERR_INVALID_ARGUMENT;
750     }
751     return ret;
752 }
753 
RemoveHandler(HilogArgs & context,const char * arg)754 static int RemoveHandler(HilogArgs& context, const char *arg)
755 {
756     LogRemoveRqst rqst = { 0 };
757     context.ToLogRemoveRqst(rqst);
758     LogIoctl ioctl(IoctlCmd::LOG_REMOVE_RQST, IoctlCmd::LOG_REMOVE_RSP);
759     int ret = ioctl.Request<LogRemoveRqst, LogRemoveRsp>(rqst, [&rqst](const LogRemoveRsp& rsp) {
760         cout << "Log type " << ComboLogType2Str(rsp.types) << " buffer clear successfully" << endl;
761         return RET_SUCCESS;
762     });
763     if (ret != RET_SUCCESS) {
764         cout << "Log buffer clear failed" << endl;
765     }
766     return ret;
767 }
768 
StatsInfoQueryHandler(HilogArgs & context,const char * arg)769 static int StatsInfoQueryHandler(HilogArgs& context, const char *arg)
770 {
771     StatsQueryRqst rqst = { 0 };
772     context.ToStatsQueryRqst(rqst);
773     LogIoctl ioctl(IoctlCmd::STATS_QUERY_RQST, IoctlCmd::STATS_QUERY_RSP);
774     int ret = ioctl.RequestStatsQuery(rqst, [&rqst](const StatsQueryRsp& rsp) {
775         HilogShowLogStatsInfo(rsp);
776         return RET_SUCCESS;
777     });
778     if (ret != RET_SUCCESS) {
779         cout << "Statistic info query failed" << endl;
780     }
781     return ret;
782 }
783 
StatsInfoClearHandler(HilogArgs & context,const char * arg)784 static int StatsInfoClearHandler(HilogArgs& context, const char *arg)
785 {
786     StatsClearRqst rqst = { 0 };
787     LogIoctl ioctl(IoctlCmd::STATS_CLEAR_RQST, IoctlCmd::STATS_CLEAR_RSP);
788     int ret = ioctl.Request<StatsClearRqst, StatsClearRsp>(rqst, [&rqst](const StatsClearRsp& rsp) {
789         cout << "Statistic info clear successfully" << endl;
790         return RET_SUCCESS;
791     });
792     if (ret != RET_SUCCESS) {
793         cout << "Statistic info clear failed" << endl;
794     }
795     return ret;
796 }
797 
TypeHandler(HilogArgs & context,const char * arg)798 static int TypeHandler(HilogArgs& context, const char *arg)
799 {
800     uint16_t types = Str2ComboLogType(arg);
801     if (types == 0) {
802         return ERR_LOG_TYPE_INVALID;
803     }
804     context.types = types;
805     return RET_SUCCESS;
806 }
807 
TagHandler(HilogArgs & context,const char * arg)808 static int TagHandler(HilogArgs& context, const char *arg)
809 {
810     context.blackTag = (arg[0] == BLACK_PREFIX);
811     std::vector<std::string> tags;
812     Split(context.blackTag ? arg + 1 : arg, tags);
813     int index = 0;
814     for (string t : tags) {
815         if (index >= MAX_TAGS) {
816             return ERR_TOO_MANY_TAGS;
817         }
818         if (t.length() >= MAX_TAG_LEN) {
819             return ERR_TAG_STR_TOO_LONG;
820         }
821         context.tags[index++] = t;
822     }
823     context.tagCount = index;
824     return RET_SUCCESS;
825 }
826 
TimeHandler(HilogArgs & context,FormatTime value)827 static int TimeHandler(HilogArgs& context, FormatTime value)
828 {
829     if (context.timeFormat != FormatTime::INVALID) {
830         return ERR_DUPLICATE_OPTION;
831     }
832     context.timeFormat = value;
833     return RET_SUCCESS;
834 }
835 
TimeAccuHandler(HilogArgs & context,FormatTimeAccu value)836 static int TimeAccuHandler(HilogArgs& context, FormatTimeAccu value)
837 {
838     if (context.timeAccuFormat != FormatTimeAccu::INVALID) {
839         return ERR_DUPLICATE_OPTION;
840     }
841     context.timeAccuFormat = value;
842     return RET_SUCCESS;
843 }
844 
FormatHandler(HilogArgs & context,const char * arg)845 static int FormatHandler(HilogArgs& context, const char *arg)
846 {
847     static std::unordered_map<std::string, std::function<int(HilogArgs&, int)>> handlers = {
848         {"color", [] (HilogArgs& context, int value) {
849             context.colorful = true;
850             return RET_SUCCESS;
851         }},
852         {"colour", [] (HilogArgs& context, int value) {
853             context.colorful = true;
854             return RET_SUCCESS;
855         }},
856         {"time", [] (HilogArgs& context, int value) {
857             return TimeHandler(context, FormatTime::TIME);
858         }},
859         {"epoch", [] (HilogArgs& context, int value) {
860             return TimeHandler(context, FormatTime::EPOCH);
861         }},
862         {"monotonic", [] (HilogArgs& context, int value) {
863             return TimeHandler(context, FormatTime::MONOTONIC);
864         }},
865         {"msec", [] (HilogArgs& context, int value) {
866             return TimeAccuHandler(context, FormatTimeAccu::MSEC);
867         }},
868         {"usec", [] (HilogArgs& context, int value) {
869             return TimeAccuHandler(context, FormatTimeAccu::USEC);
870         }},
871         {"nsec", [] (HilogArgs& context, int value) {
872             return TimeAccuHandler(context, FormatTimeAccu::NSEC);
873         }},
874         {"year", [] (HilogArgs& context, int value) {
875             context.year = true;
876             return RET_SUCCESS;
877         }},
878         {"zone", [] (HilogArgs& context, int value) {
879             context.zone = true;
880             tzset();
881             return RET_SUCCESS;
882         }},
883         {"wrap", [] (HilogArgs& context, int value) {
884             context.wrap = true;
885             return RET_SUCCESS;
886         }},
887     };
888 
889     auto handler = handlers.find(arg);
890     if (handler == handlers.end() || handler->second == nullptr) {
891         return ERR_INVALID_ARGUMENT;
892     }
893     return handler->second(context, 0);
894 }
895 
PersistTaskStart(HilogArgs & context)896 static int PersistTaskStart(HilogArgs& context)
897 {
898     PersistStartRqst rqst = { { 0 }, 0 };
899     context.ToPersistStartRqst(rqst);
900     LogIoctl ioctl(IoctlCmd::PERSIST_START_RQST, IoctlCmd::PERSIST_START_RSP);
901     int ret = ioctl.Request<PersistStartRqst, PersistStartRsp>(rqst, [&rqst](const PersistStartRsp& rsp) {
902         cout << "Persist task [jobid:" << rsp.jobId << "] start successfully" << endl;
903         return RET_SUCCESS;
904     });
905     if (ret != RET_SUCCESS) {
906         cout << "Persist task start failed" << endl;
907     }
908     return ret;
909 }
910 
PersistTaskStop(HilogArgs & context)911 static int PersistTaskStop(HilogArgs& context)
912 {
913     PersistStopRqst rqst = { 0 };
914     context.ToPersistStopRqst(rqst);
915     LogIoctl ioctl(IoctlCmd::PERSIST_STOP_RQST, IoctlCmd::PERSIST_STOP_RSP);
916     int ret = ioctl.Request<PersistStopRqst, PersistStopRsp>(rqst,  [&rqst](const PersistStopRsp& rsp) {
917         for (int i = 0; i < rsp.jobNum; i++) {
918             cout << "Persist task [jobid:" << rsp.jobId[i] << "] stop successfully" << endl;
919         }
920         return RET_SUCCESS;
921     });
922     if (ret != RET_SUCCESS) {
923         cout << "Persist task stop failed" << endl;
924     }
925     return ret;
926 }
927 
PrintTaskInfo(const PersistTaskInfo & task)928 static void PrintTaskInfo(const PersistTaskInfo& task)
929 {
930     cout << task.jobId << " " << ComboLogType2Str(task.outputFilter.types) << " " << task.stream << " ";
931     cout << task.fileName << " " << Size2Str(task.fileSize) << " " << to_string(task.fileNum) << endl;
932 }
933 
PersistTaskQuery()934 static int PersistTaskQuery()
935 {
936     PersistQueryRqst rqst = { 0 };
937     LogIoctl ioctl(IoctlCmd::PERSIST_QUERY_RQST, IoctlCmd::PERSIST_QUERY_RSP);
938     int ret = ioctl.Request<PersistQueryRqst, PersistQueryRsp>(rqst,  [&rqst](const PersistQueryRsp& rsp) {
939         for (int i = 0; i < rsp.jobNum; i++) {
940             PrintTaskInfo(rsp.taskInfo[i]);
941         }
942         return RET_SUCCESS;
943     });
944     if (ret != RET_SUCCESS) {
945         cout << "Persist task query failed" << endl;
946     }
947     return ret;
948 }
949 
PersistTaskRefresh()950 static int PersistTaskRefresh()
951 {
952     PersistRefreshRqst rqst = { 0 };
953     LogIoctl ioctl(IoctlCmd::PERSIST_REFRESH_RQST, IoctlCmd::PERSIST_REFRESH_RSP);
954     int ret = ioctl.Request<PersistRefreshRqst, PersistRefreshRsp>(rqst, [&rqst](const PersistRefreshRsp& rsp) {
955         for (int i = 0; i < rsp.jobNum; i++) {
956             PrintResult(RET_SUCCESS, (string("Persist task [jobid:") + to_string(rsp.jobId[i]) + "] refresh"));
957         }
958         return RET_SUCCESS;
959     });
960     if (ret != RET_SUCCESS) {
961         PrintResult(RET_FAIL, (string("Persist task refresh")));
962     }
963     return ret;
964 }
965 
ClearPersistLog()966 static int ClearPersistLog()
967 {
968     PersistClearRqst rqst = { 0 };
969     LogIoctl ioctl(IoctlCmd::PERSIST_CLEAR_RQST, IoctlCmd::PERSIST_CLEAR_RSP);
970     int ret = ioctl.Request<PersistClearRqst, PersistClearRsp>(rqst, [&rqst](const PersistClearRsp& rsp) {
971         PrintResult(RET_SUCCESS, (string("Persist log /data/log/hilog clear")));
972         return RET_SUCCESS;
973     });
974     if (ret != RET_SUCCESS) {
975         PrintResult(RET_FAIL, (string("Persist log /data/log/hilog clear")));
976     }
977     return ret;
978 }
979 
PersistTaskHandler(HilogArgs & context,const char * arg)980 static int PersistTaskHandler(HilogArgs& context, const char *arg)
981 {
982     string strArg = arg;
983     if (strArg == "start") {
984         return PersistTaskStart(context);
985     } else if (strArg == "stop") {
986         return PersistTaskStop(context);
987     } else if (strArg == "query") {
988         return PersistTaskQuery();
989     } else if (strArg == "refresh") {
990         return PersistTaskRefresh();
991     } else if (strArg == "clear") {
992         return ClearPersistLog();
993     } else {
994         return ERR_INVALID_ARGUMENT;
995     }
996     return RET_SUCCESS;
997 }
998 
NoBlockHandler(HilogArgs & context,const char * arg)999 static int NoBlockHandler(HilogArgs& context, const char *arg)
1000 {
1001     context.noBlock = true;
1002     return QueryLogHandler(context, arg);
1003 }
1004 
TailHandler(HilogArgs & context,const char * arg)1005 static int TailHandler(HilogArgs& context, const char *arg)
1006 {
1007     if (IsNumericStr(arg) == false) {
1008         return ERR_NOT_NUMBER_STR;
1009     }
1010     int tailLines = 0;
1011     (void)StrToInt(arg, tailLines);
1012     context.tailLines = static_cast<uint16_t>(tailLines);
1013     context.noBlock = true; // don't block implicitly
1014     return QueryLogHandler(context, arg);
1015 }
1016 
1017 struct OptEntry {
1018     const char opt;
1019     const char *longOpt;
1020     const ControlCmd cmd;
1021     const OptHandler handler;
1022     const bool needArg;
1023     // how many times can this option be used, for example:
1024     //   hilog -v msec -v color ...
1025     uint32_t count;
1026 };
1027 static OptEntry optEntries[] = {
1028     {'a', "head", ControlCmd::CMD_QUERY, HeadHandler, true, 1},
1029     {'b', "baselevel", ControlCmd::CMD_LOGLEVEL_SET, BaseLogLevelHandler, true, 1},
1030     {'D', "domain", ControlCmd::NOT_CMD, DomainHandler, true, 1},
1031     {'e', "regex", ControlCmd::NOT_CMD, RegexHandler, true, 1},
1032     {0, "persist", ControlCmd::NOT_CMD, PersistHandler, false, 1},
1033     {'f', "filename", ControlCmd::NOT_CMD, FileNameHandler, true, 1},
1034     {'g', nullptr, ControlCmd::CMD_BUFFER_SIZE_QUERY, BufferSizeGetHandler, false, 1},
1035     {'G', "buffer-size", ControlCmd::CMD_BUFFER_SIZE_SET, BufferSizeSetHandler, true, 1},
1036     {'h', "help", ControlCmd::CMD_HELP, HelpHandler, false, 1},
1037     {'j', "jobid", ControlCmd::NOT_CMD, JobIdHandler, true, 1},
1038     {'k', "kmsg", ControlCmd::CMD_KMSG_FEATURE_SET, KmsgFeatureSetHandler, true, 1},
1039     {'l', "length", ControlCmd::NOT_CMD, FileLengthHandler, true, 1},
1040     {'L', "level", ControlCmd::NOT_CMD, LevelHandler, true, 1},
1041     {'m', "stream", ControlCmd::NOT_CMD, FileCompressHandler, true, 1},
1042     {'n', "number", ControlCmd::NOT_CMD, FileNumberHandler, true, 1},
1043     {'p', "private", ControlCmd::CMD_PRIVATE_FEATURE_SET, PrivateFeatureSetHandler, true, 1},
1044     {'P', "pid", ControlCmd::NOT_CMD, PidHandler, true, 1},
1045     {'Q', "flowctrl", ControlCmd::CMD_FLOWCONTROL_FEATURE_SET, FlowControlFeatureSetHandler, true, 1},
1046     {'r', nullptr, ControlCmd::CMD_REMOVE, RemoveHandler, false, 1},
1047     {'s', "statistics", ControlCmd::CMD_STATS_INFO_QUERY, StatsInfoQueryHandler, false, 1},
1048     {'S', nullptr, ControlCmd::CMD_STATS_INFO_CLEAR, StatsInfoClearHandler, false, 1},
1049     {'t', "type", ControlCmd::NOT_CMD, TypeHandler, true, 1},
1050     {'T', "tag", ControlCmd::NOT_CMD, TagHandler, true, 1},
1051     {'v', "format", ControlCmd::NOT_CMD, FormatHandler, true, 5},
1052     {'w', "write", ControlCmd::CMD_PERSIST_TASK, PersistTaskHandler, true, 1},
1053     {'x', "exit", ControlCmd::CMD_QUERY, NoBlockHandler, false, 1},
1054     {'z', "tail", ControlCmd::CMD_QUERY, TailHandler, true, 1},
1055     {0, nullptr, ControlCmd::NOT_CMD, nullptr, false, 1}, // End default entry
1056 }; // "hxz:grsSa:v:e:t:L:G:f:l:n:j:w:p:k:D:T:b:Q:m:P:"
1057 static constexpr int OPT_ENTRY_CNT = sizeof(optEntries) / sizeof(OptEntry);
1058 
GetOpts(string & opts,struct option (& longOptions)[OPT_ENTRY_CNT])1059 static void GetOpts(string& opts, struct option(&longOptions)[OPT_ENTRY_CNT])
1060 {
1061     int longOptcount = 0;
1062     opts = "";
1063     int i;
1064     for (i = 0; i < OPT_ENTRY_CNT; i++) {
1065         if (optEntries[i].opt != 0) {
1066             // opts
1067             opts += optEntries[i].opt;
1068             if (optEntries[i].needArg) {
1069                 opts += ':';
1070             }
1071         }
1072         // long option
1073         if (optEntries[i].longOpt == nullptr) {
1074             continue;
1075         }
1076         longOptions[longOptcount].name = optEntries[i].longOpt;
1077         longOptions[longOptcount].has_arg = optEntries[i].needArg ? required_argument : no_argument;
1078         longOptions[longOptcount].flag = nullptr;
1079         longOptions[longOptcount].val = optEntries[i].opt;
1080         longOptcount++;
1081     }
1082     longOptions[longOptcount].name = nullptr;
1083     longOptions[longOptcount].has_arg = 0;
1084     longOptions[longOptcount].flag = nullptr;
1085     longOptions[longOptcount].val = 0;
1086     return;
1087 }
1088 
GetOptEntry(int choice)1089 static OptEntry* GetOptEntry(int choice)
1090 {
1091     OptEntry *entry = &(optEntries[OPT_ENTRY_CNT - 1]);
1092     int i = 0;
1093     for (i = 0; i < OPT_ENTRY_CNT; i++) {
1094         if (optEntries[i].opt == static_cast<char>(choice)) {
1095             entry = &(optEntries[i]);
1096             break;
1097         }
1098     }
1099     return entry;
1100 }
1101 
HilogEntry(int argc,char * argv[])1102 int HilogEntry(int argc, char* argv[])
1103 {
1104     struct option longOptions[OPT_ENTRY_CNT];
1105     string opts;
1106     GetOpts(opts, longOptions);
1107     HilogArgs context;
1108     int optIndex = 0;
1109 
1110     // 0. help has special case
1111     static const int argCountHelp = 3;
1112     if (argc == argCountHelp) {
1113         string arg = argv[1];
1114         if (arg == "--help" || arg == "-h") {
1115             Helper(argv[argCountHelp - 1]);
1116             return RET_SUCCESS;
1117         }
1118     }
1119     // 1. Scan all options and process NOT_CMD options' arguments
1120     int cmdCount = 0;
1121     OptEntry queryEntry =  {' ', "", ControlCmd::CMD_QUERY, QueryLogHandler, false, 0};
1122     OptEntry *cmdEntry = &queryEntry; // No cmd means CMD_QUERY cmd
1123     string cmdArgs = "";
1124     while (1) {
1125         int choice = getopt_long(argc, argv, opts.c_str(), longOptions, &optIndex);
1126         if (choice == -1) {
1127             break;
1128         }
1129         if (choice == '?') {
1130             return RET_FAIL;
1131         }
1132         OptEntry *entry = GetOptEntry(choice);
1133         if (optind < argc && argv[optind][0] != '-') { // all options need only 1 argument
1134             PrintErr(ERR_TOO_MANY_ARGUMENTS);
1135             return ERR_TOO_MANY_ARGUMENTS;
1136         }
1137         if (entry->count == 0) {
1138             PrintErr(ERR_DUPLICATE_OPTION);
1139             return ERR_DUPLICATE_OPTION;
1140         }
1141         entry->count--;
1142         if (entry->cmd == ControlCmd::NOT_CMD) {
1143             int ret = entry->handler(context, optarg);
1144             if (ret != RET_SUCCESS) {
1145                 PrintErr(ret);
1146                 return ret;
1147             } else {
1148                 continue;
1149             }
1150         }
1151         cmdEntry = entry;
1152         cmdCount++;
1153         if (optarg != nullptr) {
1154             cmdArgs = optarg;
1155         }
1156     }
1157     if (cmdCount > 1) {
1158         cerr << ErrorCode2Str(ERR_COMMAND_INVALID) << endl;
1159         return ERR_COMMAND_INVALID;
1160     }
1161     // 2. Process CMD_XXX
1162     int ret = cmdEntry->handler(context, cmdArgs.c_str());
1163     if (ret != RET_SUCCESS) {
1164         PrintErr(ret);
1165         return ret;
1166     }
1167     return RET_SUCCESS;
1168 }
1169 } // namespace HiviewDFX
1170 } // namespace OHOS
1171 
main(int argc,char * argv[])1172 int main(int argc, char* argv[])
1173 {
1174     (void)OHOS::HiviewDFX::HilogEntry(argc, argv);
1175     return 0;
1176 }
1177