+static int open_afs_tables(void)
+{
+ int i, ret;
+
+ get_database_dir();
+ PARA_NOTICE_LOG("opening %u osl tables in %s\n", NUM_AFS_TABLES,
+ database_dir);
+ for (i = 0; i < NUM_AFS_TABLES; i++) {
+ ret = afs_tables[i].open(database_dir);
+ if (ret >= 0)
+ continue;
+ PARA_ERROR_LOG("%s init: %s\n", afs_tables[i].name,
+ para_strerror(-ret));
+ break;
+ }
+ if (ret >= 0)
+ return ret;
+ while (i)
+ afs_tables[--i].close();
+ return ret;
+}
+
+static void signal_pre_select(struct sched *s, struct task *t)
+{
+ struct signal_task *st = container_of(t, struct signal_task, task);
+ para_fd_set(st->fd, &s->rfds, &s->max_fileno);
+}
+
+static int afs_signal_post_select(struct sched *s, __a_unused struct task *t)
+{
+ int signum, ret;
+
+ if (getppid() == 1) {
+ PARA_EMERG_LOG("para_server died\n");
+ goto shutdown;
+ }
+ signum = para_next_signal(&s->rfds);
+ if (signum == 0)
+ return 0;
+ if (signum == SIGHUP) {
+ close_afs_tables();
+ parse_config_or_die(1);
+ ret = open_afs_tables();
+ if (ret < 0)
+ return ret;
+ init_admissible_files(current_mop);
+ return 0;
+ }
+ PARA_EMERG_LOG("terminating on signal %d\n", signum);
+shutdown:
+ task_notify_all(s, E_AFS_SIGNAL);
+ return -E_AFS_SIGNAL;
+}
+
+static void register_signal_task(struct sched *s)
+{
+ struct signal_task *st = &signal_task_struct;
+
+ para_sigaction(SIGPIPE, SIG_IGN);
+ st->fd = para_signal_init();
+ PARA_INFO_LOG("signal pipe: fd %d\n", st->fd);
+ para_install_sighandler(SIGINT);
+ para_install_sighandler(SIGTERM);
+ para_install_sighandler(SIGHUP);
+
+ st->task.pre_select = signal_pre_select;
+ st->task.post_select = afs_signal_post_select;
+ sprintf(st->task.status, "signal task");
+ register_task(s, &st->task);
+}
+
+static struct list_head afs_client_list;
+
+/** Describes on connected afs client. */
+struct afs_client {
+ /** Position in the afs client list. */
+ struct list_head node;
+ /** The socket file descriptor for this client. */
+ int fd;
+ /** The time the client connected. */
+ struct timeval connect_time;
+};
+
+static void command_pre_select(struct sched *s, struct task *t)
+{
+ struct command_task *ct = container_of(t, struct command_task, task);
+ struct afs_client *client;
+
+ para_fd_set(server_socket, &s->rfds, &s->max_fileno);
+ para_fd_set(ct->fd, &s->rfds, &s->max_fileno);
+ list_for_each_entry(client, &afs_client_list, node)
+ para_fd_set(client->fd, &s->rfds, &s->max_fileno);
+}
+
+/**
+ * Send data as shared memory to a file descriptor.
+ *
+ * \param fd File descriptor to send the shmid to.
+ * \param band The band designator for this data.
+ * \param buf The buffer holding the data to be sent.
+ * \param size The size of \a buf.
+ *
+ * This function creates a shared memory area large enough to hold
+ * the content given by \a buf and \a size and sends the identifier
+ * of this area to the file descriptor \a fd.
+ *
+ * It is called by the AFS max_size handler as well as directly by the AFS
+ * command callbacks to send command output to the command handlers.
+ *
+ * \return Zero if \a buf is \p NULL or \a size is zero. Negative on errors,
+ * and positive on success.
+ */
+int pass_buffer_as_shm(int fd, uint8_t band, const char *buf, size_t size)
+{
+ int ret, shmid;
+ void *shm;
+ struct callback_result *cr;
+
+ if (!buf || !size)
+ return 0;
+ ret = shm_new(size + sizeof(*cr));