package network import ( "fmt" "os/exec" "strings" ) // IfDown brings an interface down via ifdown (or ip link set down as fallback). func IfDown(name string) error { out, err := exec.Command("ifdown", "--force", name).CombinedOutput() if err != nil { // fallback: ip link set down out2, err2 := exec.Command("ip", "link", "set", name, "down").CombinedOutput() if err2 != nil { return fmt.Errorf("ifdown %s: %s\nip fallback: %s", name, strings.TrimSpace(string(out)), strings.TrimSpace(string(out2))) } } return nil } // IfUp brings an interface up via ifup (or ip link set up as fallback). func IfUp(name string) error { out, err := exec.Command("ifup", name).CombinedOutput() if err != nil { out2, err2 := exec.Command("ip", "link", "set", name, "up").CombinedOutput() if err2 != nil { return fmt.Errorf("ifup %s: %s\nip fallback: %s", name, strings.TrimSpace(string(out)), strings.TrimSpace(string(out2))) } } return nil } // IfRestart brings an interface down then up. func IfRestart(name string) error { _ = IfDown(name) // ignore "already down" errors return IfUp(name) } // ApplyPending merges pending configs into /etc/network/interfaces, // writes the file, and restarts affected interfaces. // Returns a per-interface error map (nil key = write error). func ApplyPending() map[string]error { errs := map[string]error{} pending := GetAllPending() if len(pending) == 0 { return errs } // Read current file config configs, err := ParseConfig() if err != nil { errs["__parse__"] = err return errs } // Merge for name, cfg := range pending { configs[name] = cfg } // Write file if err := WriteConfig(configs); err != nil { errs["__write__"] = err return errs } // Restart each changed interface for name := range pending { if name == "lo" { ClearPendingConfig(name) continue } _ = IfDown(name) if cfg := configs[name]; cfg != nil && cfg.Auto { if err := IfUp(name); err != nil { errs[name] = err continue } } ClearPendingConfig(name) } return errs }