home *** CD-ROM | disk | FTP | other *** search
Text File | 2006-11-29 | 33.6 KB | 1,333 lines |
- /**
- * File: modules/NetworkDevices.ycp
- * Package: Network configuration
- * Summary: Interface manipulation (/etc/sysconfig/network/ifcfg-*)
- * Authors: Michal Svec <msvec@suse.cz>
- *
- * $Id: NetworkDevices.ycp 34371 2006-11-14 10:07:31Z kmachalkova $
- *
- * The new sysconfig naming is interface (eg. eth0) vs. device
- * (eg. NE2000 card), but historically yast has called them device
- * vs. module.
- */
-
- {
-
- module "NetworkDevices";
- textdomain "base";
-
- import "Arch";
- import "Map";
- import "Netmask";
- import "String";
-
- /**
- * False suppresses tones of logs 'NetworkDevices.ycp:ABC Check(eth,id-00:aa:bb:cc:dd:ee,)'
- */
- global boolean report_every_check = true;
-
- /**
- * Current device identifier
- * @example eth0, eth1:blah, lo, ...
- * Add, Edit and Delete copy the requested device info (via Select)
- * to Name and Current,
- * Commit puts it back
- */
- global string Name = "";
-
- // value is not just string, can be a map for aliases
- typedef map<string, any> ifcfg_t;
- typedef map<string, map<string, ifcfg_t> > devices_t;
-
- /**
- * Current device information
- * @example $["BOOTPROTO":"dhcp", "STARTMODE":"auto"]
- */
- global ifcfg_t Current = $[];
-
- /**
- * Interface information:
- * Devices[string type, string id] is a map with the contents of
- * ifcfg-<i>type</i>-<i>id</i>. Separating type from id is useful because
- * the type determines the fields of the interface file.
- * Multiple addresses for an interface are nested maps
- * [type, id, "_aliases", aid]
- * @see Read
- */
- devices_t Devices = $[];
-
- /**
- * Devices information
- * @see Read
- */
- devices_t OriginalDevices = $[];
-
- /**
- * Deleted devices
- */
- list<string> Deleted = [];
-
- /**
- * True if devices are already read
- */
- boolean initialized = false;
-
- /**
- * Which operation is pending?
- */
- /* global */ symbol operation = nil;
- // FIXME: used in lan/address.ycp (#17346) -> "global"
-
- /**
- * Predefined network card regular expressions
- */
- global map<string,string> CardRegex = $[
- "netcard" : "arc|bnep|ci|ctc|dummy|escon|eth|fddi|ficon|hsi|qeth|lcs|iucv|myri|tr|usb|wlan|xp",
- "modem" : "ppp|modem",
- "isdn" : "isdn|ippp",
- "dsl" : "dsl",
- /* other: irlan|lo|plip|... */
- ];
-
- // define string HotplugRegex(list<string> devs);
-
- /**
- * Supported hotplug types
- */
- list<string> HotplugTypes = [ "pcmcia", "usb"/*, "pci" */];
-
- /**
- * Create a list of hot-pluggable device names for the given devices
- */
- define string HotplugRegex(list<string> devs) {
- string ret = "";
- foreach(string dev, devs, {
- foreach(string hot, HotplugTypes, {
- ret = ret + "|" + dev + "-" + hot + "|" + dev + "-" + hot + "-";
- });
- });
- return ret;
- }
-
- /**
- * Predefined network device regular expressions
- */
- global map<string,string> DeviceRegex = $[
- /* device types */
- "netcard" : CardRegex["netcard"]:"" + HotplugRegex(["eth", "tr", "wlan"]) + "|usb-usb|usb-usb-",
- "modem" : CardRegex["modem"]:"",
- "isdn" : CardRegex["isdn"]:"" + HotplugRegex(["isdn", "ippp"]),
- "dsl" : CardRegex["dsl"]:"",
- /* device groups */
- "dialup" : CardRegex["modem"]:"" + "|" + CardRegex["dsl"]:"" + "|" + CardRegex["isdn"]:"",
- ];
-
- /**
- * Types in order from fastest to slowest.
- * @see FastestRegexps
- */
- map<integer,string> FastestTypes = $[
- 1 : "dsl",
- 2 : "isdn",
- 3 : "modem",
- 4 : "netcard"
- ];
-
- /**
- * @see Push
- */
- map stack = $[];
-
- // -------------------- components of configuration names --------------------
-
- /**
- * A single character used to separate alias id
- */
- string alias_separator = "#";
-
- /**
- * ifcfg name = type + id + alias_id
- * If id is numeric, it is not separated from type, otherwise separated by "-"
- * Id may be empty
- * Alias_id, if nonempty, is separated by alias_separator
- */
- string ifcfg_name_regex =
- "^" +
- // ip6: #48696
- "(ip6tnl|mip6mnha|[" + String::CAlpha() + "]+)" + "-?" +
- "([^" + alias_separator + "]*)" + alias_separator + "?" +
- "(.*)" +
- "$";
-
- string ifcfg_part (string ifcfg, string part) {
- if (regexpmatch (ifcfg, ifcfg_name_regex) != true)
- {
- return "";
- }
- string ret = regexpsub (ifcfg, ifcfg_name_regex, "\\" + part);
- return (ret == nil)? "": ret;
- }
-
- /**
- * Return a device type
- * @param dev device
- * @return device type
- * @example device_type("eth1") -> "eth"
- * @example device_type("eth-pcmcia-0") -> "eth-pcmcia"
- */
- global string device_type (string dev) {
- return ifcfg_part (dev, "1");
- }
-
- /**
- * Return device type in human readable form :-)
- * @param dev device
- * @return device type
- * @example GetDeviceType(eth-bus-pci-0000:01:07.0) -> "network card"
- * @example GetDeviceType(modem0) -> "modem"
- */
- global string GetDeviceType(string dev) {
- if (regexpmatch(dev,"^" + DeviceRegex["netcard"]:"")) {
- return(_("network card"));
- }
- else if (regexpmatch(dev,"^" + DeviceRegex["modem"]:"")) {
- return(_("modem"));
- }
- else if (regexpmatch(dev,"^" + DeviceRegex["isdn"]:"")) {
- return(_("ISDN"));
- }
- else if (regexpmatch(dev,"^" + DeviceRegex["dsl"]:"")) {
- return(_("DSL"));
- }
- else return(_("unknown"));
- }
-
- /**
- * Return a device number
- * @param dev device
- * @return device number
- * @example device_num("eth1") -> "1"
- * @example device_num("lo") -> ""
- */
- global string device_num (string dev) {
- return ifcfg_part (dev, "2");
- }
-
- /**
- * Return a device alias number
- * @param dev device
- * @return alias number
- * @example alias_num("eth1#2") -> "2"
- * @example alias_num("eth1#blah") -> "blah"
- */
- global string alias_num (string dev) {
- return ifcfg_part (dev, "3");
- }
-
- /**
- * Create a device name from its type and number
- * @param typ device type
- * @param num device number
- * @return device name
- * @example device_name("eth", "1") -> "eth1"
- * @example device_name("lo", "") -> "lo"
- */
- global string device_name (string typ, string num) {
- if(typ == nil || typ == "") {
- y2error("wrong type: %1", typ);
- return nil;
- }
- if(num == nil /* || num < 0 */) {
- y2error("wrong number: %1", num);
- return nil;
- }
- /* FIXME: devname
- if(IsHotplug(typ) && num != "") return sformat("%1-%2", typ, num);
- return sformat("%1%2", typ, num);
- */
- if(regexpmatch(num, "^[0-9]*$"))
- return sformat("%1%2", typ, num);
- return sformat("%1-%2", typ, num);
- }
-
- /**
- * Create a alias name from its type and numbers
- * @param typ device type
- * @param num device number
- * @param anum alias number
- * @return alias name
- * @example alias_name("eth", "1", "2") -> "eth1#2"
- */
- global string alias_name (string typ, string num, string anum) {
- if(typ == nil || typ == "") {
- y2error("wrong type: %1", typ);
- return nil;
- }
- if(num == nil /* || num < 0 */) {
- y2error("wrong number: %1", num);
- return nil;
- }
- if(anum == nil || anum == "") {
- y2error("wrong alias number: %1", anum);
- return nil;
- }
- return sformat("%1#%2", device_name(typ, num), anum);
- }
-
- /**
- * Test hotplugability of a device
- * @param type device type
- * @return true if hotpluggable
- */
- global boolean IsHotplug (string type) {
- if(type == "" || type == nil) return false;
- if(regexpmatch(type, "(pcmcia|usb|pci)$")) return true;
- return false;
- }
-
- /**
- * Return real type of the device (incl. PCMCIA, USB, ...)
- * @param type basic device type
- * @param hotplug hot plug type
- * @return real type
- * @example RealType("eth", "usb") -> "eth-usb"
- */
- global string RealType (string type, string hotplug) {
-
- y2debug("type=%1", type);
- if(type == "" || type == nil) {
- y2error("Wrong type: %1", type);
- return "eth";
- }
-
- if(hotplug == "" || hotplug == nil)
- return type;
-
- string realtype = type + "-" + hotplug;
- y2debug("realtype=%1", realtype);
- return realtype;
- }
-
- // ---------------------------------------------------------------------------
-
- /**
- * STARTMODE: onboot, on and boot are aliases for auto
- */
- global map<string, any> CanonicalizeStartmode (map<string, any> ifcfg) {
- map <string, string> canonicalize_startmode = $[
- "on": "auto",
- "boot": "auto",
- "onboot": "auto",
- ];
- string startmode = ifcfg["STARTMODE"]:"";
- ifcfg["STARTMODE"] = canonicalize_startmode[startmode]:startmode;
- return ifcfg;
- }
-
- /**
- * Canonicalize netmask data (#46885)
- * Sysconfig allows:
- * IPADDR=10.0.0.1/8
- * IPADDR=10.0.0.1 PREFIXLEN=8
- * IPADDR=10.0.0.1 NETMASK=255.0.0.0
- * (IPADDR overrides PREFIXLEN, NETMASK used only if prefix length unspecified)
- * If prefix length and NETMASK are unspecified, 32 is implied.
- * Canonicalize it to
- * IPADDR=10.0.0.1 PREFIXLEN= NETMASK=255.0.0.0
- * @param ifcfg a map containing IPADDR and possibly NETMASK, PREFIXLEN
- * and possibly other fields
- * @return the map with IPADDR, NETMASK adjusted; PREFIXLEN ""
- * others unchanged. If IPADDR is empty, return the original.
- */
- global map<string, any> CanonicalizeIP (map<string, any> ifcfg) {
- if (ifcfg == nil)
- {
- return nil;
- }
-
- list<string> ip_and_prefix = splitstring (ifcfg["IPADDR"]:"", "/");
- string ipaddr = ip_and_prefix[0]:"";
- if (ipaddr == "") // DHCP or inconsistent
- {
- return ifcfg;
- }
- string prefixlen = ip_and_prefix[1]:"";
- if (prefixlen == "")
- {
- prefixlen = ifcfg["PREFIXLEN"]:"";
- }
- if (prefixlen == "")
- {
- prefixlen = tostring (Netmask::ToBits (ifcfg["NETMASK"]:""));
- }
-
- // Now we have ipaddr and prefixlen
- // Let's compute the rest
- string netmask = Netmask::FromBits (tointeger (prefixlen));
- map<string, any> ret = ifcfg;
- ret["IPADDR"] = ipaddr;
- ret["PREFIXLEN"] = "";
- ret["NETMASK"] = netmask;
- return ret;
- }
-
- list<string> SensitiveFields = [
- "WIRELESS_WPA_PASSWORD",
- "WIRELESS_WPA_PSK",
- // the unnumbered one should be empty but just in case
- "WIRELESS_KEY",
- "WIRELESS_KEY_0",
- "WIRELESS_KEY_1",
- "WIRELESS_KEY_2",
- "WIRELESS_KEY_3",
- ];
-
- /**
- * Conceal secret information, such as WEP keys, so that the output
- * can be passed to y2log and bugzilla.
- * @param ifcfg one ifcfg
- * @return ifcfg with secret fields masked out
- */
- global map ConcealSecrets1 (map<string, any> ifcfg) {
- if (ifcfg == nil)
- {
- return nil;
- }
- map out = mapmap (string k, any v, ifcfg, {
- if (contains (SensitiveFields, k) && v != "")
- {
- v = "CONCEALED";
- }
- return $[k: v];
- });
- return out;
- }
-
- /**
- * Conceal secret information, such as WEP keys, so that the output
- * can be passed to y2log and bugzilla. (#65741)
- * @param devs a two-level map of ifcfgs like Devices
- * @return ifcfgs with secret fields masked out
- */
- global map ConcealSecrets (map devs) {
- if (devs == nil)
- {
- return nil;
- }
- map out = mapmap (string t, map<string, map<string, any> > tdevs,
- (map<string, map<string, map<string, any> > >) devs, {
- map tout = mapmap (string id, map<string, any> ifcfg, tdevs, {
- return $[id: ConcealSecrets1 (ifcfg)];
- });
- return $[t: tout];
- });
- return out;
- }
-
- /**
- * Read devices from files
- * @return true if sucess
- */
- global define boolean Read() {
-
- // initialized = true; // FIXME
- if(initialized == true) return true;
-
- Devices = $[];
-
- /* Variables which could be suffixed and thus duplicated */
- list Locals = [ "IPADDR", "REMOTE_IPADDR", "NETMASK", "PREFIXLEN",
- "BROADCAST", "SCOPE", "LABEL", "IP_OPTIONS" ];
-
- /* preparation */
- list<string> allfiles = SCR::Dir(.network.section);
- if(allfiles == nil) allfiles = [];
- list<string> devices = filter(string file, allfiles, {
- return !regexpmatch(file, "[~]");
- });
- y2debug("devices=%1", devices);
-
- /* FIXME: devname
- devices = filter(string d, devices, {
- return regexpmatch(d, "[a-z][a-z-]*[0-9]*");
- });
- y2debug("devices=%1", devices);
- */
-
- /* Read devices */
- maplist(string d, devices, {
- string devtype = device_type(d);
-
- string devnum = "";
- // if(regexpmatch(d, "[a-z][a-z-]*[0-9]+"))
- devnum = sformat("%1", device_num(d));
- y2debug("devnum=%1", devnum);
-
- map<string, ifcfg_t> dev = Devices[devtype]:$[];
- if(haskey(dev, devnum)) {
- y2error("device already present: %1", devnum);
- return;
- }
-
- string pth = ".network.value.\"" + device_name(devtype, devnum) + "\"";
- y2debug("pth=%1", pth);
- list<string> values = SCR::Dir(topath(pth));
- y2debug("values=%1", values);
-
- map<string, any> config = $[];
- maplist(string val, values, {
- string item = (string) SCR::Read(topath(pth + "." + val));
- y2debug("item=%1", item);
- if(item == nil) return;
- /* No underscore '_' -> global */
- /* Also temporarily standard globals */
- if(find(val, "_") < 0 || contains(Locals, val)) {
- config[val] = item;
- return;
- }
- /* Try to strip _suffix */
- string v = substring(val, 0, findlastof(val, "_"));
- string s = substring(val, findlastof(val, "_"));
- if(size(s) > 1) s = substring(s, 1);
- y2milestone("%1:%2:%3", val, v, s);
- /* Global */
- if(!contains(Locals, v))
- config[val] = item;
- /* Local */
- else {
- map _aliases = config["_aliases"]:$[];
- map suf = _aliases[s]:$[];
- suf[v] = item;
- _aliases[s] = suf;
- config["_aliases"] = _aliases;
- }
- });
- y2milestone("config=%1", ConcealSecrets1 (config));
-
- // canonicalize, #46885
- map <string, map> caliases = mapmap (string a, map<string, any> c, (map<string,map<string, any> >)config["_aliases"]:$[], {
- return $[a: CanonicalizeIP (c)];
- });
- if (caliases != $[]) // unconditionally?
- {
- config["_aliases"] = caliases;
- }
- config = CanonicalizeIP (config);
- config = CanonicalizeStartmode (config);
-
- dev[devnum] = config;
- Devices[devtype] = dev;
- });
- y2debug("Devices=%1", Devices);
-
- OriginalDevices = Devices;
- initialized = true;
- return true;
- }
-
- /**
- */
- define map<string,map> Filter(map<string,map> devices, string devregex) {
- if(devices == nil || devregex == nil || devregex == "")
- return devices;
-
- string regex = "^(" + DeviceRegex[devregex]:devregex + ")[0-9]*$";
- y2debug("regex=%1", regex);
- devices = filter(string file, map devmap, devices, {
- return regexpmatch(file, regex) == true;
- });
- y2debug("devices=%1", devices);
- return devices;
- }
-
- /**
- * Used in BuildSummary, BuildOverview
- */
- global map<string,map> FilterDevices (string devregex) {
- return Filter (Devices, devregex);
- }
-
- /**
- */
- define map<string,map> FilterNOT(map<string,map> devices, string devregex) {
- if(devices == nil || devregex == nil || devregex == "")
- return $[];
-
- string regex = "^(" + DeviceRegex[devregex]:devregex + ")[0-9]*$";
- y2debug("regex=%1", regex);
- devices = filter(string file, map devmap, devices, {
- return regexpmatch(file, regex) != true;
- });
- y2debug("devices=%1", devices);
- return devices;
- }
-
- /**
- * For the NAME field, filter out characters that will case problems
- * for the shell or the ini agent. (#72164)
- * It should be done in more places but this field is most susceptible.
- * @param s a string
- * @return s with some characters removed, esp. the single quote
- */
- string ShellSafe (string s) {
- s = filterchars (s, String::CGraph () + " ");
- return deletechars (s, "'");
- }
-
- /**
- * SCR::Write (p, ShellSafe (s)) and if s had to be changed,
- * log the _path_ (not the value, for privacy).
- * @see ShellSafe
- * @param p SCR path
- * @param s value
- * @return success
- */
- boolean ShellSafeWrite (path p, string s) {
- string safe_s = ShellSafe (s);
- if (safe_s != s)
- {
- y2milestone ("Changed: %1", p);
- }
- return SCR::Write (p, safe_s);
- }
-
- /**
- * Write devices to files
- * @param devregex regular expression for the device type
- * @return true if success
- * @example NetworkDevice::Write("eth|tr");
- */
- global define boolean Write(string devregex) {
-
- y2milestone("Writing configuration");
- y2debug("Devices=%1", Devices);
- y2debug("Deleted=%1", Deleted);
-
- map Devs = Filter(Devices, devregex);
- map OriginalDevs = Filter(OriginalDevices, devregex);
- y2milestone("OriginalDevs=%1", ConcealSecrets (OriginalDevs));
- y2milestone("Devs=%1", ConcealSecrets (Devs));
-
- /* Check for changes */
- if(Devs == OriginalDevs) {
- y2milestone("No changes to %1 devices -> nothing to write", devregex);
- return true;
- }
-
- /* remove deleted devices */
- y2milestone("Deleted=%1", Deleted);
- foreach(string d, Deleted, {
- // if(!haskey(OriginalDevs, d)) return;
- string anum = alias_num (d);
- if (anum == "")
- {
- /* delete config file */
- path p = add (.network.section, d);
- y2debug("deleting: %1", p);
- SCR::Write(p, nil);
- }
- else
- {
- string typ = device_type (d);
- string num = device_num (d);
- string dev = device_name (typ, num);
- path base = add (.network.value, dev);
- // look in OriginalDevs because we need to catch all variables
- // of the alias
- foreach (string key, any dummy, OriginalDevs[typ, num, "_aliases", anum]:$[], {
- path p = add (base, key + "_" + anum);
- y2debug ("deleting: %1", p);
- SCR::Write (p, nil);
- });
- }
- });
-
- /* Devices with chmod=0600 */
- list<string> chmod = [];
-
- /* write all devices */
- maplist(string typ, map<string,map<string,any> > devsmap, (map<string, map<string, map<string, any> > >) Devs, {
- maplist(string num, map<string,any> devmap, devsmap, {
- /* write sysconfig */
- string dev = device_name(typ, num);
- string p = ".network.value.\"" + dev + "\".";
-
- /* write all keys to config */
- maplist(string k, (list<string>) Map::Keys(devmap), {
- /* Write aliases */
- if(k == "_aliases") {
- maplist(string anum, map<string,string> amap, devmap[k]:$[], {
- // Normally defaulting the label would be done
- // when creating the map, not here when
- // writing, but we create it in 2 ways so it's
- // better here. Actually it does not work because
- // the edit dialog nukes LABEL :-(
- boolean seen_label = false;
-
- maplist(string ak, string av, amap, {
- string akk = ak + "_" + anum;
- ShellSafeWrite (topath (p + akk), av);
- seen_label = seen_label || ak == "LABEL";
- });
-
- if (!seen_label)
- {
- ShellSafeWrite (topath (p + ("LABEL_" + anum)), anum);
- }
- });
- }
- /* Write regular keys */
- else
- ShellSafeWrite (topath (p + k), devmap[k]:"");
- });
-
- /* update libhd unique number * /
- // FIXME: move it somewhere else: hardware
- string unq = devmap["UNIQUE"]:"";
- if(unq != "") SCR::Write(.probe.status.configured, unq, `yes);
- */
-
- /* 0600 if contains encryption key (#24842) */
- boolean has_key = find (string k, SensitiveFields,
- ``( devmap[k]:"" != "" )) != nil;
- string file = "/etc/sysconfig/network/ifcfg-" + dev;
- y2debug("Permission change: %1, %2", has_key, file);
- if(has_key) {
- y2debug("CHANGED");
- chmod = add(chmod, file);
- }
- });
- });
-
- /* Finish him */
- SCR::Write(.network, nil);
-
- /* CHMOD */
- y2debug("chmod=%1", chmod);
- maplist(string file, chmod, {
- y2debug("changing: %1", file);
- SCR::Execute(.target.bash, "/bin/chmod 0600 " + file);
- });
-
- // Deleted = [];
- // OriginalDevices = Devices;
- // Cannot do it because we have written only part of Devices.
- // This module should be rewritten to objects.
- return true;
- }
-
- /**
- * Import data
- * @param settings settings to be imported
- * @return true on success
- */
- global define boolean Import(string devregex, map<string,map> devices) {
- map Devs = FilterNOT(Devices, devregex);
- y2debug("Devs=%1", Devs);
-
- devices = mapmap(string typ, map devsmap, devices, {
- return $[typ: mapmap(string num, map<string, any> config, (map<string,map<string, any> >) devsmap, {
- config = CanonicalizeIP (config);
- config = CanonicalizeStartmode (config);
- return $[num: config];
- })];
- });
-
- Devices = (devices_t) union(Devs, devices);
- OriginalDevices = nil;
- return true;
- }
-
- /**
- * Export data
- * @return dumped settings (later acceptable by Import())
- */
- global define map<string,map> Export(string devregex) {
- map Devs = Filter(Devices, devregex);
- y2debug("Devs=%1", Devs);
- return (map<string,map>) Devs;
- }
-
- /**
- * Were the devices changed?
- * @return true if modified
- */
- global define boolean Modified(string devregex) {
- map Devs = Filter(Devices, devregex);
- map OriginalDevs = Filter(OriginalDevices, devregex);
- y2debug("OriginalDevs=%1", OriginalDevs);
- y2debug("Devs=%1", Devs);
- return Devs == OriginalDevs;
- }
-
- global define list<string> GetFreeDevices(string type, integer num) {
- y2debug("Devices=%1", Devices);
- y2debug("type,num=%1,%2", type, num);
- y2debug("Devices[%1]=%2", type, Devices[type]:$[]);
-
- list curdevs = Map::Keys(Devices[type]:$[]);
- y2debug("curdevs=%1", curdevs);
-
- integer i = 0;
- integer count = 0;
- list<string> ret = [];
-
- /* Hotpluggable devices */
- if(IsHotplug(type) && !contains(curdevs, "")) {
- y2debug("Added simple hotplug device");
- count = count + 1;
- ret = add(ret, "");
- }
-
- /* Remaining numbered devices */
- while(count < num) {
- string ii = sformat("%1", i);
- if(!contains(curdevs, ii)) {
- ret = add(ret, ii);
- count = count + 1;
- }
- i = i + 1;
- }
-
- y2debug("Free devices=%1", ret);
- return ret;
- }
-
- /**
- * Compute free devices
- * @param type device type
- * @param num how many free devices return
- * @return num of free devices
- * @example GetFreeDevices("eth", 2) -> [ 1, 2 ]
- */
- global define list GetFreeDevicesOld(string type, integer num) {
- y2debug("Devices=%1", Devices);
- y2debug("type,num=%1,%2", type, num);
- y2debug("Devices[%1]=%2", type, Devices[type]:$[]);
-
- list curdevs = Map::Keys(Devices[type]:$[]);
- y2debug("curdevs=%1", curdevs);
-
- integer i = 0;
- integer count = 0;
- list ret = [];
-
- /* Hotpluggable devices */
- if(IsHotplug(type) && !contains(curdevs, "")) {
- y2debug("Added simple hotplug device");
- count = count + 1;
- ret = add(ret, "");
- }
-
- /* Remaining numbered devices */
- while(count < num) {
- string ii = sformat("%1", i);
- if(!contains(curdevs, ii)) {
- ret = add(ret, ii);
- count = count + 1;
- }
- i = i + 1;
- }
-
- y2debug("Free devices=%1", ret);
- return ret;
- }
-
- /**
- * Return free device
- * @param type device type
- * @return free device
- * @example GetFreeDevice("eth") -> "1"
- */
- global define string GetFreeDevice(string type) {
- y2debug("type=%1", type);
- list <string> freedevs = GetFreeDevices(type, 1);
- string ret = (string) freedevs[0]:nil;
- if(ret == nil) y2error("Free device location error: %1", ret);
- y2debug("Free device=%1", ret);
- return ret;
- }
-
- /**
- * Check presence of the device (alias)
- * @param dev device identifier
- * @return true if device is present
- */
- global define boolean Check(string dev) {
-
- y2debug("Check(%1)", dev);
- string typ = device_type(dev);
- string num = device_num(dev);
- string anum = alias_num(dev);
- if (report_every_check) y2milestone("Check(%1,%2,%3)", typ, num, anum);
-
- if(!haskey(Devices, typ))
- return false;
-
- map devsmap = Devices[typ]:$[];
- if(!haskey(devsmap, num))
- return false;
-
- /* FIXME NI: not needed?
- Name = dev;
- Current = (map) eval(devsmap[num]:$[]);
- */
-
- if(anum != "") {
- map devmap = devsmap[num]:$[];
- map amap = devmap["_aliases"]:$[];
- if(!haskey(amap, anum))
- return false;
- /* FIXME NI: not needed?
- Current = (map) eval(amap[anum]:$[]);
- alias = anum;
- */
- }
-
- y2debug("Check passed");
- return true;
- }
-
- /**
- * Select the given device
- * @param device to select ("" for new device, default values)
- * @return true if success
- */
- global define boolean Select(string name) {
-
- Name = "";
- Current = $[];
-
- y2debug("name=%1", name);
- if(name != "" && !Check(name)) {
- y2error("No such device: %1", name);
- return false;
- }
-
- Name = name;
- // FIXME NI: Current = Devices[device_type(Name), device_num(Name)]:$[];
- // may be fixed already. or not: #39236
- string t = device_type(Name);
- Current = Devices[t, device_num(Name)]:$[];
- string a = alias_num(Name);
- if(a != nil && a != "") Current = Current["_aliases", a]:$[];
-
- if(Current == $[]) {
- /* Default device map */
- Current = $[
- /* FIXME: remaining items */
- ];
- }
-
- y2debug("Name=%1", Name);
- y2debug("Current=%1", Current);
-
- return true;
- }
-
- /**
- * Add a new device
- * @return true if success
- */
- global define boolean Add() {
- operation = nil;
- if(Select("") != true) return false;
- operation = `add;
- return true;
- }
-
- /**
- * Edit the given device
- * @param dev device to edit
- * @return true if success
- */
- global define boolean Edit(string name) {
- operation = nil;
- if(Select(name) != true) return false;
- operation = `edit;
- return true;
- }
-
- /**
- * Delete the given device
- * @param dev device to delete
- * @return true if success
- */
- global define boolean Delete(string name) {
- operation = nil;
- if(Select(name) != true) return false;
- operation = `delete;
- return true;
- }
-
- /**
- * Update Devices map
- * @param dev device identifier
- * @param newdev new device map
- * @param check if check if device already exists
- * @return true if success
- */
- define boolean Change2(string name, ifcfg_t newdev, boolean check) {
- y2debug("Change(%1,%2,%3)", name, newdev, check);
- y2debug("Devices=%1", Devices);
-
- if(Check(name) && check) {
- y2error("Device already present: %1", name);
- return false;
- }
-
- string t = device_type(name);
- string d = device_num(name);
- string a = alias_num(name);
- y2debug("ChangeDevice(%1,%2,%3)", t, d, a);
-
- map<string, ifcfg_t> devsmap = Devices[t]:$[];
- ifcfg_t devmap = devsmap[d]:$[];
- map amap = devmap["_aliases"]:$[];
-
- if(a != "") {
- amap[a] = newdev;
- devmap["_aliases"] = amap;
- }
- else
- devmap = newdev;
-
- devsmap[d] = devmap;
- Devices[t] = devsmap;
-
- y2debug("Devices=%1", Devices);
- return true;
- }
-
- define boolean Delete2(string name) {
-
- if(!Check(name)) {
- y2error("Device not found: %1", name);
- return false;
- }
-
- string t = device_type(name);
- string d = device_num(name);
- string a = alias_num(name);
- map<string, ifcfg_t> devsmap = Devices[t]:$[];
-
- if(a != "") {
- map amap = devsmap[d, "_aliases"]:$[];
- amap = remove(amap, a);
- devsmap[d, "_aliases"] = amap;
- }
- else
- devsmap = remove(devsmap, d);
-
- Devices[t] = devsmap;
-
- // Originally this avoided errors in the log when deleting an
- // interface that was not present at Read (had no ifcfg file).
- // #115448: OriginalDevices is not updated after Write so
- // returning to the network proposal and deleting a card would not work.
- if (true ||
- haskey(OriginalDevices, t) && haskey(OriginalDevices[t]:$[], d)) {
- y2milestone("Deleting file: %1", name);
- Deleted[size(Deleted)] = name;
- }
- else {
- y2milestone("Not deleting file: %1", name);
- y2debug("OriginalDevices=%1", OriginalDevices);
- y2debug("a=%1", a);
- }
-
- return true;
- }
-
- /**
- * Add the alias to the list of deleted items.
- * Called when exiting from the aliases-of-device dialog.
- * #48191
- */
- global boolean DeleteAlias (string device, string aid) {
- string alias = sformat ("%1#%2", device, aid);
- y2milestone("Deleting alias: %1", alias);
- Deleted[size(Deleted)] = alias;
- return true;
- }
-
- global define boolean Commit() {
- y2debug("Name=%1", Name);
- y2debug("Current=%1", Current);
- y2debug("Devices=%1", Devices);
- y2debug("Deleted=%1", Deleted);
- y2debug("operation=%1", operation);
-
- if(operation == `add || operation == `edit) {
- Change2(Name, Current, operation == `add);
- }
- else if(operation == `delete) {
- Delete2(Name);
- }
- else {
- y2error("Unknown operation: %1 (%2)", operation, Name);
- return false;
- }
-
- y2debug("Devices=%1", Devices);
- y2debug("Deleted=%1", Deleted);
-
- Name = "";
- Current = $[];
- operation = nil;
-
- return true;
- }
-
- global define string GetValue(string name, string key) {
- if(!Select(name)) return nil;
- return Current[key]:"";
- }
-
- global define boolean SetValue(string name, string key, string value) {
- if(!Edit(name)) return nil;
- if(key == nil || key == "" || value == nil) return false;
- Current[key] = value;
- return Commit();
- }
-
- /**
- * Locate devices of the given type and value
- * @param key device key
- * @param val device value
- * @return list of devices with key=val
- */
- global define list<string> Locate(string key, string val) {
- list<string> ret = [];
- maplist(string typ, map devsmap, Devices, {
- maplist(string num, map devmap, (map<string,map>) devsmap, {
- if(devmap[key]:"" == val) ret = add(ret, device_name(typ,num));
- });
- });
-
- return ret;
- }
-
- /**
- * Locate devices of the given type and value
- * @param key device key
- * @param val device value
- * @return list of devices with key!=val
- */
- global define list<string> LocateNOT(string key, string val) {
- list<string> ret = [];
- maplist(string typ, map devsmap, Devices, {
- maplist(string num, map devmap, (map<string,map>) devsmap, {
- if(devmap[key]:"" != val) ret = add(ret, device_name(typ,num));
- });
- });
-
- return ret;
- }
-
- /**
- * Check if any device is using the specified provider
- * @param provider provider identification
- * @return true if there is any
- */
- global define boolean LocateProvider(string provider) {
- list devs = Locate("PROVIDER", provider);
- return size(devs) > 0;
- }
-
- /**
- * Update /dev/modem symlink
- * @return true if success
- */
- global define boolean UpdateModemSymlink() {
- boolean ret = false;
- if(contains(Map::Keys(Devices), "modem")) {
- list ml = Map::Keys(Devices["modem"]:$[]);
- string ms = ml[0]:"0";
- // map mm = Devices["modem"]:$[][ms]:$[];
- map mm = Devices["modem", ms]:$[];
- string mdev = mm["MODEM_DEVICE"]:"";
- if(mdev != "" && mdev != "/dev/modem") {
- string curlink = nil;
- map m = (map) SCR::Read(.target.lstat, "/dev/modem");
- if(m["islink"]:false == true)
- curlink = (string) SCR::Read(.target.symlink, "/dev/modem");
- if(curlink != mdev) {
- SCR::Execute(.target.symlink, mdev, "/dev/modem");
- ret = true;
- }
- }
- }
- return ret;
- }
-
- /**
- * Clean the hotplug devices compatibility symlink,
- * usually ifcfg-eth-pcmcia -> ifcfg-eth-pcmcia-0.
- * @return true if success
- */
- global define boolean CleanHotplugSymlink() {
-
- list<string> types = [ "eth-pcmcia", "eth-usb", "tr-pcmcia", "tr-usb" ];
- maplist(string t, types, {
- string link = "/etc/sysconfig/network/ifcfg-" + t;
- y2debug("link=%1", link);
- map lstat = (map) SCR::Read(.target.lstat, link);
- if(lstat["islink"]:false == true) {
- string file = (string) SCR::Read(.target.symlink, link);
- file = "/etc/sysconfig/network/" + file;
- y2debug("file=%1", file);
- if(SCR::Read(.target.size, file) > -1) {
- y2milestone("Cleaning hotplug symlink");
- y2milestone("Devices[%1]=%2", t, Devices[t]:$[]);
- Devices[t] = remove(Devices[t]:$[], "");
- y2milestone("Devices[%1]=%2", t, Devices[t]:$[]);
- }
- }
- });
-
- y2debug("Devices=%1", Devices);
- return true;
- }
-
- /**
- * Get devices of the given type
- * @param type devices type ("" for all)
- * @return list of found devices
- */
- global define list<string> List(string devregex) {
-
- list<string> ret = [];
- if(devregex == "" || devregex == nil) {
- maplist(string t, map d, Devices, {
- maplist(string n, (list<string>) Map::Keys(d), {
- ret[size(ret)] = device_name(t,n);
- });
- });
- }
- else {
- // it's a regex for type, not the whole name
- string regex = "^(" + DeviceRegex[devregex]:devregex + ")$";
- maplist(string t, map d, Devices, {
- if(regexpmatch(t, regex)) {
- maplist(string n, (list<string>) Map::Keys(d), {
- ret[size(ret)] = device_name(t,n);
- });
- }
- });
- /*
- map d = Devices[type]:$[];
- maplist(string n, Map::Keys(d), {ret[size(ret)] = device_name(type,n);});
- */
- }
-
- y2debug("ret=%1", ret);
- return ret;
- }
-
- /**
- * Find the fastest available device
- */
- global define string Fastest() {
-
- string ret = "";
- list<string> devices = List("");
-
- /* Find the fastest device */
- foreach(integer num, string type, FastestTypes, {
- foreach(string dev, devices, {
- if(ret == "" && regexpmatch(dev, "^" + DeviceRegex[type]:"" + "[0-9]*$")) {
- //do some checking (whether the card is up and has cable connected)
- if(type == "netcard") {
- string cmd = "getcfg-interface " + dev;
- map dn =(map) SCR::Execute(.target.bash_output, cmd);
- string devname = deletechars(dn["stdout"]:"", "\n");
-
- cmd = "ethtool " + devname + " | grep \"Link detected: yes\"";
- string cmd2 = "ifstatus " + devname + " | grep \"" + devname + " is up\"";
-
- if((SCR::Execute(.target.bash, cmd) == 0) && (SCR::Execute(.target.bash, cmd2) == 0)) {
- y2milestone("%1 is up and connected", dev);
- ret = dev;
- }
- else y2milestone("%1 is down or disconnected", dev);
- }
- else ret = dev;
- }
- });
- });
-
- if (ret == "") {
- y2milestone("No suitable device found, falling back to the first device on the detected list");
- ret = devices[0]:"";
- }
-
- y2milestone("ret=%1", ret);
- return ret;
- }
-
- global define string FastestType(string name) {
- string ret = "";
- maplist(integer num, string type, FastestTypes, {
- string regex = DeviceRegex[type]:"";
- if (ret == "" && regexpmatch(name, "^" + regex + "[0-9]*$"))
- ret = type;
- });
- /*
- maplist(string typ, string regex, DeviceRegex, {
- if (ret == "" && regexpmatch(name, "^" + regex + "[0-9]*$"))
- ret = typ;
- });
- */
- return ret;
- }
-
- /**
- * Check if the given device has any virtual alias.
- * @param dev device to be checked
- * @return true if there are some aliases
- */
- global define boolean HasAliases(string name) {
-
- if(!Check(name)) {
- y2error("Device not found: %1", name);
- return false;
- }
-
- string t = device_type(name);
- string d = device_num(name);
- string a = alias_num(name);
-
- return a == "" && Devices[t, d, "_aliases"]:$[] != $[];
- }
-
- /**
- * DSL needs to save its config while the underlying network card is
- * being configured.
- */
- global define void Push() {
- if(stack != $[]) y2error("Stack not empty: %1", stack);
- stack["Name"] = Name;
- stack["Current"] = Current;
- stack["operation"] = operation;
- y2milestone("PUSH: %1", stack);
- }
-
- global define void Pop() {
- y2milestone("POP: %1", stack);
- Name = stack["Name"]:"";
- Current = stack["Current"]:$[];
- operation = (symbol) stack["operation"]:nil;
- stack = $[];
- }
-
- /**
- * #46803: forbid "/" (filename), maybe also "-" (separator) "_" (escape)
- */
- global string ValidCharsIfcfg () {
- return String::ValidCharsFilename ();
- }
-
- /* EOF */
- }
-