Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 12 Aug 2007 11:44:21 GMT
From:      Andrew Turner <andrew@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 125079 for review
Message-ID:  <200708121144.l7CBiLDs053875@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=125079

Change 125079 by andrew@andrew_hermies on 2007/08/12 11:43:52

	Always reread the tag file when looking at the db directory
	Get a count of the number of -rollback directories there are
	When we receive a SIGPIPE in the communications thread finish the current loop and wait for a new connection
	Use uname to get the release version of the kernel for update name
	Remove debugging output on stdout
	Implement the list_installed call
	Implement most of the rollback_patches call. The only part missing is the execution of freebsd-update
	Drop privileges when executing to allow the back end to be setuid as some of the directories in the freebsd-update require us to be root to access

Affected files ...

.. //depot/projects/soc2007/andrew-update/backend/facund-be.c#23 edit

Differences ...

==== //depot/projects/soc2007/andrew-update/backend/facund-be.c#23 (text+ko) ====

@@ -31,6 +31,7 @@
 #include <sys/event.h>
 #include <sys/stat.h>
 #include <sys/time.h>
+#include <sys/utsname.h>
 
 #include <assert.h>
 #include <bsdxml.h>
@@ -53,7 +54,8 @@
 /* Check if there are updates every 30min  */
 static const time_t default_check_period = 30 * 60;
 
-static int facund_in_loop = 1;
+static volatile int facund_in_loop = 1;
+static volatile int facund_comms_in_loop = 1;
 
 #define DEFAULT_CONFIG_FILE	"/etc/freebsd-update-control.conf"
 #define UPDATE_DATA_DIR		"/var/db/freebsd-update"
@@ -89,6 +91,16 @@
 static int	facund_signals[] = { SIGHUP, SIGINT, SIGTERM };
 static void	facund_signal_handler(int, siginfo_t *, void *);
 
+static void	facund_comms_signal_handler(int, siginfo_t *, void *);
+
+struct fbsd_tag_line {
+	char	*tag_platform;
+	char	*tag_release;
+	unsigned int tag_patch;
+	char	 tag_tindexhash[65];
+	char	 tag_eol[11];
+};
+
 /*
  * Structure describing the current state of
  * the freebsd-update database directory
@@ -99,20 +111,16 @@
 	int	  db_fd;
 
 	unsigned int db_next_patch;
+	unsigned int db_rollback_count;
 
 	char	 *db_tag_file;
+	struct fbsd_tag_line *db_tag_line;
 };
 
 static unsigned int watched_db_count = 0;
 static struct fbsd_update_db *watched_db = NULL;
 
-struct fbsd_tag_line {
-	char	*tag_platform;
-	char	*tag_release;
-	unsigned int tag_patch;
-	char	 tag_tindexhash[65];
-	char	 tag_eol[11];
-};
+struct utsname facund_uname;
 
 /*
  * Decodes the data in a line from the tag file
@@ -223,30 +231,63 @@
 	struct stat sb;
 	FILE *tag_fd;
 	char install_link[PATH_MAX], sha_base[PATH_MAX], sum[65], buf[1024];
+	char link_target[PATH_MAX];
 	struct fbsd_tag_line *line;
+	unsigned int rollback_count;
+	int link_len;
 
 	assert(pos < watched_db_count);
 	snprintf(sha_base, PATH_MAX, "%s\n", watched_db[pos].db_base);
 	SHA256_Data(sha_base, strlen(sha_base), sum);
+
+	/* Read in the tag file */
+	tag_fd = fopen(watched_db[pos].db_tag_file, "r");
+	if (tag_fd != NULL) {
+		if (watched_db[pos].db_tag_line != NULL)
+			facund_tag_free(watched_db[pos].db_tag_line);
+
+		while (fgets(buf, sizeof buf, tag_fd) != NULL) {
+			line = facund_tag_decode_line(buf);
+			watched_db[pos].db_tag_line = line;
+		}
+		fclose(tag_fd);
+	}
+	
+	seteuid(0);
+
+	/* Look for the install link and check if it is a symlink */
 	snprintf(install_link, PATH_MAX, "%s/%s-install",
 	    watched_db[pos].db_dir, sum);
+	if (watched_db[pos].db_tag_line != NULL &&
+	    lstat(install_link, &sb) == 0 && S_ISLNK(sb.st_mode)) {
+		watched_db[pos].db_next_patch =
+		    watched_db[pos].db_tag_line->tag_patch;
+	}
 
-	/* Look for the install link and check if it is a symlink */
-	if (lstat(install_link, &sb) == 0) {
-		if (S_ISLNK(sb.st_mode)) {
-			tag_fd = fopen(watched_db[pos].db_tag_file, "r");
-			while (fgets(buf, sizeof buf, tag_fd) != NULL) {
-				line = facund_tag_decode_line(buf);
-				if (line != NULL) {
-					watched_db[pos].db_next_patch =
-					    line->tag_patch;
-					facund_tag_free(line);
-				}
-			}
-			fclose(tag_fd);
-			return 1;
+	/* Look for the rollback link and check if it is a symlink */
+	snprintf(install_link, PATH_MAX, "%s/%s-rollback",
+	    watched_db[pos].db_dir, sum);
+	rollback_count = 0;
+	errno = 0;
+	while ((lstat(install_link, &sb) == 0) && S_ISLNK(sb.st_mode)) {
+		rollback_count++;
+		link_len = readlink(install_link, link_target,
+		    (sizeof link_target) - 1);
+		if (link_len == -1) {
+			return -1;
 		}
+		link_target[link_len] = '\0';
+		snprintf(install_link, PATH_MAX, "%s/%s/rollback",
+		    watched_db[pos].db_dir, link_target);
+		errno = 0;
 	}
+	if (errno != 0 && errno != ENOENT)
+		return -1;
+
+	seteuid(getuid());
+
+	watched_db[pos].db_rollback_count = rollback_count;
+
 	return 0;
 }
 
@@ -264,7 +305,7 @@
 look_for_updates(void *data __unused)
 {
 	struct timespec timeout;
-	int kq, use_kqueue, found_updates;
+	int kq, use_kqueue;
 	struct kevent event, changes;
 	size_t pos, signals;
 	int error, first_loop;
@@ -297,7 +338,6 @@
 	}
 
 	use_kqueue = 1;
-	found_updates = 0;
 
 	timeout.tv_sec = default_check_period;
 	timeout.tv_nsec = 0;
@@ -322,11 +362,7 @@
 			 * all directories to see if they have an update.
 			 */
 			for (pos = 0; pos < watched_db_count; pos++) {
-				if (facund_has_update(pos)) {
-					printf("Updates found in %s\n",
-					    watched_db[pos].db_base);
-					found_updates = 1;
-				}
+				facund_has_update(pos);
 			}
 			/* Check we have looked at all directories */
 			assert(pos == watched_db_count);
@@ -337,11 +373,7 @@
 			 * the directory that had file system activity.
 			 */
 			if (pos < watched_db_count) {
-				if (facund_has_update(pos)) {
-					printf("Updates found in %s\n",
-					    watched_db[pos].db_base);
-					found_updates = 1;
-				}
+				facund_has_update(pos);
 			}
 		}
 		pos = watched_db_count;
@@ -357,10 +389,9 @@
 		 * Wait for any disk activity to
 		 * quieten down before waiting again
 		 */
-		if (found_updates && use_kqueue) {
+		if (use_kqueue) {
 			sleep(10);
 		}
-		found_updates = 0;
 
 		/* Wait for posible updates */
 		if (use_kqueue == 1) {
@@ -477,13 +508,33 @@
 	return -1;
 }
 
+/* When called the front end died without disconnecting
+ * Cleanup and wait for a new connection
+ */
+static void
+facund_comms_signal_handler(int sig __unused, siginfo_t *info __unused,
+    void *uap __unused)
+{
+	facund_comms_in_loop = 0;
+}
+
 static void *
 do_communication(void *data)
 {
+	struct sigaction sa;
 	struct facund_conn *conn = (struct facund_conn *)data;
 
+	sa.sa_sigaction = facund_comms_signal_handler;
+	sigemptyset(&sa.sa_mask);
+	sa.sa_flags = SA_SIGINFO;
+	sigaction(SIGPIPE, &sa, NULL);
+
 	while(1) {
 		int ret = 0;
+
+		/* We are now in the loop. This will change on SIGPIPE */
+		facund_comms_in_loop = 1;
+
 		if(facund_server_start(conn) == -1) {
 			if (facund_in_loop != 0) {
 				/*
@@ -495,6 +546,8 @@
 			}
 			break;
 		}
+		if (facund_comms_in_loop == 0)
+			continue;
 
 		while(ret == 0) {
 			ret = facund_server_get_request(conn);
@@ -504,9 +557,15 @@
 					    "data from network\n");
 				}
 			}
+			if (facund_comms_in_loop == 0)
+				break;
 		}
+		if (facund_comms_in_loop == 0)
+			continue;
 
 		facund_server_finish(conn);
+		if (facund_comms_in_loop == 0)
+			continue;
 		if (ret == -1)
 			break;
 	}
@@ -730,7 +789,6 @@
 			if (strcmp(watched_db[i].db_base, base_dirs[pos]) != 0)
 				continue;
 
-			printf("= %u\n", watched_db[i].db_next_patch);
 			if (watched_db[i].db_next_patch == 0)
 				break;
 
@@ -744,7 +802,8 @@
 			/* Add a list of updates to the array */
 			updates = facund_object_new_array();
 			item = facund_object_new_string();
-			asprintf(&buf, "6.2-p%u", watched_db[i].db_next_patch);
+			asprintf(&buf, "%s-p%u", facund_uname.release,
+			    watched_db[i].db_next_patch);
 			if (buf == NULL)
 				return facund_response_new(id, 1,
 				    "Malloc failed", NULL);
@@ -762,7 +821,7 @@
 			break;
 		}
 	}
-	facund_object_print(args);
+
 	if (facund_object_array_size(args) == 0) {
 		facund_object_free(args);
 		args = NULL;
@@ -810,30 +869,71 @@
 	args = facund_object_new_array();
 	for (pos = 0; base_dirs[pos] != NULL; pos++) {
 		struct facund_object *pair, *item, *updates;
+		unsigned int i;
+		char *buf;
+
+		for (i = 0; i < watched_db_count; i++) {
+			unsigned int rollback_pos;
+
+			if (strcmp(watched_db[i].db_base, base_dirs[pos]) != 0)
+				continue;
+
+			if (watched_db[i].db_rollback_count == 0)
+				break;
+
+			pair = facund_object_new_array();
+
+			/* Add the directory to the start of the array */
+			item = facund_object_new_string();
+			facund_object_set_string(item, base_dirs[pos]);
+			facund_object_array_append(pair, item);
+
+			/* Add a list of updates to the array */
+			updates = facund_object_new_array();
+
+			for (rollback_pos = 0;
+			     rollback_pos < watched_db[i].db_rollback_count;
+			     rollback_pos++) {
+				unsigned int level;
+
+				/* Calculate the patch level */
+				level = watched_db[i].db_tag_line->tag_patch;
+				level -= rollback_pos + 1;
+				if (watched_db[i].db_next_patch > 0)
+					level--;
+
+				asprintf(&buf, "%s-p%u", facund_uname.release,
+				    level);
+				if (buf == NULL)
+					return facund_response_new(id, 1,
+					    "Malloc failed", NULL);
 
-		pair = facund_object_new_array();
+				/* Create the item and add it to the array */
+				item = facund_object_new_string();
+				facund_object_set_string(item, buf);
+				facund_object_array_append(updates, item);
 
-		/* Add the directory to the start of the array */
-		item = facund_object_new_string();
-		facund_object_set_string(item, base_dirs[pos]);
-		facund_object_array_append(pair, item);
+				free(buf);
+			}
+			/* If there were no rollbacks we shouldn't be here */
+			assert(rollback_pos > 0);
 
-		/* Add a list of updates to the array */
-		updates = facund_object_new_array();
-		item = facund_object_new_string();
-		facund_object_set_string(item, "6.2-p1");
-		facund_object_array_append(updates, item);
-		facund_object_array_append(pair, updates);
+			facund_object_array_append(pair, updates);
 
-		/* Add the directory on to the end of the arguments to return */
-		facund_object_array_append(args, pair);
+			/*
+			 * Add the directory on to the
+			 * end of the arguments to return
+			 */
+			facund_object_array_append(args, pair);
+			break;
+		}
+	}
+	/* There are no updates avaliable */
+	if (facund_object_array_size(args) == 0) {
+		facund_object_free(args);
+		args = NULL;
 	}
 
-	printf("STUB: %s (base: %s, ports: %s)\n", __func__,
-	    (get_base ? "yes" : "no"), (get_ports ? "yes" : "no"));
-	for (pos = 0; base_dirs[pos] != NULL; pos++) {
-		printf("Dir: %s\n", base_dirs[pos]);
-	}
 	free(base_dirs);
 	return facund_response_new(id, RESP_GOOD, "Success", args);
 }
@@ -955,6 +1055,8 @@
 {
 	const char *base_dir, **patches;
 	struct facund_response *ret;
+	unsigned int pos;
+	int failed;
 
 	if (obj == NULL) {
 		/* TODO: Don't use magic numbers */
@@ -967,14 +1069,38 @@
 	if (ret != NULL)
 		return ret;
 
-	printf("STUB: %s\n", __func__);
-	return NULL;
+	/* Check the directory is being watched */
+	for (pos = 0; pos < watched_db_count; pos++) {
+		if (strcmp(watched_db[pos].db_base, base_dir) == 0) {
+			break;
+		}
+	}
+	if (pos == watched_db_count) {
+		return facund_response_new(id, 1, "Incorrect directory", NULL);
+	}
+
+	failed = 0;
+
+	if (strcmp(patches[0], "base") == 0) {
+		/* Rollback the top most base patch */
+		if (facund_run_update("rollback", base_dir) != 0) {
+			failed = 1;
+		}
+	} else {
+		return facund_response_new(id, 1, "Unsupported patch", NULL);
+	}
+
+	if (failed != 0) {
+		return facund_response_new(id, 1,
+		    "Some patches failed to rollback", NULL);
+	}
+	return facund_response_new(id, 0, "Success", NULL);
 }
 
 static struct facund_response *
 facund_call_restart_services(const char *id __unused, struct facund_object *obj __unused)
 {
-	printf("STUB: %s\n", __func__);
+	fprintf(stderr, "STUB: %s\n", __func__);
 	return NULL;
 }
 
@@ -998,6 +1124,9 @@
 	properties config_data;
 	char ch;
 
+	/* Drop privileges */
+	seteuid(getuid());
+
 	config_file = DEFAULT_CONFIG_FILE;
 
 	while ((ch = getopt(argc, argv, "c:h")) != -1) {
@@ -1058,6 +1187,11 @@
 		errx(1, "Could not open a socket: %s\n", strerror(errno));
 	}
 
+	/* Get the uname data */
+	if (uname(&facund_uname) != 0) {
+		errx(1, "Could not get the Operating System version\n");
+	}
+
 	/* Add the callbacks for each call */
 	facund_server_add_call("ping", facund_call_ping);
 	facund_server_add_call("get_directories", facund_get_directories);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200708121144.l7CBiLDs053875>