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