Beispiel #1
0
//outputs fastQ unless add_greedy_bases_for_better_bwt_compression==true, in which case is for 1000genomes, and they want fastA
inline void error_correct_file_against_graph(char* fastq_file, char quality_cutoff, char ascii_qual_offset,
        dBGraphEc *db_graph, char* outfile,
        uint64_t *bases_modified_count_array,//distribution across reads; how many of the read_length bases are fixed
        uint64_t *posn_modified_count_array,//where in the read are we making corrections?
        int bases_modified_count_array_size,
        int min_read_len,
        HandleLowQualUncorrectable policy,
        boolean add_greedy_bases_for_better_bwt_compression,
        int num_greedy_bases,
        boolean rev_comp_read_if_on_reverse_strand)
{
    int max_read_len = bases_modified_count_array_size - 2;
    int read_len_upper_bound = max_read_len + num_greedy_bases;
    int read_len_lower_bound = min_read_len + num_greedy_bases;
    int read_len_final = 0;

    //reset the stats arrays, we get stats per input file
    set_uint64_t_array(bases_modified_count_array,bases_modified_count_array_size, (uint64_t) 0);
    set_uint64_t_array(posn_modified_count_array, bases_modified_count_array_size, (uint64_t) 0);


    //set some variables, quality etc
    quality_cutoff+=ascii_qual_offset;
    short kmer_size = db_graph->kmer_size;

    StrBuf* uncorrectedGoodQual_file = strbuf_create(outfile);
    StrBuf* uncorrectedLowQual_file = strbuf_create(outfile);
    StrBuf* corrected_file = strbuf_create(outfile);
    StrBuf* discarded_undefined_file = strbuf_create(outfile);
    StrBuf* discarded_uncorrectable_file = strbuf_create(outfile);
    StrBuf* discarded_shortread_file = strbuf_create(outfile);


    strbuf_append_str(uncorrectedGoodQual_file, ".printuncorrectedgoodqual");
    strbuf_append_str(uncorrectedLowQual_file, ".printuncorrectedlowqual");
    strbuf_append_str(corrected_file, ".printcorrected");
    strbuf_append_str(discarded_undefined_file, ".discardundefinedbase");
    strbuf_append_str(discarded_uncorrectable_file, ".discarduncorrectable");
    strbuf_append_str(discarded_shortread_file, ".discardshortread");

    FILE* uncorrectedGoodQual_fp = fopen(uncorrectedGoodQual_file->buff, "w");
    FILE* uncorrectedLowQual_fp = fopen(uncorrectedLowQual_file->buff, "w");
    FILE* corrected_fp = fopen(corrected_file->buff, "w");
    FILE* discarded_undefined_fp = fopen(discarded_undefined_file->buff, "w");
    FILE* discarded_uncorrectable_fp = fopen(discarded_uncorrectable_file->buff, "w");
    FILE* discarded_shortread_fp = fopen(discarded_shortread_file->buff, "w");

    char* suff1 = ".distrib_num_modified_bases";
    char* suff2 = ".distrib_posn_modified_bases";
    char* suff3 =".read_stats";
    char* stat1 = (char*) malloc(sizeof(char)*(strlen(outfile)+strlen(suff1)+1));
    char* stat2 = (char*) malloc(sizeof(char)*(strlen(outfile)+strlen(suff2)+1));
    char* stat3 = (char*) malloc(sizeof(char)*(strlen(outfile)+strlen(suff3)+1));

    if ( (stat1==NULL) || (stat2==NULL) || (stat3==NULL) )
    {
        die("Unable to malloc FILENAME strings. Something badly wrong with your server\n");
    }
    set_string_to_null(stat1, strlen(outfile)+strlen(suff1)+1);
    set_string_to_null(stat2, strlen(outfile)+strlen(suff2)+1);
    set_string_to_null(stat3, strlen(outfile)+strlen(suff3)+1);
    strcpy(stat1, outfile);
    strcat(stat1, suff1);
    strcat(stat2, outfile);
    strcat(stat2, suff2);
    strcat(stat3, outfile);
    strcat(stat3, suff3);

    FILE* out_stat1 = fopen(stat1, "w");
    FILE* out_stat2 = fopen(stat2, "w");
    FILE* out_stat3 = fopen(stat3, "w");
    if ( (out_stat1==NULL)|| (out_stat2==NULL) || (out_stat3==NULL) )
    {
        die("Unable to open %s or %s or %s to write to - permissions issue?\n", stat1, stat2, stat3);
    }

    SeqFile *sf = seq_file_open(fastq_file);
    if(sf == NULL)
    {
        // Error opening file
        fprintf(stderr, "Error: cannot read seq file '%s'\n", fastq_file);
        exit(EXIT_FAILURE);
    }
    char is_fastq = seq_has_quality_scores(sf);
    if (is_fastq==0)
    {
        die("Error correction is only meant to work on FASTQ and this file: %s is not\n", fastq_file);
    }

    StrBuf* buf_seq  = strbuf_new();
    StrBuf* buf_qual = strbuf_new();
    StrBuf* working_buf=strbuf_new();
    dBNodeEc* last_node_in_read;
    Orientation last_or_in_read;
    int num_original_reads=0, num_final_reads=0, num_corrected_reads=0, num_discarded_reads=0;
    int num_discarded_undefined = 0;
    int num_discarded_uncorrectable = 0;
    int num_discarded_short_read = 0;
    int num_print_uncorrected_lowqual = 0;
    int num_print_uncorrected_goodqual = 0;
    int num_print_corrected = 0;

    StrBuf* buf_dashes = strbuf_create("---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");

    while(seq_next_read(sf))
    {
        int count_corrected_bases=0;
        //NOTE - uses modified version fo Isaacs code - new func
        seq_read_all_bases_and_quals(sf, buf_seq, buf_qual);
        StrBuf* buf_seq_debug  = strbuf_clone(buf_seq);
        StrBuf* buf_seq_origin  = strbuf_clone(buf_seq);
        StrBuf* buf_seq_fixed = strbuf_clone(buf_dashes);
        strbuf_resize(buf_seq_fixed, strbuf_len(buf_seq)+1);

        int read_len = seq_get_length(sf);
        int num_kmers = read_len-kmer_size+1;
        int quality_good[read_len];
        set_int_array(quality_good, read_len, 1);

        int first_good=0;//index of first kmer in graph

        //populate the qual array showing which bases have qual >threshold
        //if all quals are high, will Print uncorrected
        //else, if all kmers NOT in graph, will discard or print uncorrected depending on policy
        //else print corrected.
        Orientation strand_first_good_kmer;
        ReadCorrectionDecison dec =
            get_first_good_kmer_and_populate_qual_array(seq_get_read_name(sf), buf_seq, buf_qual, num_kmers, read_len,
                    quality_good, quality_cutoff,
                    &first_good, &strand_first_good_kmer,
                    db_graph, policy, rev_comp_read_if_on_reverse_strand);


        //*** start of local functions

        //if going right, keep going to right hand end. if going left, keep going to left hand end
        boolean condition(WhichEndOfKmer direction, int pos)
        {
            if ((direction==Right) && (pos<num_kmers))
            {
                return true;
            }
            if ((direction==Left) && (pos>=0))
            {
                return true;
            }
            return false;
        }
        boolean kmer_is_in_graph(char* kmer, dBGraphEc* db_g)
        {
            BinaryKmer curr_kmer;
            if (seq_to_binary_kmer(kmer, kmer_size, &curr_kmer)==NULL)
            {
                //is an N
                return false;
            }

            BinaryKmer temp_key;
            element_ec_get_key(&curr_kmer, kmer_size, &temp_key);
            dBNodeEc* node = hash_table_ec_find(&temp_key, db_g);
            if (node==NULL)
            {
                return false;
            }
            else
            {
                return true;
            }
        }
        int increment(int i, WhichEndOfKmer direction)
        {
            if (direction==Right)
            {
                return i+1;
            }
            else
            {
                return i-1;
            }
        }
        char working_str[kmer_size+1];

        // start_pos is in kmer units
        boolean check_bases_to_end_of_read(int start_pos, ReadCorrectionDecison* decision,
                                           WhichEndOfKmer direction,
                                           int* num_corrected_bases_in_this_read_debug)

        {
            boolean any_correction_done=false;
            if ((start_pos<0) || (start_pos>=num_kmers))
            {
                return any_correction_done;
            }
            int pos=start_pos;
            int offset=0;
            if (direction==Right)
            {
                offset= kmer_size-1;
            }
            char local_kmer[kmer_size+1];
            local_kmer[kmer_size]='\0';

            while ( (*decision==PrintCorrected) && (condition(direction,pos)==true) )
            {
                strncpy(local_kmer, buf_seq->buff+pos, kmer_size);

                if (quality_good[pos+offset]==1)
                {
                    //nothing to do
                }
                else if (kmer_is_in_graph(local_kmer, db_graph)==true)
                {
                    //nothing to do - don't correct if kmer is in graph
                }
                else//kmer not in graph and quality bad
                {
                    boolean fixed = fix_end_if_unambiguous(direction, buf_seq, buf_seq_fixed, buf_qual, quality_cutoff, pos,
                                                           working_buf, working_str, db_graph);
                    if ( (policy==DiscardReadIfLowQualBaseUnCorrectable)
                            &&
                            (fixed==false) )
                    {
                        *decision=DiscardUncorrectable;
                    }
                    else if (fixed==true)
                    {
                        any_correction_done=true;
                        count_corrected_bases++;
                        *num_corrected_bases_in_this_read_debug=*num_corrected_bases_in_this_read_debug+1;
                        if (offset+pos<bases_modified_count_array_size)
                        {
                            posn_modified_count_array[offset+pos]++;
                        }
                        else
                        {
                            posn_modified_count_array[bases_modified_count_array_size-1]++;
                        }
                    }
                }
                pos = increment(pos, direction);
            }
            return any_correction_done;
        }
Beispiel #2
0
/* Quote STRING with double quotes if QUOTED is true, otherwise
 * by escaping whitespace, double quote and backslash as well
 * as characters in QC. Also, if the first character in STRING
 * is found in LEADING_QC, that character will be escaped.
 */
char *
quote_word_full(const char *string, bool quoted, bool add_end_quote,
		const char *qc, const char *leading_qc, bool quote_non_print_hex,
		bool quote_non_print_oct, bool quote_non_print_c, bool quote_wc)
{
    StrBuf *r = strbuf_new();
    const char *s;
    const unsigned char *u_s;

    if (quoted) {
        strbuf_append_char(r, '"');
        for (s = string; *s != '\0'; s++) {
	    if (quote_non_print_c) {
		int chr = 0;
		switch (*s) {
		case '\a': chr = 'a'; break;
		case '\b': chr = 'b'; break;
		case '\f': chr = 'f'; break;
		case '\n': chr = 'n'; break;
		case '\r': chr = 'r'; break;
		case '\t': chr = 't'; break;
		case '\v': chr = 'v'; break;
		}
		if (chr != 0) {
		    strbuf_appendf(r, "\\%c", chr);
		    continue;
		}
	    }
	    u_s = (const unsigned char *)s;
            if (quote_non_print_hex && !isprint(*u_s)) {
                strbuf_appendf(r, "\\x%02x", (unsigned)*s);
	    } else if (quote_non_print_oct && !isprint(*u_s)) {
		strbuf_appendf(r, "\\%03o", (unsigned)*s);
            } else {
                if (*s == '"' || *s == '\\')
                    strbuf_append_char(r, '\\');
                strbuf_append_char(r, *s);
            }
        }
        if (add_end_quote)
            strbuf_append_char(r, '"');
    } else {
        for (s = string; *s != '\0'; s++) {
	    if (quote_non_print_c) {
		int chr = 0;
		switch (*s) {
		case '\a': chr = 'a'; break;
		case '\b': chr = 'b'; break;
		case '\f': chr = 'f'; break;
		case '\n': chr = 'n'; break;
		case '\r': chr = 'r'; break;
		case '\t': chr = 't'; break;
		case '\v': chr = 'v'; break;
		}
		if (chr != 0) {
		    strbuf_appendf(r, "\\%c", chr);
		    continue;
		}
	    }
	    u_s = (const unsigned char *)s;
            if (quote_non_print_hex && !isprint(*u_s)) {
                strbuf_appendf(r, "\\x%02x", (unsigned)*s);
	    } else if (quote_non_print_oct && !isprint(*u_s)) {
		strbuf_appendf(r, "\\%03o", (unsigned)*u_s);
	    } else {
	        if (*s == '"'
      	                || *s == '\\'
	                || (quote_wc && *s == ' ')
  		        || strchr(qc, *s) != NULL
		        || (s == string && strchr(leading_qc, *u_s) != NULL))
		    strbuf_append_char(r, '\\');
                strbuf_append_char(r, *s);
            }
        }
    }

    return strbuf_free_to_string(r);
}
Beispiel #3
0
int main(int argc, char **argv)
{
    abrt_init(argv);
    enum {
        OPT_v = 1 << 0,
        OPT_d = 1 << 1,
        OPT_g = 1 << 2,
        OPT_b = 1 << 3,
        OPT_u = 1 << 4,
        OPT_r = 1 << 5,
    };

    const char *bugs = NULL, *release = NULL, *dump_dir_path = ".";
    /* Keep enum above and order of options below in sync! */
    struct options program_options[] = {
        OPT__VERBOSE(&g_verbose),
        OPT__DUMP_DIR(&dump_dir_path),
        OPT_GROUP(""),
        OPT_STRING('b', "bugs", &bugs, "ID1[,ID2,...]" , _("List of bug ids")),
        OPT_STRING('u', "url", &bodhi_url, "URL", _("Specify a bodhi server url")),
        OPT_OPTSTRING('r', "release", &release, "RELEASE", _("Specify a release")),
        OPT_END()
    };

    const char *program_usage_string = _(
        "& [-v] [-r[RELEASE]] (-b ID1[,ID2,...] | PKG-NAME) [PKG-NAME]... \n"
        "\n"
        "Search for updates on bodhi server"
    );

    unsigned opts =  parse_opts(argc, argv, program_options, program_usage_string);

    if (!bugs && !argv[optind])
        show_usage_and_die(program_usage_string, program_options);

    struct strbuf *query = strbuf_new();
    if (bugs)
        query = strbuf_append_strf(query, "bugs=%s&", bugs);

    if (opts & OPT_r)
    {
        if (release)
        {
            query = strbuf_append_strf(query, "release=%s&", release);
        }
        else
        {
            struct dump_dir *dd = dd_opendir(dump_dir_path, DD_OPEN_READONLY);
            if (!dd)
                xfunc_die();

            problem_data_t *problem_data = create_problem_data_from_dump_dir(dd);
            dd_close(dd);
            if (!problem_data)
                xfunc_die(); /* create_problem_data_for_reporting already emitted error msg */

            char *product, *version;
            map_string_t *osinfo = new_map_string();
            problem_data_get_osinfo(problem_data, osinfo);
            parse_osinfo_for_rhts(osinfo, &product, &version);
            query = strbuf_append_strf(query, "release=f%s&", version);
            free(product);
            free(version);
            free_map_string(osinfo);
        }
    }

    if (argv[optind])
    {
        char *escaped = g_uri_escape_string(argv[optind], NULL, 0);
        query = strbuf_append_strf(query, "package=%s&", escaped);
        free(escaped);
    }

    if (query->buf[query->len - 1] == '&')
        query->buf[query->len - 1] = '\0';

    log(_("Searching for updates"));
    GHashTable *update_hash_tbl = bodhi_query_list(query->buf, release);
    strbuf_free(query);

    if (!update_hash_tbl || !g_hash_table_size(update_hash_tbl))
    {
        log(_("No updates for this package found"));
        /*if (update_hash_tbl) g_hash_table_unref(update_hash_tbl);*/
        return 0;
    }

    GHashTableIter iter;
    char *name;
    struct bodhi *b;
    struct strbuf *q = strbuf_new();
    g_hash_table_iter_init(&iter, update_hash_tbl);
    while (g_hash_table_iter_next(&iter, (void **) &name, (void **) &b))
    {
        char *installed_pkg_nvr = rpm_get_nvr_by_pkg_name(name);
        if (installed_pkg_nvr && rpmvercmp(installed_pkg_nvr, b->nvr) >= 0)
        {
            log_info("Update %s is older or same as local version %s, skipping", b->nvr, installed_pkg_nvr);
            free(installed_pkg_nvr);
            continue;
        }
        free(installed_pkg_nvr);

        strbuf_append_strf(q, " %s", b->nvr);
    }

    /*g_hash_table_unref(update_hash_tbl);*/

    if (!q->len)
    {
        /*strbuf_free(q);*/
        log(_("Local version of the package is newer than available updates"));
        return 0;
    }

    /* Message is split into text and command in order to make
     * translator's job easier
     */

    /* We suggest the command which is most likely to exist on user's system,
     * and which is familiar to the largest population of users.
     * There are other tools (pkcon et al) which might be somewhat more
     * convenient (for example, they might be usable from non-root), but they
     * might be not present on the system, may evolve or be superseded,
     * while yum is unlikely to do so.
     */
    strbuf_prepend_str(q, "yum update --enablerepo=fedora --enablerepo=updates-testing");

    char *msg = xasprintf(_("An update exists which might fix your problem. "
                "You can install it by running: %s. "
                "Do you want to continue with reporting the bug?"),
                q->buf
    );
    /*strbuf_free(q);*/

    return !ask_yes_no(msg);
}
Beispiel #4
0
int main(int argc, char** argv)
{
  if(argc < 3 || argc > 4)
  {
    print_usage();
  }

  char* in_path = argv[1];
  char* out_path = argv[2];

  unsigned long line_wrap = 0;
  
  if(argc == 4)
  {
    char *line_wrap_str = argv[3];
    char *endptr;
    line_wrap = strtoul(line_wrap_str, &endptr, 10);

    if((unsigned)(endptr-line_wrap_str) != strlen(line_wrap_str))
    {
      print_usage();
    }
  }

  SeqFileType out_file_type = SEQ_UNKNOWN;
  char out_zipped = 0;

  seq_guess_filetype_from_path(out_path, &out_file_type, &out_zipped);

  if(out_file_type == SEQ_UNKNOWN)
  {
    fprintf(stderr, "Sorry, I cannot identify the output file's format "
                    "from its path\n");
    exit(EXIT_FAILURE);
  }

  SeqFile* in_file = seq_file_open(in_path);
  SeqFile* out_file = seq_file_open_write(out_path, out_file_type,
                                          out_zipped, line_wrap);

  if(in_file == NULL)
  {
    fprintf(stderr, "Couldn't open input file: %s\n", in_path);
    exit(EXIT_FAILURE);
  }

  if(out_file == NULL)
  {
    fprintf(stderr, "Couldn't open output file: %s\n", out_path);
    exit(EXIT_FAILURE);
  }

  printf(" In : %s [%s]\n", in_path, seq_file_get_type_str(in_file));
  printf(" Out: %s [%s]\n", out_path, seq_file_get_type_str(out_file));

  // Start converting
  size_t bytes_written = 0;
  char c[2] = ".";

  if(out_file_type == SEQ_PLAIN)
  {
    // Example reading in an entire at a time using seq_read_all_bases()
    StrBuf *bases = strbuf_new();

    while(seq_next_read(in_file))
    {
      while(seq_read_all_bases(in_file, bases))
      {
        bytes_written += seq_file_write_seq(out_file, bases->buff);
      }
    }
  }
  else
  {
    // Example reading in a char at a time using seq_read_base()
    while(seq_next_read(in_file))
    {
      const char* read_name = seq_get_read_name(in_file);
      bytes_written += seq_file_write_name(out_file, read_name);

      unsigned long seq_length = 0;

      while(seq_read_base(in_file, c))
      {
        seq_length++;

        if(!(bytes_written += seq_file_write_seq(out_file, c)))
        {
          fprintf(stderr, "Couldn't write base to file\n");
          exit(EXIT_FAILURE);
        }
      }
    
      if(seq_has_quality_scores(out_file))
      {
        size_t bytes_written_before_qual = bytes_written;

        while(seq_read_qual(in_file, c))
        {
          if(!(bytes_written += seq_file_write_qual(out_file, c)))
          {
            fprintf(stderr, "Couldn't write quality score to file\n");
            exit(EXIT_FAILURE);
          }
        }

        if(bytes_written == bytes_written_before_qual)
        {
          // No quality score were read - fill in
          unsigned long i;
          *c = '?';
          for(i = 0; i < seq_length; i++)
            bytes_written += seq_file_write_qual(out_file, c);
        }
      }
    }
  }

  seq_file_close(in_file);
  bytes_written += seq_file_close(out_file);

  printf("%lu bases read\n", seq_total_bases_passed(in_file));
  printf("%lu bytes written\n", bytes_written);
  printf("Done. \n");

  return EXIT_SUCCESS;
}
Beispiel #5
0
int main(int argc, char **argv)
{
    bool sending;
    SOCKET *sklist;
    size_t skcount, sksize;
    int exitcode;
    bool errors;
    bool use_subsystem = false;
    bool just_test_share_exists = false;
    enum TriState sanitise_stdout = AUTO, sanitise_stderr = AUTO;
    unsigned long now, next, then;
    const struct BackendVtable *vt;

    dll_hijacking_protection();

    sklist = NULL;
    skcount = sksize = 0;
    /*
     * Initialise port and protocol to sensible defaults. (These
     * will be overridden by more or less anything.)
     */
    default_protocol = PROT_SSH;
    default_port = 22;

    flags = 0;
    cmdline_tooltype |=
        (TOOLTYPE_HOST_ARG |
         TOOLTYPE_HOST_ARG_CAN_BE_SESSION |
         TOOLTYPE_HOST_ARG_PROTOCOL_PREFIX |
         TOOLTYPE_HOST_ARG_FROM_LAUNCHABLE_LOAD);

    /*
     * Process the command line.
     */
    conf = conf_new();
    do_defaults(NULL, conf);
    loaded_session = false;
    default_protocol = conf_get_int(conf, CONF_protocol);
    default_port = conf_get_int(conf, CONF_port);
    errors = false;
    {
	/*
	 * Override the default protocol if PLINK_PROTOCOL is set.
	 */
	char *p = getenv("PLINK_PROTOCOL");
	if (p) {
            const struct BackendVtable *vt = backend_vt_from_name(p);
            if (vt) {
                default_protocol = vt->protocol;
                default_port = vt->default_port;
		conf_set_int(conf, CONF_protocol, default_protocol);
		conf_set_int(conf, CONF_port, default_port);
	    }
	}
    }
    while (--argc) {
	char *p = *++argv;
        int ret = cmdline_process_param(p, (argc > 1 ? argv[1] : NULL),
                                        1, conf);
        if (ret == -2) {
            fprintf(stderr,
                    "plink: option \"%s\" requires an argument\n", p);
            errors = true;
        } else if (ret == 2) {
            --argc, ++argv;
        } else if (ret == 1) {
            continue;
        } else if (!strcmp(p, "-batch")) {
            console_batch_mode = true;
        } else if (!strcmp(p, "-s")) {
            /* Save status to write to conf later. */
            use_subsystem = true;
        } else if (!strcmp(p, "-V") || !strcmp(p, "--version")) {
            version();
        } else if (!strcmp(p, "--help")) {
            usage();
        } else if (!strcmp(p, "-pgpfp")) {
            pgp_fingerprints();
            exit(1);
        } else if (!strcmp(p, "-shareexists")) {
            just_test_share_exists = true;
        } else if (!strcmp(p, "-sanitise-stdout") ||
                   !strcmp(p, "-sanitize-stdout")) {
            sanitise_stdout = FORCE_ON;
        } else if (!strcmp(p, "-no-sanitise-stdout") ||
                   !strcmp(p, "-no-sanitize-stdout")) {
            sanitise_stdout = FORCE_OFF;
        } else if (!strcmp(p, "-sanitise-stderr") ||
                   !strcmp(p, "-sanitize-stderr")) {
            sanitise_stderr = FORCE_ON;
        } else if (!strcmp(p, "-no-sanitise-stderr") ||
                   !strcmp(p, "-no-sanitize-stderr")) {
            sanitise_stderr = FORCE_OFF;
        } else if (!strcmp(p, "-no-antispoof")) {
            console_antispoof_prompt = false;
	} else if (*p != '-') {
            strbuf *cmdbuf = strbuf_new();

            while (argc > 0) {
                if (cmdbuf->len > 0)
                    put_byte(cmdbuf, ' '); /* add space separator */
                put_datapl(cmdbuf, ptrlen_from_asciz(p));
                if (--argc > 0)
                    p = *++argv;
            }

            conf_set_str(conf, CONF_remote_cmd, cmdbuf->s);
            conf_set_str(conf, CONF_remote_cmd2, "");
            conf_set_bool(conf, CONF_nopty, true);  /* command => no tty */

            strbuf_free(cmdbuf);
            break;		       /* done with cmdline */
        } else {
            fprintf(stderr, "plink: unknown option \"%s\"\n", p);
            errors = true;
        }
    }

    if (errors)
	return 1;

    if (!cmdline_host_ok(conf)) {
	usage();
    }

    prepare_session(conf);

    /*
     * Perform command-line overrides on session configuration.
     */
    cmdline_run_saved(conf);

    /*
     * Apply subsystem status.
     */
    if (use_subsystem)
        conf_set_bool(conf, CONF_ssh_subsys, true);

    if (!*conf_get_str(conf, CONF_remote_cmd) &&
	!*conf_get_str(conf, CONF_remote_cmd2) &&
	!*conf_get_str(conf, CONF_ssh_nc_host))
	flags |= FLAG_INTERACTIVE;

    /*
     * Select protocol. This is farmed out into a table in a
     * separate file to enable an ssh-free variant.
     */
    vt = backend_vt_from_proto(conf_get_int(conf, CONF_protocol));
    if (vt == NULL) {
	fprintf(stderr,
		"Internal fault: Unsupported protocol found\n");
	return 1;
    }

    sk_init();
    if (p_WSAEventSelect == NULL) {
	fprintf(stderr, "Plink requires WinSock 2\n");
	return 1;
    }

    /*
     * Plink doesn't provide any way to add forwardings after the
     * connection is set up, so if there are none now, we can safely set
     * the "simple" flag.
     */
    if (conf_get_int(conf, CONF_protocol) == PROT_SSH &&
	!conf_get_bool(conf, CONF_x11_forward) &&
	!conf_get_bool(conf, CONF_agentfwd) &&
	!conf_get_str_nthstrkey(conf, CONF_portfwd, 0))
	conf_set_bool(conf, CONF_ssh_simple, true);

    logctx = log_init(default_logpolicy, conf);

    if (just_test_share_exists) {
        if (!vt->test_for_upstream) {
            fprintf(stderr, "Connection sharing not supported for connection "
                    "type '%s'\n", vt->name);
            return 1;
        }
        if (vt->test_for_upstream(conf_get_str(conf, CONF_host),
                                  conf_get_int(conf, CONF_port), conf))
            return 0;
        else
            return 1;
    }

    if (restricted_acl) {
        lp_eventlog(default_logpolicy, "Running with restricted process ACL");
    }

    /*
     * Start up the connection.
     */
    netevent = CreateEvent(NULL, false, false, NULL);
    {
	const char *error;
	char *realhost;
	/* nodelay is only useful if stdin is a character device (console) */
	bool nodelay = conf_get_bool(conf, CONF_tcp_nodelay) &&
	    (GetFileType(GetStdHandle(STD_INPUT_HANDLE)) == FILE_TYPE_CHAR);

        error = backend_init(vt, plink_seat, &backend, logctx, conf,
                             conf_get_str(conf, CONF_host),
                             conf_get_int(conf, CONF_port),
                             &realhost, nodelay,
                             conf_get_bool(conf, CONF_tcp_keepalives));
	if (error) {
	    fprintf(stderr, "Unable to open connection:\n%s", error);
	    return 1;
	}
	sfree(realhost);
    }

    inhandle = GetStdHandle(STD_INPUT_HANDLE);
    outhandle = GetStdHandle(STD_OUTPUT_HANDLE);
    errhandle = GetStdHandle(STD_ERROR_HANDLE);

    /*
     * Turn off ECHO and LINE input modes. We don't care if this
     * call fails, because we know we aren't necessarily running in
     * a console.
     */
    GetConsoleMode(inhandle, &orig_console_mode);
    SetConsoleMode(inhandle, ENABLE_PROCESSED_INPUT);

    /*
     * Pass the output handles to the handle-handling subsystem.
     * (The input one we leave until we're through the
     * authentication process.)
     */
    stdout_handle = handle_output_new(outhandle, stdouterr_sent, NULL, 0);
    stderr_handle = handle_output_new(errhandle, stdouterr_sent, NULL, 0);
    handle_sink_init(&stdout_hs, stdout_handle);
    handle_sink_init(&stderr_hs, stderr_handle);
    stdout_bs = BinarySink_UPCAST(&stdout_hs);
    stderr_bs = BinarySink_UPCAST(&stderr_hs);

    /*
     * Decide whether to sanitise control sequences out of standard
     * output and standard error.
     *
     * If we weren't given a command-line override, we do this if (a)
     * the fd in question is pointing at a console, and (b) we aren't
     * trying to allocate a terminal as part of the session.
     *
     * (Rationale: the risk of control sequences is that they cause
     * confusion when sent to a local console, so if there isn't one,
     * no problem. Also, if we allocate a remote terminal, then we
     * sent a terminal type, i.e. we told it what kind of escape
     * sequences we _like_, i.e. we were expecting to receive some.)
     */
    if (sanitise_stdout == FORCE_ON ||
        (sanitise_stdout == AUTO && is_console_handle(outhandle) &&
         conf_get_bool(conf, CONF_nopty))) {
        stdout_scc = stripctrl_new(stdout_bs, true, L'\0');
        stdout_bs = BinarySink_UPCAST(stdout_scc);
    }
    if (sanitise_stderr == FORCE_ON ||
        (sanitise_stderr == AUTO && is_console_handle(errhandle) &&
         conf_get_bool(conf, CONF_nopty))) {
        stderr_scc = stripctrl_new(stderr_bs, true, L'\0');
        stderr_bs = BinarySink_UPCAST(stderr_scc);
    }

    main_thread_id = GetCurrentThreadId();

    sending = false;

    now = GETTICKCOUNT();

    while (1) {
	int nhandles;
	HANDLE *handles;	
	int n;
	DWORD ticks;

        if (!sending && backend_sendok(backend)) {
	    stdin_handle = handle_input_new(inhandle, stdin_gotdata, NULL,
					    0);
	    sending = true;
	}

        if (toplevel_callback_pending()) {
            ticks = 0;
            next = now;
        } else if (run_timers(now, &next)) {
	    then = now;
	    now = GETTICKCOUNT();
	    if (now - then > next - then)
		ticks = 0;
	    else
		ticks = next - now;
	} else {
	    ticks = INFINITE;
            /* no need to initialise next here because we can never
             * get WAIT_TIMEOUT */
	}

	handles = handle_get_events(&nhandles);
	handles = sresize(handles, nhandles+1, HANDLE);
	handles[nhandles] = netevent;
	n = MsgWaitForMultipleObjects(nhandles+1, handles, false, ticks,
				      QS_POSTMESSAGE);
	if ((unsigned)(n - WAIT_OBJECT_0) < (unsigned)nhandles) {
	    handle_got_event(handles[n - WAIT_OBJECT_0]);
	} else if (n == WAIT_OBJECT_0 + nhandles) {
	    WSANETWORKEVENTS things;
	    SOCKET socket;
	    int i, socketstate;

	    /*
	     * We must not call select_result() for any socket
	     * until we have finished enumerating within the tree.
	     * This is because select_result() may close the socket
	     * and modify the tree.
	     */
	    /* Count the active sockets. */
	    i = 0;
	    for (socket = first_socket(&socketstate);
		 socket != INVALID_SOCKET;
		 socket = next_socket(&socketstate)) i++;

	    /* Expand the buffer if necessary. */
            sgrowarray(sklist, sksize, i);

	    /* Retrieve the sockets into sklist. */
	    skcount = 0;
	    for (socket = first_socket(&socketstate);
		 socket != INVALID_SOCKET;
		 socket = next_socket(&socketstate)) {
		sklist[skcount++] = socket;
	    }

	    /* Now we're done enumerating; go through the list. */
	    for (i = 0; i < skcount; i++) {
		WPARAM wp;
		socket = sklist[i];
		wp = (WPARAM) socket;
		if (!p_WSAEnumNetworkEvents(socket, NULL, &things)) {
                    static const struct { int bit, mask; } eventtypes[] = {
                        {FD_CONNECT_BIT, FD_CONNECT},
                        {FD_READ_BIT, FD_READ},
                        {FD_CLOSE_BIT, FD_CLOSE},
                        {FD_OOB_BIT, FD_OOB},
                        {FD_WRITE_BIT, FD_WRITE},
                        {FD_ACCEPT_BIT, FD_ACCEPT},
                    };
                    int e;

		    noise_ultralight(NOISE_SOURCE_IOID, socket);

                    for (e = 0; e < lenof(eventtypes); e++)
                        if (things.lNetworkEvents & eventtypes[e].mask) {
                            LPARAM lp;
                            int err = things.iErrorCode[eventtypes[e].bit];
                            lp = WSAMAKESELECTREPLY(eventtypes[e].mask, err);
                            select_result(wp, lp);
                        }
		}
	    }
	} else if (n == WAIT_OBJECT_0 + nhandles + 1) {
	    MSG msg;
	    while (PeekMessage(&msg, INVALID_HANDLE_VALUE,
			       WM_AGENT_CALLBACK, WM_AGENT_CALLBACK,
			       PM_REMOVE)) {
		struct agent_callback *c = (struct agent_callback *)msg.lParam;
		c->callback(c->callback_ctx, c->data, c->len);
		sfree(c);
	    }
	}

        run_toplevel_callbacks();

	if (n == WAIT_TIMEOUT) {
	    now = next;
	} else {
	    now = GETTICKCOUNT();
	}

	sfree(handles);

	if (sending)
            handle_unthrottle(stdin_handle, backend_sendbuffer(backend));

        if (!backend_connected(backend) &&
	    handle_backlog(stdout_handle) + handle_backlog(stderr_handle) == 0)
	    break;		       /* we closed the connection */
    }
    exitcode = backend_exitcode(backend);
    if (exitcode < 0) {
	fprintf(stderr, "Remote process exit code unavailable\n");
	exitcode = 1;		       /* this is an error condition */
    }
    cleanup_exit(exitcode);
    return 0;			       /* placate compiler warning */
}
Beispiel #6
0
/**
 *
 * @param[out] status See `man 2 wait` for status information.
 * @return Malloc'ed string
 */
static char* exec_vp(char **args, int redirect_stderr, int exec_timeout_sec, int *status)
{
    /* Nuke everything which may make setlocale() switch to non-POSIX locale:
     * we need to avoid having gdb output in some obscure language.
     */
    static const char *const env_vec[] = {
        "LANG",
        "LC_ALL",
        "LC_COLLATE",
        "LC_CTYPE",
        "LC_MESSAGES",
        "LC_MONETARY",
        "LC_NUMERIC",
        "LC_TIME",
        /* Workaround for
         * http://sourceware.org/bugzilla/show_bug.cgi?id=9622
         * (gdb emitting ESC sequences even with -batch)
         */
        "TERM",
        NULL
    };

    int flags = EXECFLG_INPUT_NUL | EXECFLG_OUTPUT | EXECFLG_SETSID | EXECFLG_QUIET;
    if (redirect_stderr)
        flags |= EXECFLG_ERR2OUT;
    VERB1 flags &= ~EXECFLG_QUIET;

    int pipeout[2];
    pid_t child = fork_execv_on_steroids(flags, args, pipeout, (char**)env_vec, /*dir:*/ NULL, /*uid(unused):*/ 0);

    /* We use this function to run gdb and unstrip. Bugs in gdb or corrupted
     * coredumps were observed to cause gdb to enter infinite loop.
     * Therefore we have a (largish) timeout, after which we kill the child.
     */
    ndelay_on(pipeout[0]);
    int t = time(NULL); /* int is enough, no need to use time_t */
    int endtime = t + exec_timeout_sec;
    struct strbuf *buf_out = strbuf_new();
    while (1)
    {
        int timeout = endtime - t;
        if (timeout < 0)
        {
            kill(child, SIGKILL);
            strbuf_append_strf(buf_out, "\n"
                        "Timeout exceeded: %u seconds, killing %s.\n"
                        "Looks like gdb hung while generating backtrace.\n"
                        "This may be a bug in gdb. Consider submitting a bug report to gdb developers.\n"
                        "Please attach coredump from this crash to the bug report if you do.\n",
                        exec_timeout_sec, args[0]
            );
            break;
        }

        /* We don't check poll result - checking read result is enough */
        struct pollfd pfd;
        pfd.fd = pipeout[0];
        pfd.events = POLLIN;
        poll(&pfd, 1, timeout * 1000);

        char buff[1024];
        int r = read(pipeout[0], buff, sizeof(buff) - 1);
        if (r <= 0)
        {
            /* I did see EAGAIN happening here */
            if (r < 0 && errno == EAGAIN)
                goto next;
            break;
        }
        buff[r] = '\0';
        strbuf_append_str(buf_out, buff);
 next:
        t = time(NULL);
    }
    close(pipeout[0]);

    /* Prevent having zombie child process, and maybe collect status
     * (note that status == NULL is ok too) */
    safe_waitpid(child, status, 0);

    return strbuf_free_nobuf(buf_out);
}
Beispiel #7
0
static bool recurrence_initialize_rrule_vcal(const char* str, RRule* rrule)
{
  int i;

  /** TODO - check for other whitespace, and multiple whitespace */
  char** strv = strsplit(str, ' ');

  rrule->interval = 1;

  if (strv[0][0] == 'D')
  {
    rrule->freq = RRuleDaily;
    rrule->interval = atoi(strv[0]+1);
    if (strv[1])
    {
      if (strv[1][0] == '#')
	rrule->count = atoi(strv[1]+1);
      else
	replace_string_with_copy(&rrule->until, strv[1]);
    }
  }
  else if (strv[0][0] == 'W')
  {
    rrule->freq = RRuleWeekly;
    rrule->interval = atoi(strv[0]+1);

    StrBuf *days_list = strbuf_new(NULL);
    for (i = 1; strv[i]; i++)
    {
      if (strv[i][0] == '#')
      {
	rrule->count = atoi(strv[i]+1);
	break;
      }
      else if (isdigit(strv[i][0]))
      {
	replace_string_with_copy(&rrule->until, strv[i]);
	break;
      }
      else
      {
	if (days_list->length > 0)
	  days_list = strbuf_append(days_list,",");
	days_list = strbuf_append(days_list,strv[i]);
      }
    }
    if (days_list->length > 0)
      replace_string_with_copy(&rrule->byday, days_list->buffer);
    strbuf_destroy(days_list,1);
  }
  else if (strv[0][0] == 'M')
  {
    rrule->freq = RRuleMonthly;
    if (strv[0][1] == 'D') /* by day in month, ie date */
    {
      rrule->interval = atoi(strv[0]+2);

      int days_found = 0;
      for (i = 1; strv[i]; i++)
      {
	if (strv[i][0] == '#')
	{
	  rrule->count = atoi(strv[i]+1);
	  break;
	}
	else if (isdigit(strv[i][0]) || STR_EQUAL(strv[i],"LD"))
	{
	  if (strlen(strv[i]) > 2)
	  {
	    replace_string_with_copy(&rrule->until, strv[i]);
	    break;
	  }

	  if (days_found == 0)
	  {
	    if (STR_EQUAL(strv[i],"LD"))
	      rrule->bymonthday = -1;
	    else
	      rrule->bymonthday = atoi(strv[i]);
	  }
	  days_found++;
	}
      }

      if (days_found > 1)
	synce_warning("Monthly by Day (MD) can only handle one day in RRA format, in RRULE '%s'", str);
    }
    else if (strv[0][1] == 'P') /* by position, ie the complicated one */
    {
      rrule->interval = atoi(strv[0]+2);

      StrBuf *days_list = strbuf_new(NULL);
      int occurence = 0;
      for (i = 1; strv[i]; i++)
      {
	if (strv[i][0] == '#')
	{
	  rrule->count = atoi(strv[i]+1);
	  break;
	}
	else if (isdigit(strv[i][0]) && strlen(strv[i]) > 2)
	{
	  replace_string_with_copy(&rrule->until, strv[i]);
	  break;
	}
	else if (isdigit(strv[i][0]))
	{
	  if (occurence != 0)
	    /* Any days following this shoukd be bound by this subsequent
	       occurence modifier, but cant be. We'll allow them to go with
	       the first occurrence modifier for now, but maybe we should
	       drop them entirely */
	    synce_info("Multiple occurence values cannot be represented by RRA in Monthly by Position recurrence");
	  else
	    occurence = atoi(strv[i]);
	}
	else
	{
	  if (days_list->length > 0)
	    days_list = strbuf_append(days_list,",");
	  days_list = strbuf_append(days_list,strv[i]);
	}
      }
      rrule->bysetpos = occurence;

      if (days_list->length > 0)
	replace_string_with_copy(&rrule->byday, days_list->buffer);
      strbuf_destroy(days_list,1);
    }
    else
      synce_error("Unexpected frequency in RRULE '%s'", str);
  }
  else if (strv[0][0] == 'Y')
  {
    rrule->freq = RRuleYearly;
    rrule->interval = atoi(strv[0]+2);

    if (strv[0][1] == 'M') /* by month number */
    {
      int months_found = 0;
      for (i = 1; strv[i]; i++)
      {
	if (strv[i][0] == '#')
	{
	  rrule->count = atoi(strv[i]+1);
	  break;
	}
	else if (isdigit(strv[i][0]))
	{
	  if (strlen(strv[i]) > 2)
	  {
	    replace_string_with_copy(&rrule->until, strv[i]);
	    break;
	  }

	  if (months_found == 0)
	  {
	    rrule->bymonth = atoi(strv[i]);
	  }
	  months_found++;
	}
      }

    }
    else if (strv[0][1] == 'D') /* by day in year */
    {
      int days_found = 0;
      for (i = 1; strv[i]; i++)
      {
	if (strv[i][0] == '#')
	{
	  rrule->count = atoi(strv[i]+1);
	  break;
	}
	else if (isdigit(strv[i][0]))
	{
	  if (strlen(strv[i]) > 2)
	  {
	    replace_string_with_copy(&rrule->until, strv[i]);
	    break;
	  }

	  if (days_found == 0)
	  {
	    rrule->bymonthday = atoi(strv[i]);
	  }
	  days_found++;
	}
      }

      if (days_found > 1)
	synce_warning("Yearly by Day (YD) (converted to monthly) can only handle one day in RRA format, in RRULE '%s'", str);

    }
    else
      synce_error("Unexpected frequency in RRULE '%s'", str);
  }
  else
  {
    synce_error("Unexpected frequency in RRULE '%s'", str);
  }
  
  strv_free(strv);
  return true;
}
Beispiel #8
0
void abrt_oops_save_data_in_dump_dir(struct dump_dir *dd, char *oops, const char *proc_modules)
{
    char *first_line = oops;
    char *second_line = (char*)strchr(first_line, '\n'); /* never NULL */
    *second_line++ = '\0';

    if (first_line[0])
        dd_save_text(dd, FILENAME_KERNEL, first_line);
    dd_save_text(dd, FILENAME_BACKTRACE, second_line);

    /* check if trace doesn't have line: 'Your BIOS is broken' */
    if (strstr(second_line, "Your BIOS is broken"))
        dd_save_text(dd, FILENAME_NOT_REPORTABLE,
                _("A kernel problem occurred because of broken BIOS. "
                  "Unfortunately, such problems are not fixable by kernel maintainers."));
    /* check if trace doesn't have line: 'Your hardware is unsupported' */
    else if (strstr(second_line, "Your hardware is unsupported"))
        dd_save_text(dd, FILENAME_NOT_REPORTABLE,
                _("A kernel problem occurred, but your hardware is unsupported, "
                  "therefore kernel maintainers are unable to fix this problem."));
    else
    {
        char *tainted_short = kernel_tainted_short(second_line);
        if (tainted_short)
        {
            log_notice("Kernel is tainted '%s'", tainted_short);
            dd_save_text(dd, FILENAME_TAINTED_SHORT, tainted_short);

            char *tnt_long = kernel_tainted_long(tainted_short);
            dd_save_text(dd, FILENAME_TAINTED_LONG, tnt_long);
            free(tnt_long);

            struct strbuf *reason = strbuf_new();
            const char *fmt = _("A kernel problem occurred, but your kernel has been "
                    "tainted (flags:%s). Kernel maintainers are unable to "
                    "diagnose tainted reports.");
            strbuf_append_strf(reason, fmt, tainted_short);

            char *modlist = !proc_modules ? NULL : abrt_oops_list_of_tainted_modules(proc_modules);
            if (modlist)
            {
                strbuf_append_strf(reason, _(" Tainted modules: %s."), modlist);
                free(modlist);
            }

            dd_save_text(dd, FILENAME_NOT_REPORTABLE, reason->buf);
            strbuf_free(reason);
            free(tainted_short);
        }
    }

    // TODO: add "Kernel oops: " prefix, so that all oopses have recognizable FILENAME_REASON?
    // kernel oops 1st line may look quite puzzling otherwise...
    char *reason_pretty = NULL;
    char *error = NULL;
    struct sr_stacktrace *trace = sr_stacktrace_parse(SR_REPORT_KERNELOOPS, second_line, &error);
    if (trace)
    {
        reason_pretty = sr_stacktrace_get_reason(trace);
        sr_stacktrace_free(trace);
    }
    else
        free(error);

    if (reason_pretty)
    {
        dd_save_text(dd, FILENAME_REASON, reason_pretty);
        free(reason_pretty);
    }
    else
        dd_save_text(dd, FILENAME_REASON, second_line);
}
Beispiel #9
0
lwan_tpl_t *
lwan_tpl_compile(const char *filename)
{
    lwan_tpl_t *tpl;
    strbuf_t *buf;
    FILE *file;
    int state = STATE_DEFAULT;
    char error_msg[512];
    
    tpl = calloc(1, sizeof(*tpl));
    if (!tpl)
        return NULL;

    buf = strbuf_new();
    if (!buf) {
        free(tpl);
        return NULL;
    }
    
    file = fopen(filename, "r");
    if (!file) {
        strbuf_free(buf);
        free(tpl);
        return NULL;
    }

    int line = 1;
    int column = 1;
    char ch;
    while ((ch = fgetc(file)) != EOF) {
        if (ch == '\n') {
            if (state == STATE_DEFAULT)
                strbuf_append_char(buf, '\n');

            line++;
            column = 1;
            continue;
        }
        ++column;

        switch (state) {
        case STATE_DEFAULT:
            if (ch == '{') {
                state = STATE_FIRST_BRACE;
                continue;
            }

            strbuf_append_char(buf, ch);
            break;
        case STATE_FIRST_BRACE:
            if (ch == '{') {
                switch (compile_append_text(tpl, buf)) {
                case -ENOMEM:
                    PARSE_ERROR("Out of memory while appending text.");
                }

                state = STATE_SECOND_BRACE;
                continue;
            }

            strbuf_append_char(buf, '{');
            strbuf_append_char(buf, ch);
            state = STATE_DEFAULT;
            break;
        case STATE_SECOND_BRACE:
            if (ch == '{')
                PARSE_ERROR("Unexpected open brace.");

            if (ch == '}') {
                state = STATE_FIRST_CLOSING_BRACE;
                continue;
            }

            strbuf_append_char(buf, ch);
            break;
        case STATE_FIRST_CLOSING_BRACE:
            if (ch == '}') {
                state = STATE_SECOND_CLOSING_BRACE;
                continue;
            }
            PARSE_ERROR("Closing brace expected.");
        case STATE_SECOND_CLOSING_BRACE:
            if (ch == '}')
                PARSE_ERROR("Unexpected close brace.");

            if (strbuf_get_length(buf) == 0)
                PARSE_ERROR("Expecting variable name.");

            switch (compile_append_var(tpl, buf)) {
            case -ENOMEM:
                PARSE_ERROR("Out of memory while appending variable.");
            case -ENOENT:
                PARSE_ERROR("Cannot find included template: ``%s''.", strbuf_get_buffer(buf) + 1);
            }

            if (ch == '{') {
                state = STATE_FIRST_BRACE;
                continue;
            }

            strbuf_append_char(buf, ch);
            state = STATE_DEFAULT;
        }
    }

    switch (state) {
    case STATE_DEFAULT:
        switch (compile_append_text(tpl, buf)) {
        case -ENOMEM:
            PARSE_ERROR("Out of memory while appending text.");
        }
        break;
    case STATE_FIRST_BRACE:
    case STATE_SECOND_BRACE:
        PARSE_ERROR("Expecting close brace.");
    case STATE_FIRST_CLOSING_BRACE:
        PARSE_ERROR("Expecting second close brace.");
    case STATE_SECOND_CLOSING_BRACE:
        if (strbuf_get_length(buf) == 0)
            PARSE_ERROR("Expecting variable name.");

        switch (compile_append_var(tpl, buf)) {
        case -ENOMEM:
            PARSE_ERROR("Out of memory while appending variable.");
        case -ENOENT:
            PARSE_ERROR("Cannot find included template: ``%s''.", strbuf_get_buffer(buf));
        }
    }

    lwan_tpl_chunk_t *last = malloc(sizeof(*last));
    if (!last)
        goto error;
    last->action = TPL_ACTION_LAST;
    last->data = NULL;
    last->next = tpl->chunks;
    tpl->chunks = last;

    lwan_tpl_chunk_t *prev = NULL;
    while (tpl->chunks) {
        lwan_tpl_chunk_t *next = tpl->chunks->next;
        tpl->chunks->next = prev;
        prev = tpl->chunks;
        tpl->chunks = next;
    }
    tpl->chunks = prev;

    strbuf_free(buf);
    return tpl;

error:
    lwan_tpl_free(tpl);
    strbuf_free(buf);
    fclose(file);
    
    printf("Line %d, column %d: %s\n", line, column, error_msg);
    return NULL;
}
Beispiel #10
0
static char *parse_solution_from_json_list(struct json_object *list, GList **reported_to)
{
    json_object *list_elem, *struct_elem;
    const char *cause, *note, *url;
    struct strbuf *solution_buf = strbuf_new();

    const unsigned length = json_object_array_length(list);

    const char *one_format = _("Your problem seems to be caused by %s\n\n%s\n");
    if (length > 1)
    {
        strbuf_append_str(solution_buf, _("Your problem seems to be caused by one of the following:\n"));
        one_format = "\n* %s\n\n%s\n";
    }

    bool empty = true;
    for (unsigned i = 0; i < length; ++i)
    {
        list_elem = json_object_array_get_idx(list, i);
        if (!list_elem)
            continue;

        struct_elem = json_object_object_get(list_elem, "cause");
        if (!struct_elem)
            continue;

        cause = json_object_get_string(struct_elem);
        if (!cause)
            continue;

        struct_elem = json_object_object_get(list_elem, "note");
        if (!struct_elem)
            continue;

        note = json_object_get_string(struct_elem);
        if (!note)
            continue;

        empty = false;
        strbuf_append_strf(solution_buf, one_format, cause, note);

        struct_elem = json_object_object_get(list_elem, "url");
        if (!struct_elem)
            continue;

        url = json_object_get_string(struct_elem);
        if (url)
        {
            char *reported_to_line = xasprintf("%s: URL=%s", cause, url);
            *reported_to = g_list_append(*reported_to, reported_to_line);
        }
    }

    if (empty)
    {
        strbuf_free(solution_buf);
        return NULL;
    }

    return strbuf_free_nobuf(solution_buf);
}
Beispiel #11
0
static void eddsa_sign(ssh_key *key, ptrlen data,
                       unsigned flags, BinarySink *bs)
{
    struct eddsa_key *ek = container_of(key, struct eddsa_key, sshk);
    const struct ecsign_extra *extra =
        (const struct ecsign_extra *)ek->sshk.vt->extra;
    assert(ek->privateKey);

    /*
     * EdDSA prescribes a specific method of generating the random
     * nonce integer for the signature. (A verifier can't tell
     * whether you followed that method, but it's important to
     * follow it anyway, because test vectors will want a specific
     * signature for a given message, and because this preserves
     * determinism of signatures even if the same signature were
     * made twice by different software.)
     */

    /*
     * First, we hash the private key integer (bare, little-endian)
     * into a hash generating 2*fieldBytes of output.
     */
    unsigned char hash[MAX_HASH_LEN];
    ssh_hash *h = ssh_hash_new(extra->hash);
    for (size_t i = 0; i < ek->curve->fieldBytes; ++i)
        put_byte(h, mp_get_byte(ek->privateKey, i));
    ssh_hash_final(h, hash);

    /*
     * The first half of the output hash is converted into an
     * integer a, by the standard EdDSA transformation.
     */
    mp_int *a = eddsa_exponent_from_hash(
        make_ptrlen(hash, ek->curve->fieldBytes), ek->curve);

    /*
     * The second half of the hash of the private key is hashed again
     * with the message to be signed, and used as an exponent to
     * generate the signature point r.
     */
    h = ssh_hash_new(extra->hash);
    put_data(h, hash + ek->curve->fieldBytes,
             extra->hash->hlen - ek->curve->fieldBytes);
    put_datapl(h, data);
    ssh_hash_final(h, hash);
    mp_int *log_r_unreduced = mp_from_bytes_le(
        make_ptrlen(hash, extra->hash->hlen));
    mp_int *log_r = mp_mod(log_r_unreduced, ek->curve->e.G_order);
    mp_free(log_r_unreduced);
    EdwardsPoint *r = ecc_edwards_multiply(ek->curve->e.G, log_r);

    /*
     * Encode r now, because we'll need its encoding for the next
     * hashing step as well as to write into the actual signature.
     */
    strbuf *r_enc = strbuf_new();
    put_epoint(r_enc, r, ek->curve, true); /* omit string header */
    ecc_edwards_point_free(r);

    /*
     * Compute the hash of (r || public key || message) just as
     * eddsa_verify does.
     */
    mp_int *H = eddsa_signing_exponent_from_data(
        ek, extra, ptrlen_from_strbuf(r_enc), data);

    /* And then s = (log(r) + H*a) mod order(G). */
    mp_int *Ha = mp_modmul(H, a, ek->curve->e.G_order);
    mp_int *s = mp_modadd(log_r, Ha, ek->curve->e.G_order);
    mp_free(H);
    mp_free(a);
    mp_free(Ha);
    mp_free(log_r);

    /* Format the output */
    put_stringz(bs, ek->sshk.vt->ssh_id);
    put_uint32(bs, r_enc->len + ek->curve->fieldBytes);
    put_data(bs, r_enc->u, r_enc->len);
    strbuf_free(r_enc);
    for (size_t i = 0; i < ek->curve->fieldBytes; ++i)
        put_byte(bs, mp_get_byte(s, i));
    mp_free(s);
}
Beispiel #12
0
static char *run_unstrip_n(const char *dump_dir_name, unsigned timeout_sec)
{
    struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
    if (!dd)
        return NULL;

    char *uid_str = dd_load_text_ext(dd, FILENAME_UID, DD_FAIL_QUIETLY_ENOENT | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE);
    dd_close(dd);
    uid_t uid = -1L;
    if (uid_str)
    {
        uid = xatoi_positive(uid_str);
        free(uid_str);
        if (uid == geteuid())
        {
            uid = -1L; /* no need to setuid/gid if we are already under right uid */
        }
    }

    int flags = EXECFLG_INPUT_NUL | EXECFLG_OUTPUT | EXECFLG_SETSID | EXECFLG_QUIET;
    if (uid != (uid_t)-1L)
        flags |= EXECFLG_SETGUID;
    VERB1 flags &= ~EXECFLG_QUIET;
    int pipeout[2];
    char* args[4];
    args[0] = (char*)"eu-unstrip";
    args[1] = xasprintf("--core=%s/"FILENAME_COREDUMP, dump_dir_name);
    args[2] = (char*)"-n";
    args[3] = NULL;
    pid_t child = fork_execv_on_steroids(flags, args, pipeout, /*env_vec:*/ NULL, /*dir:*/ NULL, uid);
    free(args[1]);

    /* Bugs in unstrip or corrupted coredumps can cause it to enter infinite loop.
     * Therefore we have a (largish) timeout, after which we kill the child.
     */
    int t = time(NULL); /* int is enough, no need to use time_t */
    int endtime = t + timeout_sec;
    struct strbuf *buf_out = strbuf_new();
    while (1)
    {
        int timeout = endtime - t;
        if (timeout < 0)
        {
            kill(child, SIGKILL);
            strbuf_append_strf(buf_out, "\nTimeout exceeded: %u seconds, killing %s\n", timeout_sec, args[0]);
            break;
        }

        /* We don't check poll result - checking read result is enough */
        struct pollfd pfd;
        pfd.fd = pipeout[0];
        pfd.events = POLLIN;
        poll(&pfd, 1, timeout * 1000);

        char buff[1024];
        int r = read(pipeout[0], buff, sizeof(buff) - 1);
        if (r <= 0)
            break;
        buff[r] = '\0';
        strbuf_append_str(buf_out, buff);
        t = time(NULL);
    }
    close(pipeout[0]);

    /* Prevent having zombie child process */
    int status;
    waitpid(child, &status, 0);

    if (status != 0)
    {
        /* unstrip didnt exit with exit code 0 */
        strbuf_free(buf_out);
        return NULL;
    }

    return strbuf_free_nobuf(buf_out);
}
Beispiel #13
0
StrBuf* strbuf_default() {
	return strbuf_new(STRBUF_DEFAULT_CAPACITY);
}
Beispiel #14
0
void error_correct_list_of_files(StrBuf* list_fastq,char quality_cutoff, char ascii_qual_offset,
                                 dBGraphEc *db_graph, HandleLowQualUncorrectable policy,
                                 int max_read_len, int min_read_len, StrBuf* suffix, char* outdir,
                                 boolean add_greedy_bases_for_better_bwt_compression,
                                 int num_greedy_bases, boolean rev_comp_read_if_on_reverse_strand)

{
    printf("error correct list of files\n");
    fflush(stdout);
    int len = max_read_len+2;
    uint64_t* distrib_num_bases_corrected     =(uint64_t*) malloc(sizeof(uint64_t)*len);
    uint64_t* distrib_position_bases_corrected=(uint64_t*) malloc(sizeof(uint64_t)*len);
    if ( (distrib_num_bases_corrected==NULL)|| (distrib_position_bases_corrected==NULL))
    {
        die("Unable to alloc arrays for keeping stats. Your machine must have hardly any spare memory\n");
    }
    set_uint64_t_array(distrib_num_bases_corrected,      len, (uint64_t) 0);
    set_uint64_t_array(distrib_position_bases_corrected, len, (uint64_t) 0);

    FILE* list_fastq_fp = fopen(list_fastq->buff, "r");
    if (list_fastq_fp==NULL)
    {
        printf("Cannot open file %s\n", list_fastq->buff);
    }
    StrBuf *next_fastq     = strbuf_new();
    StrBuf* corrected_file = strbuf_new();
    StrBuf* corrected_file_newpath = strbuf_new();

    while(strbuf_reset_readline(next_fastq, list_fastq_fp))
    {
        strbuf_chomp(next_fastq);
        if(strbuf_len(next_fastq) > 0)
        {
            strbuf_reset(corrected_file);
            strbuf_reset(corrected_file_newpath);
            strbuf_copy(corrected_file, 0,//dest
                        next_fastq,0,strbuf_len(next_fastq));
            strbuf_append_str(corrected_file, suffix->buff);
            char* corrected_file_basename = basename(corrected_file->buff);
            strbuf_append_str(corrected_file_newpath, outdir);
            strbuf_append_str(corrected_file_newpath, corrected_file_basename);

            error_correct_file_against_graph(next_fastq->buff, quality_cutoff, ascii_qual_offset,
                                             db_graph, corrected_file_newpath->buff,
                                             distrib_num_bases_corrected,
                                             distrib_position_bases_corrected,
                                             len,
                                             min_read_len,
                                             policy,
                                             add_greedy_bases_for_better_bwt_compression,
                                             num_greedy_bases, rev_comp_read_if_on_reverse_strand);


        }
    }
    fclose(list_fastq_fp);
    strbuf_free(next_fastq);
    strbuf_free(corrected_file);
    strbuf_free(corrected_file_newpath);
    free(distrib_num_bases_corrected);
    free(distrib_position_bases_corrected);
}
Beispiel #15
0
char *run_unstrip_n(const char *dump_dir_name, unsigned timeout_sec)
{
    int flags = EXECFLG_INPUT_NUL | EXECFLG_OUTPUT | EXECFLG_SETSID | EXECFLG_QUIET;
    VERB1 flags &= ~EXECFLG_QUIET;
    int pipeout[2];
    char* args[4];
    args[0] = (char*)"eu-unstrip";
    args[1] = xasprintf("--core=%s/"FILENAME_COREDUMP, dump_dir_name);
    args[2] = (char*)"-n";
    args[3] = NULL;
    pid_t child = fork_execv_on_steroids(flags, args, pipeout, /*env_vec:*/ NULL, /*dir:*/ NULL, /*uid(unused):*/ 0);
    free(args[1]);

    /* Bugs in unstrip or corrupted coredumps can cause it to enter infinite loop.
     * Therefore we have a (largish) timeout, after which we kill the child.
     */
    ndelay_on(pipeout[0]);
    int t = time(NULL); /* int is enough, no need to use time_t */
    int endtime = t + timeout_sec;
    struct strbuf *buf_out = strbuf_new();
    while (1)
    {
        int timeout = endtime - t;
        if (timeout < 0)
        {
            kill(child, SIGKILL);
            strbuf_free(buf_out);
            buf_out = NULL;
            break;
        }

        /* We don't check poll result - checking read result is enough */
        struct pollfd pfd;
        pfd.fd = pipeout[0];
        pfd.events = POLLIN;
        poll(&pfd, 1, timeout * 1000);

        char buff[1024];
        int r = read(pipeout[0], buff, sizeof(buff) - 1);
        if (r <= 0)
        {
            /* I did see EAGAIN happening here */
            if (r < 0 && errno == EAGAIN)
                goto next;
            break;
        }
        buff[r] = '\0';
        strbuf_append_str(buf_out, buff);
 next:
        t = time(NULL);
    }
    close(pipeout[0]);

    /* Prevent having zombie child process */
    int status;
    safe_waitpid(child, &status, 0);

    if (status != 0 || buf_out == NULL)
    {
        /* unstrip didnt exit with exit code 0, or we timed out */
        strbuf_free(buf_out);
        return NULL;
    }

    return strbuf_free_nobuf(buf_out);
}
Beispiel #16
0
SPREXPORT void *
sprite_to_bmp (Sprite *sprite, int i, int *size, SpriteError *error)
{
	StrBuf *buf;
	unsigned long file_size, offset, tmp;
	unsigned short tmp2;
	void *data;

	/* Sanity check arguments */
	if (!sprite || i < 0) {
		if (error) *error = SE_BADARGS;
		return NULL;
	}

	if (i >= sprite->nimages) {
		if (error) *error = SE_INDEX;
		return NULL;
	}


	buf = strbuf_new ();

	/* Bitmap file header */
	offset = 54 + sprite->palette_size;
	file_size = offset + sprite->images[i].len;
	strbuf_append (buf, (unsigned char *) "BM", 2);		/* Magic */
	strbuf_append (buf, (unsigned char *) &file_size, 4);	/* File size */
	strbuf_append (buf, (unsigned char *) "\0\0\0\0", 4);	/* Reserved */
	strbuf_append (buf, (unsigned char *) &offset, 4);	/* Offset to image data */

	/* Bitmap info header */
	tmp = 40;
	strbuf_append (buf, (unsigned char *) &tmp, 4);				/* Size of the info header */
	strbuf_append (buf, (unsigned char *) &(sprite->images[i].width), 4);	/* Width */
	strbuf_append (buf, (unsigned char *) &(sprite->images[i].height), 4);	/* Height */
	tmp2 = 1;
	strbuf_append (buf, (unsigned char *) &tmp2, 2);	/* Planes */
	tmp2 = 8;
	strbuf_append (buf, (unsigned char *) &tmp2, 2);	/* Bit count */

	tmp = 0;
	strbuf_append (buf, (unsigned char *) &tmp, 4);		/* Compression type */
	tmp = sprite->images[i].len;
	strbuf_append (buf, (unsigned char *) &tmp, 4);		/* Pixel data size */
	tmp = 0;
	strbuf_append (buf, (unsigned char *) &tmp, 4);		/* X pixels per meter */
	strbuf_append (buf, (unsigned char *) &tmp, 4);		/* Y pixels per meter */
	tmp = 256;
	strbuf_append (buf, (unsigned char *) &tmp, 4);		/* Number of colors */
	tmp = 0;
	strbuf_append (buf, (unsigned char *) &tmp, 4);		/* Number of important colors */

	/* Palette */
	strbuf_append (buf, (unsigned char *) sprite->palette, sprite->palette_size);
	/* Pixel data */
	strbuf_append (buf, sprite->images[i].data, sprite->images[i].len);


	data = buf->str;
	if (size) *size = buf->len;
	strbuf_free (buf, 0);
	return data;
}
Beispiel #17
0
char *get_backtrace(const char *dump_dir_name, unsigned timeout_sec, const char *debuginfo_dirs)
{
    INITIALIZE_LIBABRT();

    struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
    if (!dd)
        return NULL;
    char *executable = dd_load_text(dd, FILENAME_EXECUTABLE);
    dd_close(dd);

    /* Let user know what's going on */
    log(_("Generating backtrace"));

    unsigned i = 0;
    char *args[25];
    args[i++] = (char*)"gdb";
    args[i++] = (char*)"-batch";
    struct strbuf *set_debug_file_directory = strbuf_new();
    unsigned auto_load_base_index = 0;
    if(debuginfo_dirs == NULL)
    {
        // set non-existent debug file directory to prevent resolving
        // function names - we need offsets for core backtrace.
        strbuf_append_str(set_debug_file_directory, "set debug-file-directory /");
    }
    else
    {
        strbuf_append_str(set_debug_file_directory, "set debug-file-directory /usr/lib/debug");

        struct strbuf *debug_directories = strbuf_new();
        const char *p = debuginfo_dirs;
        while (1)
        {
            while (*p == ':')
                p++;
            if (*p == '\0')
                break;
            const char *colon_or_nul = strchrnul(p, ':');
            strbuf_append_strf(debug_directories, "%s%.*s/usr/lib/debug", (debug_directories->len == 0 ? "" : ":"),
                                                                          (int)(colon_or_nul - p), p);
            p = colon_or_nul;
        }

        strbuf_append_strf(set_debug_file_directory, ":%s", debug_directories->buf);

        args[i++] = (char*)"-iex";
        auto_load_base_index = i;
        args[i++] = xasprintf("add-auto-load-safe-path %s", debug_directories->buf);
        args[i++] = (char*)"-iex";
        args[i++] = xasprintf("add-auto-load-scripts-directory %s", debug_directories->buf);

        strbuf_free(debug_directories);
    }

    args[i++] = (char*)"-ex";
    const unsigned debug_dir_cmd_index = i++;
    args[debug_dir_cmd_index] = strbuf_free_nobuf(set_debug_file_directory);

    /* "file BINARY_FILE" is needed, without it gdb cannot properly
     * unwind the stack. Currently the unwind information is located
     * in .eh_frame which is stored only in binary, not in coredump
     * or debuginfo.
     *
     * Fedora GDB does not strictly need it, it will find the binary
     * by its build-id.  But for binaries either without build-id
     * (= built on non-Fedora GCC) or which do not have
     * their debuginfo rpm installed gdb would not find BINARY_FILE
     * so it is still makes sense to supply "file BINARY_FILE".
     *
     * Unfortunately, "file BINARY_FILE" doesn't work well if BINARY_FILE
     * was deleted (as often happens during system updates):
     * gdb uses specified BINARY_FILE
     * even if it is completely unrelated to the coredump.
     * See https://bugzilla.redhat.com/show_bug.cgi?id=525721
     *
     * TODO: check mtimes on COREFILE and BINARY_FILE and not supply
     * BINARY_FILE if it is newer (to at least avoid gdb complaining).
     */
    args[i++] = (char*)"-ex";
    const unsigned file_cmd_index = i++;
    args[file_cmd_index] = xasprintf("file %s", executable);
    free(executable);

    args[i++] = (char*)"-ex";
    const unsigned core_cmd_index = i++;
    args[core_cmd_index] = xasprintf("core-file %s/"FILENAME_COREDUMP, dump_dir_name);

    args[i++] = (char*)"-ex";
    const unsigned bt_cmd_index = i++;
    /*args[9] = ... see below */
    args[i++] = (char*)"-ex";
    args[i++] = (char*)"info sharedlib";
    /* glibc's abort() stores its message in __abort_msg variable */
    args[i++] = (char*)"-ex";
    args[i++] = (char*)"print (char*)__abort_msg";
    args[i++] = (char*)"-ex";
    args[i++] = (char*)"print (char*)__glib_assert_msg";
    args[i++] = (char*)"-ex";
    args[i++] = (char*)"info all-registers";
    args[i++] = (char*)"-ex";
    const unsigned dis_cmd_index = i++;
    args[dis_cmd_index] = (char*)"disassemble";
    args[i++] = NULL;

    /* Get the backtrace, but try to cap its size */
    /* Limit bt depth. With no limit, gdb sometimes OOMs the machine */
    unsigned bt_depth = 1024;
    const char *thread_apply_all = "thread apply all -ascending";
    const char *full = " full";
    char *bt = NULL;
    while (1)
    {
        args[bt_cmd_index] = xasprintf("%s backtrace %u%s", thread_apply_all, bt_depth, full);
        bt = exec_vp(args, /*redirect_stderr:*/ 1, timeout_sec, NULL);
        free(args[bt_cmd_index]);
        if ((bt && strnlen(bt, 256*1024) < 256*1024) || bt_depth <= 32)
        {
            break;
        }

        bt_depth /= 2;
        if (bt)
            log("Backtrace is too big (%u bytes), reducing depth to %u",
                        (unsigned)strlen(bt), bt_depth);
        else
            /* (NB: in fact, current impl. of exec_vp() never returns NULL) */
            log("Failed to generate backtrace, reducing depth to %u",
                        bt_depth);
        free(bt);

        /* Replace -ex disassemble (which disasms entire function $pc points to)
         * to a version which analyzes limited, small patch of code around $pc.
         * (Users reported a case where bare "disassemble" attempted to process
         * entire .bss).
         * TODO: what if "$pc-N" underflows? in my test, this happens:
         * Dump of assembler code from 0xfffffffffffffff0 to 0x30:
         * End of assembler dump.
         * (IOW: "empty" dump)
         */
        args[dis_cmd_index] = (char*)"disassemble $pc-20, $pc+64";

        if (bt_depth <= 64 && thread_apply_all[0] != '\0')
        {
            /* This program likely has gazillion threads, dont try to bt them all */
            bt_depth = 128;
            thread_apply_all = "";
        }
        if (bt_depth <= 64 && full[0] != '\0')
        {
            /* Looks like there are gigantic local structures or arrays, disable "full" bt */
            bt_depth = 128;
            full = "";
        }
    }

    if (auto_load_base_index > 0)
    {
        free(args[auto_load_base_index]);
        free(args[auto_load_base_index + 2]);
    }

    free(args[debug_dir_cmd_index]);
    free(args[file_cmd_index]);
    free(args[core_cmd_index]);
    return bt;
}
Beispiel #18
0
int main(int argc, char **argv)
{
    bool sending;
    int *fdlist;
    int fd;
    int i, fdstate;
    size_t fdsize;
    int exitcode;
    bool errors;
    enum TriState sanitise_stdout = AUTO, sanitise_stderr = AUTO;
    bool use_subsystem = false;
    bool just_test_share_exists = false;
    unsigned long now;
    struct winsize size;
    const struct BackendVtable *backvt;

    fdlist = NULL;
    fdsize = 0;
    /*
     * Initialise port and protocol to sensible defaults. (These
     * will be overridden by more or less anything.)
     */
    default_protocol = PROT_SSH;
    default_port = 22;

    bufchain_init(&stdout_data);
    bufchain_init(&stderr_data);
    bufchain_sink_init(&stdout_bcs, &stdout_data);
    bufchain_sink_init(&stderr_bcs, &stderr_data);
    stdout_bs = BinarySink_UPCAST(&stdout_bcs);
    stderr_bs = BinarySink_UPCAST(&stderr_bcs);
    outgoingeof = EOF_NO;

    flags = FLAG_STDERR_TTY;
    cmdline_tooltype |=
        (TOOLTYPE_HOST_ARG |
         TOOLTYPE_HOST_ARG_CAN_BE_SESSION |
         TOOLTYPE_HOST_ARG_PROTOCOL_PREFIX |
         TOOLTYPE_HOST_ARG_FROM_LAUNCHABLE_LOAD);

    stderr_tty_init();
    /*
     * Process the command line.
     */
    conf = conf_new();
    do_defaults(NULL, conf);
    loaded_session = false;
    default_protocol = conf_get_int(conf, CONF_protocol);
    default_port = conf_get_int(conf, CONF_port);
    errors = false;
    {
	/*
	 * Override the default protocol if PLINK_PROTOCOL is set.
	 */
	char *p = getenv("PLINK_PROTOCOL");
	if (p) {
            const struct BackendVtable *vt = backend_vt_from_name(p);
            if (vt) {
                default_protocol = vt->protocol;
                default_port = vt->default_port;
		conf_set_int(conf, CONF_protocol, default_protocol);
		conf_set_int(conf, CONF_port, default_port);
	    }
	}
    }
    while (--argc) {
	char *p = *++argv;
        int ret = cmdline_process_param(p, (argc > 1 ? argv[1] : NULL),
                                        1, conf);
        if (ret == -2) {
            fprintf(stderr,
                    "plink: option \"%s\" requires an argument\n", p);
            errors = true;
        } else if (ret == 2) {
            --argc, ++argv;
        } else if (ret == 1) {
            continue;
        } else if (!strcmp(p, "-batch")) {
            console_batch_mode = true;
        } else if (!strcmp(p, "-s")) {
            /* Save status to write to conf later. */
            use_subsystem = true;
        } else if (!strcmp(p, "-V") || !strcmp(p, "--version")) {
            version();
        } else if (!strcmp(p, "--help")) {
            usage();
            exit(0);
        } else if (!strcmp(p, "-pgpfp")) {
            pgp_fingerprints();
            exit(1);
        } else if (!strcmp(p, "-o")) {
            if (argc <= 1) {
                fprintf(stderr,
                        "plink: option \"-o\" requires an argument\n");
                errors = true;
            } else {
                --argc;
                /* Explicitly pass "plink" in place of appname for
                 * error reporting purposes. appname will have been
                 * set by be_foo.c to something more generic, probably
                 * "PuTTY". */
                provide_xrm_string(*++argv, "plink");
            }
        } else if (!strcmp(p, "-shareexists")) {
            just_test_share_exists = true;
        } else if (!strcmp(p, "-fuzznet")) {
            conf_set_int(conf, CONF_proxy_type, PROXY_FUZZ);
            conf_set_str(conf, CONF_proxy_telnet_command, "%host");
        } else if (!strcmp(p, "-sanitise-stdout") ||
                   !strcmp(p, "-sanitize-stdout")) {
            sanitise_stdout = FORCE_ON;
        } else if (!strcmp(p, "-no-sanitise-stdout") ||
                   !strcmp(p, "-no-sanitize-stdout")) {
            sanitise_stdout = FORCE_OFF;
        } else if (!strcmp(p, "-sanitise-stderr") ||
                   !strcmp(p, "-sanitize-stderr")) {
            sanitise_stderr = FORCE_ON;
        } else if (!strcmp(p, "-no-sanitise-stderr") ||
                   !strcmp(p, "-no-sanitize-stderr")) {
            sanitise_stderr = FORCE_OFF;
        } else if (!strcmp(p, "-no-antispoof")) {
            console_antispoof_prompt = false;
	} else if (*p != '-') {
            strbuf *cmdbuf = strbuf_new();

            while (argc > 0) {
                if (cmdbuf->len > 0)
                    put_byte(cmdbuf, ' '); /* add space separator */
                put_datapl(cmdbuf, ptrlen_from_asciz(p));
                if (--argc > 0)
                    p = *++argv;
            }

            conf_set_str(conf, CONF_remote_cmd, cmdbuf->s);
            conf_set_str(conf, CONF_remote_cmd2, "");
            conf_set_bool(conf, CONF_nopty, true);  /* command => no tty */

            strbuf_free(cmdbuf);
            break;		       /* done with cmdline */
        } else {
            fprintf(stderr, "plink: unknown option \"%s\"\n", p);
            errors = true;
	}
    }

    if (errors)
	return 1;

    if (!cmdline_host_ok(conf)) {
	usage();
    }

    prepare_session(conf);

    /*
     * Perform command-line overrides on session configuration.
     */
    cmdline_run_saved(conf);

    /*
     * If we have no better ideas for the remote username, use the local
     * one, as 'ssh' does.
     */
    if (conf_get_str(conf, CONF_username)[0] == '\0') {
	char *user = get_username();
	if (user) {
	    conf_set_str(conf, CONF_username, user);
	    sfree(user);
	}
    }

    /*
     * Apply subsystem status.
     */
    if (use_subsystem)
        conf_set_bool(conf, CONF_ssh_subsys, true);

    if (!*conf_get_str(conf, CONF_remote_cmd) &&
	!*conf_get_str(conf, CONF_remote_cmd2) &&
	!*conf_get_str(conf, CONF_ssh_nc_host))
	flags |= FLAG_INTERACTIVE;

    /*
     * Select protocol. This is farmed out into a table in a
     * separate file to enable an ssh-free variant.
     */
    backvt = backend_vt_from_proto(conf_get_int(conf, CONF_protocol));
    if (!backvt) {
	fprintf(stderr,
		"Internal fault: Unsupported protocol found\n");
	return 1;
    }

    /*
     * Block SIGPIPE, so that we'll get EPIPE individually on
     * particular network connections that go wrong.
     */
    putty_signal(SIGPIPE, SIG_IGN);

    /*
     * Set up the pipe we'll use to tell us about SIGWINCH.
     */
    if (pipe(signalpipe) < 0) {
	perror("pipe");
	exit(1);
    }
    /* We don't want the signal handler to block if the pipe's full. */
    nonblock(signalpipe[0]);
    nonblock(signalpipe[1]);
    cloexec(signalpipe[0]);
    cloexec(signalpipe[1]);
    putty_signal(SIGWINCH, sigwinch);

    /*
     * Now that we've got the SIGWINCH handler installed, try to find
     * out the initial terminal size.
     */
    if (ioctl(STDIN_FILENO, TIOCGWINSZ, &size) >= 0) {
	conf_set_int(conf, CONF_width, size.ws_col);
	conf_set_int(conf, CONF_height, size.ws_row);
    }

    /*
     * Decide whether to sanitise control sequences out of standard
     * output and standard error.
     *
     * If we weren't given a command-line override, we do this if (a)
     * the fd in question is pointing at a terminal, and (b) we aren't
     * trying to allocate a terminal as part of the session.
     *
     * (Rationale: the risk of control sequences is that they cause
     * confusion when sent to a local terminal, so if there isn't one,
     * no problem. Also, if we allocate a remote terminal, then we
     * sent a terminal type, i.e. we told it what kind of escape
     * sequences we _like_, i.e. we were expecting to receive some.)
     */
    if (sanitise_stdout == FORCE_ON ||
        (sanitise_stdout == AUTO && isatty(STDOUT_FILENO) &&
         conf_get_bool(conf, CONF_nopty))) {
        stdout_scc = stripctrl_new(stdout_bs, true, L'\0');
        stdout_bs = BinarySink_UPCAST(stdout_scc);
    }
    if (sanitise_stderr == FORCE_ON ||
        (sanitise_stderr == AUTO && isatty(STDERR_FILENO) &&
         conf_get_bool(conf, CONF_nopty))) {
        stderr_scc = stripctrl_new(stderr_bs, true, L'\0');
        stderr_bs = BinarySink_UPCAST(stderr_scc);
    }

    sk_init();
    uxsel_init();

    /*
     * Plink doesn't provide any way to add forwardings after the
     * connection is set up, so if there are none now, we can safely set
     * the "simple" flag.
     */
    if (conf_get_int(conf, CONF_protocol) == PROT_SSH &&
	!conf_get_bool(conf, CONF_x11_forward) &&
	!conf_get_bool(conf, CONF_agentfwd) &&
	!conf_get_str_nthstrkey(conf, CONF_portfwd, 0))
	conf_set_bool(conf, CONF_ssh_simple, true);

    if (just_test_share_exists) {
        if (!backvt->test_for_upstream) {
            fprintf(stderr, "Connection sharing not supported for connection "
                    "type '%s'\n", backvt->name);
            return 1;
        }
        if (backvt->test_for_upstream(conf_get_str(conf, CONF_host),
                                      conf_get_int(conf, CONF_port), conf))
            return 0;
        else
            return 1;
    }

    /*
     * Start up the connection.
     */
    logctx = log_init(default_logpolicy, conf);
    {
	const char *error;
	char *realhost;
	/* nodelay is only useful if stdin is a terminal device */
	bool nodelay = conf_get_bool(conf, CONF_tcp_nodelay) && isatty(0);

	/* This is a good place for a fuzzer to fork us. */
#ifdef __AFL_HAVE_MANUAL_CONTROL
	__AFL_INIT();
#endif

        error = backend_init(backvt, plink_seat, &backend, logctx, conf,
                             conf_get_str(conf, CONF_host),
                             conf_get_int(conf, CONF_port),
                             &realhost, nodelay,
                             conf_get_bool(conf, CONF_tcp_keepalives));
	if (error) {
	    fprintf(stderr, "Unable to open connection:\n%s\n", error);
	    return 1;
	}
        ldisc_create(conf, NULL, backend, plink_seat);
	sfree(realhost);
    }

    /*
     * Set up the initial console mode. We don't care if this call
     * fails, because we know we aren't necessarily running in a
     * console.
     */
    local_tty = (tcgetattr(STDIN_FILENO, &orig_termios) == 0);
    atexit(cleanup_termios);
    seat_echoedit_update(plink_seat, 1, 1);
    sending = false;
    now = GETTICKCOUNT();

    pollwrapper *pw = pollwrap_new();

    while (1) {
	int rwx;
	int ret;
        unsigned long next;

        pollwrap_clear(pw);

	pollwrap_add_fd_rwx(pw, signalpipe[0], SELECT_R);

	if (!sending &&
            backend_connected(backend) &&
            backend_sendok(backend) &&
            backend_sendbuffer(backend) < MAX_STDIN_BACKLOG) {
	    /* If we're OK to send, then try to read from stdin. */
            pollwrap_add_fd_rwx(pw, STDIN_FILENO, SELECT_R);
	}

	if (bufchain_size(&stdout_data) > 0) {
	    /* If we have data for stdout, try to write to stdout. */
            pollwrap_add_fd_rwx(pw, STDOUT_FILENO, SELECT_W);
	}

	if (bufchain_size(&stderr_data) > 0) {
	    /* If we have data for stderr, try to write to stderr. */
            pollwrap_add_fd_rwx(pw, STDERR_FILENO, SELECT_W);
	}

	/* Count the currently active fds. */
	i = 0;
	for (fd = first_fd(&fdstate, &rwx); fd >= 0;
	     fd = next_fd(&fdstate, &rwx)) i++;

	/* Expand the fdlist buffer if necessary. */
        sgrowarray(fdlist, fdsize, i);

	/*
	 * Add all currently open fds to pw, and store them in fdlist
	 * as well.
	 */
	int fdcount = 0;
	for (fd = first_fd(&fdstate, &rwx); fd >= 0;
	     fd = next_fd(&fdstate, &rwx)) {
	    fdlist[fdcount++] = fd;
            pollwrap_add_fd_rwx(pw, fd, rwx);
	}

        if (toplevel_callback_pending()) {
            ret = pollwrap_poll_instant(pw);
        } else if (run_timers(now, &next)) {
            do {
                unsigned long then;
                long ticks;

		then = now;
		now = GETTICKCOUNT();
		if (now - then > next - then)
		    ticks = 0;
		else
		    ticks = next - now;

                bool overflow = false;
                if (ticks > INT_MAX) {
                    ticks = INT_MAX;
                    overflow = true;
                }

                ret = pollwrap_poll_timeout(pw, ticks);
                if (ret == 0 && !overflow)
                    now = next;
                else
                    now = GETTICKCOUNT();
            } while (ret < 0 && errno == EINTR);
        } else {
            ret = pollwrap_poll_endless(pw);
        }

        if (ret < 0 && errno == EINTR)
            continue;

	if (ret < 0) {
	    perror("poll");
	    exit(1);
	}

	for (i = 0; i < fdcount; i++) {
	    fd = fdlist[i];
            int rwx = pollwrap_get_fd_rwx(pw, fd);
            /*
             * We must process exceptional notifications before
             * ordinary readability ones, or we may go straight
             * past the urgent marker.
             */
	    if (rwx & SELECT_X)
		select_result(fd, SELECT_X);
	    if (rwx & SELECT_R)
		select_result(fd, SELECT_R);
	    if (rwx & SELECT_W)
		select_result(fd, SELECT_W);
	}

	if (pollwrap_check_fd_rwx(pw, signalpipe[0], SELECT_R)) {
	    char c[1];
	    struct winsize size;
	    if (read(signalpipe[0], c, 1) <= 0)
		/* ignore error */;
	    /* ignore its value; it'll be `x' */
	    if (ioctl(STDIN_FILENO, TIOCGWINSZ, (void *)&size) >= 0)
                backend_size(backend, size.ws_col, size.ws_row);
	}

	if (pollwrap_check_fd_rwx(pw, STDIN_FILENO, SELECT_R)) {
	    char buf[4096];
	    int ret;

            if (backend_connected(backend)) {
		ret = read(STDIN_FILENO, buf, sizeof(buf));
                noise_ultralight(NOISE_SOURCE_IOLEN, ret);
		if (ret < 0) {
		    perror("stdin: read");
		    exit(1);
		} else if (ret == 0) {
                    backend_special(backend, SS_EOF, 0);
		    sending = false;   /* send nothing further after this */
		} else {
		    if (local_tty)
			from_tty(buf, ret);
		    else
                        backend_send(backend, buf, ret);
		}
	    }
	}

	if (pollwrap_check_fd_rwx(pw, STDOUT_FILENO, SELECT_W)) {
            backend_unthrottle(backend, try_output(false));
	}

	if (pollwrap_check_fd_rwx(pw, STDERR_FILENO, SELECT_W)) {
            backend_unthrottle(backend, try_output(true));
	}

        run_toplevel_callbacks();

        if (!backend_connected(backend) &&
	    bufchain_size(&stdout_data) == 0 &&
	    bufchain_size(&stderr_data) == 0)
	    break;		       /* we closed the connection */
    }
    exitcode = backend_exitcode(backend);
    if (exitcode < 0) {
	fprintf(stderr, "Remote process exit code unavailable\n");
	exitcode = 1;		       /* this is an error condition */
    }
    cleanup_exit(exitcode);
    return exitcode;		       /* shouldn't happen, but placates gcc */
}
Beispiel #19
0
int cmdline_process_param(const char *p, char *value,
                          int need_save, Conf *conf)
{
    int ret = 0;

    if (p[0] != '-') {
        if (need_save < 0)
            return 0;

        /*
         * Common handling for the tools whose initial command-line
         * arguments specify a hostname to connect to, i.e. PuTTY and
         * Plink. Doesn't count the file transfer tools, because their
         * hostname specification appears as part of a more
         * complicated scheme.
         */

        if ((cmdline_tooltype & TOOLTYPE_HOST_ARG) &&
            !seen_hostname_argument &&
            (!(cmdline_tooltype & TOOLTYPE_HOST_ARG_FROM_LAUNCHABLE_LOAD) ||
             !loaded_session || !conf_launchable(conf))) {
            /*
             * Treat this argument as a host name, if we have not yet
             * seen a host name argument or -load.
             *
             * Exception, in some tools (Plink): if we have seen -load
             * but it didn't create a launchable session, then we
             * still accept a hostname argument following that -load.
             * This allows you to make saved sessions that configure
             * lots of other stuff (colour schemes, terminal settings
             * etc) and then say 'putty -load sessionname hostname'.
             *
             * Also, we carefully _don't_ test conf for launchability
             * if we haven't been explicitly told to load a session
             * (otherwise saving a host name into Default Settings
             * would cause 'putty' on its own to immediately launch
             * the default session and never be able to do anything
             * else).
             */
            if (!strncmp(p, "telnet:", 7)) {
                /*
                 * If the argument starts with "telnet:", set the
                 * protocol to Telnet and process the string as a
                 * Telnet URL.
                 */

                /*
                 * Skip the "telnet:" or "telnet://" prefix.
                 */
                p += 7;
                if (p[0] == '/' && p[1] == '/')
                    p += 2;
                conf_set_int(conf, CONF_protocol, PROT_TELNET);

                /*
                 * The next thing we expect is a host name.
                 */
                {
                    const char *host = p;
                    char *buf;

                    p += host_strcspn(p, ":/");
                    buf = dupprintf("%.*s", (int)(p - host), host);
                    conf_set_str(conf, CONF_host, buf);
                    sfree(buf);
                    seen_hostname_argument = true;
                }

                /*
                 * If the host name is followed by a colon, then
                 * expect a port number after it.
                 */
                if (*p == ':') {
                    p++;

                    conf_set_int(conf, CONF_port, atoi(p));
                    /*
                     * Set the flag that will stop us from treating
                     * the next argument as a separate port; this one
                     * counts as explicitly provided.
                     */
                    seen_port_argument = true;
                } else {
                    conf_set_int(conf, CONF_port, -1);
                }
            } else {
                char *user = NULL, *hostname = NULL;
                const char *hostname_after_user;
                int port_override = -1;
                size_t len;

                /*
                 * Otherwise, treat it as a bare host name.
                 */

                if (cmdline_tooltype & TOOLTYPE_HOST_ARG_PROTOCOL_PREFIX) {
                    /*
                     * Here Plink checks for a comma-separated
                     * protocol prefix, e.g. 'ssh,hostname' or
                     * 'ssh,user@hostname'.
                     *
                     * I'm not entirely sure why; this behaviour dates
                     * from 2000 and isn't explained. But I _think_ it
                     * has to do with CVS transport or similar use
                     * cases, in which the end user invokes the SSH
                     * client indirectly, via some means that only
                     * lets them pass a single string argument, and it
                     * was occasionally useful to shoehorn the choice
                     * of protocol into that argument.
                     */
                    const char *comma = strchr(p, ',');
                    if (comma) {
                        char *prefix = dupprintf("%.*s", (int)(comma - p), p);
                        const struct BackendVtable *vt =
                            backend_vt_from_name(prefix);

                        if (vt) {
                            default_protocol = vt->protocol;
                            conf_set_int(conf, CONF_protocol,
                                         default_protocol);
                            port_override = vt->default_port;
                        } else {
                            cmdline_error("unrecognised protocol prefix '%s'",
                                          prefix);
                        }

                        sfree(prefix);
                        p = comma + 1;
                    }
                }

                hostname_after_user = p;
                if (cmdline_tooltype & TOOLTYPE_HOST_ARG_CAN_BE_SESSION) {
                    /*
                     * If the hostname argument can also be a saved
                     * session (see below), then here we also check
                     * for a user@ prefix, which will override the
                     * username from the saved session.
                     *
                     * (If the hostname argument _isn't_ a saved
                     * session, we don't do this.)
                     */
                    const char *at = strrchr(p, '@');
                    if (at) {
                        user = dupprintf("%.*s", (int)(at - p), p);
                        hostname_after_user = at + 1;
                    }
                }

                /*
                 * Write the whole hostname argument (minus only that
                 * optional protocol prefix) into the existing Conf,
                 * for tools that don't treat it as a saved session
                 * and as a fallback for those that do.
                 */
                hostname = dupstr(p + strspn(p, " \t"));
                len = strlen(hostname);
                while (len > 0 && (hostname[len-1] == ' ' ||
                                   hostname[len-1] == '\t'))
                    hostname[--len] = '\0';
                seen_hostname_argument = true;
                conf_set_str(conf, CONF_host, hostname);

                if ((cmdline_tooltype & TOOLTYPE_HOST_ARG_CAN_BE_SESSION) &&
                    !loaded_session) {
                    /*
                     * For some tools, we equivocate between a
		     * hostname argument and an argument naming a
		     * saved session. Here we attempt to load a
		     * session with the specified name, and if that
		     * session exists and is launchable, we overwrite
		     * the entire Conf with it.
                     *
                     * We skip this check if a -load option has
                     * already happened, so that
                     *
                     *   plink -load non-launchable-session hostname
                     *
                     * will treat 'hostname' as a hostname _even_ if a
                     * saved session called 'hostname' exists. (This
                     * doesn't lose any functionality someone could
                     * have needed, because if 'hostname' did cause a
                     * session to be loaded, then it would overwrite
                     * everything from the previously loaded session.
                     * So if that was the behaviour someone wanted,
                     * then they could get it by leaving off the
                     * -load completely.)
		     */
                    Conf *conf2 = conf_new();
                    if (do_defaults(hostname_after_user, conf2) &&
                        conf_launchable(conf2)) {
                        conf_copy_into(conf, conf2);
                        loaded_session = true;
                        /* And override the username if one was given. */
                        if (user)
                            conf_set_str(conf, CONF_username, user);
                    }
                    conf_free(conf2);
                }

                sfree(hostname);
                sfree(user);

                if (port_override >= 0)
                    conf_set_int(conf, CONF_port, port_override);
            }

            return 1;
        } else if ((cmdline_tooltype & TOOLTYPE_PORT_ARG) &&
                   !seen_port_argument) {
            /*
             * If we've already got a host name from the command line
             * (either as a hostname argument or a qualifying -load),
             * but not a port number, then treat the next argument as
             * a port number.
             *
             * We handle this by calling ourself recursively to
             * pretend we received a -P argument, so that it will be
             * deferred until it's a good moment to run it.
             */
            char *dup = dupstr(p);     /* 'value' is not a const char * */
            int retd = cmdline_process_param("-P", dup, 1, conf);
            sfree(dup);
            assert(retd == 2);
            seen_port_argument = true;
            return 1;
        } else {
            /*
             * Refuse to recognise this argument, and give it back to
             * the tool's own command-line processing.
             */
            return 0;
        }
    }

#ifdef PUTTYNG
	if (!stricmp(p, "-hwndparent")) {
		RETURN(2);
		hwnd_parent = atoi(value);
		return 2;
	}
#endif

    if (!strcmp(p, "-load")) {
	RETURN(2);
	/* This parameter must be processed immediately rather than being
	 * saved. */
	do_defaults(value, conf);
	loaded_session = true;
	cmdline_session_name = dupstr(value);
	return 2;
    }
    if (!strcmp(p, "-ssh")) {
	RETURN(1);
	UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK);
	SAVEABLE(0);
	default_protocol = PROT_SSH;
	default_port = 22;
	conf_set_int(conf, CONF_protocol, default_protocol);
	conf_set_int(conf, CONF_port, default_port);
	return 1;
    }
    if (!strcmp(p, "-telnet")) {
	RETURN(1);
	UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK);
	SAVEABLE(0);
	default_protocol = PROT_TELNET;
	default_port = 23;
	conf_set_int(conf, CONF_protocol, default_protocol);
	conf_set_int(conf, CONF_port, default_port);
	return 1;
    }
    if (!strcmp(p, "-rlogin")) {
	RETURN(1);
	UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK);
	SAVEABLE(0);
	default_protocol = PROT_RLOGIN;
	default_port = 513;
	conf_set_int(conf, CONF_protocol, default_protocol);
	conf_set_int(conf, CONF_port, default_port);
	return 1;
    }
    if (!strcmp(p, "-raw")) {
	RETURN(1);
	UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK);
	SAVEABLE(0);
	default_protocol = PROT_RAW;
	conf_set_int(conf, CONF_protocol, default_protocol);
    }
    if (!strcmp(p, "-serial")) {
	RETURN(1);
	/* Serial is not NONNETWORK in an odd sense of the word */
	UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK);
	SAVEABLE(0);
	default_protocol = PROT_SERIAL;
	conf_set_int(conf, CONF_protocol, default_protocol);
	/* The host parameter will already be loaded into CONF_host,
	 * so copy it across */
	conf_set_str(conf, CONF_serline, conf_get_str(conf, CONF_host));
    }
    if (!strcmp(p, "-v")) {
	RETURN(1);
	flags |= FLAG_VERBOSE;
    }
    if (!strcmp(p, "-l")) {
	RETURN(2);
	UNAVAILABLE_IN(TOOLTYPE_NONNETWORK);
	SAVEABLE(0);
	conf_set_str(conf, CONF_username, value);
    }
    if (!strcmp(p, "-loghost")) {
	RETURN(2);
	UNAVAILABLE_IN(TOOLTYPE_NONNETWORK);
	SAVEABLE(0);
	conf_set_str(conf, CONF_loghost, value);
    }
    if (!strcmp(p, "-hostkey")) {
        char *dup;
	RETURN(2);
	UNAVAILABLE_IN(TOOLTYPE_NONNETWORK);
	SAVEABLE(0);
        dup = dupstr(value);
        if (!validate_manual_hostkey(dup)) {
            cmdline_error("'%s' is not a valid format for a manual host "
                          "key specification", value);
            sfree(dup);
            return ret;
        }
	conf_set_str_str(conf, CONF_ssh_manual_hostkeys, dup, "");
        sfree(dup);
    }
    if ((!strcmp(p, "-L") || !strcmp(p, "-R") || !strcmp(p, "-D"))) {
	char type, *q, *qq, *key, *val;
	RETURN(2);
	UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK);
	SAVEABLE(0);
	if (strcmp(p, "-D")) {
	    /*
             * For -L or -R forwarding types:
             *
	     * We expect _at least_ two colons in this string. The
	     * possible formats are `sourceport:desthost:destport',
	     * or `sourceip:sourceport:desthost:destport' if you're
	     * specifying a particular loopback address. We need to
	     * replace the one between source and dest with a \t;
	     * this means we must find the second-to-last colon in
	     * the string.
	     *
	     * (This looks like a foolish way of doing it given the
	     * existence of strrchr, but it's more efficient than
	     * two strrchrs - not to mention that the second strrchr
	     * would require us to modify the input string!)
	     */

            type = p[1];               /* 'L' or 'R' */

	    q = qq = host_strchr(value, ':');
	    while (qq) {
		char *qqq = host_strchr(qq+1, ':');
		if (qqq)
		    q = qq;
		qq = qqq;
	    }

	    if (!q) {
		cmdline_error("-%c expects at least two colons in its"
			      " argument", type);
		return ret;
	    }

	    key = dupprintf("%c%.*s", type, (int)(q - value), value);
	    val = dupstr(q+1);
	} else {
            /*
             * Dynamic port forwardings are entered under the same key
             * as if they were local (because they occupy the same
             * port space - a local and a dynamic forwarding on the
             * same local port are mutually exclusive), with the
             * special value "D" (which can be distinguished from
             * anything in the ordinary -L case by containing no
             * colon).
             */
	    key = dupprintf("L%s", value);
	    val = dupstr("D");
	}
	conf_set_str_str(conf, CONF_portfwd, key, val);
	sfree(key);
	sfree(val);
    }
    if ((!strcmp(p, "-nc"))) {
	char *host, *portp;

	RETURN(2);
	UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK);
	SAVEABLE(0);

	portp = host_strchr(value, ':');
	if (!portp) {
	    cmdline_error("-nc expects argument of form 'host:port'");
	    return ret;
	}

	host = dupprintf("%.*s", (int)(portp - value), value);
	conf_set_str(conf, CONF_ssh_nc_host, host);
	conf_set_int(conf, CONF_ssh_nc_port, atoi(portp + 1));
        sfree(host);
    }
    if (!strcmp(p, "-m")) {
	const char *filename;
	FILE *fp;

	RETURN(2);
	UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK);
	SAVEABLE(0);

	filename = value;

	fp = fopen(filename, "r");
	if (!fp) {
	    cmdline_error("unable to open command file \"%s\"", filename);
	    return ret;
	}
        strbuf *command = strbuf_new();
        char readbuf[4096];
	while (1) {
            size_t nread = fread(readbuf, 1, sizeof(readbuf), fp);
            if (nread == 0)
                break;
            put_data(command, readbuf, nread);
	}
	fclose(fp);
	conf_set_str(conf, CONF_remote_cmd, command->s);
	conf_set_str(conf, CONF_remote_cmd2, "");
	conf_set_bool(conf, CONF_nopty, true);   /* command => no terminal */
	strbuf_free(command);
    }
    if (!strcmp(p, "-P")) {
	RETURN(2);
	UNAVAILABLE_IN(TOOLTYPE_NONNETWORK);
	SAVEABLE(1);		       /* lower priority than -ssh,-telnet */
	conf_set_int(conf, CONF_port, atoi(value));
    }
    if (!strcmp(p, "-pw")) {
	RETURN(2);
	UNAVAILABLE_IN(TOOLTYPE_NONNETWORK);
	SAVEABLE(1);
	/* We delay evaluating this until after the protocol is decided,
	 * so that we can warn if it's of no use with the selected protocol */
	if (conf_get_int(conf, CONF_protocol) != PROT_SSH)
	    cmdline_error("the -pw option can only be used with the "
			  "SSH protocol");
	else {
	    cmdline_password = dupstr(value);
	    /* Assuming that `value' is directly from argv, make a good faith
	     * attempt to trample it, to stop it showing up in `ps' output
	     * on Unix-like systems. Not guaranteed, of course. */
	    smemclr(value, strlen(value));
	}
    }

    if (!strcmp(p, "-agent") || !strcmp(p, "-pagent") ||
	!strcmp(p, "-pageant")) {
	RETURN(1);
	UNAVAILABLE_IN(TOOLTYPE_NONNETWORK);
	SAVEABLE(0);
	conf_set_bool(conf, CONF_tryagent, true);
    }
    if (!strcmp(p, "-noagent") || !strcmp(p, "-nopagent") ||
	!strcmp(p, "-nopageant")) {
	RETURN(1);
	UNAVAILABLE_IN(TOOLTYPE_NONNETWORK);
	SAVEABLE(0);
	conf_set_bool(conf, CONF_tryagent, false);
    }
    if (!strcmp(p, "-share")) {
	RETURN(1);
	UNAVAILABLE_IN(TOOLTYPE_NONNETWORK);
	SAVEABLE(0);
	conf_set_bool(conf, CONF_ssh_connection_sharing, true);
    }
    if (!strcmp(p, "-noshare")) {
	RETURN(1);
	UNAVAILABLE_IN(TOOLTYPE_NONNETWORK);
	SAVEABLE(0);
	conf_set_bool(conf, CONF_ssh_connection_sharing, false);
    }
    if (!strcmp(p, "-A")) {
	RETURN(1);
	UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK);
	SAVEABLE(0);
	conf_set_bool(conf, CONF_agentfwd, true);
    }
    if (!strcmp(p, "-a")) {
	RETURN(1);
	UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK);
	SAVEABLE(0);
	conf_set_bool(conf, CONF_agentfwd, false);
    }

    if (!strcmp(p, "-X")) {
	RETURN(1);
	UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK);
	SAVEABLE(0);
	conf_set_bool(conf, CONF_x11_forward, true);
    }
    if (!strcmp(p, "-x")) {
	RETURN(1);
	UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK);
	SAVEABLE(0);
	conf_set_bool(conf, CONF_x11_forward, false);
    }

    if (!strcmp(p, "-t")) {
	RETURN(1);
	UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK);
	SAVEABLE(1);	/* lower priority than -m */
	conf_set_bool(conf, CONF_nopty, false);
    }
    if (!strcmp(p, "-T")) {
	RETURN(1);
	UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK);
	SAVEABLE(1);
	conf_set_bool(conf, CONF_nopty, true);
    }

    if (!strcmp(p, "-N")) {
	RETURN(1);
	UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK);
	SAVEABLE(0);
	conf_set_bool(conf, CONF_ssh_no_shell, true);
    }

    if (!strcmp(p, "-C")) {
	RETURN(1);
	UNAVAILABLE_IN(TOOLTYPE_NONNETWORK);
	SAVEABLE(0);
	conf_set_bool(conf, CONF_compression, true);
    }

    if (!strcmp(p, "-1")) {
	RETURN(1);
	UNAVAILABLE_IN(TOOLTYPE_NONNETWORK);
	SAVEABLE(0);
	conf_set_int(conf, CONF_sshprot, 0);   /* ssh protocol 1 only */
    }
    if (!strcmp(p, "-2")) {
	RETURN(1);
	UNAVAILABLE_IN(TOOLTYPE_NONNETWORK);
	SAVEABLE(0);
	conf_set_int(conf, CONF_sshprot, 3);   /* ssh protocol 2 only */
    }

    if (!strcmp(p, "-i")) {
	Filename *fn;
	RETURN(2);
	UNAVAILABLE_IN(TOOLTYPE_NONNETWORK);
	SAVEABLE(0);
	fn = filename_from_str(value);
	conf_set_filename(conf, CONF_keyfile, fn);
        filename_free(fn);
    }

    if (!strcmp(p, "-4") || !strcmp(p, "-ipv4")) {
	RETURN(1);
	SAVEABLE(1);
	conf_set_int(conf, CONF_addressfamily, ADDRTYPE_IPV4);
    }
    if (!strcmp(p, "-6") || !strcmp(p, "-ipv6")) {
	RETURN(1);
	SAVEABLE(1);
	conf_set_int(conf, CONF_addressfamily, ADDRTYPE_IPV6);
    }
    if (!strcmp(p, "-sercfg")) {
	char* nextitem;
	RETURN(2);
	UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK);
	SAVEABLE(1);
	if (conf_get_int(conf, CONF_protocol) != PROT_SERIAL)
	    cmdline_error("the -sercfg option can only be used with the "
			  "serial protocol");
	/* Value[0] contains one or more , separated values, like 19200,8,n,1,X */
	nextitem = value;
	while (nextitem[0] != '\0') {
	    int length, skip;
	    char *end = strchr(nextitem, ',');
	    if (!end) {
		length = strlen(nextitem);
		skip = 0;
	    } else {
		length = end - nextitem;
		nextitem[length] = '\0';
		skip = 1;
	    }
	    if (length == 1) {
		switch (*nextitem) {
		  case '1':
		  case '2':
		    conf_set_int(conf, CONF_serstopbits, 2 * (*nextitem-'0'));
		    break;

		  case '5':
		  case '6':
		  case '7':
		  case '8':
		  case '9':
		    conf_set_int(conf, CONF_serdatabits, *nextitem-'0');
		    break;

		  case 'n':
		    conf_set_int(conf, CONF_serparity, SER_PAR_NONE);
		    break;
		  case 'o':
		    conf_set_int(conf, CONF_serparity, SER_PAR_ODD);
		    break;
		  case 'e':
		    conf_set_int(conf, CONF_serparity, SER_PAR_EVEN);
		    break;
		  case 'm':
		    conf_set_int(conf, CONF_serparity, SER_PAR_MARK);
		    break;
		  case 's':
		    conf_set_int(conf, CONF_serparity, SER_PAR_SPACE);
		    break;

		  case 'N':
		    conf_set_int(conf, CONF_serflow, SER_FLOW_NONE);
		    break;
		  case 'X':
		    conf_set_int(conf, CONF_serflow, SER_FLOW_XONXOFF);
		    break;
		  case 'R':
		    conf_set_int(conf, CONF_serflow, SER_FLOW_RTSCTS);
		    break;
		  case 'D':
		    conf_set_int(conf, CONF_serflow, SER_FLOW_DSRDTR);
		    break;

		  default:
		    cmdline_error("Unrecognised suboption \"-sercfg %c\"",
				  *nextitem);
		}
	    } else if (length == 3 && !strncmp(nextitem,"1.5",3)) {
		/* Messy special case */
		conf_set_int(conf, CONF_serstopbits, 3);
	    } else {
		int serspeed = atoi(nextitem);
		if (serspeed != 0) {
		    conf_set_int(conf, CONF_serspeed, serspeed);
		} else {
		    cmdline_error("Unrecognised suboption \"-sercfg %s\"",
				  nextitem);
		}
	    }
	    nextitem += length + skip;
	}
    }

    if (!strcmp(p, "-sessionlog")) {
	Filename *fn;
	RETURN(2);
	UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER);
	/* but available even in TOOLTYPE_NONNETWORK, cf pterm "-log" */
	SAVEABLE(0);
	fn = filename_from_str(value);
	conf_set_filename(conf, CONF_logfilename, fn);
	conf_set_int(conf, CONF_logtype, LGTYP_DEBUG);
        filename_free(fn);
    }

    if (!strcmp(p, "-sshlog") ||
        !strcmp(p, "-sshrawlog")) {
	Filename *fn;
	RETURN(2);
	UNAVAILABLE_IN(TOOLTYPE_NONNETWORK);
	SAVEABLE(0);
	fn = filename_from_str(value);
	conf_set_filename(conf, CONF_logfilename, fn);
	conf_set_int(conf, CONF_logtype,
                     !strcmp(p, "-sshlog") ? LGTYP_PACKETS :
                     /* !strcmp(p, "-sshrawlog") ? */ LGTYP_SSHRAW);
        filename_free(fn);
    }

    if (!strcmp(p, "-proxycmd")) {
	RETURN(2);
	UNAVAILABLE_IN(TOOLTYPE_NONNETWORK);
	SAVEABLE(0);
        conf_set_int(conf, CONF_proxy_type, PROXY_CMD);
	conf_set_str(conf, CONF_proxy_telnet_command, value);
    }

#ifdef _WINDOWS
    /*
     * Cross-tool options only available on Windows.
     */
    if (!strcmp(p, "-restrict-acl") || !strcmp(p, "-restrict_acl") ||
        !strcmp(p, "-restrictacl")) {
	RETURN(1);
        restrict_process_acl();
        restricted_acl = true;
    }
#endif

    return ret;			       /* unrecognised */
}
Beispiel #20
0
void align_scoring_load_pairwise(gzFile file, const char* file_path,
                                 scoring_t* scoring, char case_sensitive)
{
    StrBuf* sbuf = strbuf_new(200);
    size_t read_length;
    int line_num = 0;

    char a, b;
    int score;

    int num_pairs_added = 0;

    while((read_length = strbuf_reset_gzreadline(sbuf, file)) > 0)
    {
        strbuf_chomp(sbuf);

        if(sbuf->end > 0 && sbuf->b[0] != '#' && // line is not empty, not comment
                !string_is_all_whitespace(sbuf->b)) // and not whitespace
        {
            if(read_length < 5)
            {
                _loading_error("Too few column headings", file_path, line_num, 0);
            }

            if(isspace(sbuf->b[1]))
            {
                // split by whitespace
                a = sbuf->b[0];

                size_t char2_pos;

                for(char2_pos = 1;
                        sbuf->b[char2_pos] != '\0' && isspace(sbuf->b[char2_pos]);
                        char2_pos++);

                if(char2_pos+2 >= sbuf->end || !isspace(sbuf->b[char2_pos+1]))
                {
                    _loading_error("Line too short", file_path, line_num, 0);
                }

                b = sbuf->b[char2_pos];

                if(!parse_entire_int(sbuf->b+char2_pos+2, &score))
                {
                    _loading_error("Invalid number", file_path, line_num, 0);
                }
            }
            else
            {
                if(sbuf->b[1] != sbuf->b[3])
                {
                    _loading_error("Inconsistent separators used", file_path, line_num, 0);
                }

                a = sbuf->b[0];
                b = sbuf->b[2];

                if(!parse_entire_int(sbuf->b + 4, &score))
                {
                    _loading_error("Invalid number", file_path, line_num, 0);
                }
            }

            if(!case_sensitive)
            {
                a = tolower(a);
                b = tolower(b);
            }

            scoring_add_mutation(scoring, a, b, score);
            num_pairs_added++;
        }

        line_num++;
    }

    strbuf_free(sbuf);

    if(num_pairs_added == 0)
    {
        _loading_error("No pairs added from file (file empty?)",
                       file_path, line_num, 0);
    }
}
int main(int argc, char **argv)
{
    abrt_init(argv);

    /* Can't keep these strings/structs static: _() doesn't support that */
    const char *program_usage_string = _(
        "\b [options] -d DIR\n"
        "\n"
        "Analyzes C/C++ backtrace, generates duplication hash, backtrace rating, and identifies crash function in dump directory DIR"
    );
    enum {
        OPT_v = 1 << 0,
        OPT_d = 1 << 1
    };
    /* Keep enum above and order of options below in sync! */
    struct options program_options[] = {
        OPT__VERBOSE(&g_verbose),
        OPT_STRING('d', NULL, &dump_dir_name, "DIR", _("Dump directory")),
        OPT_END()
    };
    /*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string);

    export_abrt_envvars(0);

    struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
    if (!dd)
        return 1;

    char *component = dd_load_text(dd, FILENAME_COMPONENT);

    /* Read backtrace */
    char *backtrace_str = dd_load_text_ext(dd, FILENAME_BACKTRACE,
                                           DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE);
    if (!backtrace_str)
    {
        dd_close(dd);
        return 1;
    }

    /* Compute backtrace hash */
    struct btp_location location;
    btp_location_init(&location);
    char *backtrace_str_ptr = backtrace_str;
    struct btp_backtrace *backtrace = btp_backtrace_parse(&backtrace_str_ptr, &location);
    free(backtrace_str);

    /* Store backtrace hash */
    if (!backtrace)
    {
        /*
         * The parser failed. Compute the duphash from the executable
         * instead of a backtrace.
         * and component only.  This is not supposed to happen often.
         */
        log(_("Backtrace parsing failed for %s"), dump_dir_name);
        log("%d:%d: %s", location.line, location.column, location.message);
        struct strbuf *emptybt = strbuf_new();

        char *executable = dd_load_text(dd, FILENAME_EXECUTABLE);
        strbuf_prepend_str(emptybt, executable);
        free(executable);

        strbuf_prepend_str(emptybt, component);

        VERB3 log("Generating duphash: %s", emptybt->buf);
        char hash_str[SHA1_RESULT_LEN*2 + 1];
        create_hash(hash_str, emptybt->buf);

        dd_save_text(dd, FILENAME_DUPHASH, hash_str);
        /*
         * Other parts of ABRT assume that if no rating is available,
         * it is ok to allow reporting of the bug. To be sure no bad
         * backtrace is reported, rate the backtrace with the lowest
         * rating.
         */
        dd_save_text(dd, FILENAME_RATING, "0");

        strbuf_free(emptybt);
        free(component);
        dd_close(dd);

        /* Report success even if the parser failed, as the backtrace
         * has been created and rated. The failure is caused by a flaw
         * in the parser, not in the backtrace.
         */
        return 0;
    }

    /* Compute duplication hash. */
    char *str_hash_core = btp_backtrace_get_duplication_hash(backtrace);
    struct strbuf *str_hash = strbuf_new();
    strbuf_append_str(str_hash, component);
    strbuf_append_str(str_hash, str_hash_core);

    VERB3 log("Generating duphash: %s", str_hash->buf);
    char hash_str[SHA1_RESULT_LEN*2 + 1];
    create_hash(hash_str, str_hash->buf);

    dd_save_text(dd, FILENAME_DUPHASH, hash_str);
    strbuf_free(str_hash);
    free(str_hash_core);

    /* Compute the backtrace rating. */
    float quality = btp_backtrace_quality_complex(backtrace);
    const char *rating;
    if (quality < 0.6f)
        rating = "0";
    else if (quality < 0.7f)
        rating = "1";
    else if (quality < 0.8f)
        rating = "2";
    else if (quality < 0.9f)
        rating = "3";
    else
        rating = "4";
    dd_save_text(dd, FILENAME_RATING, rating);

    /* Get the function name from the crash frame. */
    struct btp_frame *crash_frame = btp_backtrace_get_crash_frame(backtrace);
    if (crash_frame)
    {
        if (crash_frame->function_name &&
            0 != strcmp(crash_frame->function_name, "??"))
        {
            dd_save_text(dd, FILENAME_CRASH_FUNCTION, crash_frame->function_name);
        }
        btp_frame_free(crash_frame);
    }
    btp_backtrace_free(backtrace);
    dd_close(dd);
    free(component);
    return 0;
}
Beispiel #22
0
void align_scoring_load_matrix(gzFile file, const char* file_path,
                               scoring_t* scoring, char case_sensitive)
{
    StrBuf* sbuf = strbuf_new(500);
    size_t read_length;
    int line_num = 0;

    // Read first line (column headings)
    while((read_length = strbuf_reset_gzreadline(sbuf, file)) > 0)
    {
        strbuf_chomp(sbuf);

        if(sbuf->end > 0 && sbuf->b[0] != '#' && // line is not empty, not comment
                !string_is_all_whitespace(sbuf->b)) // and not whitespace
        {
            // Read first line

            if(sbuf->end < 2)
            {
                _loading_error("Too few column headings", file_path, line_num, 1);
            }

            break;
        }

        line_num++;
    }

    if(line_num == 0 && sbuf->end <= 0)
    {
        _loading_error("Empty file", file_path, -1, 0);
    }

    // If the separator character is whitespace,
    // the set of whitespace characters is used
    char sep = sbuf->b[0];

    if((sep >= (int)'0' && sep <= (int)'9') || sep == '-')
    {
        _loading_error("Numbers (0-9) and dashes (-) do not make good separators",
                       file_path, line_num, 0);
    }

    char* characters = (char*)malloc(sbuf->end);
    int num_of_chars = 0;

    if(isspace(sep))
    {
        char* next = sbuf->b;

        while((next = string_next_nonwhitespace(next+1)) != NULL)
        {
            characters[num_of_chars++] = case_sensitive ? *next : tolower(*next);
        }

        // Now read lines below
        while((read_length = strbuf_reset_gzreadline(sbuf, file)) > 0)
        {
            strbuf_chomp(sbuf);

            char* from_char_pos = string_next_nonwhitespace(sbuf->b);

            if(from_char_pos == NULL || sbuf->b[0] == '#')
            {
                // skip this line
                continue;
            }

            char from_char = case_sensitive ? *from_char_pos : tolower(*from_char_pos);
            char to_char;

            char* score_txt = sbuf->b+1;
            int score;

            int i;
            for(i = 0; i < num_of_chars; i++)
            {
                to_char = characters[i];

                if(!isspace(*score_txt))
                {
                    _loading_error("Expected whitespace between elements - found character",
                                   file_path, line_num, 1);
                }

                score_txt = string_next_nonwhitespace(score_txt+1);

                char* strtol_last_char_ptr = score_txt;
                score = (int)strtol(strtol_last_char_ptr, &strtol_last_char_ptr, 10);

                // If pointer to end of number string hasn't moved -> error
                if(strtol_last_char_ptr == score_txt)
                {
                    _loading_error("Missing number value on line", file_path, line_num, 1);
                }

                scoring_add_mutation(scoring, from_char, to_char, score);

                score_txt = strtol_last_char_ptr;
            }

            if(*score_txt != '\0' && !string_is_all_whitespace(score_txt))
            {
                _loading_error("Too many columns on row", file_path, line_num, 1);
            }

            line_num++;
        }
    }
    else
    {
        size_t i;

        for(i = 0; i < sbuf->end; i += 2)
        {
            if(sbuf->b[i] != sep)
            {
                _loading_error("Separator missing from line", file_path, line_num, 1);
            }

            char c = case_sensitive ? sbuf->b[i+1] : tolower(sbuf->b[i+1]);
            characters[num_of_chars++] = c;
        }

        int score;

        // Read rows
        while((read_length = strbuf_reset_gzreadline(sbuf, file)) > 0)
        {
            strbuf_chomp(sbuf);

            char from_char = case_sensitive ? sbuf->b[0] : tolower(sbuf->b[0]);

            if(from_char == '#' || string_is_all_whitespace(sbuf->b))
            {
                // skip this line
                continue;
            }

            char* str_pos = sbuf->b;

            int to_char_index = 0;
            char to_char;

            while(*str_pos != '\0')
            {
                to_char = characters[to_char_index++];

                if(*str_pos != sep)
                {
                    _loading_error("Separator missing from line", file_path, line_num, 1);
                }

                // Move past separator
                str_pos++;

                char* after_num_str = str_pos;
                score = (int)strtol(str_pos, &after_num_str, 10);

                // If pointer to end of number string hasn't moved -> error
                if(str_pos == after_num_str)
                {
                    _loading_error("Missing number value on line", file_path, line_num, 1);
                }

                if(to_char_index >= num_of_chars)
                {
                    _loading_error("Too many columns on row", file_path, line_num, 1);
                }

                scoring_add_mutation(scoring, from_char, to_char, score);

                str_pos = after_num_str;
            }

            line_num++;
        }
    }

    free(characters);
    strbuf_free(sbuf);
}
Beispiel #23
0
static int run_post_create(const char *dirname)
{
    /* If doesn't start with "g_settings_dump_location/"... */
    if (!dir_is_in_dump_location(dirname))
    {
        /* Then refuse to operate on it (someone is attacking us??) */
        error_msg("Bad problem directory name '%s', should start with: '%s'", dirname, g_settings_dump_location);
        return 400; /* Bad Request */
    }
    if (!dir_has_correct_permissions(dirname, DD_PERM_EVENTS))
    {
        error_msg("Problem directory '%s' has wrong owner or group", dirname);
        return 400; /*  */
    }
    /* Check completness */
    {
        struct dump_dir *dd = dd_opendir(dirname, DD_OPEN_READONLY);

        char *provoker = NULL;
        const bool event_dir = dd && problem_dump_dir_was_provoked_by_abrt_event(dd, &provoker);
        if (event_dir)
        {
            if (g_settings_debug_level == 0)
            {
                error_msg("Removing problem provoked by ABRT(pid:%s): '%s'", provoker, dirname);
                dd_delete(dd);
            }
            else
            {
                char *dumpdir = NULL;
                char *event   = NULL;
                char *reason  = NULL;
                char *cmdline = NULL;

                /* Ignore errors */
                dd_get_env_variable(dd, "DUMP_DIR", &dumpdir);
                dd_get_env_variable(dd, "EVENT",    &event);
                reason  = dd_load_text(dd, FILENAME_REASON);
                cmdline = dd_load_text(dd, FILENAME_CMDLINE);

                error_msg("ABRT_SERVER_PID=%s;DUMP_DIR='%s';EVENT='%s';REASON='%s';CMDLINE='%s'",
                           provoker, dumpdir, event, reason, cmdline);

            }

            free(provoker);
            return 400;
        }

        const bool complete = dd && problem_dump_dir_is_complete(dd);
        dd_close(dd);
        if (complete)
        {
            error_msg("Problem directory '%s' has already been processed", dirname);
            return 403;
        }
    }

    int child_stdout_fd;
    int child_pid = spawn_event_handler_child(dirname, "post-create", &child_stdout_fd);

    char *dup_of_dir = NULL;
    struct strbuf *cmd_output = strbuf_new();

    bool child_is_post_create = 1; /* else it is a notify child */

 read_child_output:
    //log("Reading from event fd %d", child_stdout_fd);

    /* Read streamed data and split lines */
    for (;;)
    {
        char buf[250]; /* usually we get one line, no need to have big buf */
        errno = 0;
        int r = safe_read(child_stdout_fd, buf, sizeof(buf) - 1);
        if (r <= 0)
            break;
        buf[r] = '\0';

        /* split lines in the current buffer */
        char *raw = buf;
        char *newline;
        while ((newline = strchr(raw, '\n')) != NULL)
        {
            *newline = '\0';
            strbuf_append_str(cmd_output, raw);
            char *msg = cmd_output->buf;

            if (child_is_post_create
             && prefixcmp(msg, "DUP_OF_DIR: ") == 0
            ) {
                free(dup_of_dir);
                dup_of_dir = xstrdup(msg + strlen("DUP_OF_DIR: "));
            }
            else
                log("%s", msg);

            strbuf_clear(cmd_output);
            /* jump to next line */
            raw = newline + 1;
        }

        /* beginning of next line. the line continues by next read */
        strbuf_append_str(cmd_output, raw);
    }

    /* EOF/error */

    /* Wait for child to actually exit, collect status */
    int status = 0;
    if (safe_waitpid(child_pid, &status, 0) <= 0)
    /* should not happen */
        perror_msg("waitpid(%d)", child_pid);

    /* If it was a "notify[-dup]" event, then we're done */
    if (!child_is_post_create)
        goto ret;

    /* exit 0 means "this is a good, non-dup dir" */
    /* exit with 1 + "DUP_OF_DIR: dir" string => dup */
    if (status != 0)
    {
        if (WIFSIGNALED(status))
        {
            log("'post-create' on '%s' killed by signal %d",
                            dirname, WTERMSIG(status));
            goto delete_bad_dir;
        }
        /* else: it is WIFEXITED(status) */
        if (!dup_of_dir)
        {
            log("'post-create' on '%s' exited with %d",
                            dirname, WEXITSTATUS(status));
            goto delete_bad_dir;
        }
    }

    const char *work_dir = (dup_of_dir ? dup_of_dir : dirname);

    /* Load problem_data (from the *first dir* if this one is a dup) */
    struct dump_dir *dd = dd_opendir(work_dir, /*flags:*/ 0);
    if (!dd)
        /* dd_opendir already emitted error msg */
        goto delete_bad_dir;

    /* Update count */
    char *count_str = dd_load_text_ext(dd, FILENAME_COUNT, DD_FAIL_QUIETLY_ENOENT);
    unsigned long count = strtoul(count_str, NULL, 10);

    /* Don't increase crash count if we are working with newly uploaded
     * directory (remote crash) which already has its crash count set.
     */
    if ((status != 0 && dup_of_dir) || count == 0)
    {
        count++;
        char new_count_str[sizeof(long)*3 + 2];
        sprintf(new_count_str, "%lu", count);
        dd_save_text(dd, FILENAME_COUNT, new_count_str);

        /* This condition can be simplified to either
         * (status * != 0 && * dup_of_dir) or (count == 1). But the
         * chosen form is much more reliable and safe. We must not call
         * dd_opendir() to locked dd otherwise we go into a deadlock.
         */
        if (strcmp(dd->dd_dirname, dirname) != 0)
        {
            /* Update the last occurrence file by the time file of the new problem */
            struct dump_dir *new_dd = dd_opendir(dirname, DD_OPEN_READONLY);
            char *last_ocr = NULL;
            if (new_dd)
            {
                /* TIME must exists in a valid dump directory but we don't want to die
                 * due to broken duplicated dump directory */
                last_ocr = dd_load_text_ext(new_dd, FILENAME_TIME,
                            DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE | DD_FAIL_QUIETLY_ENOENT);
                dd_close(new_dd);
            }
            else
            {   /* dd_opendir() already produced a message with good information about failure */
                error_msg("Can't read the last occurrence file from the new dump directory.");
            }

            if (!last_ocr)
            {   /* the new dump directory may lie in the dump location for some time */
                log("Using current time for the last occurrence file which may be incorrect.");
                time_t t = time(NULL);
                last_ocr = xasprintf("%lu", (long)t);
            }

            dd_save_text(dd, FILENAME_LAST_OCCURRENCE, last_ocr);

            free(last_ocr);
        }
    }

    /* Reset mode/uig/gid to correct values for all files created by event run */
    dd_sanitize_mode_and_owner(dd);

    dd_close(dd);

    if (!dup_of_dir)
        log_notice("New problem directory %s, processing", work_dir);
    else
    {
        log_warning("Deleting problem directory %s (dup of %s)",
                    strrchr(dirname, '/') + 1,
                    strrchr(dup_of_dir, '/') + 1);
        delete_dump_dir(dirname);
    }

    /* Run "notify[-dup]" event */
    int fd;
    child_pid = spawn_event_handler_child(
                work_dir,
                (dup_of_dir ? "notify-dup" : "notify"),
                &fd
    );
    //log("Started notify, fd %d -> %d", fd, child_stdout_fd);
    xmove_fd(fd, child_stdout_fd);
    child_is_post_create = 0;
    strbuf_clear(cmd_output);
    free(dup_of_dir);
    dup_of_dir = NULL;
    goto read_child_output;

 delete_bad_dir:
    log_warning("Deleting problem directory '%s'", dirname);
    delete_dump_dir(dirname);

 ret:
    strbuf_free(cmd_output);
    free(dup_of_dir);
    close(child_stdout_fd);
    return 0;
}
Beispiel #24
0
char *make_description(problem_data_t *problem_data, char **names_to_skip,
                       unsigned max_text_size, unsigned desc_flags)
{
    struct strbuf *buf_dsc = strbuf_new();

    const char *analyzer = problem_data_get_content_or_NULL(problem_data,
                                                            FILENAME_ANALYZER);

    GList *list = g_hash_table_get_keys(problem_data);
    list = g_list_sort(list, (GCompareFunc)strcmp);
    GList *l;

    /* Print one-liners. Format:
     * NAME1: <maybe more spaces>VALUE1
     * NAME2: <maybe more spaces>VALUE2
     */
    bool empty = true;
    l = list;
    while (l)
    {
        const char *key = l->data;
        l = l->next;

        /* Skip items we are not interested in */
//TODO: optimize by doing this once, not 3 times:
        if (names_to_skip
            && rejected_name(key, names_to_skip, desc_flags))
            continue;

        struct problem_item *item = g_hash_table_lookup(problem_data, key);
        if (!item)
            continue;

        if ((desc_flags & MAKEDESC_SHOW_ONLY_LIST) && !(item->flags & CD_FLAG_LIST))
            continue;

        if ((item->flags & CD_FLAG_TXT)
         && strlen(item->content) <= max_text_size
        ) {
            char *formatted = problem_item_format(item);
            char *output = formatted ? formatted : item->content;
            char *eol = strchr(output, '\n');
            if (!eol)
            {
                int pad = 16 - (strlen(key) + 2);
                if (pad < 0) pad = 0;
                strbuf_append_strf(buf_dsc, "%s: %*s%s\n", key, pad, "", output);
                empty = false;
            }
            free(formatted);
        }
    }

    bool append_empty_line = !empty;
    if (desc_flags & MAKEDESC_SHOW_FILES)
    {
        /* Print file info. Format:
         * <empty line if needed>
         * NAME1: <maybe more spaces>Binary file, NNN bytes
         * NAME2: <maybe more spaces>Text file, NNN bytes
         *
         * In many cases, it is useful to know how big binary files are
         * (for example, helps with diagnosing bug upload problems)
         */
        l = list;
        while (l)
        {
            const char *key = l->data;
            l = l->next;

            /* Skip items we are not interested in */
            if (names_to_skip
                && rejected_name(key, names_to_skip, desc_flags))
                continue;

            struct problem_item *item = g_hash_table_lookup(problem_data, key);
            if (!item)
                continue;

            if ((desc_flags & MAKEDESC_SHOW_ONLY_LIST) && !(item->flags & CD_FLAG_LIST))
                continue;

            if ((item->flags & CD_FLAG_BIN)
             || ((item->flags & CD_FLAG_TXT) && strlen(item->content) > max_text_size)
            ) {
                if (append_empty_line)
                    strbuf_append_char(buf_dsc, '\n');
                append_empty_line = false;

                struct stat statbuf;
                int stat_err = 0;
                if (item->flags & CD_FLAG_BIN)
                    stat_err = stat(item->content, &statbuf);
                else
                    statbuf.st_size = strlen(item->content);

                /* We don't print item->content for CD_FLAG_BIN, as it is
                 * always "/path/to/dump/dir/KEY" - not informative.
                 */
                int pad = 16 - (strlen(key) + 2);
                if (pad < 0) pad = 0;
                strbuf_append_strf(buf_dsc,
                        (!stat_err ? "%s: %*s%s file, %llu bytes\n" : "%s: %*s%s file\n"),
                        key,
                        pad, "",
                        ((item->flags & CD_FLAG_BIN) ? "Binary" : "Text"),
                        (long long)statbuf.st_size
                );
                empty = false;
            }
        }
    }

    if (desc_flags & MAKEDESC_SHOW_MULTILINE)
    {
        /* Print multi-liners. Format:
         * <empty line if needed>
         * NAME:
         * :LINE1
         * :LINE2
         * :LINE3
         */
        l = list;
        while (l)
        {
            const char *key = l->data;
            l = l->next;

            /* Skip items we are not interested in */
            if (names_to_skip
                && rejected_name(key, names_to_skip, desc_flags))
                continue;

            struct problem_item *item = g_hash_table_lookup(problem_data, key);
            if (!item)
                continue;

            if ((desc_flags & MAKEDESC_SHOW_ONLY_LIST) && !(item->flags & CD_FLAG_LIST))
                continue;

            if ((item->flags & CD_FLAG_TXT)
                && (strlen(item->content) <= max_text_size
                    || (!strcmp(analyzer, "Kerneloops") && !strcmp(key, FILENAME_BACKTRACE))))
            {
                char *formatted = problem_item_format(item);
                char *output = make_description_item_multiline(key, formatted ? formatted : item->content);

                if (output)
                {
                    if (!empty)
                        strbuf_append_str(buf_dsc, "\n");

                    strbuf_append_str(buf_dsc, output);
                    empty = false;
                    free(output);
                }

                free(formatted);
            }
        }
    }

    g_list_free(list);

    return strbuf_free_nobuf(buf_dsc);
}
Beispiel #25
0
static int adm_hwdb(struct udev *udev, int argc, char *argv[]) {
        static const struct option options[] = {
                { "update", no_argument, NULL, 'u' },
                { "root", required_argument, NULL, 'r' },
                { "test", required_argument, NULL, 't' },
                { "help", no_argument, NULL, 'h' },
                {}
        };
        const char *test = NULL;
        const char *root = "";
        bool update = false;
        struct trie *trie = NULL;
        int err;
        int rc = EXIT_SUCCESS;

        for (;;) {
                int option;

                option = getopt_long(argc, argv, "ut:r:h", options, NULL);
                if (option == -1)
                        break;

                switch (option) {
                case 'u':
                        update = true;
                        break;
                case 't':
                        test = optarg;
                        break;
                case 'r':
                        root = optarg;
                        break;
                case 'h':
                        help();
                        return EXIT_SUCCESS;
                }
        }

        if (!update && !test) {
                help();
                return EXIT_SUCCESS;
        }

        if (update) {
                char **files, **f;
                _cleanup_free_ char *hwdb_bin = NULL;

                trie = calloc(sizeof(struct trie), 1);
                if (!trie) {
                        rc = EXIT_FAILURE;
                        goto out;
                }

                /* string store */
                trie->strings = strbuf_new();
                if (!trie->strings) {
                        rc = EXIT_FAILURE;
                        goto out;
                }

                /* index */
                trie->root = calloc(sizeof(struct trie_node), 1);
                if (!trie->root) {
                        rc = EXIT_FAILURE;
                        goto out;
                }
                trie->nodes_count++;

                err = conf_files_list_strv(&files, ".hwdb", root, conf_file_dirs);
                if (err < 0) {
                        log_error("failed to enumerate hwdb files: %s\n", strerror(-err));
                        rc = EXIT_FAILURE;
                        goto out;
                }
                STRV_FOREACH(f, files) {
                        log_debug("reading file '%s'", *f);
                        import_file(trie, *f);
                }
                strv_free(files);

                strbuf_complete(trie->strings);

                log_debug("=== trie in-memory ===\n");
                log_debug("nodes:            %8zu bytes (%8zu)\n",
                          trie->nodes_count * sizeof(struct trie_node), trie->nodes_count);
                log_debug("children arrays:  %8zu bytes (%8zu)\n",
                          trie->children_count * sizeof(struct trie_child_entry), trie->children_count);
                log_debug("values arrays:    %8zu bytes (%8zu)\n",
                          trie->values_count * sizeof(struct trie_value_entry), trie->values_count);
                log_debug("strings:          %8zu bytes\n",
                          trie->strings->len);
                log_debug("strings incoming: %8zu bytes (%8zu)\n",
                          trie->strings->in_len, trie->strings->in_count);
                log_debug("strings dedup'ed: %8zu bytes (%8zu)\n",
                          trie->strings->dedup_len, trie->strings->dedup_count);

                if (asprintf(&hwdb_bin, "%s/" UDEVLIBEXECDIR "/hwdb.bin", root) < 0) {
                        rc = EXIT_FAILURE;
                        goto out;
                }
                mkdir_parents(hwdb_bin, 0755);
                err = trie_store(trie, hwdb_bin);
                if (err < 0) {
                        log_error("Failure writing database %s: %s", hwdb_bin, strerror(-err));
                        rc = EXIT_FAILURE;
                }
        }
Beispiel #26
0
static
char *format_percented_string(const char *str, problem_data_t *pd)
{
    size_t old_pos[MAX_OPT_DEPTH] = { 0 };
    int okay[MAX_OPT_DEPTH] = { 1 };
    int opt_depth = 1;
    struct strbuf *result = strbuf_new();

    while (*str) {
        switch (*str) {
        default:
            strbuf_append_char(result, *str);
            str++;
            break;
        case '\\':
            if (str[1])
                str++;
            strbuf_append_char(result, *str);
            str++;
            break;
        case '[':
            if (str[1] == '[' && opt_depth < MAX_OPT_DEPTH)
            {
                old_pos[opt_depth] = result->len;
                okay[opt_depth] = 1;
                opt_depth++;
                str += 2;
            } else {
                strbuf_append_char(result, *str);
                str++;
            }
            break;
        case ']':
            if (str[1] == ']' && opt_depth > 1)
            {
                opt_depth--;
                if (!okay[opt_depth])
                {
                    result->len = old_pos[opt_depth];
                    result->buf[result->len] = '\0';
                }
                str += 2;
            } else {
                strbuf_append_char(result, *str);
                str++;
            }
            break;
        case '%': ;
            char *nextpercent = strchr(++str, '%');
            if (!nextpercent)
            {
                error_msg_and_die("Unterminated %%element%%: '%s'", str - 1);
            }

            *nextpercent = '\0';
            const problem_item *item = problem_data_get_item_or_NULL(pd, str);
            *nextpercent = '%';

            if (item && (item->flags & CD_FLAG_TXT))
                strbuf_append_str(result, item->content);
            else
                okay[opt_depth - 1] = 0;
            str = nextpercent + 1;
            break;
        }
    }

    if (opt_depth > 1)
    {
        error_msg_and_die("Unbalanced [[ ]] bracket");
    }

    if (!okay[0])
    {
        error_msg("Undefined variable outside of [[ ]] bracket");
    }

    return strbuf_free_nobuf(result);
}
Beispiel #27
0
static int curl(lua_State *L) {
	uv_loop_t *loop = (uv_loop_t *)lua_touserptr(L, lua_upvalueindex(1));

	luv_curl_t *lc = (luv_curl_t *)lua_newuserdata(L, sizeof(luv_curl_t));
	memset(lc, 0, sizeof(luv_curl_t));
	int lc_idx = 2;

	lc->loop = loop;
	lc->L = L;

	lua_getfield(L, 1, "url");
	char *url = (char *)lua_tostring(L, -1);
	if (url == NULL) 
		panic("url must be set");

	lua_getfield(L, 1, "retry");
	lc->retry = lua_tonumber(L, -1);

	lua_getfield(L, 1, "retfile");
	char *retfname = (char *)lua_tostring(L, -1);
	if (retfname)
		lc->retfname = strdup(retfname);
	else
		lc->retsb = strbuf_new(2048);

	if (lc->retfname) {
		lc->retfp = fopen(lc->retfname, "wb+");
		info("'%s' opened", lc->retfname);
		if (lc->retfp == NULL) {
			warn("open '%s' failed", lc->retfname);
			lc->stat = ERROR;
			lc->err = "open_file_failed";
		}
	}

	lc->c = curl_easy_init();

	curl_easy_setopt(lc->c, CURLOPT_URL, url);
	curl_easy_setopt(lc->c, CURLOPT_WRITEFUNCTION, write_data);
	curl_easy_setopt(lc->c, CURLOPT_WRITEDATA, lc);

	curl_easy_setopt(lc->c, CURLOPT_SSL_VERIFYPEER, 0);

	//curl_easy_setopt(lc->c, CURLOPT_VERBOSE, 1);

	lua_getfield(L, 1, "reqstr");
	lc->reqstr = (char *)lua_tostring(L, -1);
	if (lc->reqstr) {
		//lc->reqstr_len = strlen(lc->reqstr);
		//curl_easy_setopt(lc->c, CURLOPT_READFUNCTION, read_data);
		//curl_easy_setopt(lc->c, CURLOPT_READDATA, lc);
		curl_easy_setopt(lc->c, CURLOPT_POSTFIELDS, lc->reqstr);
	}

	lua_getfield(L, 1, "done");
	lua_pushvalue(L, lc_idx); // userdata: must save it until call done
	lua_pushcclosure(L, curl_done, 2);
	lua_set_global_callback(L, "curl_done", lc->c);

	lua_getfield(L, 1, "proxy");
	char *proxy = (char *)lua_tostring(L, -1);
	curl_setproxy(lc, proxy);

	lua_getfield(L, 1, "content_type");
	curl_addheader(lc, "Content-Type", (char *)lua_tostring(L, -1));

	lua_getfield(L, 1, "user_agent");
	curl_addheader(lc, "User-Agent", (char *)lua_tostring(L, -1));

	lua_getfield(L, 1, "authorization");
	curl_addheader(lc, "Authorization", (char *)lua_tostring(L, -1));

	if (lc->headers)
		curl_easy_setopt(lc->c, CURLOPT_HTTPHEADER, lc->headers);

	// return {
	//   cancel = [native function],
	//   stat = [native function],
	// }
	lua_newtable(L);

	lua_pushvalue(L, lc_idx);
	lua_pushcclosure(L, curl_cancel, 1);
	lua_setfield(L, -2, "cancel");

	lua_pushvalue(L, lc_idx);
	lua_pushcclosure(L, curl_stat, 1);
	lua_setfield(L, -2, "stat");

	debug("thread starts");

	uv_work_t *w = (uv_work_t *)zalloc(sizeof(uv_work_t));
	w->data = lc;
	uv_queue_work(loop, w, curl_thread, curl_thread_done);

	return 1;
}
Beispiel #28
0
int main(int argc, char **argv)
{
    abrt_init(argv);

    /* I18n */
    setlocale(LC_ALL, "");
#if ENABLE_NLS
    bindtextdomain(PACKAGE, LOCALEDIR);
    textdomain(PACKAGE);
#endif

    /* Can't keep these strings/structs static: _() doesn't support that */
    const char *program_usage_string = _(
        "\n& [-vbf] [-g GROUP-NAME]... [-c CONFFILE]... [-F FMTFILE] [-A FMTFILE2] -d DIR"
        "\nor:"
        "\n& [-v] [-c CONFFILE]... [-d DIR] -t[ID] FILE..."
        "\nor:"
        "\n& [-v] [-c CONFFILE]... [-d DIR] -t[ID] -w"
        "\nor:"
        "\n& [-v] [-c CONFFILE]... -h DUPHASH"
        "\n"
        "\nReports problem to Bugzilla."
        "\n"
        "\nThe tool reads DIR. Then it logs in to Bugzilla and tries to find a bug"
        "\nwith the same abrt_hash:HEXSTRING in 'Whiteboard'."
        "\n"
        "\nIf such bug is not found, then a new bug is created. Elements of DIR"
        "\nare stored in the bug as part of bug description or as attachments,"
        "\ndepending on their type and size."
        "\n"
        "\nOtherwise, if such bug is found and it is marked as CLOSED DUPLICATE,"
        "\nthe tool follows the chain of duplicates until it finds a non-DUPLICATE bug."
        "\nThe tool adds a new comment to found bug."
        "\n"
        "\nThe URL to new or modified bug is printed to stdout and recorded in"
        "\n'reported_to' element."
        "\n"
        "\nOption -t uploads FILEs to the already created bug on Bugzilla site."
        "\nThe bug ID is retrieved from directory specified by -d DIR."
        "\nIf problem data in DIR was never reported to Bugzilla, upload will fail."
        "\n"
        "\nOption -tID uploads FILEs to the bug with specified ID on Bugzilla site."
        "\n-d DIR is ignored."
        "\n"
        "\nOption -w adds bugzilla user to bug's CC list."
        "\n"
        "\nIf not specified, CONFFILE defaults to "CONF_DIR"/plugins/bugzilla.conf"
        "\nIts lines should have 'PARAM = VALUE' format."
        "\nRecognized string parameters: BugzillaURL, Login, Password, OSRelease."
        "\nRecognized boolean parameter (VALUE should be 1/0, yes/no): SSLVerify."
        "\nParameters can be overridden via $Bugzilla_PARAM environment variables."
        "\n"
        "\nFMTFILE and FMTFILE2 default to "CONF_DIR"/plugins/bugzilla_format.conf"
    );
    enum {
        OPT_v = 1 << 0,
        OPT_d = 1 << 1,
        OPT_c = 1 << 2,
        OPT_F = 1 << 3,
        OPT_A = 1 << 4,
        OPT_t = 1 << 5,
        OPT_b = 1 << 6,
        OPT_f = 1 << 7,
        OPT_w = 1 << 8,
        OPT_h = 1 << 9,
        OPT_g = 1 << 10,
        OPT_D = 1 << 11,
    };
    const char *dump_dir_name = ".";
    GList *conf_file = NULL;
    const char *fmt_file = CONF_DIR"/plugins/bugzilla_format.conf";
    const char *fmt_file2 = fmt_file;
    char *abrt_hash = NULL;
    char *ticket_no = NULL;
    char *debug_str = NULL;
    GList *group = NULL;
    /* Keep enum above and order of options below in sync! */
    struct options program_options[] = {
        OPT__VERBOSE(&g_verbose),
        OPT_STRING(   'd', NULL, &dump_dir_name , "DIR"    , _("Problem directory")),
        OPT_LIST(     'c', NULL, &conf_file     , "FILE"   , _("Configuration file (may be given many times)")),
        OPT_STRING(   'F', NULL, &fmt_file      , "FILE"   , _("Formatting file for initial comment")),
        OPT_STRING(   'A', NULL, &fmt_file2     , "FILE"   , _("Formatting file for duplicates")),
        OPT_OPTSTRING('t', "ticket", &ticket_no , "ID"     , _("Attach FILEs [to bug with this ID]")),
        OPT_BOOL(     'b', NULL, NULL,                       _("When creating bug, attach binary files too")),
        OPT_BOOL(     'f', NULL, NULL,                       _("Force reporting even if this problem is already reported")),
        OPT_BOOL(     'w', NULL, NULL,                       _("Add bugzilla user to CC list [of bug with this ID]")),
        OPT_STRING(   'h', "duphash", &abrt_hash, "DUPHASH", _("Print BUG_ID which has given DUPHASH")),
        OPT_LIST(     'g', "group", &group      , "GROUP"  , _("Restrict access to this group only")),
        OPT_OPTSTRING('D', "debug", &debug_str  , "STR"    , _("Debug")),
        OPT_END()
    };
    unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);
    argv += optind;

    export_abrt_envvars(0);

    map_string_t *settings = new_map_string();
    struct bugzilla_struct rhbz = { 0 };
    {
        if (!conf_file)
            conf_file = g_list_append(conf_file, (char*) CONF_DIR"/plugins/bugzilla.conf");
        while (conf_file)
        {
            char *fn = (char *)conf_file->data;
            VERB1 log("Loading settings from '%s'", fn);
            load_conf_file(fn, settings, /*skip key w/o values:*/ false);
            VERB3 log("Loaded '%s'", fn);
            conf_file = g_list_delete_link(conf_file, conf_file);
        }
        set_settings(&rhbz, settings);
        /* WRONG! set_settings() does not copy the strings, it merely sets up pointers
         * to settings[] dictionary:
         */
        /*free_map_string(settings);*/
    }

    VERB1 log("Initializing XML-RPC library");
    xmlrpc_env env;
    xmlrpc_env_init(&env);
    xmlrpc_client_setup_global_const(&env);
    if (env.fault_occurred)
        abrt_xmlrpc_die(&env);
    xmlrpc_env_clean(&env);

    struct abrt_xmlrpc *client;
    client = abrt_xmlrpc_new_client(rhbz.b_bugzilla_xmlrpc, rhbz.b_ssl_verify);
    unsigned rhbz_ver = rhbz_version(client);

    if (abrt_hash)
    {
        log(_("Looking for similar problems in bugzilla"));
        char *hash;
        if (prefixcmp(abrt_hash, "abrt_hash:"))
            hash = xasprintf("abrt_hash:%s", abrt_hash);
        else
            hash = xstrdup(abrt_hash);

        /* it's Fedora specific */
        xmlrpc_value *all_bugs = rhbz_search_duphash(client,
                                /*product:*/ "Fedora",
                                /*version:*/ NULL,
                                /*component:*/ NULL,
                                hash);
        free(hash);
        unsigned all_bugs_size = rhbz_array_size(all_bugs);
        if (all_bugs_size > 0)
        {
            int bug_id = rhbz_get_bug_id_from_array0(all_bugs, rhbz_ver);
            printf("%i\n", bug_id);
        }

        return EXIT_SUCCESS;
    }

    if (rhbz.b_login[0] == '\0')
    {
        free(rhbz.b_login);
        rhbz.b_login = ask_bz_login(_("Login is not provided by configuration. Please enter your BZ login:"******"Password is not provided by configuration. Please enter the password for '%s':"), rhbz.b_login);
        rhbz.b_password = ask_bz_password(question);
        free(question);
    }

    if (opts & OPT_t)
    {
        if ((!argv[0] && !(opts & OPT_w)) || (argv[0] && (opts & OPT_w)))
            show_usage_and_die(program_usage_string, program_options);

        if (!ticket_no)
        {
            struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
            if (!dd)
                xfunc_die();
            report_result_t *reported_to = find_in_reported_to(dd, "Bugzilla:");
            dd_close(dd);

            if (!reported_to || !reported_to->url)
                error_msg_and_die(_("Can't get Bugzilla ID because this problem has not yet been reported to Bugzilla."));

            char *url = reported_to->url;
            reported_to->url = NULL;
            free_report_result(reported_to);

            if (prefixcmp(url, rhbz.b_bugzilla_url) != 0)
                error_msg_and_die(_("This problem has been reported to Bugzilla '%s' which differs from the configured Bugzilla '%s'."), url, rhbz.b_bugzilla_url);

            ticket_no = strrchr(url, '=');
            if (!ticket_no)
                error_msg_and_die(_("Malformed url to Bugzilla '%s'."), url);

            /* won't ever call free on it - it simplifies the code a lot */
            ticket_no = xstrdup(ticket_no + 1);
            log(_("Using Bugzilla ID '%s'"), ticket_no);
        }

        login(client, &rhbz);

        if (opts & OPT_w)
            rhbz_mail_to_cc(client, xatoi_positive(ticket_no), rhbz.b_login, /* require mail notify */ 0);
        else
        {   /* Attach files to existing BZ */
            while (*argv)
            {
                const char *filename = *argv++;
                VERB1 log("Attaching file '%s' to bug %s", filename, ticket_no);

                int fd = open(filename, O_RDONLY);
                if (fd < 0)
                {
                    perror_msg("Can't open '%s'", filename);
                    continue;
                }

                struct stat st;
                if (fstat(fd, &st) != 0 || !S_ISREG(st.st_mode))
                {
                    error_msg("'%s': not a regular file", filename);
                    close(fd);
                    continue;
                }

                rhbz_attach_fd(client, ticket_no, filename, fd, /*flags*/ 0);
                close(fd);
            }
        }

        log(_("Logging out"));
        rhbz_logout(client);

#if 0  /* enable if you search for leaks (valgrind etc) */
        abrt_xmlrpc_free_client(client);
#endif
        return 0;
    }

    /* Create new bug in Bugzilla */

    if (!(opts & OPT_f))
    {
        struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
        if (!dd)
            xfunc_die();
        report_result_t *reported_to = find_in_reported_to(dd, "Bugzilla:");
        dd_close(dd);

        if (reported_to && reported_to->url)
        {
            char *msg = xasprintf("This problem was already reported to Bugzilla (see '%s')."
                            " Do you still want to create a new bug?",
                            reported_to->url);
            int yes = ask_yes_no(msg);
            free(msg);
            if (!yes)
                return 0;
        }
        free_report_result(reported_to);
    }

    problem_data_t *problem_data = create_problem_data_for_reporting(dump_dir_name);
    if (!problem_data)
        xfunc_die(); /* create_problem_data_for_reporting already emitted error msg */

    const char *component = problem_data_get_content_or_die(problem_data, FILENAME_COMPONENT);
    const char *duphash   = problem_data_get_content_or_NULL(problem_data, FILENAME_DUPHASH);
//COMPAT, remove after 2.1 release
    if (!duphash) duphash = problem_data_get_content_or_die(problem_data, "global_uuid");

    if (!rhbz.b_product || !*rhbz.b_product) /* if not overridden or empty... */
    {
        free(rhbz.b_product);
        free(rhbz.b_product_version);
        map_string_t *osinfo = new_map_string();
        problem_data_get_osinfo(problem_data, osinfo);
        parse_osinfo_for_bz(osinfo, &rhbz.b_product, &rhbz.b_product_version);
        free_map_string(osinfo);

        if (!rhbz.b_product)
            error_msg_and_die(_("Can't determine Bugzilla Product from problem data."));
    }

    if (opts & OPT_D)
    {
        GList *comment_fmt_spec = load_bzrep_conf_file(fmt_file);
        struct strbuf *bzcomment_buf = strbuf_new();
        generate_bz_comment(bzcomment_buf, problem_data, comment_fmt_spec);
        char *bzcomment = strbuf_free_nobuf(bzcomment_buf);
        char *summary = create_summary_string(problem_data, comment_fmt_spec);
        printf("summary: %s\n"
                "\n"
                "%s"
                , summary, bzcomment
        );
        free(bzcomment);
        free(summary);
        exit(0);
    }

    login(client, &rhbz);


    int bug_id = 0;

    /* If REMOTE_RESULT contains "DUPLICATE 12345", we consider it a dup of 12345
     * and won't search on bz server.
     */
    char *remote_result;
    remote_result = problem_data_get_content_or_NULL(problem_data, FILENAME_REMOTE_RESULT);
    if (remote_result)
    {
        char *cmd = strtok(remote_result, " \n");
        char *id = strtok(NULL, " \n");

        if (!prefixcmp(cmd, "DUPLICATE"))
        {
            errno = 0;
            char *e;
            bug_id = strtoul(id, &e, 10);
            if (errno || id == e || *e != '\0' || bug_id > INT_MAX)
            {
                /* error / no digits / illegal trailing chars / too big a number */
                bug_id = 0;
            }
        }
    }

    struct bug_info *bz = NULL;
    if (!bug_id)
    {
        log(_("Checking for duplicates"));

        int existing_id = -1;
        int crossver_id = -1;
        {
            /* Figure out whether we want to match component
             * when doing dup search.
             */
            const char *component_substitute = is_in_comma_separated_list(component, rhbz.b_DontMatchComponents) ? NULL : component;

            /* We don't do dup detection across versions (see below why),
             * but we do add a note if cross-version potential dup exists.
             * For that, we search for cross version dups first:
             */
            xmlrpc_value *crossver_bugs = rhbz_search_duphash(client, rhbz.b_product, /*version:*/ NULL,
                            component_substitute, duphash);
            unsigned crossver_bugs_count = rhbz_array_size(crossver_bugs);
            VERB3 log("Bugzilla has %i reports with duphash '%s' including cross-version ones",
                    crossver_bugs_count, duphash);
            if (crossver_bugs_count > 0)
                crossver_id = rhbz_get_bug_id_from_array0(crossver_bugs, rhbz_ver);
            xmlrpc_DECREF(crossver_bugs);

            if (crossver_bugs_count > 0)
            {
                /* In dup detection we require match in product *and version*.
                 * Otherwise we sometimes have bugs in e.g. Fedora 17
                 * considered to be dups of Fedora 16 bugs.
                 * Imagine that F16 is "end-of-lifed" - allowing cross-version
                 * match will make all newly detected crashes DUPed
                 * to a bug in a dead release.
                 */
                xmlrpc_value *dup_bugs = rhbz_search_duphash(client, rhbz.b_product,
                                rhbz.b_product_version, component_substitute, duphash);
                unsigned dup_bugs_count = rhbz_array_size(dup_bugs);
                VERB3 log("Bugzilla has %i reports with duphash '%s'",
                        dup_bugs_count, duphash);
                if (dup_bugs_count > 0)
                    existing_id = rhbz_get_bug_id_from_array0(dup_bugs, rhbz_ver);
                xmlrpc_DECREF(dup_bugs);
            }
        }

        if (existing_id < 0)
        {
            /* Create new bug */
            log(_("Creating a new bug"));

            GList *comment_fmt_spec = load_bzrep_conf_file(fmt_file);

            struct strbuf *bzcomment_buf = strbuf_new();
            generate_bz_comment(bzcomment_buf, problem_data, comment_fmt_spec);
            if (crossver_id >= 0)
                strbuf_append_strf(bzcomment_buf, "\nPotential duplicate: bug %u\n", crossver_id);
            char *bzcomment = strbuf_free_nobuf(bzcomment_buf);
            char *summary = create_summary_string(problem_data, comment_fmt_spec);
            int new_id = rhbz_new_bug(client, problem_data, rhbz.b_product, rhbz.b_product_version,
                    summary, bzcomment,
                    group
            );
            free(bzcomment);
            free(summary);

            if (new_id == -1)
            {
                error_msg_and_die(_("Failed to create a new bug."));
            }

            log(_("Adding attachments to bug %i"), new_id);
            char new_id_str[sizeof(int)*3 + 2];
            sprintf(new_id_str, "%i", new_id);

            attach_files(client, new_id_str, problem_data, comment_fmt_spec);

//TODO: free_comment_fmt_spec(comment_fmt_spec);

            bz = new_bug_info();
            bz->bi_status = xstrdup("NEW");
            bz->bi_id = new_id;
            goto log_out;
        }

        bug_id = existing_id;
    }

    bz = rhbz_bug_info(client, bug_id);

    log(_("Bug is already reported: %i"), bz->bi_id);

    /* Follow duplicates */
    if ((strcmp(bz->bi_status, "CLOSED") == 0)
     && (strcmp(bz->bi_resolution, "DUPLICATE") == 0)
    ) {
        struct bug_info *origin;
        origin = rhbz_find_origin_bug_closed_duplicate(client, bz);
        if (origin)
        {
            free_bug_info(bz);
            bz = origin;
        }
    }

    if (strcmp(bz->bi_status, "CLOSED") != 0)
    {
        /* Add user's login to CC if not there already */
        if (strcmp(bz->bi_reporter, rhbz.b_login) != 0
         && !g_list_find_custom(bz->bi_cc_list, rhbz.b_login, (GCompareFunc)g_strcmp0)
        ) {
            log(_("Adding %s to CC list"), rhbz.b_login);
            rhbz_mail_to_cc(client, bz->bi_id, rhbz.b_login, RHBZ_NOMAIL_NOTIFY);
        }

        /* Add comment and bt */
        const char *comment = problem_data_get_content_or_NULL(problem_data, FILENAME_COMMENT);
        if (comment && comment[0])
        {
            GList *comment_fmt_spec = load_bzrep_conf_file(fmt_file2);
            struct strbuf *bzcomment_buf = strbuf_new();
            generate_bz_comment(bzcomment_buf, problem_data, comment_fmt_spec);
            char *bzcomment = strbuf_free_nobuf(bzcomment_buf);
//TODO: free_comment_fmt_spec(comment_fmt_spec);

            int dup_comment = is_comment_dup(bz->bi_comments, bzcomment);
            if (!dup_comment)
            {
                log(_("Adding new comment to bug %d"), bz->bi_id);
                rhbz_add_comment(client, bz->bi_id, bzcomment, 0);
                free(bzcomment);

                const char *bt = problem_data_get_content_or_NULL(problem_data, FILENAME_BACKTRACE);
                unsigned rating = 0;
                const char *rating_str = problem_data_get_content_or_NULL(problem_data, FILENAME_RATING);
                /* python doesn't have rating file */
                if (rating_str)
                    rating = xatou(rating_str);
                if (bt && rating > bz->bi_best_bt_rating)
                {
                    char bug_id_str[sizeof(int)*3 + 2];
                    sprintf(bug_id_str, "%i", bz->bi_id);
                    log(_("Attaching better backtrace"));
                    rhbz_attach_blob(client, bug_id_str, FILENAME_BACKTRACE, bt, strlen(bt),
                                     RHBZ_NOMAIL_NOTIFY);
                }
            }
            else
            {
                free(bzcomment);
                log(_("Found the same comment in the bug history, not adding a new one"));
            }
        }
    }

 log_out:
    log(_("Logging out"));
    rhbz_logout(client);

    log(_("Status: %s%s%s %s/show_bug.cgi?id=%u"),
                bz->bi_status,
                bz->bi_resolution ? " " : "",
                bz->bi_resolution ? bz->bi_resolution : "",
                rhbz.b_bugzilla_url,
                bz->bi_id);

    struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
    if (dd)
    {
        char *msg = xasprintf("Bugzilla: URL=%s/show_bug.cgi?id=%u", rhbz.b_bugzilla_url, bz->bi_id);
        add_reported_to(dd, msg);
        free(msg);
        dd_close(dd);
    }

#if 0  /* enable if you search for leaks (valgrind etc) */
    free(rhbz.b_product);
    free(rhbz.b_product_version);
    problem_data_free(problem_data);
    free_bug_info(bz);
    abrt_xmlrpc_free_client(client);
#endif
    return 0;
}
Beispiel #29
0
// caller is reposible for freeing *product* and *version*
static void parse_release(const char *release, char** product, char** version, int flags)
{
    /* Fedora has a single non-numeric release - Rawhide */
    if (strstr(release, "Rawhide"))
    {
        *product = xstrdup("Fedora");
        *version = xstrdup("rawhide");
        log_debug("%s: version:'%s' product:'%s'", __func__, *version, *product);
        return;
    }

    /* openSUSE has two non-numeric releases - Factory and Tumbleweed
       None of them is unfortunately identified in any of /etc/SuSE-brand,
       /etc/SuSE-release or /etc/os-release. Keep this piece of code commented
       just not to forget about that. */

    /*
    if (strstr(release, "Factory"))
    {
        *product = xstrdup("openSUSE");
        *version = xstrdup("Factory");
        log_debug("%s: version:'%s' product:'%s'", __func__, *version, *product);
        return;
    }

    if (strstr(release, "Tumbleweed"))
    {
        *product = xstrdup("openSUSE");
        *version = xstrdup("Tumbleweed");
        log_debug("%s: version:'%s' product:'%s'", __func__, *version, *product);
        return;
    }
    */

    bool it_is_rhel = false;

    struct strbuf *buf_product = strbuf_new();
    if (strstr(release, "Fedora"))
    {
        strbuf_append_str(buf_product, "Fedora");
    }
    else if (strstr(release, "Red Hat Enterprise Linux"))
    {
        strbuf_append_str(buf_product, "Red Hat Enterprise Linux");
        it_is_rhel = true;
    }
    else if (strstr(release, "openSUSE"))
    {
        strbuf_append_str(buf_product, "openSUSE");
    }
    else
    {
        /* TODO: add logic for parsing other distros' names here */
        strbuf_append_str(buf_product, release);
    }

    /* Examples of release strings:
     * installed system: "Red Hat Enterprise Linux Server release 6.2 Beta (Santiago)"
     * anaconda: "Red Hat Enterprise Linux 6.2"
     */
    struct strbuf *buf_version = strbuf_new();
    const char *r = strstr(release, "release");
    const char *space = r ? strchr(r, ' ') : NULL;
    if (!space)
    {
        /* Try to find "<space><digit>" sequence */
        space = release;
        while ((space = strchr(space, ' ')) != NULL)
        {
            if (space[1] >= '0' && space[1] <= '9')
                break;
            space++;
        }
    }
    if (space)
    {
        space++;
        /* Observed also: "Fedora 16-Alpha" rhbz#730887 */
        while ((*space >= '0' && *space <= '9') || *space == '.')
        {
            /* Eat string like "5.2" */
            strbuf_append_char(buf_version, *space);
            space++;
        }

        if (flags & RETAIN_ALPHA_BETA_TAIL_IN_VER)
        {
            /* Example: "... 6.2 [Beta ](Santiago)".
             * 'space' variable points to non-digit char after "2".
             * We assume that non-parenthesized text is "Alpha"/"Beta"/etc.
             * If this text is only whitespace, we won't append it.
             */
            const char *to_append = space;
            while (*space && *space != '(') /* go to '(' */
                space++;
            while (space > to_append && space[-1] == ' ') /* back to 1st non-space */
                space--;
            strbuf_append_strf(buf_version, "%.*s", (int)(space - to_append), to_append);
        }
    }

    if ((flags & APPEND_MAJOR_VER_TO_RHEL_PRODUCT) && it_is_rhel)
    {
        char *v = buf_version->buf;
        /* Append "integer part" of version to product:
         * "10.2<anything>" -> append " 10"
         * "10 <anything>"  -> append " 10"
         * "10"             -> append " 10"
         * "10abcde"        -> append ?????
         */
        unsigned idx_dot = strchrnul(v, '.') - v;
        unsigned idx_space = strchrnul(v, ' ') - v;
        strbuf_append_strf(buf_product, " %.*s",
                        (idx_dot < idx_space ? idx_dot : idx_space), v
        );
    }

    *version = strbuf_free_nobuf(buf_version);
    *product = strbuf_free_nobuf(buf_product);

    log_debug("%s: version:'%s' product:'%s'", __func__, *version, *product);
}
Beispiel #30
0
unsigned parse_opts(int argc, char **argv, const struct options *opt,
                const char *usage)
{
    int help = 0;
    int size = parse_opt_size(opt);
    const int LONGOPT_OFFSET = 256;

    struct strbuf *shortopts = strbuf_new();

    struct option *longopts = xzalloc(sizeof(longopts[0]) * (size+2));
    struct option *curopt = longopts;
    int ii;
    for (ii = 0; ii < size; ++ii)
    {
        curopt->name = opt[ii].long_name;
        /*curopt->flag = 0; - xzalloc did it */
        if (opt[ii].short_name)
            curopt->val = opt[ii].short_name;
        else
            curopt->val = LONGOPT_OFFSET + ii;

        switch (opt[ii].type)
        {
            case OPTION_BOOL:
                curopt->has_arg = no_argument;
                if (opt[ii].short_name)
                    strbuf_append_char(shortopts, opt[ii].short_name);
                break;
            case OPTION_INTEGER:
            case OPTION_STRING:
            case OPTION_LIST:
                curopt->has_arg = required_argument;
                if (opt[ii].short_name)
                    strbuf_append_strf(shortopts, "%c:", opt[ii].short_name);
                break;
            case OPTION_OPTSTRING:
                curopt->has_arg = optional_argument;
                if (opt[ii].short_name)
                    strbuf_append_strf(shortopts, "%c::", opt[ii].short_name);
                break;
            case OPTION_GROUP:
            case OPTION_END:
                break;
        }
        //log("curopt[%d].name:'%s' .has_arg:%d .flag:%p .val:%d", (int)(curopt-longopts),
        //      curopt->name, curopt->has_arg, curopt->flag, curopt->val);
        /*
         * getopt_long() thinks that NULL name marks the end of longopts.
         * Example:
         * [0] name:'verbose' val:'v'
         * [1] name:NULL      val:'c'
         * [2] name:'force'   val:'f'
         * ... ... ...
         * In this case, --force won't be accepted!
         * Therefore we can only advance if name is not NULL.
         */
        if (curopt->name)
            curopt++;
    }
    curopt->name = "help";
    curopt->has_arg = no_argument;
    curopt->flag = &help;
    curopt->val = 1;
    /* xzalloc did it already:
    curopt++;
    curopt->name = NULL;
    curopt->has_arg = 0;
    curopt->flag = NULL;
    curopt->val = 0;
    */

    unsigned retval = 0;
    while (1)
    {
        int c = getopt_long(argc, argv, shortopts->buf, longopts, NULL);

        if (c == -1)
            break;

        if (c == '?' || help)
        {
            free(longopts);
            strbuf_free(shortopts);
            xfunc_error_retval = 0; /* this isn't error, exit code = 0 */
            show_usage_and_die(usage, opt);
        }

        for (ii = 0; ii < size; ++ii)
        {
            if (opt[ii].short_name == c || LONGOPT_OFFSET + ii == c)
            {
                if (ii < sizeof(retval)*8)
                    retval |= (1 << ii);

                if (opt[ii].value != NULL) switch (opt[ii].type)
                {
                    case OPTION_BOOL:
                        *(int*)(opt[ii].value) += 1;
                        break;
                    case OPTION_INTEGER:
                        *(int*)(opt[ii].value) = xatoi(optarg);
                        break;
                    case OPTION_STRING:
                    case OPTION_OPTSTRING:
                        if (optarg)
                            *(char**)(opt[ii].value) = (char*)optarg;
                        break;
                    case OPTION_LIST:
                        *(GList**)(opt[ii].value) = g_list_append(*(GList**)(opt[ii].value), optarg);
                        break;
                    case OPTION_GROUP:
                    case OPTION_END:
                        break;
                }
            }
        }
    }

    free(longopts);
    strbuf_free(shortopts);

    return retval;
}