https://gitlab.com/jessp011/gqlplus/-/merge_requests/1 Adapted not to change version number (1.14 -> 1.18) diff --git a/configure.ac b/configure.ac index bb192d17fd1b4089068fedf1e2e1287c95249eff..6da50669d7aaf8303ad5de9554a5b3acbe5bcc94 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,7 @@ -AC_INIT([gqlplus], [1.14]) +AC_INIT([gqlplus], [1.14],kernel01@gmail.com) AC_CONFIG_SRCDIR([gqlplus.c]) AM_INIT_AUTOMAKE +AC_PROG_MAKE_SET AC_PROG_CC AC_PROG_INSTALL AC_PROG_RANLIB diff --git a/gqlplus.c b/gqlplus.c index 41a6db258ca6b1ed67cbf0dc121ccf1ee92ab875..81602ffd7a1c1cf197d0140332b0b529f7454692 100644 --- a/gqlplus.c +++ b/gqlplus.c @@ -440,9 +440,11 @@ Copyright (C) 2004 Ljubomir J. Buturovic. All Rights Reserved. #include #include #include +#include #include #include #include +#include #include #include #include @@ -557,13 +559,19 @@ Copyright (C) 2004 Ljubomir J. Buturovic. All Rights Reserved. void save_history(void) { + int ret; + if (history_list() == NULL) /* If history is of length 0 (because set as is or slave is not executable) */ unlink(histname); else { write_history(histname); - chmod(histname, 0600); - printf("\nSession history saved to: %s\n", histname); + ret = chmod(histname, 0600); + if (ret < 0) { + fprintf(stderr, "Problem with chmod on %s\n", histname); + } else { + printf("\nSession history saved to: %s\n", histname); + } } } @@ -626,6 +634,7 @@ int startsWith(char* szOrg, const char* szPrefix) if (strstr(szOrgTrimmed, szPrefix) == szOrgTrimmed){ iMatch = 1; } + free(szOrgTrimmed); } return iMatch; } @@ -650,6 +659,7 @@ int matchCommand(char* szOrg, char* szPrefix, char* szCmd) char* szRemaining = szOrgTrimmed + strlen(szPrefix); iMatch = startsWith(szRemaining, szCmd); } + free(szOrgTrimmed); } return iMatch; @@ -871,6 +881,58 @@ static int check_password_prompt(char *str) return check_prompt; } +/* + Send your command "cmd" to SQLPlus. + If it doesn't work exit with return code "ret" and inform user with "msg". + If "ret" is 0 then the caller handles error. +*/ +int send_cmd(int outfd, int ret, char *cmd, char *msg) +{ + int status = write(outfd, cmd, strlen(cmd)); + + if ((status == -1) && (ret != 0)){ + fprintf(stderr, "%s\n",msg); + exit(ret); + } + + return(status); +} + +/* + To avoid memory leaks build the error message. + Note: You need to free the message yourself after potentially using it. +*/ +char *make_msg(const char *fmt, ...) +{ + int len; + char *buf = NULL; + va_list args; + + /* find out how big a buffer we need */ + va_start(args, fmt); + len = vsnprintf(buf, 0, fmt, args); + va_end(args); + len++; + + buf = malloc(len * sizeof(char)); + if (buf == NULL) + { + fprintf(stderr,"Out of memory when constructing error message.\n"); + exit(-ENOMEM); + } + + va_start(args, fmt); + len = vsnprintf(buf, len - 1, fmt, args); + va_end(args); + if (len < 0) + { + fprintf(stderr,"Out of memory when constructing error message.\n"); + exit(-ENOMEM); + } + + return(buf); +} + /* Get sqlplus output from `fd' and display it (*outstr is NULL) without prompt, or store it in *outstr. The prompt is returned and @@ -880,7 +942,6 @@ static int check_password_prompt(char *str) static char *get_sqlplus(int fd, char *line, char **outstr) { int done; - int cntr; int nread = 0; int plen; int llen; @@ -888,6 +949,7 @@ static char *get_sqlplus(int fd, char *line, char **outstr) int capacity; int ocapacity; int pdiff; + int status; char *lline; char *xtr; char *last_line; @@ -896,7 +958,6 @@ static char *get_sqlplus(int fd, char *line, char **outstr) char *prompt = (char *) 0; done = 0; - cntr = 0; capacity = INIT_LINE_LENGTH; ocapacity = INIT_LINE_LENGTH; @@ -980,7 +1041,9 @@ static char *get_sqlplus(int fd, char *line, char **outstr) if (!outstr) { if (plen > 0) - write(STDOUT_FILENO, lline, plen); + { + status = write(STDOUT_FILENO, lline, plen); + } } else { @@ -1029,7 +1092,9 @@ static char *get_sqlplus(int fd, char *line, char **outstr) if (!outstr) { if (llen > 0) - write(STDOUT_FILENO, lline, llen); + { + status = write(STDOUT_FILENO, lline, llen); + } } else { @@ -1163,6 +1228,7 @@ static char *accept_cmd(char *cmd, int fdin, int fdout, char *sql_prompt, char * printf("%s", fline); fflush(stdout); free(fline); + free(accept); prompt = strdup(sql_prompt); }else{ /* @@ -1172,15 +1238,11 @@ static char *accept_cmd(char *cmd, int fdin, int fdout, char *sql_prompt, char * /* Send it to sqlplus. */ - write(fdout, rline, strlen(rline)); + send_cmd(fdout, -1, rline, "sqlplus terminated - exiting..."); /* Terminate the user input sent to sqlplus. */ - status = write(fdout, "\n", 1); - if (status == -1){ - fprintf(stderr, "sqlplus terminated - exiting...\n"); - exit(-1); - } + send_cmd(fdout, -1, "\n", "sqlplus terminated - exiting..."); /* Now read the message sent from sqlplus, which should be the SQL prompt. We don't display it, since that will be done by the @@ -1279,13 +1341,11 @@ static int check_mode(mode_t st_mode) { int mode; mode_t mode1; - mode_t mode2; mode = 0; mode1 = S_ISREG(st_mode); if (mode1) { - mode2 = S_IXUSR; mode = st_mode & S_IXUSR; } return mode; @@ -1358,7 +1418,17 @@ static char *search_exe(char *exe) { mode = check_mode(buf.st_mode); if (mode) + { path = lpath; + } + else + { + free(lpath); + } + } + else + { + free(lpath); } } return path; @@ -1408,11 +1478,13 @@ char **get_environment(void) static void print_environment(char **enx) { int idx; - char *env; idx = 0; while (enx[idx]) - printf("enx[%d]: '%s'\n", idx, enx[idx++]); + { + printf("enx[%d]: '%s'\n", idx, enx[idx]); + idx++; + } } /* @@ -1497,15 +1569,19 @@ static char *read_file(const char *fname, char *line) str = malloc((buf.st_size+1)*sizeof(char)); if (str != (char *) 0){ xtr = str; - while (fgets(line, MAX_LINE_LENGTH, fptr)){ + while (NULL != fgets(line, MAX_LINE_LENGTH, fptr)){ len = strlen(line); memcpy(xtr, line, len); xtr += len; } - fclose(fptr); *xtr = '\0'; } } + fclose(fptr); + } + else + { + fprintf(stderr, "Could not read %s\n", fname); } return str; } @@ -1578,7 +1654,7 @@ static char **file_editor(FILE *fptr, char *line) { char **editor = (char **) 0; - while (fgets(line, MAX_LINE_LENGTH, fptr) && (editor == (char **) 0)) + while ((NULL != fgets(line, MAX_LINE_LENGTH, fptr)) && (editor == (char **) 0)) if ((line[0] != '#') && strstr(line, DEFINE_CMD) && (strstr(line, EDITOR))) editor = set_editor(line); fclose(fptr); @@ -1604,7 +1680,7 @@ static char **file_set_editor(char *line) char *oracle_home; FILE *fptr; - path = malloc(1024); + path = malloc(MAXPATHLEN * 2); /* Check local directory first. */ @@ -1669,7 +1745,8 @@ static void insert_line(int fdin, int fdout, char *xtr, char *ccmd, char *line) if (xtr && *xtr) { sprintf(ccmd, "i %s\n", xtr); - write(fdout, ccmd, strlen(ccmd)); + send_cmd(fdout, -1, ccmd, + "sqlplus terminated while inserting line - exiting..."); prompt = get_sqlplus(fdin, line, &str); free(prompt); free(str); @@ -1703,9 +1780,12 @@ static void pause_cmd(int fdin, int fdout, char *line, char *sql_prompt, int fir int flags; int process_response; int len; + int ret; + char *err_msg; char *lx; char *response; char *sp; + char *tmp; char *prompt; char buffer[BUF_LEN]; @@ -1713,12 +1793,20 @@ static void pause_cmd(int fdin, int fdout, char *line, char *sql_prompt, int fir Get sqlplus output without blocking. */ flags = fcntl(fdin, F_GETFL, 0); - fcntl(fdin, F_SETFL, (flags | O_NDELAY)); + ret = fcntl(fdin, F_SETFL, (flags | O_NDELAY)); + if (ret < 0) + { + fprintf(stderr, "Problem setting non blocking on sqlplus\n"); + } + /* Send the command to sqlplus. */ - write(fdout, line, strlen(line)); - write(fdout, "\n", 1); + err_msg = make_msg("sqlplus terminated while sending cmd |%s| exiting.",line); + send_cmd(fdout, -1, line, err_msg); + free(err_msg); + send_cmd(fdout, -1, "\n", "sqlplus terminated while sending cmd - exiting."); + if (first_flag) process_response = 1; else @@ -1802,8 +1890,11 @@ static void pause_cmd(int fdin, int fdout, char *line, char *sql_prompt, int fir /* Get a line from keyboard and send it to sqlplus. */ - fgets(lx, MAX_LINE_LENGTH, stdin); - write(fdout, lx, strlen(lx)); + tmp = fgets(lx, MAX_LINE_LENGTH, stdin); + err_msg = make_msg("sqlplus terminated while sending cmd |%s| exiting.", + lx); + send_cmd(fdout, -1, lx, err_msg); + free(err_msg); } } } @@ -1812,7 +1903,11 @@ static void pause_cmd(int fdin, int fdout, char *line, char *sql_prompt, int fir /* Reset pipe from sqlplus to O_NDELAY. */ - fcntl(fdin, F_SETFL, (flags &~ O_NDELAY)); + ret = fcntl(fdin, F_SETFL, (flags &~ O_NDELAY)); + if (ret < 0) + { + fprintf(stderr,"Problem setting reseting blocking on sqlplus\n"); + } free(lx); free(response); } @@ -1843,7 +1938,7 @@ static int edit(int fdin, int fdout, char *line, char **editor, char *fname) char *newline; char **xrgs = (char **) 0; char **enx = (char **) 0; - FILE *fptr; + FILE *fptr = NULL; status = 0; str = (char *) 0; @@ -1869,8 +1964,10 @@ static int edit(int fdin, int fdout, char *line, char **editor, char *fname) Get last SQL statement from sqlplus and put it in afiedt.buf, then open it in editor. */ - write(fdout, LIST_CMD, strlen(LIST_CMD)); + send_cmd(fdout, -1, LIST_CMD, + "sqlplus terminated while sending LIST cmd - exiting."); prompt = get_sqlplus(fdin, line, &str); + free(prompt); /* TBD: afiedt.buf filename hardcoded. */ rname = strdup(AFIEDT); } @@ -1900,7 +1997,7 @@ static int edit(int fdin, int fdout, char *line, char **editor, char *fname) if (!status) { free(str); - free(prompt); + str = NULL; path = editor[0]; xc = 0; while (editor[xc++] != (char *) 0); @@ -1957,7 +2054,7 @@ static int edit(int fdin, int fdout, char *line, char **editor, char *fname) { if (execve(path, xrgs, enx) < 0) { - str = malloc(100); + str = malloc(strlen(path) + 19); sprintf(str, "execve() failure; %s", path); perror(str); _exit(-1); @@ -1987,10 +2084,12 @@ static int edit(int fdin, int fdout, char *line, char **editor, char *fname) len -= 3; afiedt[len] = '\0'; } - write(fdout, DEL_CMD, strlen(DEL_CMD)); + send_cmd(fdout, -1, DEL_CMD, + "sqlplus terminated while sending del cmd - exiting."); prompt = get_sqlplus(fdin, line, &str); free(prompt); free(str); + str = NULL; xtr = afiedt; ccmd = malloc(MAX_LINE_LENGTH*sizeof(char)); while ((ptr = strchr(xtr, '\n')) != (char *) 0) @@ -2007,7 +2106,8 @@ static int edit(int fdin, int fdout, char *line, char **editor, char *fname) Last line, if not empty. */ insert_line(fdin, fdout, xtr, ccmd, line); - write(fdout, LIST_CMD, strlen(LIST_CMD)); + send_cmd(fdout, -1, LIST_CMD, + "sqlplus terminated while sending list cmd - exiting."); prompt = get_sqlplus(fdin, line, (char **) 0); free(prompt); free(ccmd); @@ -2031,6 +2131,8 @@ static int edit(int fdin, int fdout, char *line, char **editor, char *fname) else write(STDOUT_FILENO, NOTHING_TO_SAVE, strlen(NOTHING_TO_SAVE)); free(rname); + if (str) + free(str); return status; } @@ -2103,6 +2205,7 @@ static char **parse_columns(char *str) } } } + free(tokens); return columns; } @@ -2110,6 +2213,7 @@ static char **get_column_names(char *tablename, char *owner, int fdin, int fdout { int len; char *ccmd = (char *) 0; + char *err_msg; char *str = (char *) 0; char *prompt = (char *) 0; char **columns = (char **) 0; @@ -2124,7 +2228,11 @@ static char **get_column_names(char *tablename, char *owner, int fdin, int fdout sprintf(ccmd, "%s %s.%s\n", DESCRIBE, owner, tablename); else sprintf(ccmd, "%s %s\n", DESCRIBE, tablename); - write(fdout, ccmd, strlen(ccmd)); + + err_msg = make_msg("sqlplus terminated while sending cmd |%s| exiting.", + ccmd); + send_cmd(fdout, -1, ccmd, err_msg); + free(err_msg); prompt = get_sqlplus(fdin, line, &str); free(prompt); columns = parse_columns(str); @@ -2140,14 +2248,18 @@ static int get_pagesize(int fdin, int fdout, char *line) int len; char *str; char *xtr; + char *prompt = (char *) 0; - write(fdout, PAGESIZE_CMD, strlen(PAGESIZE_CMD)); - get_sqlplus(fdin, line, &str); + send_cmd(fdout, -1, PAGESIZE_CMD, + "sqlplus terminated while sending pagesize cmd - exiting."); + + prompt = get_sqlplus(fdin, line, &str); xtr = strchr(str, ' ')+1; len = strspn(xtr, DIGITS); xtr[len] = '\0'; pagesize = atoi(xtr); free(str); + free(prompt); return pagesize; } @@ -2164,7 +2276,6 @@ static struct table *get_names(char *str, int fdin, int fdout, int pagesize, cha int idx; int capacity; char *tname; - char *ltr; char **toks; char **tokens; struct table *tables = NULL; @@ -2184,15 +2295,11 @@ static struct table *get_names(char *str, int fdin, int fdout, int pagesize, cha if (pagesize > 0) { idx = 1; - ltr = (char *) 0; } - else - ltr = str; i = 0; while ((tname = toks[idx])) { idx++; - ltr = (char *) 0; if (*tname && strcmp(tname, "TABLE_NAME") && strcmp(tname, "VIEW_NAME") && !strstr(tname, "------") && !strstr(tname, "rows selected")) { @@ -2236,6 +2343,7 @@ static struct table *get_names(char *str, int fdin, int fdout, int pagesize, cha } } } + free(toks); if (fptr) fclose(fptr); return tables; @@ -2248,6 +2356,8 @@ static struct table *get_names(char *str, int fdin, int fdout, int pagesize, cha static struct table *get_completion_names(int fdin, int fdout, char *line) { int pagesize; + char *err_msg; + char *prompt; char *str; char *ccmd; struct table *tables; @@ -2257,16 +2367,23 @@ static struct table *get_completion_names(int fdin, int fdout, char *line) pagesize = get_pagesize(fdin, fdout, line); ccmd = malloc((strlen(SELECT_TABLES_1)+strlen(SELECT_TABLES_2)+1)*sizeof(char)); sprintf(ccmd, "%s%s", SELECT_TABLES_1, SELECT_TABLES_2); - write(fdout, ccmd, strlen(ccmd)); - get_sqlplus(fdin, line, &str); + err_msg = make_msg("sqlplus terminated while sending cmd |%s| exiting.",ccmd); + send_cmd(fdout, -1, ccmd, err_msg); + free(err_msg); + + prompt = get_sqlplus(fdin, line, &str); /* kehlet: ORA- error is likely because the database isn't open */ if (!strstr(str, "ORA-")) { tables = get_names(str, fdin, fdout, pagesize, line); } free(str); - write(fdout, DEL_CMD, strlen(DEL_CMD)); - get_sqlplus(fdin, line, &str); + free(prompt); + send_cmd(fdout, -1, DEL_CMD, + "sqlplus terminated while sending del cmd - exiting."); + prompt = get_sqlplus(fdin, line, &str); free(ccmd); + free(str); + free(prompt); return tables; } @@ -2434,15 +2551,22 @@ static char *get_connect_string(int argc, char **argv) if (strchr(str, '/')) { if (strchr(str, '@')) + { connect_string = strdup(str); + break; + } else if (sid != (char *) 0) { connect_string = malloc(strlen(str)+strlen(sid)+2); sprintf(connect_string, "%s@%s", str, sid); + break; } } else + { + free(username); username = strdup(str); + } } } return connect_string; @@ -2461,7 +2585,9 @@ static char *build_connect_string(char *user, char *password) if (strchr(user, '@')) { if (strchr(user, '/')) + { connect_string = strdup(user); + } else if ((password != (char *) 0)) { tokens = str_tokenize(user, "@"); @@ -2506,15 +2632,29 @@ static char *get_sql_prompt(char *old_prompt, char *sqlplus, char *connect_strin char *cmd; char *xtr; char *ptr; - char tmpdir[500]=""; + char tmpdir[MAXPATHLEN]=""; char *env_tmpdir; int fd; if (connect_string){ - if (env_tmpdir=getenv("TMPDIR")){ - }else if (env_tmpdir=getenv("TEMPDIR")){ - }else{ - env_tmpdir=getenv("TEMP"); + if ((env_tmpdir=getenv("TMPDIR"))){ + /* length "/gqlplus.XXXXXX" = 16 */ + if (16 + strlen(env_tmpdir) > MAXPATHLEN) { + fprintf(stderr,"Environment variable TMPDIR too long\n"); + env_tmpdir = (char *) 0; + } + } + if (!env_tmpdir && (env_tmpdir=getenv("TEMPDIR"))){ + if (16 + strlen(env_tmpdir) > MAXPATHLEN) { + fprintf(stderr,"Environment variable TEMPDIR too long\n"); + env_tmpdir = (char *) 0; + } + } + if (!env_tmpdir && (env_tmpdir=getenv("TEMP"))){ + if (16 + strlen(env_tmpdir) > MAXPATHLEN) { + fprintf(stderr,"Environment variable TEMP too long\n"); + env_tmpdir = (char *) 0; + } } if (env_tmpdir){ strcpy(tmpdir, env_tmpdir); @@ -2537,7 +2677,6 @@ static char *get_sql_prompt(char *old_prompt, char *sqlplus, char *connect_strin /*printf("cmd: `%s'\n", cmd);*/ *status = system(cmd); if (!*status){ - free(cmd); xtr = read_file(tmpdir, line); unlink(tmpdir); @@ -2559,7 +2698,9 @@ static char *get_sql_prompt(char *old_prompt, char *sqlplus, char *connect_strin sqlprompt[len] = '\0'; } } + free(xtr); } + free(cmd); } return sqlprompt; } @@ -2606,6 +2747,7 @@ static void get_final_sqlplus(int fdin) int result; int capacity; int llen; + int ret; char *response; char buffer[BUF_LEN]; @@ -2618,7 +2760,13 @@ static void get_final_sqlplus(int fdin) Get sqlplus output without blocking. */ flags = fcntl(fdin, F_GETFL, 0); - fcntl(fdin, F_SETFL, (flags | O_NDELAY)); + ret = fcntl(fdin, F_SETFL, (flags | O_NDELAY)); + if (ret < 0) + { + fprintf(stderr, "Problem setting non blocking on sqlplus\n"); + perror(NULL); + } + result = read(fdin, buffer, BUF_LEN); if (result > 0) { @@ -2628,6 +2776,7 @@ static void get_final_sqlplus(int fdin) response[llen] = '\0'; } printf("%s", response); + free(response); } /* @@ -2651,8 +2800,10 @@ int main(int argc, char **argv) int all_tables = 1; /* set to 0 if we cannot query or parse ALL_TABLES or ALL_VIEWS */ int pause_mode; int pstat; + int ret; char *password = (char *) 0; char *connect_string; + char *err_msg; char *path; char *spath; char *prompt; @@ -2664,7 +2815,6 @@ int main(int argc, char **argv) char *oline; char *nptr; char *shellcmd; - char *accept; char *ed; char **editor; char **xrgs; @@ -2755,6 +2905,7 @@ int main(int argc, char **argv) { connect_string = get_connect_string(argc, argv); sql_prompt = get_sql_prompt(sql_prompt, spath, connect_string, line, &pstat); + free(connect_string); } else sql_prompt = SQL_PROMPT; @@ -2791,7 +2942,7 @@ int main(int argc, char **argv) xrgs[0] = spath; if (execve(spath, xrgs, enx) < 0) { - line = malloc(100); + line = malloc(strlen(spath) + 19); sprintf(line, "execve() failure; %s", spath); perror(line); status = -1; @@ -2904,6 +3055,7 @@ int main(int argc, char **argv) connect_string = build_connect_string(username, password); sql_prompt = get_sql_prompt(sql_prompt, spath, connect_string, line, &pstat); + free(connect_string); } else if (!check_password_prompt(prompt)) add_history(rline); @@ -2919,8 +3071,11 @@ int main(int argc, char **argv) if (!strncmp(lline, SET_CMD, strlen(SET_CMD)) && xrgs && xrgs[1] && !strncmp(xrgs[1], SQLPROMPT_CMD, 4)) { - write(fds1[1], rline, strlen(rline)); - write(fds1[1], "\n", 1); + err_msg = make_msg("sqlplus terminated while sending cmd |%s| exiting.",rline); + send_cmd(fds1[1], -1, rline, err_msg); + free(err_msg); + send_cmd(fds1[1], -1, "\n", + "sqlplus terminated while sending cmd - exiting."); sql_prompt = set_sql_prompt(fds2[0], line); prompt = strdup(sql_prompt); } @@ -2938,6 +3093,7 @@ int main(int argc, char **argv) tokens = str_tokenize(oline,WHITESPACE); connect_string = get_connect_string(2,tokens); free(tokens); + free(connect_string); } } if (!strncmp(lline, DISCONNECT_CMD, 4)) @@ -2955,7 +3111,10 @@ int main(int argc, char **argv) else if (xrgs && xrgs[1] && !strncmp(lline, SET_CMD, strlen(SET_CMD)) && !strncmp(xrgs[1], PAUSE_CMD, 3)) { - write(fds1[1], rline, strlen(rline)); + err_msg = make_msg("sqlplus terminated while sending cmd |%s| exiting.",rline); + send_cmd(fds1[1], -1, rline, err_msg); + free(err_msg); + if (xrgs[2] && !strcmp(xrgs[2], ON_CMD)) pause_mode = 1; else @@ -2976,7 +3135,9 @@ int main(int argc, char **argv) */ else if (!strncmp(lline, CLEAR_CMD, 2) && nptr && !strncmp(nptr, SCREEN, strlen(SCREEN))) + { system("clear"); + } else if (!check_numeric_prompt(prompt) && (shellcmd = get_shellcmd(oline))) { system(shellcmd); @@ -2986,16 +3147,20 @@ int main(int argc, char **argv) if (check_password_prompt(prompt)){ status = tcsetattr(STDIN_FILENO, TCSAFLUSH, &save_termios); } - write(fds1[1], rline, strlen(rline)); + err_msg = make_msg("sqlplus terminated while sending cmd |%s| exiting.",rline); + send_cmd(fds1[1], -1, rline, err_msg); + free(err_msg); + if (strstr(lline, DEFINE_CMD) && (strstr(lline, EDITOR))){ editor = set_editor(lline); } } free(prompt); if (!quit_sqlplus){ - status = write(fds1[1], "\n", 1); + status = send_cmd(fds1[1], 0, "\n", + "sqlplus terminated - exiting... :("); + if (status == -1){ - fprintf(stderr, "sqlplus terminated - exiting... :( \n"); quit_sqlplus = 1; }else{