/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <mms_list.h> #include <mms_parser.h> #include <mms_par_impl.h> #include <libpq-fe.h> #include <string.h> #include <stdlib.h> #include <sys/time.h> #include <pthread.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/uuid.h> #include <netinet/in.h> #include <arpa/inet.h> #include <errno.h> #include <unistd.h> #include <signal.h> #include <stdio.h> #include <string.h> #include <fcntl.h> #include <dirent.h> #include <procfs.h> #include <mms_trace.h> #include <mms_strapp.h> #include <netdb.h> #include <sys/utsname.h> #include <strings.h> #include <ctype.h> #include <sys/resource.h> #include <syslog.h> #include <msg_sub.h> #include <host_ident.h> #include <mms_cfg.h> #include "mm_db.h" #include "mm.h" #include "mm_sql.h" #include "mm_commands.h" #include "mm_util.h" static char *_SrcFile = __FILE__; extern void uuid_clear(uuid_t uu); extern void uuid_generate_random(uuid_t uu); extern void uuid_generate(uuid_t uu); /* hits bug id 6397009 */ extern void uuid_unparse(uuid_t uu, char *out); /* * mm_err_eclass_rank * return int of the rank of this eclass * higher numbers mean more severe */ int mm_err_eclass_rank(char *eclass) { /* 13 total error classes */ if (strcmp(eclass, ECLASS_LANGUAGE) == 0) return (13); if (strcmp(eclass, ECLASS_EXPLICIT) == 0) return (12); if (strcmp(eclass, ECLASS_INTERNAL) == 0) return (11); if (strcmp(eclass, ECLASS_INVALID) == 0) return (10); if (strcmp(eclass, ECLASS_DM_INVALID) == 0) return (9); if (strcmp(eclass, ECLASS_DM_CONFIG) == 0) return (8); if (strcmp(eclass, ECLASS_EXIST) == 0) return (7); if (strcmp(eclass, ECLASS_SUBOP) == 0) return (6); if (strcmp(eclass, ECLASS_CONFIG) == 0) return (5); if (strcmp(eclass, ECLASS_STATE) == 0) return (4); if (strcmp(eclass, ECLASS_PERMPRIV) == 0) return (3); if (strcmp(eclass, ECLASS_COMPAT) == 0) return (2); if (strcmp(eclass, ECLASS_RETRY) == 0) return (1); return (0); } char * mm_return_err_text(mm_cmd_err_t *err) { /* Generate a quick text for this error */ /* to be used as error text for an end command */ char *buf = NULL; mms_trace(MMS_DEVP, "mm_return_err_text: "); if (err == NULL) { mms_trace(MMS_DEVP, "err ptr is NULL"); buf = mms_strapp(buf, "none"); return (buf); } if (err->eclass != NULL) { buf = mms_strapp(buf, "%s ", err->eclass); mms_trace(MMS_DEVP, " %s", err->eclass); } if (err->ecode != NULL) { buf = mms_strapp(buf, "%s ", err->ecode); mms_trace(MMS_DEVP, " %s", err->ecode); } if (err->retry_cart != NULL) { buf = mms_strapp(buf, "%s ", err->retry_cart); mms_trace(MMS_DEVP, " %s", err->retry_cart); } if (err->retry_drive != NULL) { buf = mms_strapp(buf, "%s ", err->retry_drive); mms_trace(MMS_DEVP, " %s", err->retry_drive); } if (err->retry_lib != NULL) { buf = mms_strapp(buf, "%s ", err->retry_lib); mms_trace(MMS_DEVP, " %s", err->retry_lib); } if (buf == NULL) { buf = mms_strapp(buf, "none"); mms_trace(MMS_DEVP, "err ptr not NULL, but empty"); } return (buf); } int mm_same_err_helper(char *str1, char *str2) { if (str1 == NULL) { if (str2 == NULL) { /* both ptrs are NULL, return 0 */ return (0); } else { /* str1 is NULL, str2 is not */ return (1); } } else { /* str1 is not NULL */ if (str2 == NULL) { /* str1 is not, str2 is NULL */ return (1); } } /* both str's are not NULL */ return (strcmp(str1, str2)); } int mm_same_err(mm_cmd_err_t *err1, mm_cmd_err_t *err2) { if ((err1 == NULL) || (err2 == NULL)) { mms_trace(MMS_DEVP, "mm_same_err: " "err1 or err2 is NULL"); return (0); } if ((err1->eclass == NULL) || (err2->eclass == NULL)) { mms_trace(MMS_DEVP, "mm_same_err: " "one or both err class was NULL"); return (0); } if (strcmp(err1->eclass, err2->eclass) != 0) { mms_trace(MMS_DEVP, "mm_same_err: " "eclasses are different"); return (0); } if (mm_same_err_helper(err1->retry_cart, err2->retry_cart) != 0) { mms_trace(MMS_DEVP, "mm_same_err: " "retry cart is different"); return (0); } if (mm_same_err_helper(err1->retry_drive, err2->retry_drive) != 0) { mms_trace(MMS_DEVP, "mm_same_err: " "retry drive is different"); return (0); } if (mm_same_err_helper(err1->retry_lib, err2->retry_lib) != 0) { mms_trace(MMS_DEVP, "mm_same_err: " "retry lib is different"); return (0); } mms_trace(MMS_DEVP, "mm_same_err: " "errors are the same"); return (1); } void mm_set_buf_to_err(mm_command_t *cmd, mm_cmd_err_t *err) { /* set current cmd_buf to least_err */ if (cmd->cmd_buf != NULL) { free(cmd->cmd_buf); cmd->cmd_buf = NULL; } cmd->cmd_buf = strdup(err->err_buf); cmd->cmd_bufsize = err->err_bufsize; if (cmd->cmd_ecode != NULL) { free(cmd->cmd_ecode); cmd->cmd_ecode = NULL; } if (cmd->cmd_eclass != NULL) { free(cmd->cmd_eclass); cmd->cmd_eclass = NULL; } cmd->cmd_ecode = strdup(err->ecode); cmd->cmd_eclass = strdup(err->eclass); } void mm_clear_cur_err(mm_command_t *cmd) { if (cmd->cmd_ecode != NULL) { free(cmd->cmd_ecode); cmd->cmd_ecode = NULL; } if (cmd->cmd_eclass != NULL) { free(cmd->cmd_eclass); cmd->cmd_eclass = NULL; } if (cmd->cmd_buf != NULL) { free(cmd->cmd_buf); cmd->cmd_buf = NULL; } cmd->cmd_bufsize = 0; } void mm_set_least_severe(mm_command_t *cmd) { mm_cmd_err_t *err = NULL; mm_cmd_err_t *least_err = NULL; int cur_rank = 0; int least_rank = 0; int first = 1; mms_list_foreach(&cmd->cmd_err_list, err) { if (err->err_already_used) { continue; } if (err->eclass == NULL) continue; if (first) { least_err = err; least_rank = mm_err_eclass_rank(least_err->eclass); first = 0; continue; } cur_rank = mm_err_eclass_rank(err->eclass); if (cur_rank < least_rank) { least_rank = cur_rank; least_err = err; } } if (first) { mms_trace(MMS_ERR, "mm_set_least_severe: " "there are no unused " "errors in the list"); cmd->cmd_err_ptr = NULL; return; } mms_trace(MMS_ERR, "mm_set_least_severe: " "setting error %s %s", least_err->eclass, least_err->ecode); mm_set_buf_to_err(cmd, least_err); cmd->cmd_err_ptr = least_err; } void mm_set_retry_drive(mm_command_t *cmd, char *drive) { mm_cmd_err_t *err = NULL; if ((err = mms_list_tail(&cmd->cmd_err_list)) == NULL) { return; } if (err->retry_drive != NULL) { free(err->retry_drive); err->retry_drive = NULL; } if (drive == NULL) { return; } err->retry_drive = mms_strapp(err->retry_drive, drive); } void mm_set_retry_lib(mm_command_t *cmd, char *lib) { mm_cmd_err_t *err = NULL; if ((err = mms_list_tail(&cmd->cmd_err_list)) == NULL) { return; } if (err->retry_lib != NULL) { free(err->retry_lib); err->retry_lib = NULL; } if (lib == NULL) { return; } err->retry_lib= mms_strapp(err->retry_lib, lib); } void mm_set_retry_cart(mm_command_t *cmd, char *cart) { mm_cmd_err_t *err = NULL; if ((err = mms_list_tail(&cmd->cmd_err_list)) == NULL) { return; } if (err->retry_cart != NULL) { free(err->retry_cart); err->retry_cart = NULL; } if (cart == NULL) { return; } err->retry_cart = mms_strapp(err->retry_cart, cart); } void mm_clear_db(PGresult **results) { if (*results != NULL) { PQclear(*results); *results = NULL; } } void mm_rm_err(mm_command_t *cmd, mm_cmd_err_t *err) { mm_cmd_err_t *cur_err = NULL; mm_cmd_err_t *next_err = NULL; for (cur_err = mms_list_head(&cmd->cmd_err_list); cur_err != NULL; cur_err = next_err) { next_err = mms_list_next(&cmd->cmd_err_list, cur_err); if (mm_same_err(err, cur_err)) { cur_err->err_already_used = 1; mms_trace(MMS_DEVP, "mm_rm_err: " "an error marked as used"); } } } void mm_print_err(mm_cmd_err_t *err) { mms_trace(MMS_DEVP, " %s, %s %s", err->eclass, err->ecode, err->err_buf); if (err->retry_drive != NULL) mms_trace(MMS_DEVP, " retry_drive = %s", err->retry_drive); if (err->retry_cart != NULL) mms_trace(MMS_DEVP, " retry_cart = %s", err->retry_cart); if (err->retry_lib != NULL) mms_trace(MMS_DEVP, " retry_lib = %s", err->retry_lib); } void mm_print_err_list(mm_command_t *cmd) { mm_cmd_err_t *err = NULL; int err_count = 1; mms_trace(MMS_DEVP, "mm_print_err_list: " "error list is :"); mms_list_foreach(&cmd->cmd_err_list, err) { if (err->err_already_used) continue; mms_trace(MMS_DEVP, " Error # %d:", err_count); mm_print_err(err); err_count ++; } } void mm_system_error(mm_command_t *cmd, char *fmt, ...) { va_list args; char *text; va_start(args, fmt); text = mms_vstrapp(NULL, fmt, args); va_end(args); mm_response_error(cmd, ECLASS_INTERNAL, "ESYSTEM", MM_5021_MSG, "text", text, NULL); free(text); } int mm_copy_cmd_buf(mm_command_t *cmd1, mm_command_t *cmd2) { SQL_CHK_LEN(&cmd1->cmd_buf, 0, &cmd1->cmd_bufsize, strlen(cmd2->cmd_buf) + 1); strcpy(cmd1->cmd_buf, cmd2->cmd_buf); no_mem: MM_ABORT_NO_MEM(); return (1); } char * mm_ret_loctext(mms_par_node_t *root) { mms_par_node_t *loctext_clause; mms_par_node_t *loctext_arg; mms_par_node_t *work = 0; int i = 0; if ((loctext_clause = mms_pn_lookup(root, "loctext", MMS_PN_CLAUSE, NULL)) == NULL) { mms_trace(MMS_DEVP, "response does not have a loctext clause"); return (NULL); } while (i < 2) { if ((loctext_arg = mms_pn_lookup(loctext_clause, NULL, MMS_PN_STRING, &work)) == NULL) { mms_trace(MMS_DEVP, "response does not have an arg " "in the loctext clause"); return (NULL); } i ++; } return (loctext_arg->pn_string); } int mm_ret_msg_id(mms_par_node_t *root) { /* This function looks up a message id */ /* from the parse tree root */ /* if there is no message id, */ /* return -1 */ mms_par_node_t *id_clause; mms_par_node_t *id_arg; mms_par_node_t *work = 0; int i = 0; int message_id = -1; if ((id_clause = mms_pn_lookup(root, "id", MMS_PN_CLAUSE, 0)) == NULL) { mms_trace(MMS_DEVP, "response does not have an id clause"); return (-1); } while (i < 3) { if ((id_arg = mms_pn_lookup_arg(id_clause, NULL, MMS_PN_STRING, &work)) == NULL) { mms_trace(MMS_DEVP, "response is missing an arg in the id clause"); return (-1); } i ++; } if (id_arg->pn_string != NULL) { message_id = atoi(id_arg->pn_string); return (message_id); } else { mms_trace(MMS_ERR, "bad id in message id arguement"); return (-1); } } char * mm_ret_response_msg(mm_command_t *cmd) { char *msg_rsp = NULL; int message_id = 0; char *local_text = NULL; /* * If there is a message, * look up the id in the catalog, * and create the loctext. * If there is no matching id, * use the id number and the * loc text from the response */ if (cmd->cmd_response == NULL) { mms_trace(MMS_DEVP, "cmd->cmd_response is NULL," "no response found"); msg_rsp = mms_strapp(msg_rsp, "none"); return (msg_rsp); } /* Get the id and loctext */ if ((message_id = mm_ret_msg_id(cmd->cmd_response)) == -1) { mms_trace(MMS_DEVP, "response does not have a message id"); } else { mms_trace(MMS_DEVP, "message id is %d", message_id); } if ((local_text = mm_ret_loctext(cmd->cmd_response)) == NULL) { mms_trace(MMS_DEVP, "response does not have a loctext"); } else { mms_trace(MMS_DEVP, "local text is %s", local_text); } if ((message_id == -1) && (local_text == NULL)) { mms_trace(MMS_DEVP, "there is no message in this response" "msg_rsp == 'none'"); msg_rsp = mms_strapp(msg_rsp, "none"); return (msg_rsp); } /* Check if the id is in the catalog */ if (mm_msg_exists(message_id) == 0) { /* no catalog message found */ /* Use the id and/or loctext */ msg_rsp = mms_strapp(msg_rsp, "id: %d", message_id); if (local_text != NULL) { msg_rsp = mms_strapp(msg_rsp, " loctext: %s", local_text); } return (msg_rsp); } if (mm_msg_parse(cmd, cmd->cmd_response)) { mms_trace(MMS_ERR, "mm_ret_response_msg: " "internal error parsing message"); } if (cmd->cmd_msg.msg_localized) { msg_rsp = mms_strapp(msg_rsp, cmd->cmd_msg.msg_localized); return (msg_rsp); } mms_trace(MMS_ERR, "error getting message from catalog"); msg_rsp = mms_strapp(msg_rsp, "none"); return (msg_rsp); } void mm_set_cmd_err_buf(mm_command_t *cmd, char *class, char *token) { mms_trace(MMS_DEBUG, "mm_set_cmd_err_buf"); /* If a child command had an error, */ /* we should include the message in this error response */ /* The error response should be in cmd->cmd_response */ mms_trace(MMS_ERR, " Class is %s, length %d", class, strlen(class)); mms_trace(MMS_ERR, " Token is %s, length %d", token, strlen(token)); mm_response_error(cmd, class, token, MM_5019_MSG, NULL); return; no_mem: MM_ABORT_NO_MEM(); } mm_command_t * mm_alloc_cmd(mm_wka_t *mm_wka) { /* Use this function to allocate mem space */ /* for any MMS command */ /* Sets up command for the given wka */ mm_data_t *mm_data = mm_wka->mm_data; mm_command_t *mm_cmd; cci_t *conn = &mm_wka->wka_conn; mm_cmd = (mm_command_t *)calloc(1, sizeof (mm_command_t)); if (mm_cmd == NULL) { mms_trace(MMS_ERR, "Unable to malloc mm_command_t: %s", strerror(errno)); return (NULL); } /* set initial values */ (void) snprintf(mm_cmd->wka_uuid, sizeof (mm_cmd->wka_uuid), "%s", mm_wka->wka_conn.cci_uuid); mm_get_uuid(mm_cmd->cmd_uuid); MM_SET_FLAG(mm_cmd->cmd_flags, MM_CMD_DISPATCHABLE); MM_SET_FLAG(mm_cmd->cmd_flags, MM_CMD_NEED_ACCEPT); mm_cmd->wka_ptr = mm_wka; mm_cmd->cmd_mm_data = mm_data; /* Zero ints */ mm_cmd->cmd_state = 0; mm_cmd->cmd_remove = 0; mm_cmd->cmd_mount_info.cmi_need_clear = 0; mm_cmd->cmd_notify_to = 0; mm_cmd->cmd_begin_has_end = 0; mm_cmd->cmd_bufsize = 0; mm_cmd->cmd_source_num = 0; mm_cmd->cmd_dest_num = 0; mm_cmd->cmd_const_num = 0; mm_cmd->cmd_begin_has_end = 0; mm_cmd->cmd_notify_to = 0; /* char ptrs */ mm_cmd->cmd_buf = NULL; mm_cmd->cmd_begin_cmd = NULL; mm_cmd->cmd_eclass = NULL; mm_cmd->cmd_ecode = NULL; mm_cmd->cmd_name = NULL; mm_cmd->cmd_task = NULL; mm_cmd->cmd_textcmd = NULL; mm_cmd->cmd_report = NULL; mm_cmd->cmd_err_ptr = NULL; /* mount command info */ mm_cmd->cmd_mount_info.cmi_dm = NULL; mm_cmd->cmd_mount_info.cmi_drive = NULL; mm_cmd->cmd_mount_info.cmi_library = NULL; mm_cmd->cmd_mount_info.cmi_cartridge = NULL; mm_cmd->cmd_mount_info.cmi_pcl = NULL; mm_cmd->cmd_mount_info.cmi_side_name = NULL; mm_cmd->cmd_mount_info.cmi_capability = NULL; mm_cmd->cmd_mount_info.cmi_handle = NULL; mm_cmd->cmd_mount_info.cmi_where = NULL; mm_cmd->cmd_mount_info.cmi_filename = NULL; mm_cmd->cmd_mount_info.cmi_user = NULL; mm_cmd->cmd_mount_info.cmi_blocksize = NULL; mm_cmd->cmd_mount_info.cmi_filesequence = NULL; mm_cmd->cmd_mount_info.cmi_volumeid = NULL; mm_cmd->cmd_mount_info.cmi_retention = NULL; mm_cmd->cmd_mount_info.cmi_first_drive = NULL; mm_cmd->cmd_mount_info.cmi_first_lib = NULL; mm_cmd->cmd_mount_info.cmi_second_drive = NULL; mm_cmd->cmd_mount_info.cmi_second_lib = NULL; mm_cmd->cmd_mount_info.cui_signature_type = NULL; mm_cmd->cmd_mount_info.cui_signature = NULL; /* Create the source and dest lists */ mm_cmd->cmd_has_list = 1; mms_list_create(&mm_cmd->cmd_source_list, sizeof (mm_char_list_t), offsetof(mm_char_list_t, mm_char_list_next)); mms_list_create(&mm_cmd->cmd_dest_list, sizeof (mm_char_list_t), offsetof(mm_char_list_t, mm_char_list_next)); mms_list_create(&mm_cmd->cmd_const_list, sizeof (mm_char_list_t), offsetof(mm_char_list_t, mm_char_list_next)); mms_list_create(&mm_cmd->cmd_resp_list, sizeof (mm_char_list_t), offsetof(mm_char_list_t, mm_char_list_next)); /* error list */ mms_list_create(&mm_cmd->cmd_err_list, sizeof (mm_cmd_err_t), offsetof(mm_cmd_err_t, mm_cmd_err_next)); /* Initalize the access mode list */ mms_list_create(&mm_cmd->cmd_mount_info.cmi_mode_list, sizeof (cmi_mode_list_t), offsetof(cmi_mode_list_t, cmi_mode_next)); mm_cmd->cmd_mount_info.cmi_total_modes = 0; /* initialize the cart list */ mms_list_create(&mm_cmd->cmd_mount_info.cmi_cart_list, sizeof (cmi_cart_list_t), offsetof(cmi_cart_list_t, cmi_cart_next)); mms_list_create(&mm_cmd->cmd_depend_list, sizeof (mm_command_t), offsetof(mm_command_t, cmd_depend_list_next)); /* Create Begin-end list */ mms_list_create(&mm_cmd->cmd_beginend_list, sizeof (mm_command_t), offsetof(mm_command_t, cmd_next)); if (mm_wka->wka_hello_needed == B_FALSE) { /* Set Cmd->language */ if (strcmp(conn->cci_language, "MMP") == 0) { mm_cmd->cmd_language = MM_LANG_MMP; } if (strcmp(conn->cci_language, "DMP") == 0) { mm_cmd->cmd_language = MM_LANG_DMP; } if (strcmp(conn->cci_language, "LMP") == 0) { mm_cmd->cmd_language = MM_LANG_LMP; } } else { /* Havent revieved a hello yet */ mm_cmd->cmd_language = MM_LANG_MMP; } return (mm_cmd); } void mm_get_uuid(uuid_text_t uuid) { uuid_t uu; uuid_clear(uu); /* * Hit bugid 6397009 core dumped from get_ethernet_address() using * uuid_generate(uu); so use uuid_generate_random(uu); instead. */ uuid_generate_random(uu); uuid_unparse(uu, uuid); } int mm_is_fd_valid(int fd) { if (fcntl(fd, F_GETFD, 0) == -1) { return (-1); /* failed, fd is invalid */ } return (0); /* success, fd is valid */ } int mm_set_fd_limit(int fd_limit) { struct rlimit rlp; char buf[20]; if (getrlimit(RLIMIT_NOFILE, &rlp) != 0) { mms_trace(MMS_ERR, "fd limit query %d: %s", errno, strerror(errno)); return (1); } if (fd_limit == -1) { snprintf(buf, sizeof (buf), "\"default\""); } else { snprintf(buf, sizeof (buf), "%d", fd_limit); } mms_trace(MMS_DEVP, "mm fd limit is %s", buf); mms_trace(MMS_DEVP, "current fd limit is %d", rlp.rlim_cur); mms_trace(MMS_DEVP, "max fd limit is %d", rlp.rlim_max); /* wants to use system's open file descriptor max */ if (fd_limit == -1) { return (0); } /* sanity check */ if (fd_limit < MM_FD_LIMIT_MIN) { fd_limit = MM_FD_LIMIT_MIN; } else if (fd_limit > MM_FD_LIMIT_MAX) { fd_limit = MM_FD_LIMIT_MAX; } if (fd_limit > rlp.rlim_max) { fd_limit = rlp.rlim_max; } /* change the current limit */ rlp.rlim_cur = fd_limit; if (setrlimit(RLIMIT_NOFILE, &rlp) != 0) { mms_trace(MMS_ERR, "fd limit set %d: %s", errno, strerror(errno)); /* don't exit. see that the limit is unchanged */ } if (getrlimit(RLIMIT_NOFILE, &rlp) != 0) { mms_trace(MMS_ERR, "fd limit get %d: %s", errno, strerror(errno)); return (1); } mms_trace(MMS_INFO, "current fd limit is %d", rlp.rlim_cur); mms_trace(MMS_INFO, "max fd limit is %d", rlp.rlim_max); return (0); } void mm_input_file(char *buf, int *result, void *callback_parm) { mm_cb_file_t *parm = (mm_cb_file_t *)callback_parm; if (parm->mm_cbf_index == parm->mm_cbf_len) { parm->mm_cbf_index = 0; parm->mm_cbf_len = 0; if (fgets(parm->mm_cbf_buf, parm->mm_cbf_size, parm->mm_cbf_fp) == NULL) { buf[0] = EOF; *result = 0; } else { parm->mm_cbf_len = strlen(parm->mm_cbf_buf); buf[0] = parm->mm_cbf_buf[parm->mm_cbf_index++]; *result = 1; } } else { buf[0] = parm->mm_cbf_buf[parm->mm_cbf_index++]; *result = 1; } } char * mm_parse_error(mms_list_t *err_list) { mms_par_err_t *err; char *resp; if ((err = mms_list_head(err_list)) == NULL) { return (NULL); } resp = mms_strnew("response unacceptable " "message [ id [ \"ieee\" \"1244\" \"5000\" ] " "arguments [ " "\"line\" \"%d\" " "\"col\" \"%d\" " "\"token\" \"%s\" " "\"code\" \"%d\" " "\"msg\" \"%s\" ] " "loctext [ \"en\" \"line %d col %d " "token %s code %d msg %s\" ] ]; ", err->pe_line, err->pe_col, err->pe_token, err->pe_code, err->pe_msg, err->pe_line, err->pe_col, err->pe_token, err->pe_code, err->pe_msg); return (resp); } mms_par_node_t * mm_text_to_par_node(char *buf, parser_func_t parse_func) { mms_par_node_t *cmd; mms_list_t err_list; int rc; mms_par_err_t *err; rc = parse_func(&cmd, &err_list, buf); if (rc) { if (err = mms_list_head(&err_list)) { mms_trace(MMS_ERR, "parse error\n" "line %d col %d token %s code %d msg %s\n%s", err->pe_line, err->pe_col, err->pe_token, err->pe_code, err->pe_msg, buf); } else { mms_trace(MMS_ERR, "parse error"); } mms_pe_destroy(&err_list); mms_pn_destroy(cmd); return (NULL); } mms_pe_destroy(&err_list); return (cmd); } void mm_send_response(mms_t *conn, mm_command_t *cmd) { /* Response list */ mms_list_t *resp_list = &cmd->cmd_resp_list; mm_char_list_t *cur_resp; mm_char_list_t *next_resp; int sent_one = 0; int sent_count = 0; mms_trace(MMS_DEVP, "mm_send_response"); for (cur_resp = mms_list_head(resp_list); cur_resp != NULL; cur_resp = next_resp) { next_resp = mms_list_next(resp_list, cur_resp); if (cur_resp->text != NULL) { mm_send_text(conn, cur_resp->text); sent_count ++; sent_one = 1; } } mms_trace(MMS_DEVP, "sent %d responses from list", sent_count); if (!sent_one) { /* If there was not a response in the list */ /* check the cmd_buf and send */ mms_trace(MMS_DEVP, "no response in list"); if (cmd->cmd_buf != NULL) { /* No response in the list */ /* send the cmd_buf */ mms_trace(MMS_DEVP, "no resp in list, send cmd_buf"); mm_send_text(conn, cmd->cmd_buf); } } } void mm_send_text(mms_t *conn, char *buf) { int rc; char ebuf[MMS_EBUF_LEN]; int len; len = strlen(buf); rc = mms_writer(conn, buf); if (rc != len) { mms_get_error_string(&conn->mms_err, ebuf, MMS_EBUF_LEN); mms_trace(MMS_ERR, "send buf fd -> %d, count %d\n\n%s\n%s\n", conn->mms_fd, len, buf, ebuf); mms_close(conn); return; } else { mms_trace(MMS_DEVP, "sent fd -> %d, count %d\n\n%s\n", conn->mms_fd, len, buf); } } void mm_send_text_si(mms_t *conn, char *buf) { int rc; char ebuf[MMS_EBUF_LEN]; int len; len = strlen(buf); rc = mms_writer(conn, buf); if (rc != len) { mms_get_error_string(&conn->mms_err, ebuf, MMS_EBUF_LEN); mms_trace(MMS_ERR, "send buf fd -> %d, count %d\n\n%s\n%s\n", conn->mms_fd, len, buf, ebuf); mms_close(conn); return; } else { mms_trace(MMS_DEVP, "sent fd -> %d, count %d\n\n", conn->mms_fd, len); } } int mm_parse_response(mms_par_node_t *root, mm_response_t *response) { mms_par_node_t *arg; mms_par_node_t *value; mms_par_node_t *work; char *text; text = mms_pn_build_cmd_text(root); mms_trace(MMS_DEVP, "parse response\n%s", text); free(text); if (mms_pn_lookup(root, "response", MMS_PN_CMD, NULL) == NULL) { return (1); } if (arg = mms_pn_lookup(root, "accepted", MMS_PN_KEYWORD, NULL)) { response->response_type = MM_RESPONSE_ACCEPTED; response->response_string = arg->pn_string; } else if (arg = mms_pn_lookup(root, "unacceptable", MMS_PN_KEYWORD, NULL)) { response->response_type = MM_RESPONSE_UNACCEPTABLE; response->response_string = arg->pn_string; } else if (arg = mms_pn_lookup(root, "success", MMS_PN_KEYWORD, NULL)) { response->response_type = MM_RESPONSE_SUCCESS; response->response_string = arg->pn_string; } else if (arg = mms_pn_lookup(root, "cancelled", MMS_PN_KEYWORD, NULL)) { response->response_type = MM_RESPONSE_CANCELLED; response->response_string = arg->pn_string; } else if (arg = mms_pn_lookup(root, "error", MMS_PN_CLAUSE, NULL)) { response->response_type = MM_RESPONSE_ERROR; response->response_string = arg->pn_string; work = NULL; if (value = mms_pn_lookup(arg, NULL, MMS_PN_KEYWORD, &work)) { response->error_class = value->pn_string; } if (value = mms_pn_lookup(arg, NULL, MMS_PN_KEYWORD, &work)) { response->error_code = value->pn_string; } } /* TODO: response text and message clauses */ return (0); } /* get client connection hostname and ip mms_address from IPv4 or IPv6 */ int mm_connect_info(int fd, cci_t *conn) { int sa_len; union { struct sockaddr *sa; struct sockaddr_in *sin; struct sockaddr_in6 *sin6; } sa; const int host_len = sizeof (mms_cli_host_t); mms_cli_host_t host_str; sa.sa = (struct sockaddr *)calloc(sizeof (char), host_len); if (sa.sa == NULL) { return (1); } sa_len = host_len; if (getpeername(fd, sa.sa, &sa_len)) { free(sa.sa); return (1); } else if (sa.sa->sa_family == AF_INET) { if (inet_ntop(AF_INET, &sa.sin->sin_addr, host_str, host_len) == NULL) { free(sa.sa); return (1); } conn->cci_port = sa.sin->sin_port; } else if (sa.sa->sa_family == AF_INET6) { if (inet_ntop(AF_INET6, &sa.sin6->sin6_addr, host_str, host_len) == NULL) { free(sa.sa); return (1); } conn->cci_port = sa.sin6->sin6_port; } else { free(sa.sa); return (1); } free(sa.sa); if (mms_host_ident(host_str, conn->cci_host, conn->cci_ip) == NULL) { return (1); } return (0); } /* get host from mm data as represented internally by mm */ char * mm_data_host_ident(mm_data_t *data) { return (data->mm_host_ip); } /* get host from work area as represented internally by mm */ char * mm_wka_host_ident(mm_wka_t *wka) { return (wka->wka_conn.cci_ip); } /* get host from command as represented internally by mm */ char * mm_cmd_host_ident(mm_command_t *cmd) { return (cmd->wka_ptr->wka_conn.cci_ip); } /* get host from cci as represented internally by mm */ char * mm_cci_host_ident(cci_t *conn) { return (conn->cci_ip); } /* get host from string as represented internally by mm */ char * mm_host_ident(char *host_str) { mms_cli_host_t host; cci_ip_t ip; char *ident; if ((ident = mms_host_ident(host_str, host, ip)) == NULL) { return (NULL); } return (strdup(ident)); } void mm_write_trace_level(mms_trace_sev_t severity) { char *value; if ((value = mms_trace_sev2str(severity)) == NULL) { value = mms_trace_sev2str(MMS_SEV_ERROR); } (void) mms_cfg_setvar(MMS_CFG_MM_TRACE, value); } mms_trace_sev_t mm_read_trace_level(void) { char *value; mms_trace_sev_t severity; if ((value = mms_cfg_alloc_getvar(MMS_CFG_MM_TRACE, NULL)) == NULL) { severity = MMS_SEV_ERROR; } else { (void) mms_trace_str2sev(value, &severity); } if (value) free(value); return (severity); } void mm_reconcile_trace_level(mm_db_t *db) { char *level; mms_trace_sev_t db_severity; mms_trace_sev_t file_severity; /* * Reconcile file and database mms_trace level. */ if (mm_db_exec(HERE, db, "select \"TraceLevel\" from " "\"SYSTEM\";") != MM_DB_DATA) { mm_clear_db(&db->mm_db_results); return; } if (PQntuples(db->mm_db_results) != 1) { mm_clear_db(&db->mm_db_results); return; } level = PQgetvalue(db->mm_db_results, 0, 0); (void) mms_trace_str2sev(level, &db_severity); mm_clear_db(&db->mm_db_results); file_severity = mm_read_trace_level(); if (file_severity != db_severity) { if ((level = mms_trace_sev2str(file_severity)) == NULL) { mm_write_trace_level(db_severity); (void) mms_trace_filter(db_severity); } else if (mm_db_exec(HERE, db, "update \"SYSTEM\" set " "\"TraceLevel\" = '%s';", level) != MM_DB_OK) { mm_clear_db(&db->mm_db_results); } } } int mm_get_fd_limit(mm_db_t *db) { int limit; /* * Get the allowed number of open sockets from the database */ if (mm_db_exec(HERE, db, "select \"SocketFdLimit\" from " "\"SYSTEM\";") != MM_DB_DATA) { limit = -1; } else if (PQntuples(db->mm_db_results) != 1) { limit = -1; } else { limit = atoi(PQgetvalue(db->mm_db_results, 0, 0)); } mm_clear_db(&db->mm_db_results); if (!(limit == -1 || (limit >= 1 && limit <= 65536))) { limit = -1; } mms_trace(MMS_DEVP, "socket fd limit %d", limit); return (limit); } char * mm_return_char(mms_list_t *list, int index) { mm_char_list_t *node; mm_char_list_t *next; int count = 0; for (node = mms_list_head(list); node != NULL; node = next) { next = mms_list_next(list, node); if (count == index) { return (node->text); } count ++; } return (NULL); } int mm_add_char(char *str, mms_list_t *list) { mm_char_list_t *node; node = (mm_char_list_t *)malloc(sizeof (mm_char_list_t)); if (node == NULL) { mms_trace(MMS_ERR, "Error malloc source object"); return (1); } else { memset(node, 0, sizeof (mm_char_list_t)); node->text = NULL; node->text = mms_strapp(node->text, str); mms_list_insert_tail(list, node); } return (0); } void mm_free_list(mms_list_t *list) { mm_char_list_t *cur; mm_char_list_t *next; for (cur = mms_list_head(list); cur != NULL; cur = next) { next = mms_list_next(list, cur); if (cur->text) free(cur->text); mms_list_remove(list, cur); free(cur); } } int mm_add_int(int number, mms_list_t *list) { mm_char_list_t *node; node = (mm_char_list_t *)malloc(sizeof (mm_char_list_t)); if (node == NULL) { mms_trace(MMS_ERR, "Error malloc source object"); return (1); } else { memset(node, 0, sizeof (mm_char_list_t)); node->number = number; mms_list_insert_tail(list, node); } return (0); } void mm_print_char_list(mms_list_t *list) { mm_char_list_t *node; mm_char_list_t *next; for (node = mms_list_head(list); node != NULL; node = next) { next = mms_list_next(list, node); mms_trace(MMS_DEVP, " %s", node->text); } } int mm_in_char_list(mms_list_t *list, char *str) { mm_char_list_t *node; mm_char_list_t *next; for (node = mms_list_head(list); node != NULL; node = next) { next = mms_list_next(list, node); if (strcmp(node->text, str) == 0) { /* same */ return (1); } } return (0); } int mm_replace_char(mms_list_t *list, int index, char *str) { mm_char_list_t *node; mm_char_list_t *next; int count = 0; for (node = mms_list_head(list); node != NULL; node = next) { next = mms_list_next(list, node); if (count == index) { free(node->text); node->text = strdup(str); return (0); } } return (1); } int mm_add_obj_list(mms_list_t *list, char *obj) { mm_char_list_t *mm_char_struct; mm_char_list_t *cur_char; mm_char_list_t *next; /* If the obj is already in the list, skip */ for (cur_char = mms_list_head(list); cur_char != NULL; cur_char = next) { next = mms_list_next(list, cur_char); if (strcmp(cur_char->text, obj) == 0) { /* already have this obj */ return (1); } } /* Don't have this obj yet */ mm_char_struct = (mm_char_list_t *) calloc(1, sizeof (mm_char_list_t)); if (mm_char_struct == NULL) { mms_trace(MMS_ERR, "Unable to malloc mm_char_list_t: %s", strerror(errno)); return (1); } mm_char_struct->text = strdup(obj); mms_list_insert_tail(list, mm_char_struct); return (0); } int mm_add_to_source(mm_command_t *cmd, char *str) { mms_list_t *source_list = &cmd->cmd_source_list; if (mm_add_obj_list(source_list, str) == 0) { cmd->cmd_source_num ++; return (0); } return (1); } int mm_add_to_dest(mm_command_t *cmd, char *str) { mms_list_t *dest_list = &cmd->cmd_dest_list; if (mm_add_obj_list(dest_list, str) == 0) { cmd->cmd_dest_num ++; return (0); } return (1); } int mm_add_to_const(mm_command_t *cmd, char *str) { mms_list_t *const_list = &cmd->cmd_const_list; if (mm_add_obj_list(const_list, str) == 0) { cmd->cmd_const_num ++; return (0); } return (1); } /* * mm_free_err: * -free's memory inside mm_cmd_err_t * -caller should free the struct itself */ void mm_free_err(mm_cmd_err_t *cmd_error) { if (cmd_error->ecode != NULL) { free(cmd_error->ecode); cmd_error->ecode = NULL; } if (cmd_error->eclass != NULL) { free(cmd_error->eclass); cmd_error->eclass = NULL; } if (cmd_error->err_buf != NULL) { free(cmd_error->err_buf); cmd_error->err_buf = NULL; } if (cmd_error->retry_drive != NULL) { free(cmd_error->retry_drive); cmd_error->retry_drive = NULL; } if (cmd_error->retry_cart != NULL) { free(cmd_error->retry_cart); cmd_error->retry_cart = NULL; } if (cmd_error->retry_lib != NULL) { free(cmd_error->retry_lib); cmd_error->retry_lib = NULL; } cmd_error->err_bufsize = 0; } /* * mm_free_err_list: * -free's an entire cmd's err list * -caller should call list destroy on the actual list */ void mm_free_err_list(mm_command_t *cmd) { mm_cmd_err_t *cur_err; mm_cmd_err_t *next_err; mms_list_t *err_list; err_list = &cmd->cmd_err_list; /* If the obj is already in the list, skip */ for (cur_err = mms_list_head(err_list); cur_err != NULL; cur_err = next_err) { next_err = mms_list_next(err_list, cur_err); /* remove this from the list and free */ mms_list_remove(err_list, cur_err); mm_free_err(cur_err); free(cur_err); } } /* * mm_alloc_err: * -allocates and initializes a new mm_cmd_err_t struct */ mm_cmd_err_t * mm_alloc_err() { mm_cmd_err_t *err = NULL; err = (mm_cmd_err_t *)calloc(1, sizeof (mm_cmd_err_t)); if (err == NULL) { mms_trace(MMS_ERR, "mm_alloc_err: " "Unable to malloc mm_cmd_err_t: %s", strerror(errno)); return (NULL); } err->eclass = NULL; err->ecode = NULL; err->err_buf = NULL; err->err_bufsize = 0; err->retry_drive = NULL; err->retry_cart = NULL; err->retry_lib = NULL; err->err_already_used = 0; return (err); }