1/** @file
2  Main file for time, timezone, and date shell level 2 and shell level 3 functions.
3
4  (C) Copyright 2012-2015 Hewlett-Packard Development Company, L.P.<BR>
5  Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
6  This program and the accompanying materials
7  are licensed and made available under the terms and conditions of the BSD License
8  which accompanies this distribution.  The full text of the license may be found at
9  http://opensource.org/licenses/bsd-license.php
10
11  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14**/
15
16#include "UefiShellLevel2CommandsLib.h"
17
18/**
19  Determine if String is a valid representation for a time or date.
20
21  @param[in] String     The pointer to the string to test.
22  @param[in] Char       The delimeter character.
23  @param[in] Min        The minimum value allowed.
24  @param[in] Max        The maximum value allowed.
25  @param[in] MinusOk    Whether negative numbers are permitted.
26
27  @retval TRUE    String is a valid representation.
28  @retval FALSE   String is invalid.
29**/
30BOOLEAN
31EFIAPI
32InternalIsTimeLikeString (
33  IN CONST CHAR16   *String,
34  IN CONST CHAR16   Char,
35  IN CONST UINTN    Min,
36  IN CONST UINTN    Max,
37  IN CONST BOOLEAN  MinusOk
38  )
39{
40  UINTN Count;
41  Count = 0;
42
43  if (MinusOk) {
44    //
45    // A single minus is ok.
46    //
47    if (*String == L'-') {
48      String++;
49    }
50  }
51
52  //
53  // the first char must be numeric.
54  //
55  if (!ShellIsDecimalDigitCharacter(*String)) {
56    return (FALSE);
57  }
58  //
59  // loop through the characters and use the lib function
60  //
61  for ( ; String != NULL && *String != CHAR_NULL ; String++){
62    if (*String == Char) {
63      Count++;
64      if (Count > Max) {
65        return (FALSE);
66      }
67      continue;
68    }
69    if (!ShellIsDecimalDigitCharacter(*String)) {
70      return (FALSE);
71    }
72  }
73  if (Count < Min) {
74    return (FALSE);
75  }
76  return (TRUE);
77}
78
79/**
80  Verify that the DateString is valid and if so set that as the current
81  date.
82
83  @param[in] DateString     The pointer to a string representation of the date.
84
85  @retval SHELL_INVALID_PARAMETER   DateString was NULL.
86  @retval SHELL_INVALID_PARAMETER   DateString was mis-formatted.
87  @retval SHELL_SUCCESS             The operation was successful.
88**/
89SHELL_STATUS
90EFIAPI
91CheckAndSetDate (
92  IN CONST CHAR16 *DateString
93  )
94{
95  EFI_TIME      TheTime;
96  EFI_STATUS    Status;
97  CHAR16        *DateStringCopy;
98  CHAR16        *Walker;
99  CHAR16        *Walker1;
100
101  if (!InternalIsTimeLikeString(DateString, L'/', 2, 2, FALSE)) {
102    return (SHELL_INVALID_PARAMETER);
103  }
104
105  Status = gRT->GetTime(&TheTime, NULL);
106  if (EFI_ERROR(Status)) {
107    ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_UEFI_FUNC_WARN), gShellLevel2HiiHandle, L"date", L"gRT->GetTime", Status);
108    return (SHELL_DEVICE_ERROR);
109  }
110
111  DateStringCopy = NULL;
112  DateStringCopy = StrnCatGrow(&DateStringCopy, NULL, DateString, 0);
113  if (DateStringCopy == NULL) {
114    return (SHELL_OUT_OF_RESOURCES);
115  }
116  Walker = DateStringCopy;
117
118  TheTime.Month = 0xFF;
119  TheTime.Day   = 0xFF;
120  TheTime.Year  = 0xFFFF;
121
122  Walker1 = StrStr(Walker, L"/");
123  if (Walker1 != NULL && *Walker1 == L'/') {
124    *Walker1 = CHAR_NULL;
125  }
126
127  TheTime.Month = (UINT8)ShellStrToUintn (Walker);
128  if (Walker1 != NULL) {
129    Walker = Walker1 + 1;
130  }
131  Walker1 = Walker!=NULL?StrStr(Walker, L"/"):NULL;
132  if (Walker1 != NULL && *Walker1 == L'/') {
133    *Walker1 = CHAR_NULL;
134  }
135  if (Walker != NULL && Walker[0] != CHAR_NULL) {
136    TheTime.Day = (UINT8)ShellStrToUintn (Walker);
137    if (Walker1 != NULL) {
138      Walker = Walker1 + 1;
139    }
140    Walker1 = Walker!=NULL?StrStr(Walker, L"/"):NULL;
141    if (Walker1 != NULL && *Walker1 == L'/') {
142      *Walker1 = CHAR_NULL;
143    }
144    if (Walker != NULL && Walker[0] != CHAR_NULL) {
145      TheTime.Year = (UINT16)ShellStrToUintn (Walker);
146    }
147  }
148
149  if (TheTime.Year < 100) {
150    if (TheTime.Year >= 98) {
151      TheTime.Year = (UINT16)(1900 + TheTime.Year);
152    } else {
153      TheTime.Year = (UINT16)(2000 + TheTime.Year);
154    }
155  }
156
157  Status = gRT->SetTime(&TheTime);
158
159  if (!EFI_ERROR(Status)){
160    return (SHELL_SUCCESS);
161  }
162  return (SHELL_INVALID_PARAMETER);
163}
164
165/**
166  Function for 'date' command.
167
168  @param[in] ImageHandle  Handle to the Image (NULL if Internal).
169  @param[in] SystemTable  Pointer to the System Table (NULL if Internal).
170**/
171SHELL_STATUS
172EFIAPI
173ShellCommandRunDate (
174  IN EFI_HANDLE        ImageHandle,
175  IN EFI_SYSTEM_TABLE  *SystemTable
176  )
177{
178  EFI_STATUS    Status;
179  LIST_ENTRY    *Package;
180  EFI_TIME      TheTime;
181  CHAR16        *ProblemParam;
182  SHELL_STATUS  ShellStatus;
183  CONST CHAR16  *Param1;
184
185  ShellStatus  = SHELL_SUCCESS;
186  ProblemParam = NULL;
187
188  //
189  // initialize the shell lib (we must be in non-auto-init...)
190  //
191  Status = ShellInitialize();
192  ASSERT_EFI_ERROR(Status);
193
194  //
195  // parse the command line
196  //
197  Status = ShellCommandLineParse (SfoParamList, &Package, &ProblemParam, TRUE);
198  if (EFI_ERROR(Status)) {
199    if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
200      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"date", ProblemParam);
201      FreePool(ProblemParam);
202      ShellStatus = SHELL_INVALID_PARAMETER;
203    } else {
204      ASSERT(FALSE);
205    }
206  } else {
207    //
208    // check for "-?"
209    //
210    if (ShellCommandLineGetFlag(Package, L"-?")) {
211      ASSERT(FALSE);
212    } else if (ShellCommandLineGetRawValue(Package, 2) != NULL) {
213      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"date");
214      ShellStatus = SHELL_INVALID_PARAMETER;
215    } else {
216      //
217      // If there are 0 value parameters, then print the current date
218      // else If there are any value paramerers, then print error
219      //
220      if (ShellCommandLineGetRawValue(Package, 1) == NULL) {
221        //
222        // get the current date
223        //
224        Status = gRT->GetTime(&TheTime, NULL);
225        if (EFI_ERROR(Status)) {
226          ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_UEFI_FUNC_WARN), gShellLevel2HiiHandle, L"date", L"gRT->GetTime", Status);
227          return (SHELL_DEVICE_ERROR);
228        }
229
230        //
231        // ShellPrintEx the date in SFO or regular format
232        //
233        if (ShellCommandLineGetFlag(Package, L"-sfo")) {
234          //
235          // Match UEFI Shell spec:
236          // ShellCommand,"date"
237          // Date,"DD","MM","YYYY"
238          //
239          ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_SFO_HEADER), gShellLevel2HiiHandle, L"date");
240          ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DATE_SFO_FORMAT), gShellLevel2HiiHandle, TheTime.Day, TheTime.Month, TheTime.Year);
241        } else {
242          ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_DATE_FORMAT), gShellLevel2HiiHandle, TheTime.Month, TheTime.Day, TheTime.Year);
243        }
244      } else {
245        if (PcdGet8(PcdShellSupportLevel) == 2) {
246          ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"date");
247          ShellStatus = SHELL_INVALID_PARAMETER;
248        } else {
249          //
250          // perform level 3 operation here.
251          //
252          Param1 = ShellCommandLineGetRawValue(Package, 1);
253          if (Param1 == NULL) {
254            ShellStatus = SHELL_INVALID_PARAMETER;
255          } else {
256            ShellStatus = CheckAndSetDate(Param1);
257          }
258          if (ShellStatus != SHELL_SUCCESS) {
259            ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"date", Param1);
260            ShellStatus = SHELL_INVALID_PARAMETER;
261          }
262        }
263      }
264    }
265  }
266  //
267  // free the command line package
268  //
269  ShellCommandLineFreeVarList (Package);
270
271  //
272  // return the status
273  //
274  return (ShellStatus);
275}
276
277//
278// Note "-tz" is invalid for this (non-interactive) version of 'time'.
279//
280STATIC CONST SHELL_PARAM_ITEM TimeParamList2[] = {
281  {L"-d", TypeValue},
282  {NULL, TypeMax}
283  };
284
285STATIC CONST SHELL_PARAM_ITEM TimeParamList3[] = {
286  {L"-d", TypeValue},
287  {L"-tz", TypeValue},
288  {NULL, TypeMax}
289  };
290
291/**
292  Verify that the TimeString is valid and if so set that as the current
293  time.
294
295  @param[in] TimeString     The pointer to a string representation of the time.
296  @param[in] Tz             The value to set for TimeZone.
297  @param[in] Daylight       The value to set for Daylight.
298
299  @retval SHELL_INVALID_PARAMETER   TimeString was NULL.
300  @retval SHELL_INVALID_PARAMETER   TimeString was mis-formatted.
301  @retval SHELL_SUCCESS             The operation was successful.
302**/
303SHELL_STATUS
304EFIAPI
305CheckAndSetTime (
306  IN CONST CHAR16 *TimeString,
307  IN CONST INT16  Tz,
308  IN CONST UINT8  Daylight
309  )
310{
311  EFI_TIME      TheTime;
312  EFI_STATUS    Status;
313  CHAR16        *TimeStringCopy;
314  CHAR16        *Walker1;
315  CHAR16        *Walker2;
316
317  if (TimeString != NULL && !InternalIsTimeLikeString(TimeString, L':', 1, 2, FALSE)) {
318    return (SHELL_INVALID_PARAMETER);
319  }
320  if (Daylight != 0xFF &&((Daylight & (EFI_TIME_IN_DAYLIGHT|EFI_TIME_ADJUST_DAYLIGHT)) != Daylight)) {
321    return (SHELL_INVALID_PARAMETER);
322  }
323
324  Status = gRT->GetTime(&TheTime, NULL);
325  if (EFI_ERROR(Status)) {
326    ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_UEFI_FUNC_WARN), gShellLevel2HiiHandle, L"time", L"gRT->GetTime", Status);
327    return (SHELL_DEVICE_ERROR);
328  }
329
330  if (TimeString != NULL) {
331    TimeStringCopy = NULL;
332    TimeStringCopy = StrnCatGrow(&TimeStringCopy, NULL, TimeString, 0);
333    Walker1          = TimeStringCopy;
334    TheTime.Hour    = 0xFF;
335    TheTime.Minute  = 0xFF;
336
337    Walker2          = Walker1!=NULL?StrStr(Walker1, L":"):NULL;
338    if (Walker2 != NULL && *Walker2 == L':') {
339      *Walker2 = CHAR_NULL;
340    }
341    TheTime.Hour    = (UINT8)ShellStrToUintn (Walker1);
342    if (Walker2 != NULL) {
343      Walker1 = Walker2 + 1;
344    }
345    Walker2          = Walker1!=NULL?StrStr(Walker1, L":"):NULL;
346    if (Walker2 != NULL && *Walker2 == L':') {
347      *Walker2 = CHAR_NULL;
348      TheTime.Second = (UINT8)0;
349    }
350    else if (Walker2 == NULL) {
351      TheTime.Second = (UINT8)0;
352    }
353    if (Walker1 != NULL && Walker1[0] != CHAR_NULL) {
354      TheTime.Minute = (UINT8)ShellStrToUintn (Walker1);
355      if (Walker2 != NULL) {
356        Walker1 = Walker2 + 1;
357        if (Walker1 != NULL && Walker1[0] != CHAR_NULL) {
358          TheTime.Second = (UINT8)ShellStrToUintn (Walker1);
359        }
360      }
361    }
362    SHELL_FREE_NON_NULL(TimeStringCopy);
363  }
364
365
366  if (Tz >= -1440 && Tz <= 1440) {
367    //
368    // EFI_TIME TimeZone is stored to meet the following calculation (see UEFI Spec):
369    // Localtime = UTC - TimeZone
370    // This means the sign must be changed for the user provided Tz.
371    // EX: User wants to set TimeZone to Pacific Standard Time, so runs
372    // time -tz -480 # set to UTC-08:00
373    // To meet the calculation, the sign must be changed.
374    //
375    TheTime.TimeZone = -Tz;
376  } else if (Tz == EFI_UNSPECIFIED_TIMEZONE) {
377    TheTime.TimeZone = Tz;
378  }
379
380  if (Daylight != 0xFF) {
381    TheTime.Daylight = Daylight;
382  }
383
384  Status = gRT->SetTime(&TheTime);
385
386  if (!EFI_ERROR(Status)){
387    return (SHELL_SUCCESS);
388  }
389
390  return (SHELL_INVALID_PARAMETER);
391}
392
393/**
394  Function for 'time' command.
395
396  @param[in] ImageHandle  Handle to the Image (NULL if Internal).
397  @param[in] SystemTable  Pointer to the System Table (NULL if Internal).
398**/
399SHELL_STATUS
400EFIAPI
401ShellCommandRunTime (
402  IN EFI_HANDLE        ImageHandle,
403  IN EFI_SYSTEM_TABLE  *SystemTable
404  )
405{
406  EFI_STATUS    Status;
407  LIST_ENTRY    *Package;
408  EFI_TIME      TheTime;
409  CHAR16        *ProblemParam;
410  SHELL_STATUS  ShellStatus;
411  INT16         Tz;
412  UINT8         Daylight;
413  CONST CHAR16  *TempLocation;
414  UINTN         TzMinutes;
415
416  //
417  // Initialize variables
418  //
419  ShellStatus  = SHELL_SUCCESS;
420  ProblemParam = NULL;
421
422  //
423  // initialize the shell lib (we must be in non-auto-init...)
424  //
425  Status = ShellInitialize();
426  ASSERT_EFI_ERROR(Status);
427
428  //
429  // parse the command line
430  //
431  if (PcdGet8(PcdShellSupportLevel) == 2) {
432    Status = ShellCommandLineParseEx (TimeParamList2, &Package, &ProblemParam, TRUE, TRUE);
433  } else {
434    ASSERT(PcdGet8(PcdShellSupportLevel) == 3);
435    Status = ShellCommandLineParseEx (TimeParamList3, &Package, &ProblemParam, TRUE, TRUE);
436  }
437  if (EFI_ERROR(Status)) {
438    if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
439      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"time", ProblemParam);
440      FreePool(ProblemParam);
441      ShellStatus = SHELL_INVALID_PARAMETER;
442    } else {
443      ASSERT(FALSE);
444    }
445  } else {
446    //
447    // check for "-?"
448    //
449    Status = gRT->GetTime(&TheTime, NULL);
450    if (EFI_ERROR(Status)) {
451      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_UEFI_FUNC_WARN), gShellLevel2HiiHandle, L"time", L"gRT->GetTime", Status);
452      return (SHELL_DEVICE_ERROR);
453    }
454
455    if (ShellCommandLineGetFlag(Package, L"-?")) {
456      ASSERT(FALSE);
457    } else if (ShellCommandLineGetRawValue(Package, 2) != NULL) {
458      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"time");
459      ShellStatus = SHELL_INVALID_PARAMETER;
460    } else {
461      //
462      // If there are no parameters, then print the current time
463      //
464      if (ShellCommandLineGetRawValue(Package, 1) == NULL
465        && !ShellCommandLineGetFlag(Package, L"-d")
466        && !ShellCommandLineGetFlag(Package, L"-tz")) {
467        //
468        // ShellPrintEx the current time
469        //
470        if (TheTime.TimeZone == EFI_UNSPECIFIED_TIMEZONE) {
471          TzMinutes = 0;
472        } else {
473          TzMinutes = (ABS(TheTime.TimeZone)) % 60;
474        }
475
476        if (TheTime.TimeZone != EFI_UNSPECIFIED_TIMEZONE) {
477          ShellPrintHiiEx (
478            -1,
479            -1,
480            NULL,
481            STRING_TOKEN (STR_TIME_FORMAT),
482            gShellLevel2HiiHandle,
483            TheTime.Hour,
484            TheTime.Minute,
485            TheTime.Second,
486            (TheTime.TimeZone > 0?L"-":L"+"),
487            ((ABS(TheTime.TimeZone)) / 60),
488            TzMinutes
489            );
490        } else {
491          ShellPrintHiiEx (
492            -1,
493            -1,
494            NULL,
495            STRING_TOKEN (STR_TIME_FORMAT_LOCAL),
496            gShellLevel2HiiHandle,
497            TheTime.Hour,
498            TheTime.Minute,
499            TheTime.Second
500            );
501        }
502        ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_CRLF), gShellLevel2HiiHandle);
503      } else if (ShellCommandLineGetFlag(Package, L"-d") && ShellCommandLineGetValue(Package, L"-d") == NULL) {
504        if (TheTime.TimeZone == EFI_UNSPECIFIED_TIMEZONE) {
505          ShellPrintHiiEx (
506            -1,
507            -1,
508            NULL,
509            STRING_TOKEN (STR_TIME_FORMAT_LOCAL),
510            gShellLevel2HiiHandle,
511            TheTime.Hour,
512            TheTime.Minute,
513            TheTime.Second
514            );
515        } else {
516          TzMinutes = (ABS(TheTime.TimeZone)) % 60;
517          ShellPrintHiiEx (
518            -1,
519            -1,
520            NULL,
521            STRING_TOKEN (STR_TIME_FORMAT),
522            gShellLevel2HiiHandle,
523            TheTime.Hour,
524            TheTime.Minute,
525            TheTime.Second,
526            (TheTime.TimeZone > 0?L"-":L"+"),
527            ((ABS(TheTime.TimeZone)) / 60),
528            TzMinutes
529           );
530        }
531          switch (TheTime.Daylight) {
532            case 0:
533              ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_TIME_DST0), gShellLevel2HiiHandle);
534              break;
535            case EFI_TIME_ADJUST_DAYLIGHT:
536              ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_TIME_DST1), gShellLevel2HiiHandle);
537              break;
538            case EFI_TIME_IN_DAYLIGHT:
539              ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_TIME_DST2), gShellLevel2HiiHandle);
540              break;
541            case EFI_TIME_IN_DAYLIGHT|EFI_TIME_ADJUST_DAYLIGHT:
542              ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_TIME_DST3), gShellLevel2HiiHandle);
543              break;
544            default:
545              ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_UEFI_FUNC_ERROR), gShellLevel2HiiHandle, L"time", L"gRT->GetTime", L"TheTime.Daylight", TheTime.Daylight);
546          }
547      } else {
548        if (PcdGet8(PcdShellSupportLevel) == 2) {
549          ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"time");
550          ShellStatus = SHELL_INVALID_PARAMETER;
551        } else {
552          //
553          // perform level 3 operation here.
554          //
555          if ((TempLocation = ShellCommandLineGetValue(Package, L"-tz")) != NULL) {
556            if (StrniCmp (TempLocation, L"_local", StrLen (TempLocation)) == NULL) {
557              Tz = EFI_UNSPECIFIED_TIMEZONE;
558            } else if (TempLocation[0] == L'-') {
559
560              Tz = (INT16) ShellStrToUintn (++TempLocation);
561              //
562              // When the argument of "time [-tz tz]" is not numeric, ShellStrToUintn() returns "-1".
563              // Here we can detect the argument error by checking the return of ShellStrToUintn().
564              //
565              if (Tz == -1) {
566                Tz = 1441; //make it to be out of bounds value
567              } else {
568                Tz *= (-1); //sign convert
569              }
570            } else {
571              if (TempLocation[0] == L'+') {
572                Tz = (INT16)ShellStrToUintn (++TempLocation);
573              } else {
574                Tz = (INT16)ShellStrToUintn (TempLocation);
575              }
576              //
577              // Detect the return of ShellStrToUintn() to make sure the argument is valid.
578              //
579              if (Tz == -1) {
580                Tz = 1441; //make it to be out of bounds value
581              }
582            }
583            if (!(Tz >= -1440 && Tz <= 1440) && Tz != EFI_UNSPECIFIED_TIMEZONE) {
584              ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellLevel2HiiHandle, L"time", TempLocation, L"-tz");
585              ShellStatus = SHELL_INVALID_PARAMETER;
586            }
587          } else {
588            //
589            // intentionally out of bounds value will prevent changing it...
590            //
591            Tz = 1441;
592          }
593          TempLocation = ShellCommandLineGetValue(Package, L"-d");
594          if (TempLocation != NULL) {
595            Daylight = (UINT8)ShellStrToUintn(TempLocation);
596            //
597            // The argument of "time [-d dl]" is unsigned, if the first character is '-',
598            // the argument is incorrect.  That's because ShellStrToUintn() will skip past
599            // any '-' sign and convert what's next, forgetting the sign is here.
600            //
601            if (TempLocation[0] == '-') {
602              Daylight = 0xff; //make it invalid = will not use
603            }
604            if (Daylight != 0 && Daylight != 1 && Daylight != 3) {
605              ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellLevel2HiiHandle, L"time", TempLocation, L"-d");
606              ShellStatus = SHELL_INVALID_PARAMETER;
607            }
608          } else {
609            //
610            // invalid = will not use
611            //
612            Daylight = 0xFF;
613          }
614          if (ShellStatus == SHELL_SUCCESS) {
615            ShellStatus = CheckAndSetTime(ShellCommandLineGetRawValue(Package, 1), Tz, Daylight);
616            if (ShellStatus != SHELL_SUCCESS) {
617              ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"time", ShellCommandLineGetRawValue(Package, 1));
618              ShellStatus = SHELL_INVALID_PARAMETER;
619            }
620          }
621        }
622      }
623    }
624  }
625
626  //
627  // free the command line package
628  //
629  ShellCommandLineFreeVarList (Package);
630
631  //
632  // return the status
633  //
634  return (ShellStatus);
635}
636
637typedef struct {
638  INT16         TimeZone;
639  EFI_STRING_ID StringId;
640} TIME_ZONE_ITEM;
641
642STATIC CONST SHELL_PARAM_ITEM TimeZoneParamList2[] = {
643  {L"-l", TypeFlag},
644  {L"-f", TypeFlag},
645  {NULL, TypeMax}
646  };
647STATIC CONST SHELL_PARAM_ITEM TimeZoneParamList3[] = {
648  {L"-l", TypeFlag},
649  {L"-f", TypeFlag},
650  {L"-s", TypeTimeValue},
651  {NULL, TypeMax}
652  };
653
654  STATIC CONST TIME_ZONE_ITEM TimeZoneList[] = {
655    {720, STRING_TOKEN (STR_TIMEZONE_M12)},
656    {660, STRING_TOKEN (STR_TIMEZONE_M11)},
657    {600, STRING_TOKEN (STR_TIMEZONE_M10)},
658    {540, STRING_TOKEN (STR_TIMEZONE_M9)},
659    {480, STRING_TOKEN (STR_TIMEZONE_M8)},
660    {420, STRING_TOKEN (STR_TIMEZONE_M7)},
661    {360, STRING_TOKEN (STR_TIMEZONE_M6)},
662    {300, STRING_TOKEN (STR_TIMEZONE_M5)},
663    {270, STRING_TOKEN (STR_TIMEZONE_M430)},
664    {240, STRING_TOKEN (STR_TIMEZONE_M4)},
665    {210, STRING_TOKEN (STR_TIMEZONE_M330)},
666    {180, STRING_TOKEN (STR_TIMEZONE_M3)},
667    {120, STRING_TOKEN (STR_TIMEZONE_M2)},
668    {60 , STRING_TOKEN (STR_TIMEZONE_M1)},
669    {0   , STRING_TOKEN (STR_TIMEZONE_0)},
670    {-60  , STRING_TOKEN (STR_TIMEZONE_P1)},
671    {-120 , STRING_TOKEN (STR_TIMEZONE_P2)},
672    {-180 , STRING_TOKEN (STR_TIMEZONE_P3)},
673    {-210 , STRING_TOKEN (STR_TIMEZONE_P330)},
674    {-240 , STRING_TOKEN (STR_TIMEZONE_P4)},
675    {-270 , STRING_TOKEN (STR_TIMEZONE_P430)},
676    {-300 , STRING_TOKEN (STR_TIMEZONE_P5)},
677    {-330 , STRING_TOKEN (STR_TIMEZONE_P530)},
678    {-345 , STRING_TOKEN (STR_TIMEZONE_P545)},
679    {-360 , STRING_TOKEN (STR_TIMEZONE_P6)},
680    {-390 , STRING_TOKEN (STR_TIMEZONE_P630)},
681    {-420 , STRING_TOKEN (STR_TIMEZONE_P7)},
682    {-480 , STRING_TOKEN (STR_TIMEZONE_P8)},
683    {-540 , STRING_TOKEN (STR_TIMEZONE_P9)},
684    {-570 , STRING_TOKEN (STR_TIMEZONE_P930)},
685    {-600 , STRING_TOKEN (STR_TIMEZONE_P10)},
686    {-660 , STRING_TOKEN (STR_TIMEZONE_P11)},
687    {-720 , STRING_TOKEN (STR_TIMEZONE_P12)},
688    {-780 , STRING_TOKEN (STR_TIMEZONE_P13)},
689    {-840 , STRING_TOKEN (STR_TIMEZONE_P14)},
690    {EFI_UNSPECIFIED_TIMEZONE, STRING_TOKEN (STR_TIMEZONE_LOCAL)}
691};
692
693/**
694  Verify that the TimeZoneString is valid and if so set that as the current
695  timezone.
696
697  @param[in] TimeZoneString     The pointer to a string representation of the timezone.
698
699  @retval SHELL_INVALID_PARAMETER   TimeZoneString was NULL.
700  @retval SHELL_INVALID_PARAMETER   TimeZoneString was mis-formatted.
701  @retval SHELL_SUCCESS             The operation was successful.
702**/
703SHELL_STATUS
704EFIAPI
705CheckAndSetTimeZone (
706  IN CONST CHAR16 *TimeZoneString
707  )
708{
709  EFI_TIME      TheTime;
710  EFI_STATUS    Status;
711  CHAR16        *TimeZoneCopy;
712  CHAR16        *Walker;
713  CHAR16        *Walker2;
714  UINTN         LoopVar;
715
716  if (TimeZoneString == NULL) {
717    return (SHELL_INVALID_PARAMETER);
718  }
719
720  if (StrniCmp (TimeZoneString, L"_local", StrLen (TimeZoneString)) == NULL) {
721    Status = gRT->GetTime (&TheTime, NULL);
722    if (EFI_ERROR (Status)) {
723      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_UEFI_FUNC_WARN), gShellLevel2HiiHandle, L"gRT->GetTime", Status);
724      return (SHELL_DEVICE_ERROR);
725    }
726
727    TheTime.TimeZone = EFI_UNSPECIFIED_TIMEZONE;
728    Status = gRT->SetTime (&TheTime);
729    if (!EFI_ERROR(Status)){
730      return (SHELL_SUCCESS);
731    }
732    return (SHELL_INVALID_PARAMETER);
733  }
734  if (TimeZoneString != NULL && !InternalIsTimeLikeString(TimeZoneString, L':', 1, 1, TRUE)) {
735    return (SHELL_INVALID_PARAMETER);
736  }
737
738  Status = gRT->GetTime(&TheTime, NULL);
739  if (EFI_ERROR(Status)) {
740    ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_UEFI_FUNC_WARN), gShellLevel2HiiHandle, L"timezone", L"gRT->GetTime", Status);
741    return (SHELL_DEVICE_ERROR);
742  }
743
744  TimeZoneCopy = NULL;
745  TimeZoneCopy = StrnCatGrow(&TimeZoneCopy, NULL, TimeZoneString, 0);
746  if (TimeZoneCopy == NULL) {
747    return (SHELL_OUT_OF_RESOURCES);
748  }
749  Walker = TimeZoneCopy;
750  Walker2 = StrStr(Walker, L":");
751  if (Walker2 != NULL && *Walker2 == L':') {
752    *Walker2 = CHAR_NULL;
753  }
754  if (*Walker == L'-') {
755    TheTime.TimeZone = (INT16)((ShellStrToUintn (++Walker)) * 60);
756  } else {
757    TheTime.TimeZone = (INT16)((INT16)(ShellStrToUintn (Walker)) * -60);
758  }
759  if (Walker2 != NULL) {
760    Walker = Walker2 + 1;
761  }
762  if (Walker != NULL && Walker[0] != CHAR_NULL) {
763    if (TheTime.TimeZone < 0) {
764      TheTime.TimeZone = (INT16)(TheTime.TimeZone - (UINT8)ShellStrToUintn (Walker));
765    } else {
766      TheTime.TimeZone = (INT16)(TheTime.TimeZone + (UINT8)ShellStrToUintn (Walker));
767    }
768  }
769
770  Status = EFI_INVALID_PARAMETER;
771
772  for ( LoopVar = 0
773      ; LoopVar < sizeof(TimeZoneList) / sizeof(TimeZoneList[0])
774      ; LoopVar++
775     ){
776    if (TheTime.TimeZone == TimeZoneList[LoopVar].TimeZone) {
777        Status = gRT->SetTime(&TheTime);
778        break;
779    }
780  }
781
782  FreePool(TimeZoneCopy);
783
784  if (!EFI_ERROR(Status)){
785    return (SHELL_SUCCESS);
786  }
787  return (SHELL_INVALID_PARAMETER);
788}
789
790
791/**
792  Function for 'timezone' command.
793
794  @param[in] ImageHandle  Handle to the Image (NULL if Internal).
795  @param[in] SystemTable  Pointer to the System Table (NULL if Internal).
796**/
797SHELL_STATUS
798EFIAPI
799ShellCommandRunTimeZone (
800  IN EFI_HANDLE        ImageHandle,
801  IN EFI_SYSTEM_TABLE  *SystemTable
802  )
803{
804  //
805  // non interactive
806  //
807  EFI_STATUS    Status;
808  LIST_ENTRY    *Package;
809  CHAR16        *ProblemParam;
810  SHELL_STATUS  ShellStatus;
811  UINT8         LoopVar;
812  EFI_TIME      TheTime;
813  BOOLEAN       Found;
814  UINTN         TzMinutes;
815
816  ShellStatus  = SHELL_SUCCESS;
817  ProblemParam = NULL;
818
819  //
820  // initialize the shell lib (we must be in non-auto-init...)
821  //
822  Status = ShellInitialize();
823  ASSERT_EFI_ERROR(Status);
824
825  //
826  // parse the command line
827  //
828  if (PcdGet8(PcdShellSupportLevel) == 2) {
829    Status = ShellCommandLineParse (TimeZoneParamList2, &Package, &ProblemParam, TRUE);
830  } else {
831    ASSERT(PcdGet8(PcdShellSupportLevel) == 3);
832    Status = ShellCommandLineParseEx (TimeZoneParamList3, &Package, &ProblemParam, TRUE, TRUE);
833  }
834  if (EFI_ERROR(Status)) {
835    if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
836      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"timezone", ProblemParam);
837      FreePool(ProblemParam);
838      ShellStatus = SHELL_INVALID_PARAMETER;
839    } else {
840      ASSERT(FALSE);
841    }
842  } else {
843    //
844    // check for "-?"
845    //
846    if (ShellCommandLineGetCount(Package) > 1) {
847      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"timezone");
848      ShellStatus = SHELL_INVALID_PARAMETER;
849    } else if (ShellCommandLineGetFlag(Package, L"-?")) {
850      ASSERT(FALSE);
851    } else if (ShellCommandLineGetFlag(Package, L"-s")) {
852      if ((ShellCommandLineGetFlag(Package, L"-l")) || (ShellCommandLineGetFlag(Package, L"-f"))) {
853        ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"timezone", L"-l or -f");
854        ShellStatus = SHELL_INVALID_PARAMETER;
855      } else {
856        ASSERT(PcdGet8(PcdShellSupportLevel) == 3);
857        if (ShellCommandLineGetValue(Package, L"-s") == NULL) {
858          ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellLevel2HiiHandle, L"timezone", L"-s");
859          ShellStatus = SHELL_INVALID_PARAMETER;
860        } else {
861          //
862          // Set the time zone
863          //
864          ShellStatus = CheckAndSetTimeZone(ShellCommandLineGetValue(Package, L"-s"));
865          if (ShellStatus != SHELL_SUCCESS) {
866            ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"timezone", ShellCommandLineGetValue(Package, L"-s"));
867            ShellStatus = SHELL_INVALID_PARAMETER;
868          }
869        }
870      }
871    } else if (ShellCommandLineGetFlag(Package, L"-l")) {
872      //
873      // Print a list of all time zones
874      //
875      for ( LoopVar = 0
876          ; LoopVar < sizeof(TimeZoneList) / sizeof(TimeZoneList[0])
877          ; LoopVar++
878         ){
879        ShellPrintHiiEx (-1, -1, NULL, TimeZoneList[LoopVar].StringId, gShellLevel2HiiHandle);
880      }
881    } else {
882      //
883      // Get Current Time Zone Info
884      //
885      Status = gRT->GetTime(&TheTime, NULL);
886      if (EFI_ERROR(Status)) {
887        ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_UEFI_FUNC_WARN), gShellLevel2HiiHandle, L"timezone", L"gRT->GetTime", Status);
888        return (SHELL_DEVICE_ERROR);
889      }
890
891      if (TheTime.TimeZone != EFI_UNSPECIFIED_TIMEZONE) {
892        Found = FALSE;
893        for ( LoopVar = 0
894            ; LoopVar < sizeof(TimeZoneList) / sizeof(TimeZoneList[0])
895            ; LoopVar++
896           ){
897          if (TheTime.TimeZone == TimeZoneList[LoopVar].TimeZone) {
898            if (ShellCommandLineGetFlag(Package, L"-f")) {
899              //
900              //  Print all info about current time zone
901              //
902              ShellPrintHiiEx (-1, -1, NULL, TimeZoneList[LoopVar].StringId, gShellLevel2HiiHandle);
903            } else {
904              //
905              // Print basic info only
906              //
907              TzMinutes = (ABS(TheTime.TimeZone)) % 60;
908
909              ShellPrintHiiEx (
910                -1,
911                -1,
912                NULL,
913                STRING_TOKEN(STR_TIMEZONE_SIMPLE),
914                gShellLevel2HiiHandle,
915                (TheTime.TimeZone > 0?L"-":L"+"),
916                (ABS(TheTime.TimeZone)) / 60,
917                TzMinutes);
918            }
919            Found = TRUE;
920            break;
921          }
922        }
923        if (!Found) {
924          //
925          // Print basic info only
926          //
927          TzMinutes = (ABS(TheTime.TimeZone)) % 60;
928
929          ShellPrintHiiEx (
930            -1,
931            -1,
932            NULL,
933            STRING_TOKEN(STR_TIMEZONE_SIMPLE),
934            gShellLevel2HiiHandle,
935            (TheTime.TimeZone > 0?L"-":L"+"),
936            (ABS(TheTime.TimeZone)) / 60,
937            TzMinutes);
938
939          if (ShellCommandLineGetFlag(Package, L"-f")) {
940            ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN(STR_TIMEZONE_NI), gShellLevel2HiiHandle);
941          }
942        }
943      } else {
944        //
945        // TimeZone was EFI_UNSPECIFIED_TIMEZONE (local) from GetTime()
946        //
947        if (ShellCommandLineGetFlag (Package, L"-f")) {
948          for ( LoopVar = 0
949              ; LoopVar < sizeof (TimeZoneList) / sizeof (TimeZoneList[0])
950              ; LoopVar++
951             ){
952            if (TheTime.TimeZone == TimeZoneList[LoopVar].TimeZone) {
953              //
954              //  Print all info about current time zone
955              //
956              ShellPrintHiiEx (-1, -1, NULL, TimeZoneList[LoopVar].StringId, gShellLevel2HiiHandle);
957              break;
958            }
959          }
960        } else {
961          //
962          // Print basic info only
963          //
964          ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_TIMEZONE_SIMPLE_LOCAL), gShellLevel2HiiHandle);
965        }
966      }
967    }
968  }
969
970  //
971  // free the command line package
972  //
973  ShellCommandLineFreeVarList (Package);
974
975  return (ShellStatus);
976}
977