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>