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 **/
30 BOOLEAN
31 EFIAPI
InternalIsTimeLikeString(IN CONST CHAR16 * String,IN CONST CHAR16 Char,IN CONST UINTN Min,IN CONST UINTN Max,IN CONST BOOLEAN MinusOk)32 InternalIsTimeLikeString (
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 **/
89 SHELL_STATUS
90 EFIAPI
CheckAndSetDate(IN CONST CHAR16 * DateString)91 CheckAndSetDate (
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 **/
171 SHELL_STATUS
172 EFIAPI
ShellCommandRunDate(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)173 ShellCommandRunDate (
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 //
280 STATIC CONST SHELL_PARAM_ITEM TimeParamList2[] = {
281   {L"-d", TypeValue},
282   {NULL, TypeMax}
283   };
284 
285 STATIC 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 **/
303 SHELL_STATUS
304 EFIAPI
CheckAndSetTime(IN CONST CHAR16 * TimeString,IN CONST INT16 Tz,IN CONST UINT8 Daylight)305 CheckAndSetTime (
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 **/
399 SHELL_STATUS
400 EFIAPI
ShellCommandRunTime(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)401 ShellCommandRunTime (
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 
637 typedef struct {
638   INT16         TimeZone;
639   EFI_STRING_ID StringId;
640 } TIME_ZONE_ITEM;
641 
642 STATIC CONST SHELL_PARAM_ITEM TimeZoneParamList2[] = {
643   {L"-l", TypeFlag},
644   {L"-f", TypeFlag},
645   {NULL, TypeMax}
646   };
647 STATIC 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 **/
703 SHELL_STATUS
704 EFIAPI
CheckAndSetTimeZone(IN CONST CHAR16 * TimeZoneString)705 CheckAndSetTimeZone (
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 **/
797 SHELL_STATUS
798 EFIAPI
ShellCommandRunTimeZone(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)799 ShellCommandRunTimeZone (
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