File module-init-tools-suse.diff of Package module-init-tools

This patch contains suse-specific changes against upstream commit 9a1c905651a38d1f2c6d4d836f81b5e06a503521

diff --git a/depmod.c b/depmod.c
index 4c8caa0..b4e52b4 100644
--- a/depmod.c
+++ b/depmod.c
@@ -193,7 +193,7 @@ static void load_module_symvers(const char *filename)
 
 	/* eg. "0xb352177e\tfind_first_bit\tvmlinux\tEXPORT_SYMBOL" */
 	while (fgets(line, sizeof(line)-1, module_symvers)) {
-		const char *ver, *sym, *where;
+		const char *ver, *sym, *where, *slash;
 
 		ver = strtok(line, " \t");
 		sym = strtok(NULL, " \t");
@@ -201,7 +201,9 @@ static void load_module_symvers(const char *filename)
 		if (!ver || !sym || !where)
 			continue;
 
-		if (streq(where, "vmlinux"))
+		if (streq(where, "vmlinux") ||
+		    (((slash = strrchr(where, '/'))) &&
+		    streq(slash, "/built-in")))
 			add_symbol(sym, strtoull(ver, NULL, 16), NULL);
 	}
 
@@ -434,7 +436,7 @@ static const char *compress_path(const char *path, const char *basedir)
 	return path;
 }
 
-static void output_deps(struct module *modules,
+static int output_deps(struct module *modules,
 			FILE *out, char *dirname)
 {
 	struct module *i;
@@ -453,12 +455,13 @@ static void output_deps(struct module *modules,
 		}
 		fprintf(out, "\n");
 	}
+	return 1;
 }
 
 /* warn whenever duplicate module aliases, deps, or symbols are found. */
 int warn_dups = 0;
 
-static void output_deps_bin(struct module *modules,
+static int output_deps_bin(struct module *modules,
 			FILE *out, char *dirname)
 {
 	struct module *i;
@@ -495,6 +498,8 @@ static void output_deps_bin(struct module *modules,
 	
 	index_write(index, out);
 	index_destroy(index);
+
+	return 1;
 }
 
 
@@ -769,7 +774,7 @@ static struct module *parse_modules(struct module *list)
 }
 
 /* Simply dump hash table. */
-static void output_symbols(struct module *unused, FILE *out, char *dirname)
+static int output_symbols(struct module *unused, FILE *out, char *dirname)
 {
 	unsigned int i;
 
@@ -786,9 +791,10 @@ static void output_symbols(struct module *unused, FILE *out, char *dirname)
 			}
 		}
 	}
+	return 1;
 }
 
-static void output_symbols_bin(struct module *unused, FILE *out, char *dirname)
+static int output_symbols_bin(struct module *unused, FILE *out, char *dirname)
 {
 	struct index_node *index;
 	unsigned int i;
@@ -817,9 +823,54 @@ static void output_symbols_bin(struct module *unused, FILE *out, char *dirname)
 	
 	index_write(index, out);
 	index_destroy(index);
+
+	return 1;
 }
 
-static void output_aliases(struct module *modules, FILE *out, char *dirname)
+static int output_builtin_bin(struct module *unused, FILE *out, char *dirname)
+{
+	struct index_node *index;
+	char *textfile, *line;
+	unsigned int linenum;
+	FILE *f;
+
+	nofail_asprintf(&textfile, "%s/modules.builtin", dirname);
+	if (!(f = fopen(textfile, "r"))) {
+		if (errno != ENOENT)
+			fatal("Could not open '%s': %s\n",
+					textfile, strerror(errno));
+		free(textfile);
+		return 0;
+	}
+	free(textfile);
+	index = index_create();
+
+	while ((line = getline_wrapped(f, &linenum)) != NULL) {
+		char *module = strrchr(line, '/');
+
+		if (!*line || *line == '#') {
+			free(line);
+			continue;
+		}
+		module = strrchr(line, '/');
+		if (module)
+			module++;
+		else
+			module = line;
+		if (ends_in(module, ".ko"))
+			module[strlen(module) - 3] = '\0';
+		underscores(module);
+		index_insert(index, module, "", 0);
+		free(line);
+	}
+	fclose(f);
+	index_write(index, out);
+	index_destroy(index);
+
+	return 1;
+}
+
+static int output_aliases(struct module *modules, FILE *out, char *dirname)
 {
 	struct module *i;
 	struct elf_file *file;
@@ -849,9 +900,10 @@ static void output_aliases(struct module *modules, FILE *out, char *dirname)
 		}
 		strtbl_free(tbl);
 	}
+	return 1;
 }
 
-static void output_aliases_bin(struct module *modules, FILE *out, char *dirname)
+static int output_aliases_bin(struct module *modules, FILE *out, char *dirname)
 {
 	struct module *i;
 	struct elf_file *file;
@@ -901,11 +953,13 @@ static void output_aliases_bin(struct module *modules, FILE *out, char *dirname)
 	
 	index_write(index, out);
 	index_destroy(index);
+
+	return 1;
 }
 
 struct depfile {
 	char *name;
-	void (*func)(struct module *, FILE *, char *dirname);
+	int (*func)(struct module *, FILE *, char *dirname);
 	int map_file;
 };
 
@@ -923,7 +977,8 @@ static struct depfile depfiles[] = {
 	{ "modules.alias", output_aliases, 0 },
 	{ "modules.alias.bin", output_aliases_bin, 0 },
 	{ "modules.symbols", output_symbols, 0 },
-	{ "modules.symbols.bin", output_symbols_bin, 0 }
+	{ "modules.symbols.bin", output_symbols_bin, 0 },
+	{ "modules.builtin.bin", output_builtin_bin, 0 },
 };
 
 /* If we can't figure it out, it's safe to say "true". */
@@ -1368,6 +1423,7 @@ int main(int argc, char *argv[])
 
 	for (i = 0; i < sizeof(depfiles)/sizeof(depfiles[0]); i++) {
 		FILE *out;
+		int res;
 		struct depfile *d = &depfiles[i];
 		char depname[strlen(dirname) + 1 + strlen(d->name) + 1];
 		char tmpname[strlen(dirname) + 1 + strlen(d->name) +
@@ -1388,12 +1444,18 @@ int main(int argc, char *argv[])
 			if (ends_in(depname, ".bin"))
 				continue;
 		}
-		d->func(list, out, dirname);
-		if (!doing_stdout) {
-			fclose(out);
+		res = d->func(list, out, dirname);
+		if (doing_stdout)
+			continue;
+		fclose(out);
+		if (res) {
 			if (rename(tmpname, depname) < 0)
 				fatal("Could not rename %s into %s: %s\n",
 					tmpname, depname, strerror(errno));
+		} else {
+			if (unlink(tmpname) < 0)
+				warn("Could not delete %s: %s\n",
+					tmpname, strerror(errno));
 		}
 	}
 
diff --git a/doc/modprobe.conf.sgml b/doc/modprobe.conf.sgml
index cacc006..cd94511 100644
--- a/doc/modprobe.conf.sgml
+++ b/doc/modprobe.conf.sgml
@@ -176,6 +176,19 @@
 	  </para>
         </listitem>
       </varlistentry>
+      <varlistentry>
+        <term>allow_unsupported_modules <replaceable>[0|1]</replaceable>
+        </term>
+	<listitem>
+	  <para>
+            In SUSE kernels, every kernel module has a flag 'supported'. If
+            this flag is not set loading this module will taint your kernel.
+            Setting this option to 0 disables loading of unsupported modules
+            and avoids tainting the kernel. This is typically set in
+            <filename>/etc/modprobe.d/unsupported-modules</filename>.
+	  </para>
+        </listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
   <refsect1>
diff --git a/doc/modprobe.sgml b/doc/modprobe.sgml
index fde8ca7..01ee9e1 100644
--- a/doc/modprobe.sgml
+++ b/doc/modprobe.sgml
@@ -430,9 +430,28 @@
           </para>
         </listitem>
       </varlistentry>
+      <varlistentry>
+        <term><option>--allow-unsupported-modules</option>
+        </term>
+        <listitem>
+          <para>
+            Load unsupported modules even if disabled in configuration.
+	  </para>
+        </listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
   <refsect1>
+    <title>RETURN VALUE</title>
+
+    <para>
+      <command>modprobe</command> returns 0 on success, 1 on an unspecified
+      error and 2 if the module is not supported. Use the
+      <option>--allow-unsupported-modules</option> option to force
+      using an unsupported module.
+    </para>
+  </refsect1>
+  <refsect1>
     <title>ENVIRONMENT</title>
     <para>
       The MODPROBE_OPTIONS environment variable can also be used to
diff --git a/logging.c b/logging.c
index 4330269..46257ff 100644
--- a/logging.c
+++ b/logging.c
@@ -57,13 +57,15 @@ void error(const char *fmt, ...)
 	va_end(arglist);
 }
 
+/* can be overriden for different kinds of errors */
+int fatal_exit_code = 1;
 void fatal(const char *fmt, ...)
 {
 	va_list arglist;
 	va_start(arglist, fmt);
 	message("FATAL: ", fmt, &arglist);
 	va_end(arglist);
-	exit(1);
+	exit(fatal_exit_code);
 }
 
 /* If we don't flush, then child processes print before we do */
diff --git a/logging.h b/logging.h
index c01187b..7445ab4 100644
--- a/logging.h
+++ b/logging.h
@@ -10,6 +10,9 @@ extern int quiet;
 /* Do we want informative messages as well as errors? */
 extern int verbose;
 
+/* Exit code returned by fatal() */
+extern int fatal_exit_code;
+
 extern void fatal(const char *fmt, ...);
 extern void error(const char *fmt, ...);
 extern void warn(const char *fmt, ...);
diff --git a/modprobe.c b/modprobe.c
index 21a3111..72d9c10 100644
--- a/modprobe.c
+++ b/modprobe.c
@@ -51,6 +51,9 @@
 
 int use_binary_indexes = 1; /* default to enabled. */
 
+/* Allow loading of unsupported modules? */
+static int allow_unsupported = 1;
+
 extern long init_module(void *, unsigned long, const char *);
 extern long delete_module(const char *, unsigned int);
 
@@ -69,8 +72,9 @@ typedef enum
 	mit_ignore_commands = 16,
 	mit_ignore_loaded = 32,
 	mit_strip_vermagic = 64,
-	mit_strip_modversion = 128
+	mit_strip_modversion = 128,
 
+	mit_force_allow_unsupported = 1<<20,
 } modprobe_flags_t;
 
 #ifndef MODULE_DIR
@@ -354,6 +358,23 @@ static void clear_magic(struct elf_file *module)
 	}
 }
 
+static int module_supported(struct elf_file *module)
+{
+	struct string_table *tbl;
+	int j;
+
+	/* Grab from new-style .modinfo section. */
+	tbl = module->ops->load_strings(module, ".modinfo", NULL, fatal);
+	for (j = 0; tbl && j < tbl->cnt; j++) {
+		const char *p = tbl->str[j];
+		if (streq(p, "supported=yes") ||
+		    streq(p, "supported=external")) {
+			return 1;
+		}
+	}
+	return 0;
+}
+
 struct module_options
 {
 	struct module_options *next;
@@ -537,6 +558,24 @@ static int read_attribute(const char *filename, char *buf, size_t buflen)
 	return (s == NULL) ? -1 : 1;
 }
 
+/* is this a built-in module?
+ * 0: no, 1: yes, -1: don't know
+ */
+static int module_builtin(const char *dirname, const char *modname)
+{
+	struct index_file *index;
+	char *filename, *value;
+
+	nofail_asprintf(&filename, "%s/modules.builtin.bin", dirname);
+	index = index_file_open(filename);
+	free(filename);
+	if (!index)
+		return -1;
+	value = index_search(index, modname);
+	free(value);
+	return value ? 1 : 0;
+}
+
 /* Is module in /sys/module?  If so, fill in usecount if not NULL. 
    0 means no, 1 means yes, -1 means unknown.
  */
@@ -787,6 +826,16 @@ static int parse_config_file(const char *filename,
 				if (streq(tmp, "no"))
 					use_binary_indexes = 0;
 			}
+		} else if (strcmp(cmd, "allow_unsupported_modules") == 0) {
+			const char *option = strsep_skipspace(&ptr, "\t ");
+			if (!option)
+				grammar(cmd, filename, linenum);
+			else if (streq(option, "yes") || streq(option, "1"))
+				allow_unsupported = 1;
+			else if (streq(option, "no") || streq(option, "0"))
+				allow_unsupported = 0;
+			else
+				grammar(cmd, filename, linenum);
 		} else
 			grammar(cmd, filename, linenum);
 
@@ -1144,6 +1193,17 @@ static int insmod(struct list_head *list,
 				strerror(errno));
 		goto out_unlock;
 	}
+	/* Supported? */
+	if (!allow_unsupported && !module_supported(module)) {
+		if (error == fatal)
+			fatal_exit_code = 2;
+		error("module '%s' is unsupported\n"
+		      "Use --allow-unsupported or set allow_unsupported_modules to 1 in\n"
+		      "/etc/modprobe.d/10-unsupported-modules.conf\n",
+		      mod->filename);
+		goto out;
+	}
+
 	if (newname)
 		rename_module(module, mod->modname, newname);
 	if (flags & mit_strip_modversion)
@@ -1309,6 +1369,16 @@ int do_modprobe(char *modname,
 	/* Returns the resolved alias, options */
 	parse_toplevel_config(configname, modname, 0,
 	     flags & mit_remove, &modoptions, &commands, &aliases, &blacklist);
+	if (flags & mit_force_allow_unsupported)
+		allow_unsupported = 1;
+	/* Be nice to people running non-suse kernels and allow
+	 * unsupported modules */
+	if (!allow_unsupported) {
+		if (access("/proc/sys/kernel/", F_OK) == 0 &&
+		    access("/proc/sys/kernel/unsupported", F_OK) == -1 &&
+		    errno == ENOENT)
+			allow_unsupported = 1;
+	}
 
 	/* Read module options from kernel command line */
 	parse_kcmdline(0, &modoptions);
@@ -1331,6 +1401,11 @@ int do_modprobe(char *modname,
 					  modname, 0, flags & mit_remove,
 					  &modoptions, &commands,
 					  &aliases, &blacklist);
+			/* builtin module? */
+			if (!aliases && module_builtin(dirname, modname) == 1) {
+				info("builtin %s\n", modname);
+				return 0;
+			}
 		}
 	}
 
@@ -1390,6 +1465,8 @@ static struct option options[] = { { "version", 0, NULL, 'V' },
 				   { "force-modversion", 0, NULL, 2 },
 				   { "first-time", 0, NULL, 3 },
 				   { "dump-modversions", 0, NULL, 4 },
+				   { "allow-unsupported-modules", 0, NULL, 128 },
+				   { "use-blacklist", 0, NULL, 'b' },
 				   { NULL, 0, NULL, 0 } };
 
 int main(int argc, char *argv[])
@@ -1494,6 +1571,9 @@ int main(int argc, char *argv[])
 		case 4:
 			dump_modver = 1;
 			break;
+		case 128:
+			flags |= mit_force_allow_unsupported;
+			break;
 		default:
 			print_usage(argv[0]);
 		}
diff --git a/tables.c b/tables.c
index 2f44450..c862920 100644
--- a/tables.c
+++ b/tables.c
@@ -34,7 +34,7 @@ static void output_pci_entry(struct pci_device_id *pci, char *name, FILE *out,
 		END(pci->class_mask, conv));
 }
 
-void output_pci_table(struct module *modules, FILE *out, char *dirname)
+int output_pci_table(struct module *modules, FILE *out, char *dirname)
 {
 	struct module *i;
 
@@ -53,6 +53,7 @@ void output_pci_table(struct module *modules, FILE *out, char *dirname)
 		for (e = t->pci_table; e->vendor; e = (void *)e + t->pci_size)
 			output_pci_entry(e, shortname, out, i->file->conv);
 	}
+	return 1;
 }
 
 /* We set driver_info to zero */
@@ -78,7 +79,7 @@ static void output_usb_entry(struct usb_device_id *usb, char *name, FILE *out,
 		END(usb->bInterfaceProtocol, conv));
 }
 
-void output_usb_table(struct module *modules, FILE *out, char *dirname)
+int output_usb_table(struct module *modules, FILE *out, char *dirname)
 {
 	struct module *i;
 
@@ -104,6 +105,7 @@ void output_usb_table(struct module *modules, FILE *out, char *dirname)
 		     e = (void *)e + t->usb_size)
 			output_usb_entry(e, shortname, out, i->file->conv);
 	}
+	return 1;
 }
 
 static void output_ieee1394_entry(struct ieee1394_device_id *fw, char *name,
@@ -118,7 +120,7 @@ static void output_ieee1394_entry(struct ieee1394_device_id *fw, char *name,
 		END(fw->version, conv));
 }
 
-void output_ieee1394_table(struct module *modules, FILE *out, char *dirname)
+int output_ieee1394_table(struct module *modules, FILE *out, char *dirname)
 {
 	struct module *i;
 
@@ -138,6 +140,7 @@ void output_ieee1394_table(struct module *modules, FILE *out, char *dirname)
 		     fw = (void *) fw + t->ieee1394_size)
 			output_ieee1394_entry(fw, shortname, out, i->file->conv);
 	}
+	return 1;
 }
 
 
@@ -151,7 +154,7 @@ static void output_ccw_entry(struct ccw_device_id *ccw, char *name, FILE *out,
 		END(ccw->dev_type, conv), END(ccw->dev_model, conv));
 }
 
-void output_ccw_table(struct module *modules, FILE *out, char *dirname)
+int output_ccw_table(struct module *modules, FILE *out, char *dirname)
 {
 	struct module *i;
 
@@ -172,6 +175,7 @@ void output_ccw_table(struct module *modules, FILE *out, char *dirname)
 		     e = (void *) e + t->ccw_size)
 			output_ccw_entry(e, shortname, out, i->file->conv);
 	}
+	return 1;
 }
 
 #define ISAPNP_VENDOR(a,b,c)	(((((a)-'A'+1)&0x3f)<<2)|\
@@ -192,7 +196,7 @@ static void put_isapnp_id(FILE *out, const char *id)
 	fprintf(out, " 0x%04x     0x%04x    ", vendor, device);
 }
 
-void output_isapnp_table(struct module *modules, FILE *out, char *dirname)
+int output_isapnp_table(struct module *modules, FILE *out, char *dirname)
 {
 	struct module *i;
 
@@ -238,6 +242,7 @@ void output_isapnp_table(struct module *modules, FILE *out, char *dirname)
 			}
 		}
 	}
+	return 1;
 }
 
 #define MATCH_bustype   1
@@ -412,7 +417,7 @@ static int output_input_entry_64_old(struct input_device_id_old_64 *input,
 	return 0;
 }
 
-void output_input_table(struct module *modules, FILE *out, char *dirname)
+int output_input_table(struct module *modules, FILE *out, char *dirname)
 {
 	struct module *i;
 
@@ -468,6 +473,7 @@ void output_input_table(struct module *modules, FILE *out, char *dirname)
 			}
 		}				
 	}
+	return 1;
 }
 
 static void output_serio_entry(struct serio_device_id *serio, char *name, FILE *out)
@@ -482,7 +488,7 @@ static void output_serio_entry(struct serio_device_id *serio, char *name, FILE *
 }
 
 
-void output_serio_table(struct module *modules, FILE *out, char *dirname)
+int output_serio_table(struct module *modules, FILE *out, char *dirname)
 {
 	struct module *i;
 
@@ -500,6 +506,7 @@ void output_serio_table(struct module *modules, FILE *out, char *dirname)
 		for (e = t->serio_table; e->type || e->proto; e = (void *)e + t->serio_size)
 			output_serio_entry(e, shortname, out);
 	}
+	return 1;
 }
 
 
@@ -542,7 +549,7 @@ static void output_of_entry(struct of_device_id *dev, char *name, FILE *out)
 	free(compatible);
 }
 
-void output_of_table(struct module *modules, FILE *out, char *dirname)
+int output_of_table(struct module *modules, FILE *out, char *dirname)
 {
 	struct module *i;
 
@@ -560,4 +567,5 @@ void output_of_table(struct module *modules, FILE *out, char *dirname)
                      e = (void *)e + t->of_size)
 			output_of_entry(e, shortname, out);
 	}
+	return 1;
 }
diff --git a/tables.h b/tables.h
index 8a1420f..920e8df 100644
--- a/tables.h
+++ b/tables.h
@@ -175,13 +175,13 @@ struct of_device_id {
 
 /* Functions provided by tables.c */
 struct module;
-void output_usb_table(struct module *modules, FILE *out, char *dirname);
-void output_ieee1394_table(struct module *modules, FILE *out, char *dirname);
-void output_pci_table(struct module *modules, FILE *out, char *dirname);
-void output_ccw_table(struct module *modules, FILE *out, char *dirname);
-void output_isapnp_table(struct module *modules, FILE *out, char *dirname);
-void output_input_table(struct module *modules, FILE *out, char *dirname);
-void output_serio_table(struct module *modules, FILE *out, char *dirname);
-void output_of_table(struct module *modules, FILE *out, char *dirname);
+int output_usb_table(struct module *modules, FILE *out, char *dirname);
+int output_ieee1394_table(struct module *modules, FILE *out, char *dirname);
+int output_pci_table(struct module *modules, FILE *out, char *dirname);
+int output_ccw_table(struct module *modules, FILE *out, char *dirname);
+int output_isapnp_table(struct module *modules, FILE *out, char *dirname);
+int output_input_table(struct module *modules, FILE *out, char *dirname);
+int output_serio_table(struct module *modules, FILE *out, char *dirname);
+int output_of_table(struct module *modules, FILE *out, char *dirname);
 
 #endif /* MODINITTOOLS_TABLES_H */
diff --git a/zlibsupport.c b/zlibsupport.c
index b159765..0f78524 100644
--- a/zlibsupport.c
+++ b/zlibsupport.c
@@ -12,6 +12,8 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/mman.h>
+#include <stdio.h>
+#include <string.h>
 
 #include "zlibsupport.h"
 #include "logging.h"
@@ -19,69 +21,35 @@
 
 #ifdef CONFIG_USE_ZLIB
 #include <zlib.h>
+#endif
 
-void *grab_contents(gzFile *gzfd, unsigned long *size)
+#ifdef CONFIG_USE_ZLIB
+static int check_gz_magic(int fd)
 {
-	unsigned int max = 16384;
-	void *buffer = NOFAIL(malloc(max));
-	int ret;
-
-	*size = 0;
-	while ((ret = gzread(gzfd, buffer + *size, max - *size)) > 0) {
-		*size += ret;
-		if (*size == max)
-			buffer = NOFAIL(realloc(buffer, max *= 2));
-	}
-	if (ret < 0) {
-		free(buffer);
-		buffer = NULL;
-	}
-
-	return buffer;
+	unsigned char magic[2];
+
+	if (read(fd, magic, 2) != 2)
+		return -1;
+	lseek(fd, 0, SEEK_SET);
+	if (magic[0] == 0x1f && magic[1] == 0x8b)
+		return 1;
+	return 0;
 }
 
-void *grab_fd(int fd, unsigned long *size)
+static char *tmpdir(void)
 {
-	gzFile gzfd;
-
-	gzfd = gzdopen(fd, "rb");
-	if (!gzfd) {
-		if (errno == ENOMEM)
-			fatal("Memory allocation failure in gzdopen\n");
-		return NULL;
-	}
-
-	/* gzclose(gzfd) would close fd, which would drop locks.
-	   Don't blame zlib: POSIX locking semantics are so horribly
-	   broken that they should be ripped out. */
-	return grab_contents(gzfd, size);
+	static char *TMPDIR;
+
+	if (TMPDIR)
+		return TMPDIR;
+	TMPDIR = getenv("TMPDIR");
+	if (!TMPDIR)
+		TMPDIR = "/tmp";
+	return TMPDIR;
 }
+#endif
 
-/* gzopen handles uncompressed files transparently. */
-void *grab_file(const char *filename, unsigned long *size)
-{
-	gzFile gzfd;
-	void *buffer;
-
-	errno = 0;
-	gzfd = gzopen(filename, "rb");
-	if (!gzfd) {
-		if (errno == ENOMEM)
-			fatal("Memory allocation failure in gzopen\n");
-		return NULL;
-	}
-	buffer = grab_contents(gzfd, size);
-	gzclose(gzfd);
-	return buffer;
-}
-
-void release_file(void *data, unsigned long size)
-{
-	free(data);
-}
-#else /* ... !CONFIG_USE_ZLIB */
-
-void *grab_fd(int fd, unsigned long *size)
+void *do_grab_fd(int fd, unsigned long *size)
 {
 	struct stat st;
 	void *map;
@@ -97,6 +65,60 @@ void *grab_fd(int fd, unsigned long *size)
 	return map;
 }
 
+void *grab_fd(int fd, unsigned long *size)
+{
+#ifdef CONFIG_USE_ZLIB
+	int magic = check_gz_magic(fd);
+	if (magic == -1)
+		return NULL;
+	if (magic) {
+		gzFile gzfd;
+		int tmp;
+		char buffer[4096];
+		char *template;
+		int r, w;
+		void *ret = NULL;
+
+		template = NOFAIL(malloc(strlen(tmpdir()) + sizeof("/m-i-t.XXXXXX")));
+		sprintf(template, "%s/m-i-t.XXXXXX", tmpdir());
+		gzfd = gzdopen(dup(fd), "rb");
+		if (!gzfd) {
+			if (errno == ENOMEM)
+				fatal("Memory allocation failure in gzdopen\n");
+			goto out_template;
+		}
+		tmp = mkstemp(template);
+		if (tmp == -1)
+			goto out_template;
+
+		while ((r = gzread(gzfd, buffer, sizeof(buffer))) > 0) {
+			char *p = buffer;
+			do {
+				w = write(tmp, p, r);
+				if (w > 0) {
+					r -= w;
+					p += w;
+				}
+			} while (w > 0 || (w == -1 && errno == EINTR));
+			if (w == -1)
+				goto out;
+		}
+		if (r < 0)
+			goto out;
+		gzclose(gzfd);
+		ret = do_grab_fd(tmp, size);
+out:
+		close(tmp);
+		unlink(template);
+out_template:
+		free(template);
+		return ret;
+	} else
+#endif
+		return do_grab_fd(fd, size);
+}
+
+
 void *grab_file(const char *filename, unsigned long *size)
 {
 	int fd;
@@ -114,4 +136,4 @@ void release_file(void *data, unsigned long size)
 {
 	munmap(data, size);
 }
-#endif
+
openSUSE Build Service is sponsored by