PERFORCE change 125079 for review
Andrew Turner
andrew at FreeBSD.org
Sun Aug 12 04:44:22 PDT 2007
http://perforce.freebsd.org/chv.cgi?CH=125079
Change 125079 by andrew at 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);
More information about the p4-projects
mailing list