+ server_child_fork *fork;
+ struct server_child_data *child, *tmp;
+ int i;
+
+ fork = (server_child_fork *) children->fork + forkid;
+ for (i = 0; i < CHILD_HASHSIZE; i++) {
+ child = fork->table[i];
+ while (child) {
+ tmp = child->next;
+ kill(child->pid, sig);
+ child = tmp;
+ }
+ }
+}
+
+/* send kill to a child processes.
+ * a plain-old linked list
+ * FIXME use resolve_child ?
+ */
+static int kill_child(struct server_child_data *child)
+{
+ if (!child->killed) {
+ kill(child->pid, SIGTERM);
+ /* we don't wait because there's no guarantee that we can really kill it */
+ child->killed = 1;
+ return 1;
+ } else {
+ LOG(log_info, logtype_default, "Unresponsive child[%d], sending SIGKILL", child->pid);
+ kill(child->pid, SIGKILL);
+ }
+ return 1;
+}
+
+/*!
+ * Try to find an old session and pass socket
+ * @returns -1 on error, 0 if no matching session was found, 1 if session was found and socket passed
+ */
+int server_child_transfer_session(server_child *children,
+ int forkid,
+ pid_t pid,
+ uid_t uid,
+ int afp_socket,
+ uint16_t DSI_requestID)
+{
+ EC_INIT;
+ server_child_fork *fork;
+ struct server_child_data *child;
+ int i;
+
+ fork = (server_child_fork *) children->fork + forkid;
+ if ((child = resolve_child(fork->table, pid)) == NULL) {
+ LOG(log_note, logtype_default, "Reconnect: no child[%u]", pid);
+ if (kill(pid, 0) == 0) {
+ LOG(log_note, logtype_default, "Reconnect: terminating old session[%u]", pid);
+ kill(pid, SIGTERM);
+ sleep(2);
+ if (kill(pid, 0) == 0) {
+ LOG(log_error, logtype_default, "Reconnect: killing old session[%u]", pid);
+ kill(pid, SIGKILL);
+ sleep(2);
+ }
+ }
+ return 0;
+ }
+
+ if (!child->valid) {
+ /* hmm, client 'guess' the pid, rogue? */
+ LOG(log_error, logtype_default, "Reconnect: invalidated child[%u]", pid);
+ return 0;
+ } else if (child->uid != uid) {
+ LOG(log_error, logtype_default, "Reconnect: child[%u] not the same user", pid);
+ return 0;
+ }
+
+ LOG(log_note, logtype_default, "Reconnect: transfering session to child[%u]", pid);
+
+ if (writet(child->ipc_fds[0], &DSI_requestID, 2, 0, 2) != 2) {
+ LOG(log_error, logtype_default, "Reconnect: error sending DSI id to child[%u]", pid);
+ EC_STATUS(-1);
+ goto EC_CLEANUP;
+ }
+ EC_ZERO_LOG(send_fd(child->ipc_fds[0], afp_socket));
+ EC_ZERO_LOG(kill(pid, SIGURG));
+
+ EC_STATUS(1);
+
+EC_CLEANUP:
+ EC_EXIT;
+}
+
+
+/* see if there is a process for the same mac */
+/* if the times don't match mac has been rebooted */
+void server_child_kill_one_by_id(server_child *children, int forkid, pid_t pid,
+ uid_t uid, uint32_t idlen, char *id, uint32_t boottime)
+{
+ server_child_fork *fork;
+ struct server_child_data *child, *tmp;
+ int i;
+
+ fork = (server_child_fork *)children->fork + forkid;
+
+ for (i = 0; i < CHILD_HASHSIZE; i++) {
+ child = fork->table[i];
+ while (child) {
+ tmp = child->next;
+ if ( child->pid != pid) {
+ if (child->idlen == idlen && memcmp(child->clientid, id, idlen) == 0) {
+ if ( child->time != boottime ) {
+ /* Client rebooted */
+ if (uid == child->uid) {
+ kill_child(child);
+ LOG(log_warning, logtype_default,
+ "Terminated disconnected child[%u], client rebooted.",
+ child->pid);
+ } else {
+ LOG(log_warning, logtype_default,
+ "Session with different pid[%u]", child->pid);
+ }
+ } else {
+ /* One client with multiple sessions */
+ LOG(log_debug, logtype_default,
+ "Found another session[%u] for client[%u]", child->pid, pid);
+ }
+ }
+ } else {
+ /* update childs own slot */
+ child->time = boottime;
+ if (child->clientid)
+ free(child->clientid);
+ LOG(log_debug, logtype_default, "Setting client ID for %u", child->pid);
+ child->uid = uid;
+ child->valid = 1;
+ child->idlen = idlen;
+ child->clientid = id;
+ }
+ child = tmp;
+ }