On 01/13/2016 11:08 AM, Gabriel Krisman Bertazi wrote: > Heitor Ricardo Alves de Siqueira <hal...@linux.vnet.ibm.com> writes: > >> This commit rewrites some functions in iprconfig that are used to >> display log information to the user. We now use standard C code instead >> of system() calls and other OS utilities like grep. To view the >> requested log info, the less pager is invoked with the environment >> variable LESSSECURE set to 1 to prevent arbitrary command execution. >> >> This commit also introduces a zlib depency to iprutils. This is needed >> so that we can seamlessly work with compressed and uncompressed log files. > > Thanks for the patch! A few stylish issues below: > Hi Gabriel,
Thanks for taking the time to sift through the patch! A few comments to your review below: >> diff --git a/iprconfig.c b/iprconfig.c >> index fadf562062ea..644ba1de37da 100644 >> --- a/iprconfig.c >> +++ b/iprconfig.c >> @@ -94,8 +94,7 @@ static int use_curses; >> #define for_each_raid_cmd(cmd) for (cmd = raid_cmd_head; cmd; cmd = >> cmd->next) >> >> #define DEFAULT_LOG_DIR "/var/log" >> -#define DEFAULT_EDITOR "vi -R" >> -#define FAILSAFE_EDITOR "vi -R -" >> +#define DEFAULT_EDITOR "/usr/bin/less" > > I like moving the default editor from vi to less. But I guess we can > avoid using the absolute path here... you know the drill :) > Done. :) >> >> #define IS_CANCEL_KEY(c) ((c == KEY_F(12)) || (c == 'q') || (c == 'Q')) >> #define CANCEL_KEY_LABEL "q=Cancel " >> @@ -11935,44 +11934,69 @@ int ibm_storage_log_tail(i_container *i_con) >> int rc, len; >> int log_fd; >> char *logfile; >> + FILE *logsource; >> >> logfile = strdup(_PATH_TMP"iprerror-XXXXXX"); >> log_fd = mkstemp(logfile); >> + if (log_fd < 0) { >> + closelog(); >> + openlog(tool_name, LOG_PERROR | LOG_PID | LOG_CONS, LOG_USER); >> + syslog(LOG_ERR, "Could not create temp log file: %m\n"); >> + closelog(); >> + openlog(tool_name, LOG_PID | LOG_CONS, LOG_USER); > > Why do you invoke closelog may times? Is that required? From the > manpage, closelog seems to be optional.. > You're right, we don't really need this. I think this was a workaround to print the message to syslog and stdout at the same time, but I've changed this to use the return code messages. >> + return 65; > > Why 65? Is that expected by the caller? Can we change this to use a > constant or something more meaningful? > Yes, turns out that it is an expected value. Depending on this function's return value, a different error message will be displayed to the user. I've changed the code to use some defined constants for this, should make it a bit more clear. >> + } >> >> def_prog_mode(); >> + endwin(); >> >> - if (log_fd == -1) { >> - len = sprintf(cmnd, "cd %s; zcat -f messages", log_root_dir); >> - >> - len += sprintf(cmnd + len," | grep ipr | "); >> - len += sprintf(cmnd + len, "sed \"s/ `hostname -s` kernel: >> ipr//g\" | "); >> - len += sprintf(cmnd + len, "sed \"s/ localhost kernel: ipr//g\" >> | "); >> - len += sprintf(cmnd + len, "sed \"s/ kernel: ipr//g\" | "); >> - len += sprintf(cmnd + len, "sed \"s/\\^M//g\" | "); >> - len += sprintf(cmnd + len, FAILSAFE_EDITOR); >> + snprintf(cmnd, sizeof(cmnd), "%s/messages", log_root_dir); > > Guess we could use a more meaningful name than cmnd for this variable, > since it doesn't holds a command anymore, but a file name. > Done. >> + logsource = fopen(cmnd, "r"); >> + if (logsource < 0) { >> closelog(); >> - openlog("iprconfig", LOG_PERROR | LOG_PID | LOG_CONS, LOG_USER); >> - syslog(LOG_ERR, "Error encountered concatenating log >> files...\n"); >> - syslog(LOG_ERR, "Using failsafe editor...\n"); >> + openlog(tool_name, LOG_PERROR | LOG_PID | LOG_CONS, LOG_USER); >> + syslog(LOG_ERR, "Could not open %s: %m\n", cmnd); >> closelog(); >> - openlog("iprconfig", LOG_PID | LOG_CONS, LOG_USER); >> - sleep(3); >> - } else { >> - len = sprintf(cmnd,"cd %s; zcat -f messages | grep ipr |", >> log_root_dir); >> - len += sprintf(cmnd + len, "sed \"s/ `hostname -s` kernel: >> ipr//g\""); >> - len += sprintf(cmnd + len, " | sed \"s/ localhost kernel: >> ipr//g\""); >> - len += sprintf(cmnd + len, " | sed \"s/ kernel: ipr//g\""); >> - len += sprintf(cmnd + len, " | sed \"s/\\^M//g\" "); >> - len += sprintf(cmnd + len, ">> %s", logfile); >> - system(cmnd); >> - >> - sprintf(cmnd, "%s %s", editor, logfile); >> + openlog(tool_name, LOG_PID | LOG_CONS, LOG_USER); >> + close(log_fd); >> + return 65; >> } >> >> - rc = system(cmnd); >> + while (fgets(cmnd, sizeof(cmnd), logsource)) { >> + /* ignore lines that dont contain 'ipr' */ >> + if (strstr(cmnd, "ipr") == NULL) >> + continue; >> >> - if (log_fd != -1) >> - close(log_fd); >> + const char *local_s = "localhost kernel: ipr"; >> + const char *kernel_s = "kernel: ipr"; >> + char regex[256]; >> + char host[256]; >> + char *dot; > > Please move the declarations to the top of the function or to the top of > the current code block. I find it bad to mix declarations with actual > code. > You're right, that was sloppy from me. I've fixed this in v2. >> + >> + gethostname(host, sizeof(host)); >> + dot = strchr(host, '.'); >> + if (dot) >> + *dot = '\0'; >> + snprintf(regex, sizeof(regex), "%s kernel: ipr", host); >> + >> + /* erase regex from cmnd */ >> + if (dot = strstr(cmnd, regex)) { > > I was confused by the usage of cmnd here. Wasn't it pointing to the log > file name? Let's use another variable here, with a better name. > Also done. >> + memmove(dot, dot + strlen(regex), >> + strlen(dot) - strlen(regex) + 1); >> + } else if (dot = strstr(cmnd, local_s)) { >> + memmove(dot, dot+strlen(local_s), >> + strlen(dot) - strlen(local_s) + 1); >> + } else if (dot = strstr(cmnd, kernel_s)) { >> + memmove(dot, dot+strlen(kernel_s), >> + strlen(dot) - strlen(kernel_s) + 1); >> + } >> + >> + write(log_fd, cmnd, strlen(cmnd)); > > I had a hard time understanding this block. Would please add a comment > in the code? :) > I can see that this block is confusing, sorry for that. That is usually not a good sign, so if you have any suggestions for this, please let me know. For now, I added some clarification to the code. >> int log_fd; >> char *logfile; >> - >> + FILE *logsource; >> >> sprintf(cmnd,"%s/boot.msg",log_root_dir); >> rc = stat(cmnd, &file_stat); >> @@ -12488,35 +12534,41 @@ int ibm_boot_log(i_container *i_con) >> >> logfile = strdup(_PATH_TMP"iprerror-XXXXXX"); >> log_fd = mkstemp(logfile); >> + if (log_fd < 0) { >> + closelog(); >> + openlog(tool_name, LOG_PERROR | LOG_PID | LOG_CONS, LOG_USER); >> + syslog(LOG_ERR, "Could not create temp log file: %m\n"); >> + closelog(); >> + openlog(tool_name, LOG_PID | LOG_CONS, LOG_USER); >> + return 65; >> + } >> >> def_prog_mode(); >> + endwin(); >> >> - if (log_fd == -1) { >> - len = sprintf(cmnd, "cd %s; zcat -f ", log_root_dir); >> - >> - /* Probably have a read-only root file system */ > > Do we still handle the case where the rootfs is RO? > Not directly, no. This will probably fail in that case, because we may not be able to create a new file with mkstemp. I don't see a very good way to handle a RO rootfs with the current code, since we need a temp. file to filter log info before we show it to the user. Do you have any ideas for this, or should we just fail and inform the user? > >> - len += sprintf(cmnd + len, "boot.msg"); >> - len += sprintf(cmnd + len," | grep ipr |"); >> - len += sprintf(cmnd + len, FAILSAFE_EDITOR); >> + snprintf(cmnd, sizeof(cmnd), "%s/boot.msg", log_root_dir); >> + logsource = fopen(cmnd, "r"); >> + if (logsource < 0) { >> closelog(); >> - openlog("iprconfig", LOG_PERROR | LOG_PID | LOG_CONS, LOG_USER); >> - syslog(LOG_ERR, "Error encountered concatenating log >> files...\n"); >> - syslog(LOG_ERR, "Using failsafe editor...\n"); >> + openlog(tool_name, LOG_PERROR | LOG_PID | LOG_CONS, LOG_USER); >> + syslog(LOG_ERR, "Could not open %s: %m\n", cmnd); >> closelog(); >> - openlog("iprconfig", LOG_PID | LOG_CONS, LOG_USER); >> - sleep(3); >> - } else { >> - len = sprintf(cmnd,"cd %s; zcat -f boot.msg | grep ipr | " >> - "sed 's/<[0-9]>ipr-err: //g' | sed 's/<[0-9]>ipr: >> //g'", >> - log_root_dir); >> - len += sprintf(cmnd + len, ">> %s", logfile); >> - system(cmnd); >> - sprintf(cmnd, "%s %s", editor, logfile); >> + openlog(tool_name, LOG_PID | LOG_CONS, LOG_USER); >> + close(log_fd); >> + return 65; >> } >> - rc = system(cmnd); >> >> - if (log_fd != -1) >> - close(log_fd); >> + while (fgets(cmnd, sizeof(cmnd), logsource)) { >> + /* ignore lines that dont contain 'ipr' */ >> + if (strstr(cmnd, "ipr") == NULL) >> + continue; >> + >> + write(log_fd, cmnd, strlen(cmnd)); >> + } >> + >> + fclose(logsource); >> + close(log_fd); >> + rc = invoke_pager(logfile); >> >> if ((rc != 0) && (rc != 127)) { >> s_status.num = rc; >> diff --git a/iprlib.c b/iprlib.c >> index c5dfd8bb50c0..26c7a500d29b 100644 >> --- a/iprlib.c >> +++ b/iprlib.c >> @@ -10079,3 +10079,23 @@ int ipr_jbod_sysfs_bind(struct ipr_dev *dev, u8 op) >> close(fd); >> return 0; >> } >> + >> +int invoke_pager(char *filename) >> +{ >> + int pid, status; >> + char *argv[] = { >> + "/usr/bin/less", "-c", > > Replace with macro DEFAULT_EDITOR. Done. >> + filename, NULL >> + }; >> + >> + pid = fork(); >> + if (pid) { >> + waitpid(pid, &status, 0); >> + } else { >> + /* disable insecure pager features */ >> + putenv("LESSSECURE=1"); >> + execv(argv[0], argv); >> + _exit(errno); >> + } >> + return WEXITSTATUS(status); >> +} >> diff --git a/iprlib.h b/iprlib.h >> index 16fe1e162650..cec70cd976a7 100644 >> --- a/iprlib.h >> +++ b/iprlib.h >> @@ -38,6 +38,7 @@ >> #include <sys/stat.h> >> #include <sys/types.h> >> #include <sys/socket.h> >> +#include <sys/wait.h> >> #include <ctype.h> >> #include <syslog.h> >> #include <term.h> >> @@ -49,6 +50,7 @@ >> #include <bits/sockaddr.h> >> #include <linux/netlink.h> >> #include <time.h> >> +#include <zlib.h> >> >> typedef uint8_t u8; >> typedef uint16_t u16; >> @@ -2906,6 +2908,7 @@ u32 get_ioa_ucode_version(char *); >> int ipr_improper_device_type(struct ipr_dev *); >> int ipr_get_fw_version(struct ipr_dev *, u8 release_level[4]); >> int ipr_get_live_dump(struct ipr_ioa *); >> +int invoke_pager(char *filename); >> >> static inline u32 ipr_get_dev_res_handle(struct ipr_ioa *ioa, struct >> ipr_dev_record *dev_rcd) >> { >> diff --git a/spec/iprutils.spec b/spec/iprutils.spec >> index 461d97799786..fe246e4f7b2c 100644 >> --- a/spec/iprutils.spec >> +++ b/spec/iprutils.spec >> @@ -8,7 +8,7 @@ Vendor: IBM >> URL: http://sourceforge.net/projects/iprdd/ >> Source0: iprutils-%{version}.tar.gz >> BuildRoot: %{_tmppath}/%{name}-root >> -BuildRequires: ncurses-devel >> +BuildRequires: ncurses-devel zlib-devel >> >> # Predicate whether we want to build -static package. >> %bcond_with static > > This breaks static build. In a RHEL system, we have the zlib-static > package, other distros will have similar packages. Please add them as > proper build dependencies for the static subpackage. > Right. I had some difficulties with that, but as we talked in private these should be sorted out now. I did some tests on building and it looks alright now. If I missed anything again, please let me know. I'll send v2 to the list shortly. > Thanks, > Thank you, -- Heitor Ricardo Alves de Siqueira IBM Linux Technology Center ------------------------------------------------------------------------------ Site24x7 APM Insight: Get Deep Visibility into Application Performance APM + Mobile APM + RUM: Monitor 3 App instances at just $35/Month Monitor end-to-end web transactions and take corrective actions now Troubleshoot faster and improve end-user experience. Signup Now! http://pubads.g.doubleclick.net/gampad/clk?id=267308311&iu=/4140 _______________________________________________ Iprdd-devel mailing list Iprdd-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/iprdd-devel