Patches: inline 'binaries', feature requirements, tmp file fix

Ludwig Nussel ludwig.nussel at gmx.de
Sun Sep 19 17:40:56 EDT 2004


Hi,

loki_setup-binaryinline.diff - New attribute 'inline' for 'binary'
	elements. Can be used to put start scripts directly in the
	xml file. It's kind of a hack, it first saves the content to
	a file an then calls the normal copy_file() to do the job.
loki_setup-feature.diff - Allows to specify features that the
	installer must have to be able to install the xml file.
loki_uninstall-tmpfix.diff - loki-uninstall appends error messages
	to /tmp/uninstall.log. No idea what's that good for except
	for inviting someone to place an evil symlink.

cu
Ludwig

-- 
(o_  Ludwig.Nussel at gmx.de
//\  PGP Key ID: FF8135CE
V_/_ ICQ:        52166811
-------------- next part --------------
Index: loki_setup/file.h
===================================================================
--- loki_setup.orig/file.h
+++ loki_setup/file.h
@@ -55,4 +55,12 @@ extern int dir_exists(const char *path);
 extern void file_create_hierarchy(install_info *info, const char *path);
 extern void dir_create_hierarchy(install_info *info, const char *path, int mode);
 extern int dir_is_accessible(const char *path);
+
+/** create a temporary directory and return it's name. Failure to create the
+ * directory will abort the program. It is only allowed to created inodes that
+ * can be removed with unlink() in that directory */
+extern const char* tmpdir();
+
+/** clean all files in the temporary directory and remove it */
+extern int cleantmpdir();
 #endif
Index: loki_setup/main.c
===================================================================
--- loki_setup.orig/main.c
+++ loki_setup/main.c
@@ -75,6 +75,7 @@ void exit_setup(int ret)
     FreePlugins();
 	free_corrupt_files();
     unmount_filesystems();
+	cleantmpdir();
 	log_exit();
     exit(ret);
 }
Index: loki_setup/file.c
===================================================================
--- loki_setup.orig/file.c
+++ loki_setup/file.c
@@ -11,6 +11,7 @@
 #include <errno.h>
 #include <unistd.h>
 #include <dirent.h>
+#include <time.h>
 
 #include <zlib.h>
 
@@ -783,3 +784,71 @@ static void dobz2init()
 }
 
 #endif
+
+static char tmpdirname[PATH_MAX] = "\0";
+
+const char* tmpdir()
+{
+	unsigned count;
+
+	if(*tmpdirname)
+		return tmpdirname;
+
+	srand(time(NULL));
+	for(count = 0; count < 1000; ++count)
+	{
+		snprintf(tmpdirname, sizeof(tmpdirname), "/tmp/setuptmp.%06X", rand());
+		if(mkdir(tmpdirname, 0700) == 0)
+		{
+			log_debug("temporary directory %s created", tmpdirname);
+			return tmpdirname;
+		}
+	}
+	log_fatal(_("Unable to create temporary directory: %s"), strerror(errno));
+	
+	return NULL;
+}
+
+int cleantmpdir()
+{
+	DIR* dir;
+	struct dirent *entry;
+	char cwd[PATH_MAX];
+
+	if(!*tmpdirname)
+		return 0;
+
+	if(!getcwd(cwd, sizeof(cwd)))
+		cwd[0] = '\0';
+
+	if(chdir(tmpdirname) == -1)
+	{
+		log_warning(_("Can not chdir to temporary directory: %s"), strerror(errno));
+		return -1;
+	}
+
+	dir = opendir(tmpdirname);
+	if(!dir)
+	{
+		log_warning(_("Can not open temporary directory: %s"), strerror(errno));
+		return -1;
+	}
+
+	while((entry = readdir(dir)) != NULL)
+	{
+		if(!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
+			continue;
+
+		log_debug("unlink temporary file %s", entry->d_name);
+		if(unlink(entry->d_name) == -1)
+			log_warning(_("Can not remove %s/%s: %s"), tmpdirname, entry->d_name, strerror(errno));
+	}
+
+	closedir(dir);
+
+	if(*cwd)
+		chdir(cwd);
+
+	return rmdir(tmpdirname);
+}
+
Index: loki_setup/copy.c
===================================================================
--- loki_setup.orig/copy.c
+++ loki_setup/copy.c
@@ -108,6 +108,8 @@ typedef struct _corrupt_list {
 
 static corrupt_list *corrupts = NULL;
 
+static void copy_binary_finish(install_info* info, xmlNodePtr node, const char* fn, struct file_elem *file);
+
 void add_corrupt_file(const product_t *prod, const char *path, const char *option)
 {
 	corrupt_list *item;
@@ -585,6 +587,50 @@ ssize_t copy_manpage(install_info *info,
 	return copied;
 }
 
+/** write memory 'data' with length 'len' to a temporary file called 'name'.
+ * The full path to the created file is returned in name_out which must hold at
+ * least PATH_MAX characters.
+ * @return pointer to name_out for convenience. On error NULL is returned.
+ * content of name_out is undefined in this case.
+ */
+static char* write_temp_script(const char* name, char* name_out,
+		const char* data,
+		size_t len)
+{
+	int fd;
+	ssize_t ret;
+
+	if(!name_out)
+		return NULL;
+
+	if(strrchr(name, '/'))
+	{
+		log_warning("'name' must not contain slashes");
+		return NULL;
+	}
+
+	name_out[PATH_MAX-1] = '\0';
+	name_out[PATH_MAX-2] = '\0';
+	strncpy(name_out, tmpdir(), PATH_MAX-2);
+	name_out[strlen(name_out)] = '/';
+	strncpy(name_out+strlen(name_out), name, PATH_MAX-strlen(name_out)-1);
+
+	if((fd = open(name_out, O_WRONLY|O_CREAT, 0755)) == -1)
+	{
+		log_warning(_("Could not create temporary script: %s"), strerror(errno));
+		return NULL;
+	}
+
+	ret = write(fd, data, len);
+	if(ret < 0 || (unsigned)ret != len)
+	{
+		log_warning(_("Could not create temporary script: %s"), strerror(errno));
+		name_out = NULL;
+	}
+	close(fd);
+	return name_out;
+}
+
 ssize_t copy_binary(install_info *info, xmlNodePtr node, const char *filedesc, const char *dest, 
 		    const char *from_cdrom,
 		    int (*update)(install_info *info, const char *path, size_t progress, size_t size, const char *current))
@@ -617,6 +663,36 @@ ssize_t copy_binary(install_info *info, 
     copied = 0;
     size = 0;
 
+	if(xmlNodePropIsTrue(node, "inline"))
+	{
+		if(!binpath)
+		{
+			log_warning(_("'binpath' attribute is mandatory for inline 'binary' tag"));
+			goto copy_binary_exit; 
+		}
+		else if(strrchr(binpath, '/'))
+		{
+			log_warning(_("'binpath' attribute must not contain slashes for inline 'binary' tag"));
+			goto copy_binary_exit; 
+		}
+
+		strncpy(fdest, dest, sizeof(fdest));
+		fdest[sizeof(fdest)-1] = '\0';
+
+		if(!write_temp_script(binpath, bin, filedesc, strlen(filedesc)))
+			goto copy_binary_exit;
+
+		copied = copy_file(info, NULL, bin, fdest, final, 1, 1, node, update, &file);
+		if(copied > 0)
+		{
+			size += copied;
+
+			copy_binary_finish(info, node, final, file);
+		}
+		unlink(bin);
+		goto copy_binary_exit;
+	}
+
     while ( filedesc && parse_line(&filedesc, final, (sizeof final)) ) {
 		if (! in_rpm) {
 			const char *cdpath = NULL;
@@ -716,23 +792,9 @@ ssize_t copy_binary(install_info *info, 
 			log_warning(_("Unable to copy file '%s'"), fpat);
 			ui_fatal_error(_("Unable to copy file '%s'"), fpat);
         } else if ( copied > 0 || in_rpm ) {
-            char *symlink = xmlGetProp(node, "symlink");
-            char sym_to[PATH_MAX];
-
             size += copied;
-            /* Create the symlink */
-            if ( *info->symlinks_path && symlink ) {
-                snprintf(sym_to, sizeof(sym_to), "%s/%s", info->symlinks_path, symlink);
-                file_symlink(info, final, sym_to);
-            }
-            add_bin_entry(info, current_option, file, symlink,
-						  xmlGetProp(node, "desc"),
-						  xmlGetProp(node, "menu"),
-						  xmlGetProp(node, "name"),
-						  xmlGetProp(node, "icon"),
-						  xmlGetProp(node, "args"),
-						  xmlGetProp(node, "play")
-						  );
+
+			copy_binary_finish(info, node, final, file);
         }
     }
  copy_binary_exit:
@@ -740,6 +802,29 @@ ssize_t copy_binary(install_info *info, 
     return size;
 }
 
+/** to be called when binary was successfully installed. creates optional
+ * symlink and registers the file in the setup database.
+ */
+static void copy_binary_finish(install_info* info, xmlNodePtr node, const char* fn, struct file_elem *file)
+{
+	char *symlink = xmlGetProp(node, "symlink");
+	char sym_to[PATH_MAX];
+
+	/* Create the symlink */
+	if ( *info->symlinks_path && symlink ) {
+		snprintf(sym_to, sizeof(sym_to), "%s/%s", info->symlinks_path, symlink);
+		file_symlink(info, fn, sym_to);
+	}
+	add_bin_entry(info, current_option, file, symlink,
+			xmlGetProp(node, "desc"),
+			xmlGetProp(node, "menu"),
+			xmlGetProp(node, "name"),
+			xmlGetProp(node, "icon"),
+			xmlGetProp(node, "args"),
+			xmlGetProp(node, "play")
+			);
+}
+
 static int copy_script(install_info *info, xmlNodePtr node, const char *script, const char *dest, size_t size,
 				int (*update)(install_info *info, const char *path, size_t progress, size_t size, const char *current), const char *from_cdrom, const char *msg)
 {
@@ -1196,7 +1281,8 @@ unsigned long long size_node(install_inf
 					size += size_list(info, from_cdrom, srcpath,
 									  xmlNodeListGetString(info->config, node->childs, 1));
 				} else if ( strcmp(node->name, "binary") == 0 ) {
-					size += size_binary(info, from_cdrom,
+					if(!xmlNodePropIsTrue(node, "inline"))
+						size += size_binary(info, from_cdrom,
 									xmlNodeListGetString(info->config, node->childs, 1));
 				} else if ( strcmp(node->name, "manpage") == 0 ) {
 					size += size_manpage(info, node, from_cdrom);
@@ -1257,3 +1343,4 @@ int has_binaries(install_info *info, xml
 }
 
 
+
Index: loki_setup/README.xml
===================================================================
--- loki_setup.orig/README.xml
+++ loki_setup/README.xml
@@ -652,6 +652,10 @@ There are several optional attributes of
 
  args       Specify optional arguments to be added on the command line when running the binary.
 
+ inline     When set to 'yes' the text content of the element is used as script
+	    content instead of a path. The value of 'binarypath' is used as
+	    script name in this case
+
 The FILES element:
 
 The files element contains a list of files and directories, one per line,
-------------- next part --------------
Index: loki_setup/install.c
===================================================================
--- loki_setup.orig/install.c
+++ loki_setup/install.c
@@ -129,6 +129,32 @@ int disable_binary_path = 0;
 static int install_updatemenus_script = 0;
 static int uninstall_generated = 0;
 
+typedef struct
+{
+	const char* name;
+	unsigned version;
+} SetupFeature;
+
+/** features supported by this installer */
+static SetupFeature features[] =
+{
+	{ "inline-scripts", 1 },
+	{ NULL, 0 }
+};
+
+static int have_feature(const char* name, unsigned version)
+{
+	SetupFeature* f;
+	
+	for (f = features; f->name; ++f)
+	{
+		if(!strcmp(f->name, name) && f->version >= version)
+			return 1;
+	}
+	
+	return 0;
+}
+
 /* Functions to retrieve attribution information from the XML tree */
 const char *GetProductName(install_info *info)
 {
@@ -1241,13 +1267,15 @@ int CheckRequirements(install_info *info
 			 match_arch(info, arch) &&
 			 match_libc(info, libc) &&
 			 match_distro(info, distro) ) {
-			char *prop = xmlGetProp(node, "command");
+			char *commandprop = xmlGetProp(node, "command");
+			char *featureprop = xmlGetProp(node, "feature");
 			xmlFree(lang); xmlFree(arch); xmlFree(libc); xmlFree(distro);
-			if ( !prop ) {
-				log_fatal(_("XML: 'require' tag doesn't have a mandatory 'command' attribute"));
-			} else {
+			if ( !commandprop && !featureprop ) {
+				log_fatal(_("XML: 'require' tag doesn't have a mandatory 'command' or 'feature' attribute"));
+			}
+			if(commandprop) {
 				/* Launch the command */
-				if ( run_script(info, prop, 0, 0) != 0 ) {
+				if ( run_script(info, commandprop, 0, 0) != 0 ) {
 					/* We failed: print out error message */
 					text = xmlNodeListGetString(info->config, node->childs, 1);
 					if(text) {
@@ -1259,11 +1287,30 @@ int CheckRequirements(install_info *info
 						}
 						UI.prompt(buf, RESPONSE_OK);
 					}
-					xmlFree(prop);
+					xmlFree(commandprop);
+					return 0;
+				}
+				xmlFree(commandprop);
+			} else if(featureprop) {
+				char *verprop = xmlGetProp(node, "version");
+				unsigned version = 1;
+				if(verprop) {
+					version = atoi(verprop);
+					xmlFree(verprop);
+				}
+				if(!have_feature(featureprop, version))
+				{
+					char buf[1024];
+					snprintf(buf, sizeof(buf),
+							_("The installer is not suitable for installing this product "
+								"(missing feature '%s' version '%u')"), featureprop, version);
+					UI.prompt(buf, RESPONSE_OK);
+					xmlFree(featureprop);
 					return 0;
 				}
-				xmlFree(prop);
 			}
+
+			xmlFree(featureprop);
 		} else {
 			xmlFree(lang); xmlFree(arch); xmlFree(libc); xmlFree(distro);
 		}
@@ -2626,7 +2673,7 @@ int run_script(install_info *info, const
        (to avoid problems with 'sh script.sh')
     */
     working_dir[0] = '\0'; 
-    if ( access(script, R_OK) == 0 ) {
+    if ( *script != '/' && access(script, R_OK) == 0 ) {
         if ( getcwd(working_dir, sizeof(working_dir)) == NULL ) {
 			perror("run_script: getcwd");
 		}
Index: loki_setup/README.xml
===================================================================
--- loki_setup.orig/README.xml
+++ loki_setup/README.xml
@@ -326,10 +326,13 @@ are fulfilled.
 are parsed in sequential order. Installation will abort if any of the specified commands return
 a non-nil value.
 
-This element takes one mandatory attribute :
+This element takes either of the following mandatory attributes :
 
  command     Specify the command to be run to determine the condition. A nil value means success.
 
+ feature     Specify the name of a feature that must be present in the
+             installer to be able to process this XML file.
+
 This element takes some optional attributes :
   lang      Specify the language for the message. Used for localization. The command will be executed
             only if the locale settings match.
@@ -345,13 +348,20 @@ This element takes some optional attribu
   distro    This component applies only to the specified OS distribution.
             Look at the end of this file for a list of possible values.
 
-The text specified in the element will be displayed to the user if the condition fails.
-Example:
+  version   [only for feature attribute] the minimum integer version number
+            required for the specified feature.
+
+The text specified in the element will be displayed to the user if the
+condition of the command attribute fails. It has no meaning for the feature
+attribute.
+Examples:
 
 <require command="/bin/false">
 This is always failing! Thus this message is always displayed.
 </require>
 
+<require feature="inline-scripts" version="1"/>
+
 The POST_INSTALL_MSG element :
 
 This element displays an optional message to the user at the end of a successful installation.
-------------- next part --------------
Index: loki_setup/uninstall.c
===================================================================
--- loki_setup.orig/uninstall.c
+++ loki_setup/uninstall.c
@@ -58,12 +58,7 @@ static void print_usage(const char *argv
 
 static void log_file(const char *name, const char *reason)
 {
-    FILE *log = fopen("/tmp/uninstall.log", "a");
     fprintf(stderr, "%s : %s\n", name, reason);
-    if(log) {
-        fprintf(log, "%s : %s\n", name, reason);
-        fclose(log);
-    }
 }
 
 struct dir_entry {
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
URL: <http://icculus.org/pipermail/lokisetup/attachments/20040919/44ab787d/attachment.pgp>


More information about the Lokisetup mailing list