UEFI shell의 모든 명령어를 보면, -? 옵션을 추가하면, 도움말 메시지를 출력할 수 있다. 예를 들어,
Shell> reset -?
Resets the system.
RESET [-w [string]]
RESET [-s [string]]
RESET [-c [string]]
-s - Performs a shutdown.
-w - Performs a warm boot.
-c - Performs a cold boot.
string - Describes a reason for the reset.
NOTES:
1. This command resets the system.
2. The default is to perform a cold reset unless the -w parameter is
specified.
3. If a reset string is specified, it is passed into the Reset()
function, and the system records the reason for the system reset.
이번 장에서는 help/man 기능을 애플리케이션에 추가하는 방법을 알아볼 것이다.
man finding 및 파싱을 담당하는 Shell 모듈은 ShellManParser이다.
$ vi UefiLessonsPkg/UefiLessonsPkg.dsc
---
[Components]
UefiLessonsPkg/HIIStringsMan/HIIStringsMan.inf
기억할 것이라 생각하지만, ShellManParser는 gEfiHiiPackageListProtocolGuid 프로토콜 데이터에서 maunal 문자열을 검색했다. 따라서 manual 문자열을 이미지 리소스 Section(HIIStringsMan.inf)에 직접 포함해야 한다.
#langdef en-US "English"
#string STR_HELP #language en-US ""
".TH HIIStringsMan 0 "Simple application with a manual inside."\r\n"
".SH NAME\r\n"
"HIIStringsMan application.\r\n"
".SH SYNOPSIS\r\n"
"This is the synopsis section.\r\n"
".SH DESCRIPTION\r\n"
"This is the description section.\r\n"
".SH OPTIONS\r\n"
"This is the options section.\r\n"
".SH RETURN VALUES\r\n"
"This is the return values section.\r\n"
".SH ENVIRONMENT VARIABLES\r\n"
"This is the section for used environment variables\r\n"
".SH FILES\r\n"
"This is the section for files associated with the subject.\r\n"
".SH EXAMPLES\r\n"
"This is the section for examples and suggestions.\r\n"
".SH ERRORS\r\n"
"This is the section for errors reported by the command.\r\n"
".SH STANDARDS\r\n"
"This is the section for conformance to applicable standards.\r\n"
".SH BUGS\r\n"
"This is the section for errors and caveats.\r\n"
".SH CATEGORY\r\n"
"This is the section for categories.\r\n"
".SH CUSTOMSECTION\r\n"
"This is an example of a custom section.\r\n"
여기까지 빌드하고, 실행하면 다음 내용이 출력되는 것을 확인할 수 있다.
FS0:\> HIIStringsMan.efi -?
HIIStringsMan application.
This is the synopsis section.
This is the description section.
This is the options section.
This is the section for examples and suggestions.
보다시피, 넣어준 모든 섹션에 대한 print가 되지 않았다는 것을 알 수 있다. 그 이유에 대해 알아보자.
먼저 명령어에 -? 옵션을 추가해주면, 어떤 일이 일어나는지 알아보도록 하자. shell의 소스코드를 보면 shell이 -?를 명령 인수 중 하나로, command 및 나머지 모든 인수를 Shell.c의 도움말 명령으로 리다이렉트한다.
$ cat ShellPkg/Application/Shell/Shell.c
---
/**
Reprocess the command line to direct all -? to the help command.
if found, will add "help" as argv[0], and move the rest later.
@param[in,out] CmdLine pointer to the command line to update
**/
EFI_STATUS
DoHelpUpdate(
IN OUT CHAR16 **CmdLine
)
{
...
if (StrStr(CurrentParameter, L"-?") == CurrentParameter) {
CurrentParameter[0] = L' ';
CurrentParameter[1] = L' ';
NewCmdLineSize = StrSize(L"help ") + StrSize(*CmdLine);
NewCommandLine = AllocateZeroPool(NewCmdLineSize);
if (NewCommandLine == NULL) {
Status = EFI_OUT_OF_RESOURCES;
break;
}
//
// We know the space is sufficient since we just calculated it.
//
StrnCpyS(NewCommandLine, NewCmdLineSize/sizeof(CHAR16), L"help ", 5);
StrnCatS(NewCommandLine, NewCmdLineSize/sizeof(CHAR16), *CmdLine, StrLen(*CmdLine));
SHELL_FREE_NON_NULL(*CmdLine);
*CmdLine = NewCommandLine;
break;
}
...
}
프로그램에 직접 help 명령을 사용하면, 결과가 동일하게 출력되는지 확인할 수 있다.
FS0:\> help HIIStringsMan.efi
HIIStringsMan application.
This is the synopsis section.
This is the description section.
This is the options section.
This is the section for examples and suggestions.
이제 도움말 명령 소스 코드(Help.c)를 살펴보자.
$ cat ShellPkg/Library/UefiShellLevel3CommmandsLib/Help.c
---
SHELL_STATUS
EFIAPI
ShellCommandRunHelp (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
...
//
// Get the section name for the given command name
//
if (ShellCommandLineGetFlag(Package, L"-section")) {
StrnCatGrow(&SectionToGetHelpOn, NULL, ShellCommandLineGetValue(Package, L"-section"), 0);
} else if (ShellCommandLineGetFlag(Package, L"-usage")) {
StrnCatGrow(&SectionToGetHelpOn, NULL, L"NAME,SYNOPSIS", 0);
} else if (ShellCommandLineGetFlag(Package, L"-verbose") || ShellCommandLineGetFlag(Package, L"-v")) {
} else {
//
// The output of help <command> will display NAME, SYNOPSIS, OPTIONS, DESCRIPTION, and EXAMPLES sections.
//
StrnCatGrow (&SectionToGetHelpOn, NULL, L"NAME,SYNOPSIS,OPTIONS,DESCRIPTION,EXAMPLES", 0);
}
...
}
여기에서 help를 넣어줄 인수를 파싱하는 방법을 찾아볼 수 있다.
기본적으로 NAME, SYNOPSIS, OPTIONS, DESCRIPTION, EXAMPLES 섹션이 프린트된다.
-section <SECTION NAME> 인수를 사용해 특정 섹션을 출력할 수 있다.
-verbose 혹은 -v 인수를 사용해 모든 섹션들을 출력할 수 있다.
Shell에서 이 내용을 직접 확인해 볼 수 있다.
FS0:\> help HIIStringsMan.efi -v
HIIStringsMan application.
This is the synopsis section.
This is the description section.
This is the options section.
This is the return values section.
This is the section for used environment variables
This is the section for files associated with the subject.
This is the section for examples and suggestions.
This is the section for errors reported by the command.
This is the section for conformance to applicable standards.
This is the section for errors and caveats.
This is the section for categories.
This is an example of a custom section.
FS0:\> help HIIStringsMan.efi -section BUGS
This is the section for errors and caveats.
-? 옵션도 마찬가지다.
FS0:\> HIIStringsMan.efi -? -section "RETURN VALUES"
This is the return values section.
FS0:\> HIIStringsMan.efi -? -verbose
HIIStringsMan application.
This is the synopsis section.
This is the description section.
This is the options section.
This is the return values section.
This is the section for used environment variables
This is the section for files associated with the subject.
This is the section for examples and suggestions.
This is the section for errors reported by the command.
This is the section for conformance to applicable standards.
This is the section for errors and caveats.
This is the section for categories.
This is an example of a custom section.
ShellManParser가 호출되는 방식
ShellManParser가 애플리케이션 문자열을 파싱한 것이라는 가정으로, 이번 장을 시작했었다. 도움말 프로그램이 이 모듈을 사용하여, 어떻게 끝나는 지 조사해보자.
모든 걸 따져보면, ShellCommandRunHelp는 ShellPrintHelp 함수(Help.c)를 호출한다.
$ cat ShellPkg/Library/UefiShellLevel3CommandsLib/Help.c
---
SHELL_STATUS
EFIAPI
ShellCommandRunHelp (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
...
Status = ShellPrintHelp(CommandToGetHelpOn, SectionToGetHelpOn, FALSE);
...
}
이 ShellPrintHelp 함수는 UefiShellLib.c에 정의되어 있다. 주로 EFI_SHELL_PROTOCOL에서 GetHelpText 함수를 호출한다.
EFI_STATUS
EFIAPI
ShellPrintHelp (
IN CONST CHAR16 *CommandToGetHelpOn,
IN CONST CHAR16 *SectionToGetHelpOn,
IN BOOLEAN PrintCommandText
)
{
...
Status = gEfiShellProtocol->GetHelpText (CommandToGetHelpOn, SectionToGetHelpOn, &OutText);
...
}
다음은 UEFI Shell 규격에서의 위 함수에 대한 설명이다.
EFI_SHELL_PROTOCOL.GetHelpText()
Summary:
Return help information about a specific command.
Prototype:
typedef
EFI_STATUS
(EFIAPI *EFI_SHELL_GET_HELP_TEXT) (
IN CONST CHAR16 *Command,
IN CONST CHAR16 *Sections,
OUT CHAR16 **HelpText
);
Parameters:
Command Points to the null-terminated UEFI Shell command name.
Sections Points to the null-terminated comma-delimited section names to return. If NULL, then all sections will be returned.
HelpText On return, points to a callee-allocated buffer containing all specified help text.
EDKII의 EFI_SHELL_PROTOCOL structure에 대한 프로토타입은 Shell.h에 나와있다.