/*************************************************************************** * Pinfo is a ncurses based lynx style info documentation browser * * Copyright (C) 1999 Przemek Borys * Copyright (C) 2005 Bas Zoetekouw * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 * USA ***************************************************************************/ #include "common_includes.h" RCSID(PKG_VER "$Id: pinfo.c 280 2006-03-09 19:44:48Z bas $") #ifdef HAVE_GETOPT_LONG #include #endif char *version = VERSION; int DontHandleWithoutTagTable = 0; /* currently viewed filename */ char *curfile = 0; /* node specified by --node option */ char *pinfo_start_node = 0; /* strip `.info' suffix from "file" */ void strip_file_from_info_suffix(char *file); /* add `.info' suffix to "file" */ char *addinfosuffix(char *file); /* protect against bad, bad macros */ void checksu(); int main(int argc, char *argv[]) { int filenotfound = 0; char filename[256]; WorkRVal work_return_value = {0, 0}; int i, userdefinedrc = 0; int command_line_option; FILE *id = NULL; /* line count in message */ long lines = 0; /* this will hold node's text */ char **message = 0; /* this will hold the node's header */ char *type = 0; int tag_table_pos = 1; char *file_name_force = NULL; #ifdef HAVE_GETOPT_LONG static struct option long_options[] = { {"help", 0, 0, 'h'}, {"version", 0, 0, 'v'}, {"manual", 0, 0, 'm'}, {"file", 0, 0, 'f'}, {"raw-filename", 0, 0, 'r'}, {"apropos", 0, 0, 'a'}, {"plain-apropos", 0, 0, 'p'}, {"cut-man-headers", 0, 0, 'c'}, {"squeeze-manlines", 0, 0, 's'}, {"dont-handle-without-tag-table", 0, 0, 'd'}, {"force-manual-tag-table", 0, 0, 't'}, {"node", 1, 0, 'n'}, {"long-manual-links", 0, 0, 'l'}, {"clear-at-exit", 0, 0, 'x'}, /* no one-letter shortcut :( */ {"rcfile", 1, 0, 1}, {0, 0, 0, 0}}; #endif /* take care of SIGSEGV, SIGTERM, SIGINT */ signal_handler(); searchagain.type = 0; searchagain.search = 0; initlocale(); inithistory(); for (i = 1; i < argc; i++) if (strncmp(argv[i], "--rcfile", 8) == 0) userdefinedrc = 1; /* read config information */ if (!userdefinedrc) parse_config(); if (verbose) printf("Przemek's Info Viewer v%s\n", version); /* if no arguments were given */ if (argc == 1) { id = openinfo("dir", 0); curfile = xmalloc(150); strcpy(curfile, "dir"); strcpy(filename, "dir"); } if ((strlen(argv[0]) >= 3)||(use_manual)) /* handle any 'man' alias to 'pinfo' */ if ((strstr(argv[0], "man") != NULL)||(use_manual)) { if (verbose) printf(_("Looking for man page...\n")); strcpy(filename, ""); /* * pass all arguments to the `man' command(manhandler calls * `man') */ for (i = 1; i < argc; i++) { strcat(filename, argv[i]); strcat(filename, " "); } exit(handlemanual(filename)); } #ifdef HAVE_GETOPT_LONG /****************************************************************************** * Parse command line options(getopt) * ******************************************************************************/ do { char *tmp; command_line_option = getopt_long(argc, argv, "hvmfrapcsdtnlx", long_options, NULL); switch(command_line_option) { case 'x': ClearScreenAtExit = 1; break; case 'l': LongManualLinks = 1; break; case 'n': if (!optarg) { printf(_("--node option used without argument\n")); exit(1); } pinfo_start_node = malloc(strlen(optarg) + 1); strcpy(pinfo_start_node, optarg); break; /* rcfile */ case 1: if (!optarg) { printf(_("--rcfile option used without argument\n")); exit(1); } rcfile = strdup(optarg); /* parse user-defined config file */ parse_config(); break; case 't': ForceManualTagTable = 1; break; case 'h': printf(_("Usage:\n" \ "%s [options] [info|manual]\n" \ "Options:\n" \ "-h, --help help\n" \ "-v, --version version\n" \ "-m, --manual use man page\n" \ "-r, --raw-filename use raw filename\n" \ "-f, --file synonym for -r\n" \ "-a, --apropos call apropos if nothing found\n" \ "-p, --plain-apropos call only apropos\n" \ "-c, --cut-man-headers cut out repeated man headers\n" \ "-l, --long-manual-links use long link names in manuals\n" \ "-s, --squeeze-manlines cut empty lines from manual pages\n" \ "-d, --dont-handle-without-tag-table don't display texinfo pages without tag\n" \ " tables\n" \ "-t, --force-manual-tag-table force manual detection of tag table\n" \ "-x, --clear-at-exit clear screen at exit\n" \ " --node=nodename, --node nodename jump directly to the node nodename\n" \ " --rcfile=file, --rcfile file use alternate rcfile\n"), argv[0]); exit(0); case 'v': exit(0); case 'm': checksu(); if (verbose) printf(_("Looking for man page...\n")); strcpy(filename, ""); for (i = optind; i < argc; i++) { strcat(filename, argv[i]); strcat(filename, " "); } exit(handlemanual(filename)); case 'f': case 'r': strncpy(filename, argv[argc - 1], 200); /* security check */ checkfilename(filename); /* add the raw path to searchpath */ addrawpath(filename); tmp = filename + strlen(filename) - 1; /* later, openinfo automaticaly adds them */ strip_compression_suffix(filename); /* get basename */ while ((tmp > filename) &&(*tmp != '/')) tmp--; if (*tmp == '/') tmp++; /* and try it without '.info' suffix */ id = openinfo(tmp, 0); break; case 'a': use_apropos = 1; break; case 'p': use_apropos = 1; plain_apropos = 1; strncpy(filename, argv[argc - 1], 200); exit(handlemanual(filename)); break; case 'c': CutManHeaders = 1; break; case 'd': DontHandleWithoutTagTable = 1; break; case 's': CutEmptyManLines = 1; break; } } while (command_line_option != EOF); /***************************************************************/ #endif checksu(); initpaths(); if (argc > 1) { #ifdef HAVE_GETOPT_LONG if (optind < argc) { /* the paths will be searched by openinfo() */ strncpy(filename, argv[optind], 200); } else { strcpy(filename, "dir"); } #else /* the paths will be searched by openinfo() */ strncpy(filename, argv[argc - 1], 200); #endif if (filename[0]=='(') { int fnamelen=strlen(filename); /* erase the leading '(' */ for (i=0;i 5) { if (strcmp(file + strlen(file) - 5, ".info") == 0) { file = file + strlen(file) - 5; *file = 0; } } } char * addinfosuffix(char *info) { char *withsuffix = xmalloc(strlen(info) + 150); strcpy(withsuffix, info); if (strlen(info) == 3) { if (strcmp("dir", info) != 0) strcat(withsuffix, ".info"); } else strcat(withsuffix, ".info"); return withsuffix; } /* * If pinfo was called by root then it should work as nobody. * This protect us against .pso and .open macros which could * be used for breaking the system's security. */ void checksu() { struct passwd *pswd; struct group *grwd; if (!getegid() || !getgid()) { grwd = getgrnam(safe_group); if (!grwd) { if (verbose) { printf(_("Security warning: Unable to get GID of group called: %s\n"), safe_group); sleep(1); } } else { if (!getgid() && !getuid()) setgid(grwd->gr_gid); else setegid(grwd->gr_gid); } } if (!geteuid() || !getuid()) { pswd = getpwnam(safe_user); if (!pswd) { if (verbose) { printf(_("Security warning: Unable to get UID of user called: %s\n"), safe_user); sleep(1); } } else { if (!getuid()) setuid(pswd->pw_uid); else seteuid(pswd->pw_uid); } } }