📄 recoverymgrd.c
字号:
if (client->ch->ch_status == IPC_DISCONNECT) { client->deleteme = TRUE; }else{ if (!recoverymgr_read_msg(client)) { break; } } } return !client->deleteme;}/** * Shutdown the connection for this client */voidrecoverymgr_client_remove(gpointer Client){ recoverymgr_client_t* client = Client; cl_log(LOG_INFO, "recoverymgr_client_remove: client: %ld\n" , (long)client->pid); if (debug >= DBGMIN) { cl_log(LOG_DEBUG, "recoverymgr_client_remove: client pid: %ld\n" , (long)client->pid); } G_main_del_IPC_Channel(client->source); g_free(client->appname); g_free(client->appinst); memset(client, 0, sizeof(*client));}/** * Selects and calls the appropriate function to handle the message * This is called from the dispatch function for each * message. */static gbooleanrecoverymgr_read_msg(recoverymgr_client_t *client){ struct IPC_MESSAGE* msg = NULL; switch (client->ch->ops->recv(client->ch, &msg)) { case IPC_OK: recoverymgr_process_msg(client, msg->msg_body, msg->msg_len); if (msg->msg_done) { msg->msg_done(msg); } return TRUE; break; case IPC_BROKEN: client->deleteme = TRUE; return FALSE; break; case IPC_FAIL: return FALSE; break; } return FALSE;}/* * Mappings between commands and strings */struct cmd { const char * msg; gboolean senderrno; int (*fun)(recoverymgr_client_t* client, void* msg, size_t len);};/** */struct cmd cmds[] ={ {RECOVERYMGR_EVENT, TRUE, recoverymgr_client_event}, {RECOVERYMGR_CONNECT, TRUE, recoverymgr_client_connect}, {RECOVERYMGR_DISCONNECT, TRUE, recoverymgr_client_disconnect},};/** * Process a message from client process */voidrecoverymgr_process_msg(recoverymgr_client_t* client, void* Msg, size_t length){ struct recoverymgr_msg * msg = Msg; const int sz1 = sizeof(msg->msgtype)-1; int rc = EINVAL; gboolean sendrc = TRUE; int j; if (length < sizeof(*msg)) { return; } msg->msgtype[sz1] = EOS; if (debug >= DBGDETAIL) { cl_log(LOG_DEBUG, "recoverymgr_process_msg: client: 0x%x" " type=%s" , GPOINTER_TO_UINT(client) , msg->msgtype); } for (j=0; j < DIMOF(cmds); ++j) { if (strcmp(msg->msgtype, cmds[j].msg) == 0) { sendrc = cmds[j].senderrno; if (client->appname == NULL && cmds[j].fun != recoverymgr_client_connect) { rc = ESRCH; break; } rc = cmds[j].fun(client, Msg, length); } } if (sendrc) { if (debug >= DBGMIN) { cl_log(LOG_DEBUG, "recoverymgr_process_msg: client: 0x%x" " type=%s, rc=%d" , GPOINTER_TO_UINT(client) , msg->msgtype, rc); } recoverymgr_putrc(client, rc); }}/** * Send return code from current operation back to client. */static voidrecoverymgr_putrc(recoverymgr_client_t* client, int rc){ client->rc.rc = rc; if (client->ch->ops->send(client->ch, &client->rcmsg) != IPC_OK) { client->deleteme = TRUE; }}/** * This function is called when a client issues a connection message. * It occurs after a connection is established. * * @todo Ensure that the app connecting is appbhd (?) * * @return EINVAL if message is not a recoverymgr_connectmsg */static intrecoverymgr_client_connect(recoverymgr_client_t *client, void *Msg, size_t length){ struct recoverymgr_connectmsg* msg = Msg; int namelen = -1; /*uid_t uidlist[1]; gid_t gidlist[1]; IPC_Auth* clientauth;*/ if (debug >= DBGDETAIL) { cl_log(LOG_DEBUG, "recoverymgr_client_connect\n"); } if (client->appname) { return EEXIST; } if (length < sizeof(*msg) || (namelen = strnlen(msg->appname, sizeof(msg->appname))) < 1 || namelen >= (int)sizeof(msg->appname) || strnlen(msg->appinstance, sizeof(msg->appinstance)) >= sizeof(msg->appinstance)) { return EINVAL; } if (msg->pid < 2 || (CL_KILL(msg->pid, 0) < 0 && errno != EPERM) || (client->ch->farside_pid != msg->pid)) { return EINVAL; } client->pid = msg->pid;#if 0 /* Make sure client is who they claim to be... */ uidlist[0] = msg->uid; gidlist[0] = msg->gid; clientauth = ipc_set_auth(uidlist, gidlist, 1, 1); if (client->ch->ops->verify_auth(client->ch, clientauth) != IPC_OK) { ipc_destroy_auth(clientauth); return EINVAL; } ipc_destroy_auth(clientauth);#endif client->appname = g_strdup(msg->appname); client->appinst = g_strdup(msg->appinstance); client->uid = msg->uid; client->gid = msg->gid; if (debug >= DBGMIN) { cl_log(LOG_DEBUG , "recoverymgr_client_connect: client: [%s]/[%s] pid %ld" " (uid,gid) = (%ld,%ld)\n" , client->appname , client->appinst , (long)client->pid , (long)client->uid , (long)client->gid); } return 0;}/** * Client requested disconnect */static intrecoverymgr_client_disconnect(recoverymgr_client_t* client , void * msg, size_t msgsize){ if (debug >= DBGDETAIL) { cl_log(LOG_DEBUG, "recoverymgr_client_disconnect\n"); } client->deleteme=TRUE; return 0;}/** * This message is received when a client * of apphbd produces an event. * * This function needs to determine if an action should * be taken, such as restarting the app, etc. * * @param client The connected client that sent the message * @param Msg The message * @param msgsize The size of the message * * @return zero on success; * EINVAL if message size is not correct * * @todo Confirm that the client is the apphbd * @todo determine action to take on the given event * */static intrecoverymgr_client_event(recoverymgr_client_t *client, void *Msg, size_t msgsize){ struct recoverymgr_event_msg *msg = Msg; RecoveryInfo *info = NULL; if (debug >= DBGDETAIL) { cl_log(LOG_CRIT,"recoverymgr_client_event: event=%d\n", msg->event); } if (msgsize < sizeof(*msg)) { return EINVAL; } /* FINISH HERE -- confirm that client is the apphbd or at least one that is permitted to request recovery (?)*/ if (debug >= DBGMIN) { cl_log(LOG_DEBUG , "recoverymgr_client_event: client: [%s]/[%s] pid [%ld]" " (uid,gid)(%ld,%ld)" " message type [%s]" , msg->appname , msg->appinstance , (long)msg->pid , (long)msg->uid , (long)msg->gid , msg->msgtype); } info = g_hash_table_lookup(scripts, msg->appname); if (NULL == info) { cl_log(LOG_INFO, "No script available to recover %s\n", msg->appname); return 0; } if (info->event[msg->event].inuse == FALSE) { cl_log(LOG_INFO,"Script does not handle this event\n"); return 0; } recover_app(info, msg->event); return 0;}/** * *@return 0 on success * -1 and errno is ENOMEM */int recover_app(RecoveryInfo *info, int eventindex){ pid_t pid; pid = fork(); if (pid < 0) { cl_log(LOG_CRIT,"Failed to fork recovery process\n"); return -1; } else if (0 == pid) { child_setup_function(info); if (debug >= DBGDETAIL) { cl_log(LOG_INFO, "current euid[%ld]", (long)geteuid()); cl_log(LOG_INFO, "current egid[%ld]", (long)getegid()); cl_log(LOG_DEBUG,"script = %s\n", info->scriptname); cl_log(LOG_DEBUG,"args = %s\n", info->event[eventindex].args); } if (eventindex > MAXEVENTS) { eventindex = 0; } if (execl(info->scriptname, info->scriptname, info->event[eventindex].args, (const char *)NULL) < 0) { cl_perror("Failed to exec recovery script for %s\n", info->appname); _exit(EXIT_FAILURE); } } return 0;}/** * Attempts to set the uid and gid of the executing script. * * @param a_user_data A pointer to a RecoveryInfo structure */void child_setup_function(RecoveryInfo *info){ if (info == NULL) { if (debug >= DBGDETAIL) { cl_log(LOG_INFO,"Unable to get app data for recovery.\n"); } return; } /* Change both uid, and euid since we are root */ if ( 0 != setgid(info->gid)) { if (debug >= DBGDETAIL) { cl_log(LOG_INFO, "error:[%s]", strerror(errno)); cl_log(LOG_INFO, "Unable to setgid for recovery of %s\n", info->appname); } } if ( 0 != setuid(info->uid)) { if (debug >= DBGDETAIL) { cl_log(LOG_INFO, "error:[%s]", strerror(errno)); cl_log(LOG_INFO, "Unable to setuid for recovery of %s\n", info->appname); } }}/** * Used to avoid zombie processes */voidsigchld_handler (int signum){ int pid; int status; while (1) { pid = waitpid ((-1), &status, WNOHANG); if (pid < 0) { break; } if (pid == 0) break; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -