• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 "account_command.h"
16 #include <getopt.h>
17 #include "account_log_wrapper.h"
18 #include "singleton.h"
19 
20 using namespace OHOS::AAFwk;
21 
22 namespace OHOS {
23 namespace AccountSA {
24 namespace {
25 const std::string SHORT_OPTIONS = "hn:t:i:c:ea";
26 const struct option LONG_OPTIONS[] = {
27     {"help", no_argument, nullptr, 'h'},
28     {"name", required_argument, nullptr, 'n'},
29     {"type", required_argument, nullptr, 't'},
30     {"id", required_argument, nullptr, 'i'},
31     {"constraint", required_argument, nullptr, 'c'},
32     {"enable", no_argument, nullptr, 'e'},
33     {"all", no_argument, nullptr, 'a'},
34 };
35 
36 static const std::string STOP_COMMAND = "stop";
37 static const std::string DELETE_COMMAND = "delete";
38 static const std::string SWITCH_COMMAND = "switch";
39 static const std::string DUMP_COMMAND = "dump";
40 static const std::string SET_COMMAND = "set";
41 static const std::string CREATE_COMMAND = "create";
42 
43 }  // namespace
44 
AccountCommand(int argc,char * argv[])45 AccountCommand::AccountCommand(int argc, char *argv[]) : ShellCommand(argc, argv, TOOL_NAME)
46 {
47     ACCOUNT_LOGD("enter");
48     for (int i = 0; i < argc_; i++) {
49         ACCOUNT_LOGD("argv_[%{public}d]: %{public}s", i, argv_[i]);
50     }
51 }
52 
CreateCommandMap()53 ErrCode AccountCommand::CreateCommandMap()
54 {
55     ACCOUNT_LOGD("enter");
56 
57     commandMap_ = {
58         {"help", std::bind(&AccountCommand::RunAsHelpCommand, this)},
59         {"create", std::bind(&AccountCommand::RunAsCreateCommand, this)},
60         {"delete", std::bind(&AccountCommand::RunAsDeleteCommand, this)},
61         {"dump", std::bind(&AccountCommand::RunAsDumpCommand, this)},
62         {"set", std::bind(&AccountCommand::RunAsSetCommand, this)},
63         {"switch", std::bind(&AccountCommand::RunAsSwitchCommand, this)},
64 #ifdef ENABLE_MULTIPLE_ACTIVE_ACCOUNTS
65         {"stop", std::bind(&AccountCommand::RunAsStopCommand, this)},
66 #endif // ENABLE_MULTIPLE_ACTIVE_ACCOUNTS
67     };
68 
69     return ERR_OK;
70 }
71 
CreateMessageMap()72 ErrCode AccountCommand::CreateMessageMap()
73 {
74     return ERR_OK;
75 }
76 
init()77 ErrCode AccountCommand::init()
78 {
79     return ERR_OK;
80 }
81 
RunAsHelpCommand(void)82 ErrCode AccountCommand::RunAsHelpCommand(void)
83 {
84     ACCOUNT_LOGD("enter");
85     resultReceiver_.append(HELP_MSG);
86     return ERR_OK;
87 }
88 
RunAsCreateCommand(void)89 ErrCode AccountCommand::RunAsCreateCommand(void)
90 {
91     ACCOUNT_LOGD("enter");
92     ErrCode result = ERR_OK;
93     int counter = 0;
94     std::string name = "";
95     OsAccountType osAccountType = static_cast<OsAccountType>(-1);
96 
97     while (true) {
98         counter++;
99 
100         int option = getopt_long(argc_, argv_, SHORT_OPTIONS.c_str(), LONG_OPTIONS, nullptr);
101         ACCOUNT_LOGD("option: %{public}d, optopt: %{public}d, optind: %{public}d", option, optopt, optind);
102 
103         if (option == -1) {
104             if (counter == 1) {
105                 result = RunCommandError(CREATE_COMMAND);
106             }
107             break;
108         }
109 
110         if (option == '?') {
111             result = RunAsCreateCommandMissingOptionArgument();
112             break;
113         }
114 
115         result = RunAsCreateCommandExistentOptionArgument(option, name, osAccountType);
116     }
117 
118     if (result == ERR_OK) {
119         if (name.size() == 0 || osAccountType == static_cast<OsAccountType>(-1)) {
120             ACCOUNT_LOGD("'acm create' without enough options");
121 
122             if (name.size() == 0) {
123                 resultReceiver_.append(HELP_MSG_NO_NAME_OPTION + "\n");
124             }
125 
126             if (osAccountType == static_cast<OsAccountType>(-1)) {
127                 resultReceiver_.append(HELP_MSG_NO_TYPE_OPTION + "\n");
128             }
129 
130             result = ERR_INVALID_VALUE;
131         }
132     }
133 
134     if (result != ERR_OK) {
135         resultReceiver_.append(HELP_MSG_CREATE);
136     } else {
137         /* create */
138 
139         // make os account info
140         OsAccountInfo osAccountInfo;
141 
142         // create an os account
143         result = OsAccount::GetInstance().CreateOsAccount(name, osAccountType, osAccountInfo);
144         if (result == ERR_OK) {
145             resultReceiver_ = STRING_CREATE_OS_ACCOUNT_OK + "\n";
146         } else {
147             resultReceiver_ = STRING_CREATE_OS_ACCOUNT_NG + "\n";
148         }
149     }
150 
151     ACCOUNT_LOGD("result = %{public}d, name = %{public}s, type = %{public}d", result, name.c_str(), osAccountType);
152     return result;
153 }
154 
RunAsDeleteCommand(void)155 ErrCode AccountCommand::RunAsDeleteCommand(void)
156 {
157     ErrCode result = ERR_OK;
158     int id = -1;
159 
160     ParseCommandOpt(DELETE_COMMAND, result, id);
161 
162     if (result != ERR_OK) {
163         resultReceiver_.append(HELP_MSG_DELETE);
164     } else {
165         /* delete */
166 
167         // delete an os account
168         result = OsAccount::GetInstance().RemoveOsAccount(id);
169         if (result == ERR_OK) {
170             resultReceiver_ = STRING_DELETE_OS_ACCOUNT_OK + "\n";
171         } else {
172             resultReceiver_ = STRING_DELETE_OS_ACCOUNT_NG + "\n";
173         }
174     }
175 
176     ACCOUNT_LOGD("result = %{public}d, id = %{public}d", result, id);
177     return result;
178 }
179 
RunAsDumpCommand(void)180 ErrCode AccountCommand::RunAsDumpCommand(void)
181 {
182     ErrCode result = ERR_OK;
183     int id = -1;
184 
185     ParseCommandOpt(DUMP_COMMAND, result, id);
186 
187     if (result != ERR_OK) {
188         resultReceiver_.append(HELP_MSG_DUMP);
189     } else {
190         /* dump */
191 
192         // dump state
193         std::vector<std::string> state;
194         result = OsAccount::GetInstance().DumpState(id, state);
195         if (result == ERR_OK) {
196             for (auto info : state) {
197                 resultReceiver_ += info + "\n";
198             }
199         } else {
200             resultReceiver_ = STRING_DUMP_OS_ACCOUNT_NG + "\n";
201         }
202     }
203 
204     ACCOUNT_LOGD("result = %{public}d, id = %{public}d", result, id);
205     return result;
206 }
207 
RunCommand(int & counter,ErrCode & result,bool & enable,int & id,std::vector<std::string> & constraints)208 void AccountCommand::RunCommand(
209     int &counter, ErrCode &result, bool &enable, int &id, std::vector<std::string> &constraints)
210 {
211     while (true) {
212         counter++;
213 
214         int option = getopt_long(argc_, argv_, SHORT_OPTIONS.c_str(), LONG_OPTIONS, nullptr);
215         ACCOUNT_LOGD("option: %{public}d, optopt: %{public}d, optind: %{public}d", option, optopt, optind);
216 
217         if (option == -1) {
218             if (counter == 1) {
219                 result = RunCommandError(SET_COMMAND);
220             }
221             break;
222         }
223 
224         if (option == '?') {
225             result = RunAsSetCommandMissingOptionArgument();
226             break;
227         }
228 
229         result = RunAsSetCommandExistentOptionArgument(option, id, constraints, enable);
230     }
231 }
232 
RunAsSetCommand(void)233 ErrCode AccountCommand::RunAsSetCommand(void)
234 {
235     ErrCode result = ERR_OK;
236     int counter = 0;
237     int id = -1;
238     std::vector<std::string> constraints;
239     bool enable = false;
240 
241     RunCommand(counter, result, enable, id, constraints);
242 
243     if (result == ERR_OK) {
244         if (id == -1 || constraints.size() == 0) {
245             ACCOUNT_LOGD("'acm set' without enough options");
246 
247             if (id == -1) {
248                 resultReceiver_.append(HELP_MSG_NO_ID_OPTION + "\n");
249             }
250 
251             if (constraints.size() == 0) {
252                 resultReceiver_.append(HELP_MSG_NO_CONSTRAINTS_OPTION + "\n");
253             }
254 
255             result = ERR_INVALID_VALUE;
256         }
257     }
258 
259     if (result != ERR_OK) {
260         resultReceiver_.append(HELP_MSG_SET);
261     } else {
262         /* set */
263 
264         // set os account constraints
265         result = OsAccount::GetInstance().SetOsAccountConstraints(id, constraints, enable);
266         if (result == ERR_OK) {
267             resultReceiver_ = STRING_SET_OS_ACCOUNT_CONSTRAINTS_OK + "\n";
268         } else {
269             resultReceiver_ = STRING_SET_OS_ACCOUNT_CONSTRAINTS_NG + "\n";
270         }
271     }
272 
273     ACCOUNT_LOGD("result = %{public}d, id = %{public}d, enable = %{public}d", result, id, enable);
274     for (auto constraint : constraints) {
275         ACCOUNT_LOGD("constraint = %{public}s", constraint.c_str());
276     }
277 
278     return result;
279 }
280 
ParseCommandOpt(const std::string & command,ErrCode & result,int & id)281 void AccountCommand::ParseCommandOpt(const std::string &command, ErrCode &result, int &id)
282 {
283     int counter = 0;
284     while (true) {
285         counter++;
286 
287         int option = getopt_long(argc_, argv_, SHORT_OPTIONS.c_str(), LONG_OPTIONS, nullptr);
288         ACCOUNT_LOGD("option: %{public}d, optopt: %{public}d, optind: %{public}d", option, optopt, optind);
289 
290         if (option == -1) {
291             if (counter == 1) {
292                 result = RunCommandError(command);
293             }
294             break;
295         }
296 
297         if (option == '?') {
298             result = RunAsCommonCommandMissingOptionArgument(command);
299             break;
300         }
301 
302         result = RunAsCommonCommandExistentOptionArgument(option, id);
303     }
304 }
305 
RunAsSwitchCommand(void)306 ErrCode AccountCommand::RunAsSwitchCommand(void)
307 {
308     ErrCode result = ERR_OK;
309     int id = -1;
310     ParseCommandOpt(SWITCH_COMMAND, result, id);
311 
312     if (result != ERR_OK) {
313         resultReceiver_.append(HELP_MSG_SWITCH);
314     } else {
315         /* switch */
316 
317         // switch an os account
318         result = OsAccount::GetInstance().ActivateOsAccount(id);
319         if (result == ERR_OK) {
320             resultReceiver_ = STRING_SWITCH_OS_ACCOUNT_OK + "\n";
321         } else {
322             resultReceiver_ = STRING_SWITCH_OS_ACCOUNT_NG + "\n";
323         }
324     }
325 
326     ACCOUNT_LOGD("result = %{public}d, id = %{public}d", result, id);
327     return result;
328 }
329 
RunAsStopCommand(void)330 ErrCode AccountCommand::RunAsStopCommand(void)
331 {
332     ErrCode result = ERR_OK;
333     int id = -1;
334 
335     ParseCommandOpt(STOP_COMMAND, result, id);
336 
337     if (result != ERR_OK) {
338         resultReceiver_.append(HELP_MSG_STOP);
339     } else {
340         /* stop */
341 
342         // stop an os account
343         result = OsAccount::GetInstance().StopOsAccount(id);
344         if (result == ERR_OK) {
345             resultReceiver_ = STRING_STOP_OS_ACCOUNT_OK + "\n";
346         } else {
347             resultReceiver_ = STRING_STOP_OS_ACCOUNT_NG + "\n";
348         }
349     }
350 
351     ACCOUNT_LOGD("result = %{public}d, id = %{public}d", result, id);
352 
353     return result;
354 }
355 
RunAsCreateCommandMissingOptionArgument(void)356 ErrCode AccountCommand::RunAsCreateCommandMissingOptionArgument(void)
357 {
358     ErrCode result = ERR_OK;
359 
360     switch (optopt) {
361         case 'n': {
362             // 'acm create -n <name>' with no argument: acm create -n
363             // 'acm create --name <name>' with no argument: acm create --name
364             ACCOUNT_LOGD("'acm create -n' with no argument.");
365 
366             resultReceiver_.append(HELP_MSG_OPTION_REQUIRES_AN_ARGUMENT + "\n");
367             result = ERR_INVALID_VALUE;
368             break;
369         }
370         case 't': {
371             // 'acm create -t <type>' with no argument: acm create -t
372             // 'acm create --type <type>' with no argument: acm create --type
373             ACCOUNT_LOGD("'acm create -t' with no argument.");
374 
375             resultReceiver_.append(HELP_MSG_OPTION_REQUIRES_AN_ARGUMENT + "\n");
376 
377             result = ERR_INVALID_VALUE;
378             break;
379         }
380         default: {
381             // 'acm create' with an unknown option: acm create -x
382             // 'acm create' with an unknown option: acm create -xxx
383             std::string unknownOption = "";
384             std::string unknownOptionMsg = GetUnknownOptionMsg(unknownOption);
385 
386             ACCOUNT_LOGD("'acm create' with an unknown option.");
387 
388             resultReceiver_.append(unknownOptionMsg);
389             result = ERR_INVALID_VALUE;
390             break;
391         }
392     }
393 
394     ACCOUNT_LOGD("end, result = %{public}d", result);
395     return result;
396 }
397 
RunAsCreateCommandExistentOptionArgument(const int & option,std::string & name,OsAccountType & type)398 ErrCode AccountCommand::RunAsCreateCommandExistentOptionArgument(
399     const int &option, std::string &name, OsAccountType &type)
400 {
401     ErrCode result = ERR_OK;
402 
403     switch (option) {
404         case 'h': {
405             // 'acm create -h'
406             // 'acm create --help'
407             result = ERR_INVALID_VALUE;
408             break;
409         }
410         case 'n': {
411             // 'acm create -n <name>'
412             // 'acm create --name <name>'
413             name = optarg;
414             break;
415         }
416         case 't': {
417             // 'acm create -t <type>'
418             // 'acm create --type <type>'
419             result = AnalyzeTypeArgument(type);
420             break;
421         }
422         default: {
423             break;
424         }
425     }
426 
427     ACCOUNT_LOGD("end, result = %{public}d", result);
428     return result;
429 }
430 
RunAsCommonCommandMissingOptionArgument(const std::string & command)431 ErrCode AccountCommand::RunAsCommonCommandMissingOptionArgument(const std::string &command)
432 {
433     ErrCode result = ERR_OK;
434 
435     switch (optopt) {
436         case 'i': {
437             // 'acm command -i <id>' with no argument: acm command -i
438             // 'acm command --id <id>' with no argument: acm command --id
439             ACCOUNT_LOGD("'acm %{public}s -i' with no argument.", command.c_str());
440 
441             resultReceiver_.append(HELP_MSG_OPTION_REQUIRES_AN_ARGUMENT + "\n");
442             result = ERR_INVALID_VALUE;
443             break;
444         }
445         default: {
446             // 'acm delete' with an unknown option: acm delete -x
447             // 'acm delete' with an unknown option: acm delete -xxx
448             std::string unknownOption = "";
449             std::string unknownOptionMsg = GetUnknownOptionMsg(unknownOption);
450 
451             ACCOUNT_LOGD("'acm %{public}s' with an unknown option.",  command.c_str());
452 
453             resultReceiver_.append(unknownOptionMsg);
454             result = ERR_INVALID_VALUE;
455             break;
456         }
457     }
458     ACCOUNT_LOGD("end, result = %{public}d", result);
459     return result;
460 }
461 
RunCommandError(const std::string & command)462 ErrCode AccountCommand::RunCommandError(const std::string &command)
463 {
464     ErrCode result = ERR_OK;
465 
466     if (optind < 0 || optind >= argc_) {
467         ACCOUNT_LOGD("optind %{public}d invalid", optind);
468         return ERR_INVALID_VALUE;
469     }
470 
471     // When scanning the first argument
472     if (strcmp(argv_[optind], cmd_.c_str()) == 0) {
473         // 'acm command' with no option: acm command
474         // 'acm command' with a wrong argument: acm command xxx
475         ACCOUNT_LOGD("'acm %{public}s' with no option.", command.c_str());
476 
477         resultReceiver_.append(HELP_MSG_NO_OPTION + "\n");
478         result = ERR_INVALID_VALUE;
479     }
480 
481     ACCOUNT_LOGD("end, result = %{public}d", result);
482 
483     return result;
484 }
485 
RunAsSetCommandMissingOptionArgument(void)486 ErrCode AccountCommand::RunAsSetCommandMissingOptionArgument(void)
487 {
488     ErrCode result = ERR_OK;
489 
490     switch (optopt) {
491         case 'i': {
492             // 'acm set -i <id>' with no argument: acm set -i
493             // 'acm set --id <id>' with no argument: acm set --id
494             ACCOUNT_LOGD("'acm set -i' with no argument.");
495 
496             resultReceiver_.append(HELP_MSG_OPTION_REQUIRES_AN_ARGUMENT + "\n");
497             result = ERR_INVALID_VALUE;
498             break;
499         }
500         case 'c': {
501             // 'acm set -c <constraints>' with no argument: acm set -c
502             // 'acm set --constraint <constraints>' with no argument: acm set --constraint
503             ACCOUNT_LOGD("'acm set -c' with no argument.");
504 
505             resultReceiver_.append(HELP_MSG_OPTION_REQUIRES_AN_ARGUMENT + "\n");
506             result = ERR_INVALID_VALUE;
507             break;
508         }
509         default: {
510             // 'acm set' with an unknown option: acm set -x
511             // 'acm set' with an unknown option: acm set -xxx
512             std::string unknownOption = "";
513             std::string unknownOptionMsg = GetUnknownOptionMsg(unknownOption);
514 
515             ACCOUNT_LOGD("'set dump' with an unknown option.");
516 
517             resultReceiver_.append(unknownOptionMsg);
518             result = ERR_INVALID_VALUE;
519             break;
520         }
521     }
522     ACCOUNT_LOGD("end, result = %{public}d", result);
523     return result;
524 }
525 
RunAsSetCommandExistentOptionArgument(const int & option,int & id,std::vector<std::string> & constraints,bool & enable)526 ErrCode AccountCommand::RunAsSetCommandExistentOptionArgument(
527     const int &option, int &id, std::vector<std::string> &constraints, bool &enable)
528 {
529     ErrCode result = ERR_OK;
530 
531     switch (option) {
532         case 'h': {
533             // 'acm set -h'
534             // 'acm set --help'
535             result = ERR_INVALID_VALUE;
536             break;
537         }
538         case 'i': {
539             // 'acm set -i <id>'
540             // 'acm set --id <id>'
541             result = AnalyzeLocalIdArgument(id);
542             break;
543         }
544         case 'c': {
545             // 'acm set -c <constraints>'
546             // 'acm set --constraint <constraints>'
547             result = AnalyzeConstraintArgument(constraints);
548             break;
549         }
550         case 'e': {
551             // 'acm set -e'
552             // 'acm set --enable'
553             enable = true;
554             break;
555         }
556         default: {
557             break;
558         }
559     }
560 
561     ACCOUNT_LOGD("end, result = %{public}d, id = %{public}d", result, id);
562     return result;
563 }
564 
RunAsCommonCommandExistentOptionArgument(const int & option,int & id)565 ErrCode AccountCommand::RunAsCommonCommandExistentOptionArgument(const int &option, int &id)
566 {
567     ErrCode result = ERR_OK;
568 
569     switch (option) {
570         case 'h': {
571             // 'acm command -h'
572             // 'acm command --help'
573             // command includes stop, switch, dump, delete
574             result = ERR_INVALID_VALUE;
575             break;
576         }
577         case 'i': {
578             // 'acm command -i <id>'
579             // 'acm command --id <id>
580             // command includes stop, switch, dump, delete
581             result = AnalyzeLocalIdArgument(id);
582             break;
583         }
584         default: {
585             break;
586         }
587     }
588     ACCOUNT_LOGD("end, result = %{public}d, id = %{public}d", result, id);
589     return result;
590 }
591 
AnalyzeTypeArgument(OsAccountType & type)592 ErrCode AccountCommand::AnalyzeTypeArgument(OsAccountType &type)
593 {
594     ErrCode result = ERR_OK;
595     std::string typeByUser = optarg;
596 
597     if (typeByUser == "admin") {
598         type = OsAccountType::ADMIN;
599     } else if (typeByUser == "normal") {
600         type = OsAccountType::NORMAL;
601     } else if (typeByUser == "guest") {
602         type = OsAccountType::GUEST;
603     } else {
604         resultReceiver_.append(HELP_MSG_INVALID_TYPE_ARGUMENT + "\n");
605         result = ERR_INVALID_VALUE;
606     }
607 
608     return result;
609 }
610 
AnalyzeLocalIdArgument(int & id)611 ErrCode AccountCommand::AnalyzeLocalIdArgument(int &id)
612 {
613     std::string idByUser = optarg;
614     if (idByUser == "0") {
615         id = 0;
616         return ERR_OK;
617     }
618 
619     if (atoi(optarg) == 0) {
620         resultReceiver_.append(HELP_MSG_INVALID_ID_ARGUMENT + "\n");
621         return ERR_INVALID_VALUE;
622     }
623 
624     id = atoi(optarg);
625 
626     return ERR_OK;
627 }
628 
AnalyzeConstraintArgument(std::vector<std::string> & constraints)629 ErrCode AccountCommand::AnalyzeConstraintArgument(std::vector<std::string> &constraints)
630 {
631     std::string constraintsByUser = optarg;
632     ACCOUNT_LOGD("constraintsByUser = %{public}s", constraintsByUser.c_str());
633 
634     constraints.clear();
635     std::string constraint = "";
636     std::string delimiter = ",";
637     size_t last = 0;
638     size_t next = 0;
639 
640     while ((next = constraintsByUser.find(delimiter, last)) != std::string::npos) {
641         constraint = constraintsByUser.substr(last, next - last);
642         ACCOUNT_LOGD("constraint = %{public}s", constraint.c_str());
643 
644         constraints.emplace_back(constraint);
645         last = next + 1;
646     }
647     constraint = constraintsByUser.substr(last);
648     ACCOUNT_LOGD("constraint = %{public}s", constraint.c_str());
649     constraints.emplace_back(constraint);
650 
651     return ERR_OK;
652 }
653 }  // namespace AccountSA
654 }  // namespace OHOS