diff --git a/system.go b/system.go index bb484d7..a8381b3 100644 --- a/system.go +++ b/system.go @@ -1,10 +1,14 @@ package alpine_builder import ( + "bufio" "fmt" "io/ioutil" "os" "os/exec" + "path" + "path/filepath" + "sort" "strings" "github.com/GehirnInc/crypt" @@ -17,6 +21,8 @@ var systemDropbearConfig = "/data/etc/dropbear/dropbear.conf" var systemDropbearRestart = "rc-service dropbear restart" var systemShutdown = "poweroff" var systemReboot = "reboot" +var systemZoneinfo = "/usr/share/zoneinfo/" +var systemLocaltimeFile = "/data/etc/localtime" // SystemSetRootPassword update shadow file func SystemSetRootPassword(password string) error { @@ -94,3 +100,52 @@ func SystemReboot() error { } return nil } + +// SystemListTimeZones available on system +func SystemListTimeZones() ([]string, error) { + // load zone info tab + file, err := os.Open(path.Join(systemZoneinfo, "zone1970.tab")) + if err != nil { + return nil, err + } + defer file.Close() + + // parse file + zones := make([]string, 0) + scanner := bufio.NewScanner(file) + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + if strings.HasPrefix(line, "#") { + continue + } + + lineSplit := strings.Split(line, "\t") + if len(lineSplit) < 3 { + continue + } + + zones = append(zones, strings.TrimSpace(lineSplit[2])) + } + zones = append(zones, "Etc/UTC") + + sort.Strings(zones) + return zones, nil +} + +// SystemSetTimeZone for operating system +func SystemSetTimeZone(name string) error { + if _, err := os.Stat(path.Join(systemZoneinfo, name)); err != nil { + return fmt.Errorf("invalid time zone given: %s", name) + } + _ = os.Remove(systemLocaltimeFile) + return os.Symlink(path.Join(systemZoneinfo, name), systemLocaltimeFile) +} + +// SystemGetTimeZone currently set for operating system +func SystemGetTimeZone() (string, error) { + link, err := os.Readlink(systemLocaltimeFile) + if err != nil { + return "", fmt.Errorf("failed to get local time zone") + } + return filepath.Rel(systemZoneinfo, link) +} diff --git a/system_test.go b/system_test.go index 0c5adf2..4121360 100644 --- a/system_test.go +++ b/system_test.go @@ -3,6 +3,7 @@ package alpine_builder import ( "io/ioutil" "os" + "path" "strings" "testing" @@ -17,6 +18,9 @@ func init() { systemDropbearRestart = "restart_dropbear_command" systemReboot = "reboot_command" systemShutdown = "shutdown_command" + + systemZoneinfo = "zoneinfo/" + systemLocaltimeFile = "test_localtime" } func TestSystemSetRootPassword(t *testing.T) { @@ -92,3 +96,74 @@ func TestSystemShutdown(t *testing.T) { ass.EqualError(SystemShutdown(), "failed to start system shutdown: exec: \"shutdown_command\": executable file not found in $PATH") } + +var zoneTab = ` +# +#country- +#codes coordinates TZ comments +AD +4230+00131 Europe/Andorra +AE,OM +2518+05518 Asia/Dubai +AQ -6617+11031 Antarctica/Casey Casey +` + +func TestSystemListTimeZones(t *testing.T) { + ass := assert.New(t) + + _, err := SystemListTimeZones() + ass.EqualError(err, "open zoneinfo/zone1970.tab: no such file or directory") + + ass.NoError(os.MkdirAll(systemZoneinfo, os.ModePerm)) + testZoneTab := path.Join(systemZoneinfo, "zone1970.tab") + ass.NoError(ioutil.WriteFile(testZoneTab, []byte(zoneTab), os.ModePerm)) + + zones, err := SystemListTimeZones() + ass.NoError(err) + ass.Equal([]string{ + "Antarctica/Casey", + "Asia/Dubai", + "Etc/UTC", + "Europe/Andorra", + }, zones) + + ass.NoError(os.Remove(testZoneTab)) + ass.NoError(os.Remove(systemZoneinfo)) +} + +func TestSystemSetTimeZone(t *testing.T) { + ass := assert.New(t) + + ass.NoError(os.MkdirAll(systemZoneinfo, os.ModePerm)) + testZone := path.Join(systemZoneinfo, "test") + ass.NoError(ioutil.WriteFile(testZone, []byte(""), os.ModePerm)) + + ass.EqualError(SystemSetTimeZone("test2"), + "invalid time zone given: test2") + + ass.NoError(SystemSetTimeZone("test")) + ass.NoError(SystemSetTimeZone("test")) + + ass.NoError(os.Remove(systemLocaltimeFile)) + ass.NoError(os.Remove(testZone)) + ass.NoError(os.Remove(systemZoneinfo)) +} + +func TestSystemGetTimeZone(t *testing.T) { + ass := assert.New(t) + + ass.NoError(os.MkdirAll(systemZoneinfo, os.ModePerm)) + testZone := path.Join(systemZoneinfo, "test") + ass.NoError(ioutil.WriteFile(testZone, []byte(""), os.ModePerm)) + + _, err := SystemGetTimeZone() + ass.EqualError(err, "failed to get local time zone") + + ass.NoError(os.Symlink(path.Join(systemZoneinfo, "test"), systemLocaltimeFile)) + + zone, err := SystemGetTimeZone() + ass.NoError(err) + ass.Equal("test", zone) + + ass.NoError(os.Remove(systemLocaltimeFile)) + ass.NoError(os.Remove(testZone)) + ass.NoError(os.Remove(systemZoneinfo)) +}