• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2024 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 
16 #include "atm_command.h"
17 
18 #include <getopt.h>
19 #include <string>
20 
21 #include "access_token_error.h"
22 #include "accesstoken_kit.h"
23 #include "privacy_kit.h"
24 #include "to_string.h"
25 
26 namespace OHOS {
27 namespace Security {
28 namespace AccessToken {
29 namespace {
30 static constexpr int32_t MAX_COUNTER = 1000;
31 static constexpr int32_t MIN_ARGUMENT_NUMBER = 2;
32 static constexpr int32_t MAX_ARGUMENT_NUMBER = 4096;
33 static const std::string HELP_MSG_NO_OPTION = "error: you must specify an option at least.\n";
34 static const std::string SHORT_OPTIONS_DUMP = "d::h::t::r::v::i:p:b:n:";
35 static const std::string TOOLS_NAME = "atm";
36 static const std::string HELP_MSG =
37     "usage: atm <command> <option>\n"
38     "These are common atm commands list:\n"
39     "  help    list available commands\n"
40 #ifndef ATM_BUILD_VARIANT_USER_ENABLE
41     "  perm    grant/cancel permission\n"
42     "  toggle  set/get toggle request/record status\n"
43 #endif
44     "  dump    dump system command\n";
45 
46 static const std::string HELP_MSG_DUMP =
47     "usage: atm dump <option>.\n"
48     "options list:\n"
49     "  -h, --help                                               list available options\n"
50     "  -d, --definition [-p <permission-name>]                  list all permission definitions in system\n"
51     "  -t, --all                                                list all name of token info in system\n"
52     "  -t, --token-info -i <token-id>                           list single token info by specific tokenId\n"
53     "  -t, --token-info -b <bundle-name>                        list all token info by specific bundleName\n"
54     "  -t, --token-info -n <process-name>                       list single token info by specific native processName\n"
55 #ifndef ATM_BUILD_VARIANT_USER_ENABLE
56     "  -r, --record-info [-i <token-id>] [-p <permission-name>] list used records in system\n"
57     "  -v, --visit-type [-i <token-id>] [-p <permission-name>]  list all token used type in system\n";
58 #else
59     "";
60 #endif
61 
62 static const std::string HELP_MSG_PERM =
63 #ifndef ATM_BUILD_VARIANT_USER_ENABLE
64     "usage: atm perm <option>.\n"
65     "options list:\n"
66     "  -h, --help                                       list available options\n"
67     "  -g, --grant -i <token-id> -p <permission-name>   grant a permission by a specified token-id\n"
68     "  -c, --cancel -i <token-id> -p <permission-name>  cancel a permission by a specified token-id\n";
69 #else
70     "";
71 #endif
72 
73 static const std::string HELP_MSG_TOGGLE =
74 #ifndef ATM_BUILD_VARIANT_USER_ENABLE
75     "usage: atm toggle request <option>.\n"
76     "options list:\n"
77     "  -h, --help                                                  list available options\n"
78     "  -r -s, --set -i <user-id> -p <permission-name> -k <status>  set request status by specified user-id and perm\n"
79     "  -r -o, --get -i <user-id> -p <permission-name>              get request status by specified user-id and perm\n"
80     "  -u -s, --set -i <user-id> -k <status>                       set record status by a specified user-id\n"
81     "  -u -o, --get -i <user-id>                                   get record status by a specified user-id\n"
82     "  <status>                                                    0 is closed, 1 is open\n";
83 #else
84     "";
85 #endif
86 
87 static const struct option LONG_OPTIONS_DUMP[] = {
88     {"definition", no_argument, nullptr, 'd'},
89     {"help", no_argument, nullptr, 'h'},
90     {"token-info", no_argument, nullptr, 't'},
91     {"record-info", no_argument, nullptr, 'r'},
92     {"token-id", required_argument, nullptr, 'i'},
93     {"permission-name", required_argument, nullptr, 'p'},
94     {"bundle-name", required_argument, nullptr, 'b'},
95     {"process-name", required_argument, nullptr, 'n'},
96     {nullptr, 0, nullptr, 0}
97 };
98 static const std::string SHORT_OPTIONS_PERM = "hg::c::i:p:";
99 static const struct option LONG_OPTIONS_PERM[] = {
100     {"help", no_argument, nullptr, 'h'},
101     {"grant", no_argument, nullptr, 'g'},
102     {"cancel", no_argument, nullptr, 'c'},
103     {"token-id", required_argument, nullptr, 'i'},
104     {"permission-name", required_argument, nullptr, 'p'},
105     {nullptr, 0, nullptr, 0}
106 };
107 
108 // required option
109 static const std::vector<char> REQUIRED_OPTIONS_DUMP = {'b', 'i', 'n', 'p'};
110 static const std::vector<char> REQUIRED_OPTIONS_PERM = {'g', 'c', 'i', 'p'};
111 static const std::vector<char> REQUIRED_OPTIONS_TOGGLE = {'i', 'k', 'p'};
112 
113 static const std::string SHORT_OPTIONS_TOGGLE = "hr::u::s::o::i:p:k:";
114 static const struct option LONG_OPTIONS_TOGGLE[] = {
115     {"help", no_argument, nullptr, 'h'},
116     {"request", no_argument, nullptr, 'r'},
117     {"record", no_argument, nullptr, 'u'},
118     {"set", no_argument, nullptr, 's'},
119     {"get", no_argument, nullptr, 'o'},
120     {"user-id", required_argument, nullptr, 'i'},
121     {"permission-name", required_argument, nullptr, 'p'},
122     {"status", required_argument, nullptr, 'k'},
123     {nullptr, 0, nullptr, 0}
124 };
125 
126 std::map<char, OptType> DUMP_COMMAND_TYPE = {
127     // dump
128     {'d', DUMP_PERM},
129     {'t', DUMP_TOKEN},
130     {'r', DUMP_RECORD},
131     {'v', DUMP_TYPE},
132 };
133 
134 std::map<char, ToggleModeType> TOGGLE_MODE_TYPE = {
135     {'r', TOGGLE_REQUEST},
136     {'u', TOGGLE_RECORD},
137 };
138 std::map<char, ToggleOperateType> TOGGLE_OPERATE_TYPE = {
139     {'s', TOGGLE_SET},
140     {'o', TOGGLE_GET},
141 };
142 }
143 
AtmCommand(int32_t argc,char * argv[])144 AtmCommand::AtmCommand(int32_t argc, char* argv[]) : argc_(argc), argv_(argv), name_(TOOLS_NAME)
145 {
146     opterr = 0;
147 
148     commandMap_ = {
149         {"help", [this](){return RunAsHelpCommand();}},
150         {"dump", [this]() {return RunAsCommonCommandForDump();}},
151 #ifndef ATM_BUILD_VARIANT_USER_ENABLE
152         {"perm", [this]() {return RunAsCommonCommandForPerm();}},
153         {"toggle", [this]() {return RunAsCommonCommandForToggle();}},
154 #endif
155     };
156 
157     if ((argc < MIN_ARGUMENT_NUMBER) || (argc > MAX_ARGUMENT_NUMBER)) {
158         cmd_ = "help";
159 
160         return;
161     }
162 
163     cmd_ = argv[1];
164 
165     for (int32_t i = 2; i < argc; i++) {
166         argList_.push_back(argv[i]);
167     }
168 }
169 
GetCommandErrorMsg() const170 std::string AtmCommand::GetCommandErrorMsg() const
171 {
172     std::string commandErrorMsg =
173         name_ + ": '" + cmd_ + "' is not a valid " + name_ + " command. See '" + name_ + " help'.\n";
174 
175     return commandErrorMsg;
176 }
177 
ExecCommand()178 std::string AtmCommand::ExecCommand()
179 {
180     auto respond = commandMap_[cmd_];
181     if (respond == nullptr) {
182         resultReceiver_.append(GetCommandErrorMsg());
183     } else {
184         respond();
185     }
186 
187     return resultReceiver_;
188 }
189 
RunAsHelpCommand()190 int32_t AtmCommand::RunAsHelpCommand()
191 {
192     resultReceiver_.append(HELP_MSG);
193 
194     return RET_SUCCESS;
195 }
196 
RunAsCommandError(void)197 int32_t AtmCommand::RunAsCommandError(void)
198 {
199     int32_t result = RET_SUCCESS;
200 
201     if ((optind < 0) || (optind >= argc_)) {
202         return ERR_INVALID_VALUE;
203     }
204 
205     // When scanning the first argument
206     if (strcmp(argv_[optind], cmd_.c_str()) == 0) {
207         // 'atm dump' with no option: atm dump
208         // 'atm dump' with a wrong argument: atm dump xxx
209 
210         resultReceiver_.append(HELP_MSG_NO_OPTION + "\n");
211         result = ERR_INVALID_VALUE;
212     }
213     return result;
214 }
215 
GetUnknownOptionMsg() const216 std::string AtmCommand::GetUnknownOptionMsg() const
217 {
218     std::string result;
219 
220     if ((optind < 0) || (optind > argc_)) {
221         return result;
222     }
223 
224     result.append("error: unknown option.\n");
225 
226     return result;
227 }
228 
RunAsCommandMissingOptionArgument(const std::vector<char> & requiredOptions)229 int32_t AtmCommand::RunAsCommandMissingOptionArgument(const std::vector<char>& requiredOptions)
230 {
231     if (optopt == 'h') {
232         return ERR_INVALID_VALUE;
233     }
234     auto iter = std::find(requiredOptions.begin(), requiredOptions.end(), optopt);
235     if (iter == requiredOptions.end()) {
236         resultReceiver_.append(GetUnknownOptionMsg());
237         return ERR_INVALID_VALUE;
238     }
239     resultReceiver_.append("error: option requires a value.\n\n");
240     return ERR_INVALID_VALUE;
241 }
242 
RunAsCommandExistentOptionForDump(const int32_t & option,AtmToolsParamInfo & info,OptType & type,std::string & permissionName)243 void AtmCommand::RunAsCommandExistentOptionForDump(
244     const int32_t& option, AtmToolsParamInfo& info, OptType& type, std::string& permissionName)
245 {
246     switch (option) {
247         case 'd':
248         case 't':
249         case 'r':
250         case 'v':
251             type = DUMP_COMMAND_TYPE[option];
252             break;
253         case 'i':
254             if (optarg != nullptr) {
255                 info.tokenId = static_cast<AccessTokenID>(std::atoi(optarg));
256             }
257             break;
258         case 'p':
259             if (optarg != nullptr) {
260                 permissionName = optarg;
261             }
262             break;
263         case 'b':
264             if (optarg != nullptr) {
265                 info.bundleName = optarg;
266             }
267             break;
268         case 'n':
269             if (optarg != nullptr) {
270                 info.processName = optarg;
271             }
272             break;
273         default:
274             break;
275     }
276 }
277 
RunAsCommandExistentOptionForPerm(const int32_t & option,bool & isGranted,AccessTokenID & tokenID,std::string & permission)278 void AtmCommand::RunAsCommandExistentOptionForPerm(
279     const int32_t& option, bool& isGranted, AccessTokenID& tokenID, std::string& permission)
280 {
281     switch (option) {
282         case 'g':
283             isGranted = true;
284             break;
285         case 'c':
286             isGranted = false;
287             break;
288         case 'i':
289             tokenID = (optarg != nullptr) ? static_cast<AccessTokenID>(std::atoi(optarg)) : INVALID_TOKENID;
290             break;
291         case 'p':
292             permission = (optarg != nullptr) ? optarg : "";
293             break;
294         default:
295             break;
296         }
297 }
298 
RunAsCommandExistentOptionForToggle(const int32_t & option,AtmToggleParamInfo & info)299 void AtmCommand::RunAsCommandExistentOptionForToggle(const int32_t& option, AtmToggleParamInfo& info)
300 {
301     switch (option) {
302         case 'r':
303         case 'u':
304             info.toggleMode = TOGGLE_MODE_TYPE[option];
305             break;
306         case 's':
307         case 'o':
308             info.type = TOGGLE_OPERATE_TYPE[option];
309             break;
310         case 'p':
311             info.permissionName = (optarg != nullptr) ? optarg : "";;
312             break;
313         case 'i':
314             if (optarg != nullptr) {
315                 if (IsNumericString(optarg)) {
316                     info.userID = static_cast<int32_t>(std::atoi(optarg));
317                 } else {
318                     info.userID = -1;
319                 }
320             }
321             break;
322         case 'k':
323             if (optarg != nullptr && (strcmp(optarg, "0") == 0 || strcmp(optarg, "1") == 0)) {
324                 info.status = static_cast<uint32_t>(std::atoi(optarg));
325             }
326             break;
327         default:
328             break;
329     }
330 }
331 
IsNumericString(const char * string)332 bool AtmCommand::IsNumericString(const char* string)
333 {
334     if (string == nullptr || string[0] == '\0') {
335         return false;
336     }
337 
338     for (int32_t i = 0; string[i] != '\0'; i++) {
339         if (!isdigit(string[i])) {
340             return false;
341         }
342     }
343 
344     return true;
345 }
346 
DumpRecordInfo(uint32_t tokenId,const std::string & permissionName)347 std::string AtmCommand::DumpRecordInfo(uint32_t tokenId, const std::string& permissionName)
348 {
349     PermissionUsedRequest request;
350     request.tokenId = tokenId;
351     request.flag = FLAG_PERMISSION_USAGE_DETAIL;
352     if (!permissionName.empty()) {
353         request.permissionList.emplace_back(permissionName);
354     }
355 
356     PermissionUsedResult result;
357     if (PrivacyKit::GetPermissionUsedRecords(request, result) != 0) {
358         return "";
359     }
360 
361     return ToString::PermissionUsedResultToString(result);
362 }
363 
DumpUsedTypeInfo(uint32_t tokenId,const std::string & permissionName)364 std::string AtmCommand::DumpUsedTypeInfo(uint32_t tokenId, const std::string& permissionName)
365 {
366     std::vector<PermissionUsedTypeInfo> results;
367     if (PrivacyKit::GetPermissionUsedTypeInfos(tokenId, permissionName, results) != 0) {
368         return "";
369     }
370 
371     return ToString::PermissionUsedTypeInfoToString(results);
372 }
373 
ModifyPermission(bool isGranted,AccessTokenID tokenId,const std::string & permissionName)374 int32_t AtmCommand::ModifyPermission(bool isGranted, AccessTokenID tokenId, const std::string& permissionName)
375 {
376     int32_t result = 0;
377     if (isGranted) {
378         result = AccessTokenKit::GrantPermission(tokenId, permissionName, PERMISSION_USER_FIXED);
379     } else {
380         result = AccessTokenKit::RevokePermission(tokenId, permissionName, PERMISSION_USER_FIXED);
381     }
382     return result;
383 }
384 
SetToggleStatus(int32_t userID,const std::string & permissionName,const uint32_t & status)385 int32_t AtmCommand::SetToggleStatus(int32_t userID, const std::string& permissionName, const uint32_t& status)
386 {
387     if ((userID < 0) || (permissionName.empty()) ||
388         ((status != PermissionRequestToggleStatus::OPEN) &&
389          (status != PermissionRequestToggleStatus::CLOSED))) {
390         return ERR_INVALID_VALUE;
391     }
392 
393     return AccessTokenKit::SetPermissionRequestToggleStatus(permissionName, status, userID);
394 }
395 
GetToggleStatus(int32_t userID,const std::string & permissionName,std::string & statusInfo)396 int32_t AtmCommand::GetToggleStatus(int32_t userID, const std::string& permissionName, std::string& statusInfo)
397 {
398     if ((userID < 0) || (permissionName.empty())) {
399         return ERR_INVALID_VALUE;
400     }
401 
402     uint32_t status;
403     int32_t result = AccessTokenKit::GetPermissionRequestToggleStatus(permissionName, status, userID);
404     if (result != RET_SUCCESS) {
405         return result;
406     }
407 
408     if (status == PermissionRequestToggleStatus::OPEN) {
409         statusInfo = "Toggle status is open";
410     } else {
411         statusInfo = "Toggle status is closed";
412     }
413 
414     return result;
415 }
416 
RunCommandByOperationType(const AtmToolsParamInfo & info,OptType type,std::string & permissionName)417 int32_t AtmCommand::RunCommandByOperationType(const AtmToolsParamInfo& info, OptType type, std::string& permissionName)
418 {
419     std::string dumpInfo;
420     int32_t ret = RET_SUCCESS;
421     switch (type) {
422         case DUMP_PERM:
423             dumpInfo = ToString::DumpPermDefinition(permissionName);
424             break;
425         case DUMP_TOKEN:
426             AccessTokenKit::DumpTokenInfo(info, dumpInfo);
427             break;
428         case DUMP_RECORD:
429 #ifndef ATM_BUILD_VARIANT_USER_ENABLE
430             dumpInfo = DumpRecordInfo(info.tokenId, permissionName);
431             break;
432         case DUMP_TYPE:
433             dumpInfo = DumpUsedTypeInfo(info.tokenId, permissionName);
434             break;
435 #endif
436         default:
437             resultReceiver_.append("error: miss option \n");
438             return ERR_INVALID_VALUE;
439     }
440     resultReceiver_.append(dumpInfo + "\n");
441     return ret;
442 }
443 
SetRecordToggleStatus(int32_t userID,const uint32_t & recordStatus,std::string & statusInfo)444 int32_t AtmCommand::SetRecordToggleStatus(int32_t userID, const uint32_t& recordStatus, std::string& statusInfo)
445 {
446     if ((userID < 0)) {
447         statusInfo = "Invalid userID\n";
448         return ERR_INVALID_VALUE;
449     }
450 
451     if ((recordStatus != 0) && (recordStatus != 1)) {
452         statusInfo = "Invalid status\n";
453         return ERR_INVALID_VALUE;
454     }
455 
456     bool status = (recordStatus == 1);
457 
458     return PrivacyKit::SetPermissionUsedRecordToggleStatus(userID, status);
459 }
460 
GetRecordToggleStatus(int32_t userID,std::string & statusInfo)461 int32_t AtmCommand::GetRecordToggleStatus(int32_t userID, std::string& statusInfo)
462 {
463     if ((userID < 0)) {
464         statusInfo = "Invalid userID\n";
465         return ERR_INVALID_VALUE;
466     }
467 
468     bool status = true;
469     int32_t result = PrivacyKit::GetPermissionUsedRecordToggleStatus(userID, status);
470     if (result != RET_SUCCESS) {
471         return result;
472     }
473 
474     statusInfo = status ? "Record toggle status is open \n" : "Record toggle status is closed \n";
475 
476     return result;
477 }
478 
HandleToggleRequest(const AtmToggleParamInfo & info,std::string & dumpInfo)479 int32_t AtmCommand::HandleToggleRequest(const AtmToggleParamInfo& info, std::string& dumpInfo)
480 {
481     int32_t ret = RET_SUCCESS;
482 
483 #ifndef ATM_BUILD_VARIANT_USER_ENABLE
484     switch (info.type) {
485         case TOGGLE_SET:
486             ret = SetToggleStatus(info.userID, info.permissionName, info.status);
487             dumpInfo = (ret == RET_SUCCESS) ? "Success" : "Failure";
488             break;
489         case TOGGLE_GET:
490             ret = GetToggleStatus(info.userID, info.permissionName, dumpInfo);
491             if (ret != RET_SUCCESS) {
492                 dumpInfo = "Failure";
493             }
494             break;
495         default:
496             resultReceiver_.append("error: miss option \n");
497             return ERR_INVALID_VALUE;
498         }
499 #endif
500 
501     return ret;
502 }
503 
HandleToggleRecord(const AtmToggleParamInfo & info,std::string & dumpInfo)504 int32_t AtmCommand::HandleToggleRecord(const AtmToggleParamInfo& info, std::string& dumpInfo)
505 {
506     int32_t ret = RET_SUCCESS;
507 
508 #ifndef ATM_BUILD_VARIANT_USER_ENABLE
509     switch (info.type) {
510         case TOGGLE_SET:
511             ret = SetRecordToggleStatus(info.userID, info.status, dumpInfo);
512             dumpInfo += (ret == RET_SUCCESS) ? "Success" : "Failure";
513             break;
514         case TOGGLE_GET:
515             ret = GetRecordToggleStatus(info.userID, dumpInfo);
516             dumpInfo += (ret == RET_SUCCESS) ? "Success" : "Failure";
517             break;
518         default:
519             resultReceiver_.append("error: miss option \n");
520             return ERR_INVALID_VALUE;
521     }
522 #endif
523     return ret;
524 }
525 
RunToggleCommandByOperationType(const AtmToggleParamInfo & info)526 int32_t AtmCommand::RunToggleCommandByOperationType(const AtmToggleParamInfo& info)
527 {
528     std::string dumpInfo;
529     int32_t ret = RET_SUCCESS;
530 
531     switch (info.toggleMode) {
532         case TOGGLE_REQUEST:
533             ret = HandleToggleRequest(info, dumpInfo);
534             break;
535         case TOGGLE_RECORD:
536             ret = HandleToggleRecord(info, dumpInfo);
537             break;
538         default:
539             resultReceiver_.append("error: unspecified toggle mode \n");
540             return ERR_INVALID_VALUE;
541     }
542 
543     resultReceiver_.append(dumpInfo + "\n");
544     return ret;
545 }
546 
RunAsCommonCommandForDump()547 int32_t AtmCommand::RunAsCommonCommandForDump()
548 {
549     int32_t result = RET_SUCCESS;
550     AtmToolsParamInfo info;
551     int32_t counter = 0;
552     OptType type = DEFAULT_OPER;
553     std::string permissionName;
554     while (true) {
555         ++counter;
556         int32_t option = getopt_long(argc_, argv_, SHORT_OPTIONS_DUMP.c_str(), LONG_OPTIONS_DUMP, nullptr);
557         if ((optind < 0) || (optind > argc_)) {
558             return ERR_INVALID_VALUE;
559         }
560 
561         if (option == -1) {
562             if (counter == 1) {
563                 result = RunAsCommandError();
564             }
565             break;
566         }
567 
568         if (option == '?') {
569             result = RunAsCommandMissingOptionArgument(REQUIRED_OPTIONS_DUMP);
570             break;
571         }
572 
573         if (option == 'h') {
574             // 'atm dump -h'
575             result = ERR_INVALID_VALUE;
576             continue;
577         }
578         RunAsCommandExistentOptionForDump(option, info, type, permissionName);
579     }
580 
581     if (result != RET_SUCCESS) {
582         resultReceiver_.append(HELP_MSG_DUMP + "\n");
583         return result;
584     }
585     return RunCommandByOperationType(info, type, permissionName);
586 }
587 
RunAsCommonCommandForPerm()588 int32_t AtmCommand::RunAsCommonCommandForPerm()
589 {
590     int32_t result = RET_SUCCESS;
591     int32_t counter = 0;
592     AccessTokenID tokenID;
593     std::string permission;
594     bool isGranted = false;
595     while (true) {
596         ++counter;
597         int32_t option = getopt_long(argc_, argv_, SHORT_OPTIONS_PERM.c_str(), LONG_OPTIONS_PERM, nullptr);
598         if ((optind < 0) || (optind > argc_)) {
599             return ERR_INVALID_VALUE;
600         }
601         if (option == -1) {
602             if (counter == 1) {
603                 result = RunAsCommandError();
604             }
605             break;
606         }
607 
608         if (option == '?') {
609             result = RunAsCommandMissingOptionArgument(REQUIRED_OPTIONS_PERM);
610             break;
611         }
612         if (option == 'h') {
613             result = ERR_INVALID_VALUE;
614             continue;
615         }
616         RunAsCommandExistentOptionForPerm(option, isGranted, tokenID, permission);
617     }
618     if (result != RET_SUCCESS) {
619         resultReceiver_.append(HELP_MSG_DUMP + "\n");
620         return result;
621     }
622     result = ModifyPermission(isGranted, tokenID, permission);
623     if (result == RET_SUCCESS) {
624         resultReceiver_.append("Success\n");
625     } else {
626         resultReceiver_.append("Failure\n");
627     }
628     return result;
629 }
630 
RunAsCommonCommandForToggle()631 int32_t AtmCommand::RunAsCommonCommandForToggle()
632 {
633     int32_t result = RET_SUCCESS;
634     AtmToggleParamInfo info;
635     int32_t counter = 0;
636     while (counter < MAX_COUNTER) {
637         ++counter;
638         int32_t option = getopt_long(argc_, argv_, SHORT_OPTIONS_TOGGLE.c_str(), LONG_OPTIONS_TOGGLE, nullptr);
639         if ((optind < 0) || (optind > argc_)) {
640             return ERR_INVALID_VALUE;
641         }
642 
643         if (option == -1) {
644             if (counter == 1) {
645                 result = RunAsCommandError();
646             }
647             break;
648         }
649 
650         if (option == '?') {
651             result = RunAsCommandMissingOptionArgument(REQUIRED_OPTIONS_TOGGLE);
652             break;
653         }
654 
655         if (option == 'h') {
656             result = ERR_INVALID_VALUE;
657             continue;
658         }
659         RunAsCommandExistentOptionForToggle(option, info);
660     }
661 
662     if (result != RET_SUCCESS) {
663         resultReceiver_.append(HELP_MSG_TOGGLE + "\n");
664         return result;
665     }
666     return RunToggleCommandByOperationType(info);
667 }
668 } // namespace AccessToken
669 } // namespace Security
670 } // namespace OHOS
671