// Copyright (C) 2016-2017 Luke Shumaker // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package sd_login import ( "strconv" "strings" "golang.org/x/sys/unix" ) // A MachineName is a name representing a locally running container or // virtual machine that is registerd with (systemd-)machined. type MachineName string func (m MachineName) isValid() bool { if len(m) > host_name_max { // Note that Linux HOST_NAME_MAX is 64, but DNS allows // 255, so names from DNS might be invalid. return false } n_dots := 0 dot := true for _, c := range m { if c == '.' { if dot { return false } dot = true n_dots++ } else { if !strings.ContainsRune(letters+digits+"-_.", c) { return false } dot = false } } if dot { // trailing dot or empty return false } return true } // GetMachines returns a list of currently running containers/virtual // machines. func GetMachines() ([]MachineName, error) { strs, err := get_files_in_directory("/run/systemd/machines/") if err != nil { return nil, err } var machines []MachineName for _, str := range strs { machine := MachineName(str) if strings.HasPrefix(str, "unit:") || machine.isValid() { continue } machines = append(machines, machine) } return machines, nil } // GetClass returns the class of a locally running machine. The class // is either "vm" or "container", depending on if the machine is an // virtual machine or a container. func (m MachineName) GetClass() (string, error) { if !m.isValid() { return "", unix.EINVAL } env, err := parse_env_file("/run/systemd/machines/" + string(m)) if err != nil { return "", err } class, ok := env["CLASS"] if !ok { return "", unix.ENXIO // or EIO? } return class, nil } // GetIfIndices returns the numeric indices of the network interfaces // on the host that are pointing toward this machine. func (m MachineName) GetIfIndices() ([]int, error) { if !m.isValid() { return nil, unix.EINVAL } env, err := parse_env_file("/run/systemd/machines/" + string(m)) if err != nil { return nil, err } netif, ok := env["NETIF"] if !ok { return nil, unix.ENXIO // or EIO? } var ifindices []int for _, word := range strings.FieldsFunc(netif, func(c rune) bool { return strings.ContainsRune(whitespace, c) }) { ifindex, err := strconv.Atoi(word) if err != nil { return nil, err } ifindices = append(ifindices, ifindex) } return ifindices, nil }