Author: mzugec
Date: Tue Jan 8 18:32:30 2008
New Revision: 43480
URL: http://svn.opensuse.org/viewcvs/yast?rev=43480&view=rev
Log:
added NetworkInterfaces module (NetworkDevices will be deprecated)
Added:
trunk/yast2/library/network/src/NetworkInterfaces.ycp
Modified:
trunk/yast2/VERSION
trunk/yast2/package/yast2.changes
Modified: trunk/yast2/VERSION
URL: http://svn.opensuse.org/viewcvs/yast/trunk/yast2/VERSION?rev=43480&r1=43479&r2=43480&view=diff
==============================================================================
--- trunk/yast2/VERSION (original)
+++ trunk/yast2/VERSION Tue Jan 8 18:32:30 2008
@@ -1 +1 @@
-2.16.19
+2.16.20
Added: trunk/yast2/library/network/src/NetworkInterfaces.ycp
URL: http://svn.opensuse.org/viewcvs/yast/trunk/yast2/library/network/src/NetworkInterfaces.ycp?rev=43480&view=auto
==============================================================================
--- trunk/yast2/library/network/src/NetworkInterfaces.ycp (added)
+++ trunk/yast2/library/network/src/NetworkInterfaces.ycp Tue Jan 8 18:32:30 2008
@@ -0,0 +1,1535 @@
+/**
+ * File: modules/NetworkInterfaces.ycp
+ * Package: Network configuration
+ * Summary: Interface manipulation (/etc/sysconfig/network/ifcfg-*)
+ * Authors: Michal Svec
+ *
+ * $Id: NetworkInterfaces.ycp 43062 2007-12-13 16:12:26Z mzugec $
+ *
+ * The new sysconfig naming is interface (eg. eth0) vs. device
+ * (eg. NE2000 card), but historically yast has called them device
+ * vs. module.
+ */
+
+{
+
+module "NetworkInterfaces";
+textdomain "base";
+
+import "Arch";
+import "Map";
+import "Mode";
+import "Netmask";
+import "String";
+
+/**
+ * False suppresses tones of logs 'NetworkInterfaces.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 ifcfg_t;
+typedef map > 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 CardRegex = $[
+ "netcard" : "arc|ath|bnep|ci|ctc|dummy|bond|escon|eth|fddi|ficon|hsi|qeth|lcs|iucv|myri|tr|usb|wlan|xp|vlan|br",
+ "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 DeviceRegex = $[
+ /* device types */
+ "netcard" : CardRegex["netcard"]:"" + HotplugRegex(["ath", "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 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");
+}
+
+global string GetType(string dev) {
+ string type = ifcfg_part (dev, "1");
+ foreach(string dev_type,map confs, Devices, {
+ if (haskey(confs, dev)){
+ string int_type = confs[dev, "INTERFACETYPE"]:"";
+ if(size(int_type)>0) type = int_type;
+ }
+ });
+ return type;
+}
+
+/**
+ * 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 matching inteface for this hardware ID (uses getcfg-interface)
+ * @param dev unique device string
+ * return interface name
+ * @example MatchInterface("eth-id-00:01:DE:AD:BE:EF") -> "eth0"
+ */
+/*
+global string MatchInterface(string dev) {
+ string cmd = "getcfg-interface " + dev;
+ map dn =(map) SCR::Execute(.target.bash_output, cmd);
+ string devname = deletechars(dn["stdout"]:"", "\n");
+
+ return devname;
+}
+*/
+/**
+ * Test whether device is connected (Link:up)
+ * The info is taken from sysfs
+ * @param dev unique device string
+ * @return true if connected
+ */
+global boolean IsConnected(string dev) {
+ if (!Mode::testsuite()) {
+// string iface = MatchInterface(dev);
+ string cmd = "cat /sys/class/net/" + dev + "/carrier";
+
+ map ret = (map) SCR::Execute(.target.bash_output, cmd);
+ y2milestone("Sysfs returned %1", ret);
+
+ return ( deletechars( ret["stdout"]:"", "\n") == "1" ? true : false );
+ }
+ else
+ //Assume all devices are connected in testsuite mode
+ return true;
+
+}
+
+/**
+ * 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 CanonicalizeStartmode (map ifcfg) {
+ map 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 CanonicalizeIP (map 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 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 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 > tdevs,
+ (map > >) devs, {
+ map tout = mapmap (string id, map 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 dev = Devices[devtype]:$[];
+ string pth = ".network.value.\"" + d + "\"";
+ y2debug("pth=%1", pth);
+ list<string> values = SCR::Dir(topath(pth));
+ y2debug("values=%1", values);
+
+ map 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 caliases = mapmap (string a, map c, (map >)config["_aliases"]:$[], {
+ return $[a: CanonicalizeIP (c)];
+ });
+ if (caliases != $[]) // unconditionally?
+ {
+ config["_aliases"] = caliases;
+ }
+ config = CanonicalizeIP (config);
+ config = CanonicalizeStartmode (config);
+
+ if (size(config["INTERFACETYPE"]:"")>0) {
+ y2milestone("option INTERFACETYPE changes devtype from %1 to %2", devtype, config["INTERFACETYPE"]:"");
+ devtype=config["INTERFACETYPE"]:"";
+ dev = Devices[devtype]:$[];
+ }
+/*
+ if(haskey(dev, devnum)) {
+ y2error("device already present: %1", devnum);
+ return;
+ }
+*/
+ dev[d] = config;
+ Devices[devtype] = dev;
+ });
+ y2debug("Devices=%1", Devices);
+
+ OriginalDevices = Devices;
+ initialized = true;
+ return true;
+}
+
+/**
+ * re-read all settings again from system
+ * for creating new proposal from scratch (#170558)
+ */
+global boolean CleanCacheRead(){
+ initialized = false;
+ return Read();
+}
+
+
+/**
+ */
+define map Filter(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 FilterDevices (string devregex) {
+ return Filter (Devices, devregex);
+}
+
+/**
+ */
+define map FilterNOT(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 > devsmap, (map > >) Devs, {
+ maplist(string config, map devmap, devsmap, {
+ /* write sysconfig */
+// string dev = device_name(typ, num);
+ string p = ".network.value.\"" + config + "\".";
+
+ if (size(devmap["IPADDR"]:"")>0 && size(devmap["NETMASK"]:"")>0){
+ devmap["IPADDR"] = sformat("%1/%2", devmap["IPADDR"]:"", Netmask::ToBits(devmap["NETMASK"]:""));
+ devmap=remove(devmap, "NETMASK");
+ //TODO : delete NETMASK, UNIQUE from config file
+ }
+ /* write all keys to config */
+ maplist(string k, (list<string>) Map::Keys(devmap), {
+ /* Write aliases */
+ if(k == "_aliases") {
+ maplist(string anum, map 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;
+
+ if (size(amap["IPADDR"]:"")>0 && size(amap["NETMASK"]:"")>0){
+ amap["IPADDR"] = sformat("%1/%2", amap["IPADDR"]:"", Netmask::ToBits(amap["NETMASK"]:""));
+ amap=remove(amap, "NETMASK");
+ //TODO : delete NETMASK from config file
+ }
+
+ 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-" + config;
+ 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 devices) {
+ map Devs = FilterNOT(Devices, devregex);
+ y2debug("Devs=%1", Devs);
+
+ devices = mapmap(string typ, map devsmap, devices, {
+ return $[typ: mapmap(string num, map config, (map >) devsmap, {
+ config = CanonicalizeIP (config);
+ config = CanonicalizeStartmode (config);
+ return $[num: config];
+ })];
+ });
+
+ Devices = (devices_t) union(Devs, devices);
+ OriginalDevices = nil;
+ return true;
+}
+
+/**
+ * Return supported network device types (for type netcard)
+ * for this hardware
+ */
+global list<string> GetDeviceTypes(){
+ list<string> dev_types = ["eth", "tr", "vlan", "br"];
+ if(Arch::s390 ()) dev_types = (list<string>) merge(dev_types, [ "hsi", "ctc", "escon", "ficon", "iucv", "qeth", "lcs"]);
+ else dev_types = (list<string>) merge(dev_types, [ "arc", "bnep", "dummy", "fddi", "myri", "usb", "wlan", "bond" ]);
+ if(Arch::ia64 ()) dev_types = add(dev_types, "xp");
+
+ foreach(string device,dev_types, {
+ if (!contains(splitstring(DeviceRegex["netcard"]:"", "|"), device)) y2error("%1 is not contained in DeviceRegex[\"netcard\"]", device);
+ });
+ return dev_types;
+}
+
+/**
+ * Return textual device type
+ * @param type device type
+ * @param type description type
+ * @return textual form of device type
+ * @example GetDevTypeDescription("eth", false) -> "Ethernet"
+ * @example GetDevTypeDescription("eth", true) -> "Ethernet Network Card"
+ */
+global string GetDevTypeDescription(string type, boolean longdescr){
+ if(issubstring(type, "#"))
+ /* Device type label */
+ // This is what used to be Virtual Interface (eth0:1).
+ // In our data model, additional addresses for an interface
+ // are represented as its sub-interfaces.
+ // And also we frequently confuse "device" and "interface"
+ // :-(
+ return _("Additional Address");
+
+ map device_types = $[
+ /* Device type label */
+ "arc" : [ _("ARCnet"), _("ARCnet Network Card") ],
+ /* Device type label */
+ "atm" : [ _("ATM"), _("Asynchronous Transfer Mode (ATM)") ],
+ /* Device type label */
+ "bnep" : [ _("Bluetooth"), _("Bluetooth Connection") ],
+ /* Device type label */
+ "bond" : [ _("Bond"), _("Bond Network") ],
+ /* Device type label */
+ "ci" : [ _("CLAW"), _("Common Link Access for Workstation (CLAW)") ],
+ /* Device type label */
+ "contr" : [ _("ISDN"), _("ISDN Card") ],
+ /* Device type label */
+ "ctc" : [ _("CTC"), _("Channel to Channel Interface (CTC)") ],
+ /* Device type label */
+ "dsl" : [ _("DSL"), _("DSL Connection") ],
+ /* Device type label */
+ "dummy" : [ _("Dummy"), _("Dummy Network Device") ],
+ /* Device type label */
+ "escon" : [ _("ESCON"), _("Enterprise System Connector (ESCON)") ],
+ /* Device type label */
+ "eth" : [ _("Ethernet"), _("Ethernet Network Card") ],
+ /* Device type label */
+ "fddi" : [ _("FDDI"), _("FDDI Network Card") ],
+ /* Device type label */
+ "ficon" : [ _("FICON"), _("Fiberchannel System Connector (FICON)") ],
+ /* Device type label */
+ "hippi" : [ _("HIPPI"), _("HIgh Performance Parallel Interface (HIPPI)") ],
+ /* Device type label */
+ "hsi" : [ _("Hipersockets"), _("Hipersockets Interface (HSI)") ],
+ /* Device type label */
+ "ippp" : [ _("ISDN"), _("ISDN Connection") ],
+ /* Device type label */
+ "irlan" : [ _("IrDA"), _("Infrared Network Device") ],
+ /* Device type label */
+ "irda" : [ _("IrDA"), _("Infrared Device") ],
+ /* Device type label */
+ "isdn" : [ _("ISDN"), _("ISDN Connection") ],
+ /* Device type label */
+ "iucv" : [ _("IUCV"), _("Inter User Communication Vehicle (IUCV)") ],
+ /* Device type label */
+ "lcs" : [ _("OSA LCS"), _("OSA LCS Network Card") ],
+ /* Device type label */
+ "lo" : [ _("Loopback"), _("Loopback Device") ],
+ /* Device type label */
+ "modem" : [ _("Modem"), _("Modem") ],
+ /* Device type label */
+ "myri" : [ _("Myrinet"), _("Myrinet Network Card") ],
+ /* Device type label */
+ "net" : [ _("ISDN"), _("ISDN Connection") ],
+ /* Device type label */
+ "plip" : [ _("Parallel Line"), _("Parallel Line Connection") ],
+ /* Device type label */
+ "ppp" : [ _("Modem"), _("Modem") ],
+ /* Device type label */
+ "qeth" : [ _("QETH"), _("OSA-Express or QDIO Device (QETH)") ],
+ /* Device type label */
+ "sit" : [ _("IPv6-in-IPv4"), _("IPv6-in-IPv4 Encapsulation Device") ],
+ /* Device type label */
+ "slip" : [ _("Serial Line"), _("Serial Line Connection") ],
+ /* Device type label */
+ "tr" : [ _("Token Ring"), _("Token Ring Network Card") ],
+ /* Device type label */
+ "usb" : [ _("USB"), _("USB Network Device") ],
+ /* Device type label */
+ "vmnet" : [ _("VMWare"), _("VMWare Network Device") ],
+ /* Device type label */
+ "wlan" : [ _("Wireless"), _("Wireless Network Card") ],
+ /* Device type label */
+ "xp" : [ _("XPNET"), _("XP Network") ],
+ /* Device type label */
+ "vlan" : [ _("VLAN"), _("Virtual LAN") ],
+ /* Device type label */
+ "br" : [ _("Network Bridge"), _("Network Bridge") ],
+ ];
+
+ if(haskey(device_types, type)) return device_types[type, (longdescr==true) ? 1 : 0]:"";
+
+ string type1 = String::FirstChunk (type, "-");
+ if(haskey(device_types, type1))
+ return device_types[type1, (longdescr==true) ? 1 : 0]:"";
+
+ y2error("Unknown type: %1", type);
+ return type;
+}
+
+/**
+ * Export data
+ * @return dumped settings (later acceptable by Import())
+ */
+global define map Export(string devregex) {
+ map Devs = Filter(Devices, devregex);
+ y2debug("Devs=%1", Devs);
+ return (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 = GetType(dev);
+// string num = device_num(dev);
+// string anum = alias_num(dev);
+ if (report_every_check) y2milestone("Check(%1)", dev);
+ if(!haskey(Devices, typ)) return false;
+
+ map devsmap = Devices[typ]:$[];
+ if(!haskey(devsmap, dev)) 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 = GetType(Name);
+ Current = Devices[t, 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 = GetType(name);
+ if (name==Name) {
+ string int_type = Current["INTERFACETYPE"]:"";
+ if(size(int_type)>0) t = int_type;
+ }
+ string a = alias_num(name);
+ y2debug("ChangeDevice(%1)", name);
+
+ map devsmap = Devices[t]:$[];
+ ifcfg_t devmap = devsmap[name]:$[];
+ map amap = devmap["_aliases"]:$[];
+
+ if(a != "") {
+ amap[a] = newdev;
+ devmap["_aliases"] = amap;
+ }
+ else
+ devmap = newdev;
+
+ devsmap[name] = devmap;
+ Devices[t] = devsmap;
+
+ y2debug("Devices=%1", Devices);
+ return true;
+}
+
+global boolean Delete2(string name) {
+ if(!Check(name)) {
+ y2error("Device not found: %1", name);
+ return false;
+ }
+
+ string t = GetType(name);
+// string d = device_num(name);
+ string a = alias_num(name);
+ map devsmap = Devices[t]:$[];
+
+ if(a != "") {
+ map amap = devsmap[name, "_aliases"]:$[];
+ amap = remove(amap, a);
+ devsmap[name, "_aliases"] = amap;
+ }
+ else
+ devsmap = remove(devsmap, name);
+
+ 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]:$[], name)) {
+ 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();
+}
+
+/**
+ * get IP addres + additional IP addresses
+ * @param identifier for network interface
+ * @return list of IP addresses of selected interface
+ */
+
+global list<string> GetIP(string device){
+ Select(device);
+ list<string> ips = [ GetValue(device, "IPADDR") ];
+ foreach(string key, map value, (map >)Current["_aliases"]:$[], {
+ ips = add(ips, value["IPADDR"]:"");
+ });
+ return ips;
+}
+
+
+/**
+ * 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) 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) 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);});
+ */
+ }
+ ret = filter(string row, ret, {
+ if (row!=nil) return true;
+ y2error("Filtering out : %1", row);
+ return false;
+ });
+ y2milestone("List( %1 ) = %2", devregex, 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]*$")
+ && IsConnected(dev))
+ ret = dev;
+ });
+ });
+
+ 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 ();
+}
+
+/**
+ * list of all devices except given one by parameter dev
+ * also loopback is ommited
+ */
+
+global list<string> ListDevicesExcept(string dev){
+ list<string> devices = filter(string s, LocateNOT("DEVICE", dev), {return s!="lo";});
+ return devices;
+}
+
+/* EOF */
+}
Modified: trunk/yast2/package/yast2.changes
URL: http://svn.opensuse.org/viewcvs/yast/trunk/yast2/package/yast2.changes?rev=43480&r1=43479&r2=43480&view=diff
==============================================================================
--- trunk/yast2/package/yast2.changes (original)
+++ trunk/yast2/package/yast2.changes Tue Jan 8 18:32:30 2008
@@ -1,4 +1,11 @@
-------------------------------------------------------------------
+Fri Dec 14 17:20:27 CET 2007 - mzugec@suse.cz
+
+- added NetworkInterfaces module (NetworkDevices will be deprecated)
+- 2.16.20
+
+-------------------------------------------------------------------
+=======
Tue Jan 8 13:06:46 CET 2008 - jsrain@suse.cz
- disable tab-completion after -i, --install, --remove and
--
To unsubscribe, e-mail: yast-commit+unsubscribe@opensuse.org
For additional commands, e-mail: yast-commit+help@opensuse.org