static void test_should_pass(const char *p) { usec_t t, q; char buf[FORMAT_TIMESTAMP_MAX], buf_relative[FORMAT_TIMESTAMP_RELATIVE_MAX]; log_info("Test: %s", p); assert_se(parse_timestamp(p, &t) >= 0); assert_se(format_timestamp_us(buf, sizeof(buf), t)); log_info("\"%s\" → \"%s\"", p, buf); assert_se(parse_timestamp(buf, &q) >= 0); if (q != t) { char tmp[FORMAT_TIMESTAMP_MAX]; log_error("round-trip failed: \"%s\" → \"%s\"", buf, format_timestamp_us(tmp, sizeof(tmp), q)); } assert_se(q == t); assert_se(format_timestamp_relative(buf_relative, sizeof(buf_relative), t)); log_info("%s", strna(buf_relative)); }
static int process_deepen_since(const char *line, timestamp_t *deepen_since, int *deepen_rev_list) { const char *arg; if (skip_prefix(line, "deepen-since ", &arg)) { char *end = NULL; *deepen_since = parse_timestamp(arg, &end, 0); if (!end || *end || !deepen_since || /* revisions.c's max_age -1 is special */ *deepen_since == -1) die("Invalid deepen-since: %s", line); *deepen_rev_list = 1; return 1; } return 0; }
static timestamp_t parse_tag_date(const char *buf, const char *tail) { const char *dateptr; while (buf < tail && *buf++ != '>') /* nada */; if (buf >= tail) return 0; dateptr = buf; while (buf < tail && *buf++ != '\n') /* nada */; if (buf >= tail) return 0; /* dateptr < buf && buf[-1] == '\n', so parsing will stop at buf-1 */ return parse_timestamp(dateptr, NULL, 10); }
const char *show_ident_date(const struct ident_split *ident, const struct date_mode *mode) { timestamp_t date = 0; long tz = 0; if (ident->date_begin && ident->date_end) date = parse_timestamp(ident->date_begin, NULL, 10); if (date_overflows(date)) date = 0; else { if (ident->tz_begin && ident->tz_end) tz = strtol(ident->tz_begin, NULL, 10); if (tz >= INT_MAX || tz <= INT_MIN) tz = 0; } return show_date(date, tz, mode); }
static int fsck_ident(const char **ident, struct object *obj, struct fsck_options *options) { const char *p = *ident; char *end; *ident = strchrnul(*ident, '\n'); if (**ident == '\n') (*ident)++; if (*p == '<') return report(options, obj, FSCK_MSG_MISSING_NAME_BEFORE_EMAIL, "invalid author/committer line - missing space before email"); p += strcspn(p, "<>\n"); if (*p == '>') return report(options, obj, FSCK_MSG_BAD_NAME, "invalid author/committer line - bad name"); if (*p != '<') return report(options, obj, FSCK_MSG_MISSING_EMAIL, "invalid author/committer line - missing email"); if (p[-1] != ' ') return report(options, obj, FSCK_MSG_MISSING_SPACE_BEFORE_EMAIL, "invalid author/committer line - missing space before email"); p++; p += strcspn(p, "<>\n"); if (*p != '>') return report(options, obj, FSCK_MSG_BAD_EMAIL, "invalid author/committer line - bad email"); p++; if (*p != ' ') return report(options, obj, FSCK_MSG_MISSING_SPACE_BEFORE_DATE, "invalid author/committer line - missing space before date"); p++; if (*p == '0' && p[1] != ' ') return report(options, obj, FSCK_MSG_ZERO_PADDED_DATE, "invalid author/committer line - zero-padded date"); if (date_overflows(parse_timestamp(p, &end, 10))) return report(options, obj, FSCK_MSG_BAD_DATE_OVERFLOW, "invalid author/committer line - date causes integer overflow"); if ((end == p || *end != ' ')) return report(options, obj, FSCK_MSG_BAD_DATE, "invalid author/committer line - bad date"); p = end + 1; if ((*p != '+' && *p != '-') || !isdigit(p[1]) || !isdigit(p[2]) || !isdigit(p[3]) || !isdigit(p[4]) || (p[5] != '\n')) return report(options, obj, FSCK_MSG_BAD_TIMEZONE, "invalid author/committer line - bad time zone"); p += 6; return 0; }
static void test_timestamp(void) { char buf[FORMAT_TIMESTAMP_MAX]; _cleanup_free_ char *t = NULL; CalendarSpec *c; usec_t x, y; /* Ensure that a timestamp is also a valid calendar specification. Convert forth and back */ x = now(CLOCK_REALTIME); assert_se(format_timestamp_us(buf, sizeof(buf), x)); printf("%s\n", buf); assert_se(calendar_spec_from_string(buf, &c) >= 0); assert_se(calendar_spec_to_string(c, &t) >= 0); calendar_spec_free(c); printf("%s\n", t); assert_se(parse_timestamp(t, &y) >= 0); assert_se(y == x); }
int read_extern_data(struct uftrace_extern_reader *extn) { char buf[EXTERN_DATA_MAX + 64]; char *pos; int len; if (extn == NULL) return -1; if (extn->valid) return 0; do { pos = fgets(buf, sizeof(buf), extn->fp); if (pos == NULL) return -1; /* end of file */ buf[sizeof(buf)-1] = '\0'; while (isspace(*pos)) pos++; } while (*pos == '#' || *pos == '\n'); /* ignore comment or blank */ extn->time = parse_timestamp(pos); pos = strpbrk(pos, "\t "); if (pos == NULL) return -1; /* invalid data */ while (isspace(*pos)) pos++; len = strlen(pos); if (pos[len-1] == '\n') pos[len-1] = '\0'; strcpy(extn->msg, pos); extn->valid = true; return 0; }
/* * Parse a string like "0 +0000" as ancient timestamp near epoch, but * only when it appears not as part of any other string. */ static int match_object_header_date(const char *date, timestamp_t *timestamp, int *offset) { char *end; timestamp_t stamp; int ofs; if (*date < '0' || '9' < *date) return -1; stamp = parse_timestamp(date, &end, 10); if (*end != ' ' || stamp == TIME_MAX || (end[1] != '+' && end[1] != '-')) return -1; date = end + 2; ofs = strtol(date, &end, 10); if ((*end != '\0' && (*end != '\n')) || end != date + 4) return -1; ofs = (ofs / 100) * 60 + (ofs % 100); if (date[-1] == '-') ofs = -ofs; *timestamp = stamp; *offset = ofs; return 0; }
static const char *approxidate_digit(const char *date, struct tm *tm, int *num, time_t now) { char *end; timestamp_t number = parse_timestamp(date, &end, 10); switch (*end) { case ':': case '.': case '/': case '-': if (isdigit(end[1])) { int match = match_multi_number(number, *end, date, end, tm, now); if (match) return date + match; } } /* Accept zero-padding only for small numbers ("Dec 02", never "Dec 0002") */ if (date[0] != '0' || end - date <= 2) *num = number; return end; }
/* *************************************************************************** * Main entry to the sar program. *************************************************************************** */ int main(int argc, char **argv) { int i, rc, opt = 1, args_idx = 2; int fd[2]; int day_offset = 0; char from_file[MAX_FILE_LEN], to_file[MAX_FILE_LEN]; char ltemp[20]; /* Get HZ */ get_HZ(); /* Compute page shift in kB */ get_kb_shift(); from_file[0] = to_file[0] = '\0'; #ifdef USE_NLS /* Init National Language Support */ init_nls(); #endif tm_start.use = tm_end.use = FALSE; /* Allocate and init activity bitmaps */ allocate_bitmaps(act); init_structures(); /* Process options */ while (opt < argc) { if (!strcmp(argv[opt], "-I")) { if (argv[++opt]) { /* Parse -I option */ if (parse_sar_I_opt(argv, &opt, act)) { usage(argv[0]); } } else { usage(argv[0]); } } else if (!strcmp(argv[opt], "-D")) { /* Option to tell sar to write to saYYYYMMDD data files */ flags |= S_F_SA_YYYYMMDD; opt++; } else if (!strcmp(argv[opt], "-P")) { /* Parse -P option */ if (parse_sa_P_opt(argv, &opt, &flags, act)) { usage(argv[0]); } } else if (!strcmp(argv[opt], "-o")) { if (to_file[0]) { /* Output file already specified */ usage(argv[0]); } /* Save stats to a file */ if ((argv[++opt]) && strncmp(argv[opt], "-", 1) && (strspn(argv[opt], DIGITS) != strlen(argv[opt]))) { strncpy(to_file, argv[opt++], MAX_FILE_LEN); to_file[MAX_FILE_LEN - 1] = '\0'; } else { strcpy(to_file, "-"); } } else if (!strcmp(argv[opt], "-f")) { if (from_file[0]) { /* Input file already specified */ usage(argv[0]); } /* Read stats from a file */ if ((argv[++opt]) && strncmp(argv[opt], "-", 1) && (strspn(argv[opt], DIGITS) != strlen(argv[opt]))) { strncpy(from_file, argv[opt++], MAX_FILE_LEN); from_file[MAX_FILE_LEN - 1] = '\0'; /* Check if this is an alternate directory for sa files */ check_alt_sa_dir(from_file, day_offset, -1); } else { set_default_file(from_file, day_offset, -1); } } else if (!strcmp(argv[opt], "-s")) { /* Get time start */ if (parse_timestamp(argv, &opt, &tm_start, DEF_TMSTART)) { usage(argv[0]); } } else if (!strcmp(argv[opt], "-e")) { /* Get time end */ if (parse_timestamp(argv, &opt, &tm_end, DEF_TMEND)) { usage(argv[0]); } } else if (!strcmp(argv[opt], "-h")) { /* Display help message */ display_help(argv[0]); } else if (!strcmp(argv[opt], "-i")) { if (!argv[++opt] || (strspn(argv[opt], DIGITS) != strlen(argv[opt]))) { usage(argv[0]); } interval = atol(argv[opt++]); if (interval < 1) { usage(argv[0]); } flags |= S_F_INTERVAL_SET; } else if (!strcmp(argv[opt], "-m")) { if (argv[++opt]) { /* Parse option -m */ if (parse_sar_m_opt(argv, &opt, act)) { usage(argv[0]); } } else { usage(argv[0]); } } else if (!strcmp(argv[opt], "-n")) { if (argv[++opt]) { /* Parse option -n */ if (parse_sar_n_opt(argv, &opt, act)) { usage(argv[0]); } } else { usage(argv[0]); } } else if ((strlen(argv[opt]) > 1) && (strlen(argv[opt]) < 4) && !strncmp(argv[opt], "-", 1) && (strspn(argv[opt] + 1, DIGITS) == (strlen(argv[opt]) - 1))) { day_offset = atoi(argv[opt++] + 1); } else if (!strncmp(argv[opt], "-", 1)) { /* Other options not previously tested */ if ((rc = parse_sar_opt(argv, &opt, act, &flags, C_SAR)) != 0) { if (rc == 1) { usage(argv[0]); } exit(1); } opt++; } else if (interval < 0) { /* Get interval */ if (strspn(argv[opt], DIGITS) != strlen(argv[opt])) { usage(argv[0]); } interval = atol(argv[opt++]); if (interval < 0) { usage(argv[0]); } } else { /* Get count value */ if ((strspn(argv[opt], DIGITS) != strlen(argv[opt])) || !interval) { usage(argv[0]); } if (count) { /* Count parameter already set */ usage(argv[0]); } count = atol(argv[opt++]); if (count < 1) { usage(argv[0]); } } } /* 'sar' is equivalent to 'sar -f' */ if ((argc == 1) || ((interval < 0) && !from_file[0] && !to_file[0])) { set_default_file(from_file, day_offset, -1); } if (tm_start.use && tm_end.use && (tm_end.tm_hour < tm_start.tm_hour)) { tm_end.tm_hour += 24; } /* * Check option dependencies. */ /* You read from a file OR you write to it... */ if (from_file[0] && to_file[0]) { fprintf(stderr, _("-f and -o options are mutually exclusive\n")); exit(1); } /* Use time start or option -i only when reading stats from a file */ if ((tm_start.use || INTERVAL_SET(flags)) && !from_file[0]) { fprintf(stderr, _("Not reading from a system activity file (use -f option)\n")); exit(1); } /* Don't print stats since boot time if -o or -f options are used */ if (!interval && (from_file[0] || to_file[0])) { usage(argv[0]); } /* Cannot enter a day shift with -o option */ if (to_file[0] && day_offset) { usage(argv[0]); } if (USE_PRETTY_OPTION(flags)) { dm_major = get_devmap_major(); } if (!count) { /* * count parameter not set: Display all the contents of the file * or generate a report continuously. */ count = -1; } /* Default is CPU activity... */ select_default_activity(act); /* Reading stats from file: */ if (from_file[0]) { if (interval < 0) { interval = 1; } /* Read stats from file */ read_stats_from_file(from_file); /* Free stuctures and activity bitmaps */ free_bitmaps(act); free_structures(act); return 0; } /* Reading stats from sadc: */ /* Create anonymous pipe */ if (pipe(fd) == -1) { perror("pipe"); exit(4); } switch (fork()) { case -1: perror("fork"); exit(4); break; case 0: /* Child */ if (dup2(fd[1], STDOUT_FILENO) < 0) { perror("dup2"); exit(4); } CLOSE_ALL(fd); /* * Prepare options for sadc. */ /* Program name */ salloc(0, SADC); /* Interval value */ if (interval < 0) { usage(argv[0]); } else if (!interval) { strcpy(ltemp, "1"); } else { sprintf(ltemp, "%ld", interval); } salloc(1, ltemp); /* Count number */ if (count >= 0) { sprintf(ltemp, "%ld", count + 1); salloc(args_idx++, ltemp); } /* Flags to be passed to sadc */ salloc(args_idx++, "-z"); /* Writing data to a file (option -o) */ if (to_file[0]) { /* Set option -D if entered */ if (USE_SA_YYYYMMDD(flags)) { salloc(args_idx++, "-D"); } /* Collect all possible activities (option -S XALL for sadc) */ salloc(args_idx++, "-S"); salloc(args_idx++, K_XALL); /* Outfile arg */ salloc(args_idx++, to_file); } else { /* * If option -o hasn't been used, then tell sadc * to collect only activities that will be displayed. */ int act_id = 0; for (i = 0; i < NR_ACT; i++) { if (IS_SELECTED(act[i]->options)) { act_id |= act[i]->group; } } if (act_id) { act_id <<= 8; snprintf(ltemp, 19, "%d", act_id); ltemp[19] = '\0'; salloc(args_idx++, "-S"); salloc(args_idx++, ltemp); } } /* Last arg is NULL */ args[args_idx] = NULL; /* Call now the data collector */ execv(SADC_PATH, args); execvp(SADC, args); /* * Note: Don't use execl/execlp since we don't have a fixed number of * args to give to sadc. */ fprintf(stderr, _("Cannot find the data collector (%s)\n"), SADC); perror("exec"); exit(4); break; default: /* Parent */ if (dup2(fd[0], STDIN_FILENO) < 0) { perror("dup2"); exit(4); } CLOSE_ALL(fd); /* Get now the statistics */ read_stats(); break; } /* Free structures and activity bitmaps */ free_bitmaps(act); free_structures(act); return 0; }
/* The line handler for certificate searches. This is invoked for each complete line found by search_certs. */ static gpg_error_t search_certs_line (struct search_ctx *ctx) { char *line; enum { RT_NONE, RT_CRT, RT_CRS, RT_FPR, RT_GRP, RT_UID } rectype = RT_NONE; #define NR_FIELDS 16 char *field[NR_FIELDS]; int fields = 0; struct cert *cert; /* Strip a trailing carriage return. */ if (ctx->pending_len > 0 && ctx->pending[ctx->pending_len - 1] == '\r') ctx->pending_len--; ctx->pending[ctx->pending_len - 1] = '\0'; ctx->pending_len = 0; cert = &ctx->cert; line = ctx->pending; while (line && fields < NR_FIELDS) { field[fields++] = line; line = strchr (line, ':'); if (line) *(line++) = '\0'; } if (!strcmp (field[0], "crt")) rectype = RT_CRT; else if (!strcmp (field[0], "crs")) rectype = RT_CRS; else if (!strcmp (field[0], "fpr")) rectype = RT_FPR; else if (!strcmp (field[0], "grp")) rectype = RT_GRP; else if (!strcmp (field[0], "uid")) rectype = RT_UID; else rectype = RT_NONE; switch (rectype) { case RT_CRT: case RT_CRS: /* Reinitialize CERT. */ if (cert->valid) { gpg_error_t err; err = search_certs_cert (ctx); if (err) return err; cert_reset (cert); } cert->valid = true; #if 0 /* Field 2 has the trust info. */ if (fields >= 2) set_mainkey_trust_info (key, field[1]); #endif /* Field 3 has the key length. */ if (fields >= 3) { int i = atoi (field[2]); /* Ignore invalid values. */ if (i > 1) cert->length = i; } /* Field 4 has the public key algorithm. */ if (fields >= 4) { int i = atoi (field[3]); if (i >= 1 && i < 128) cert->pubkey_algo = i; } /* Field 5 has the long keyid. Allow short key IDs for the output of an external keyserver listing. */ if (fields >= 5 && strlen (field[4]) <= sizeof (cert->keyid) - 1) strcpy (cert->keyid, field[4]); /* Field 6 has the timestamp (seconds). */ if (fields >= 6) cert->timestamp = parse_timestamp (field[5], NULL); /* Field 7 has the expiration time (seconds). */ if (fields >= 7) cert->expires = parse_timestamp (field[6], NULL); /* Field 8 has the X.509 serial number. */ if (fields >= 8) { cert->issuer_serial = strdup (field[7]); if (!cert->issuer_serial) return gpg_error_from_syserror (); } #if 0 /* Field 9 has the ownertrust. */ if (fields >= 9) set_ownertrust (key, field[8]); #endif /* Field 10 is the issuer name. */ if (fields >= 10) if (decode_c_string (field[9], &cert->issuer_name, 0)) return gpg_error (GPG_ERR_ENOMEM); /* FIXME */ /* Field 11 has the signature class. */ #if 0 /* Field 12 has the capabilities. */ if (fields >= 12) set_mainkey_capability (key, field[11]); #endif break; case RT_UID: if (cert->valid) { /* Field 2 has the trust info, and field 10 has the user ID. Note that more than one UID field can appear. We only remember the last one. It's not used anyway. */ if (fields >= 10 && !cert->uid) { if (decode_c_string (field[9], &cert->uid, 0)) return gpg_error (GPG_ERR_ENOMEM); /* FIXME */ } } break; case RT_FPR: if (cert->valid) { /* Field 10 has the fingerprint (take only the first one). */ if (fields >= 10 && strlen (field[9]) <= sizeof (cert->fpr) - 1) strcpy (cert->fpr, field[9]); /* Field 13 has the gpgsm chain ID (take only the first one). */ if (fields >= 13 && strlen (field[12]) <= sizeof (cert->chain_id) - 1) strcpy (cert->chain_id, field[12]); } break; case RT_GRP: if (cert->valid) { /* Field 10 has the key grip. */ if (fields >= 10 && strlen (field[9]) <= sizeof (cert->grip) - 1) strcpy (cert->grip, field[9]); } break; case RT_NONE: /* Unknown record. */ break; } return 0; }
TEST(timestamp, rfc850_wednesday) { const std::string str = "Wednesday, 14-Apr-93 00:00:00 GMT"; const time_t timestamp = parse_timestamp(str.data(), str.size()); EXPECT_EQ(734745600, timestamp); }
TEST(timestamp, rfc850_sunday) { const std::string str = "Sunday, 14-Apr-85 00:00:00 GMT"; const time_t timestamp = parse_timestamp(str.data(), str.size()); EXPECT_EQ(482284800, timestamp); }
TEST(timestamp, jul_date) { const std::string str = "Wed, 01 Jul 1970 00:00:00 GMT"; const time_t timestamp = parse_timestamp(str.data(), str.size()); EXPECT_EQ(15638400, timestamp); }
TEST(timestamp, jun_date) { const std::string str = "Mon, 01 Jun 1970 00:00:00 GMT"; const time_t timestamp = parse_timestamp(str.data(), str.size()); EXPECT_EQ(13046400, timestamp); }
TEST(timestamp, rfc1123_tolerant_date) { const std::string str = "Sun,06Nov1994 08:49:37GMT"; const time_t timestamp = parse_timestamp(str.data(), str.size()); EXPECT_EQ(784111777, timestamp); }
TEST(timestamp, rfc1123_erroneous_gmt) { const std::string str = "Sun, 06 Nov 1994 08:49:37 TNT"; const time_t timestamp = parse_timestamp(str.data(), str.size()); EXPECT_EQ(-1, timestamp); }
TEST(timestamp, aug_date) { const std::string str = "Sat, 01 Aug 1970 00:00:00 GMT"; const time_t timestamp = parse_timestamp(str.data(), str.size()); EXPECT_EQ(18316800, timestamp); }
TEST(timestamp, rfc850_tuesday) { const std::string str = "Tuesday, 14-Apr-87 00:00:00 GMT"; const time_t timestamp = parse_timestamp(str.data(), str.size()); EXPECT_EQ(545356800, timestamp); }
TEST(timestamp, sep_date) { const std::string str = "Tue, 01 Sep 1970 00:00:00 GMT"; const time_t timestamp = parse_timestamp(str.data(), str.size()); EXPECT_EQ(20995200, timestamp); }
TEST(timestamp, rfc850_thursday) { const std::string str = "Thursday, 14-Apr-88 00:00:00 GMT"; const time_t timestamp = parse_timestamp(str.data(), str.size()); EXPECT_EQ(576979200, timestamp); }
TEST(timestamp, oct_date) { const std::string str = "Thu, 01 Oct 1970 00:00:00 GMT"; const time_t timestamp = parse_timestamp(str.data(), str.size()); EXPECT_EQ(23587200, timestamp); }
/** * Need to set up differently. * Get a status in order to return at end and release memeory. */ WEBVTT_INTERN webvtt_status webvtt_cuetext_tokenizer( webvtt_byte **position, webvtt_cuetext_token **token ) { webvtt_token_state token_state = DATA; webvtt_string result, annotation; webvtt_stringlist *css_classes; webvtt_timestamp time_stamp = 0; webvtt_status status = WEBVTT_UNFINISHED; if( !position ) { return WEBVTT_INVALID_PARAM; } webvtt_create_string( 10, &result ); webvtt_create_string( 10, &annotation ); webvtt_create_stringlist( &css_classes ); /** * Loop while the tokenizer is not finished. * Based on the state of the tokenizer enter a function to handle that * particular tokenizer state. Those functions will loop until they either * change the state of the tokenizer or reach a valid token end point. */ while( status == WEBVTT_UNFINISHED ) { switch( token_state ) { case DATA : status = webvtt_data_state( position, &token_state, &result ); break; case ESCAPE: status = webvtt_escape_state( position, &token_state, &result ); break; case TAG: status = webvtt_tag_state( position, &token_state, &result ); break; case START_TAG: status = webvtt_start_tag_state( position, &token_state, &result ); break; case START_TAG_CLASS: status = webvtt_class_state( position, &token_state, css_classes ); break; case START_TAG_ANNOTATION: status = webvtt_annotation_state( position, &token_state, &annotation ); break; case END_TAG: status = webvtt_end_tag_state( position, &token_state, &result ); break; case TIME_STAMP_TAG: status = webvtt_timestamp_state( position, &token_state, &result ); break; } if( token_state == START_TAG_ANNOTATION ) { webvtt_skipwhite( position ); } } if( **position == UTF8_GREATER_THAN ) { (*position)++; } if( status == WEBVTT_SUCCESS ) { /** * The state that the tokenizer left off on will tell us what kind of token * needs to be made. */ if( token_state == DATA || token_state == ESCAPE ) { status = webvtt_create_text_token( token, &result ); } else if(token_state == TAG || token_state == START_TAG || token_state == START_TAG_CLASS || token_state == START_TAG_ANNOTATION) { /** * If the tag does not accept an annotation then release the current * annotation and intialize annotation to a safe empty state */ if( !tag_accepts_annotation( &result ) ) { webvtt_release_string( &annotation ); webvtt_init_string( &annotation ); } status = webvtt_create_start_token( token, &result, css_classes, &annotation ); } else if( token_state == END_TAG ) { status = webvtt_create_end_token( token, &result ); } else if( token_state == TIME_STAMP_TAG ) { parse_timestamp( webvtt_string_text( &result ), &time_stamp ); status = webvtt_create_timestamp_token( token, time_stamp ); } else { status = WEBVTT_INVALID_TOKEN_STATE; } } webvtt_release_stringlist( &css_classes ); webvtt_release_string( &result ); webvtt_release_string( &annotation ); return status; }
TEST(timestamp, nov_date) { const std::string str = "Sun, 01 Nov 1970 00:00:00 GMT"; const time_t timestamp = parse_timestamp(str.data(), str.size()); EXPECT_EQ(26265600, timestamp); }
// Support for iteratively locating the offsets of history items // Pass the address and length of a mapped region. // Pass a pointer to a cursor size_t, initially 0 // If custoff_timestamp is nonzero, skip items created at or after that timestamp // Returns (size_t)(-1) when done static size_t offset_of_next_item(const char *begin, size_t mmap_length, size_t *inout_cursor, time_t cutoff_timestamp) { size_t cursor = *inout_cursor; size_t result = (size_t)(-1); while (cursor < mmap_length) { const char * const line_start = begin + cursor; /* Advance the cursor to the next line */ const char *newline = (const char *)memchr(line_start, '\n', mmap_length - cursor); if (newline == NULL) break; /* Advance the cursor past this line. +1 is for the newline */ size_t line_len = newline - line_start; cursor += line_len + 1; /* Skip lines with a leading space, since these are in the interior of one of our items */ if (line_start[0] == ' ') continue; /* Skip very short lines to make one of the checks below easier */ if (line_len < 3) continue; /* Try to be a little YAML compatible. Skip lines with leading %, ---, or ... */ if (! memcmp(line_start, "%", 1) || ! memcmp(line_start, "---", 3) || ! memcmp(line_start, "...", 3)) continue; /* At this point, we know line_start is at the beginning of an item. But maybe we want to skip this item because of timestamps. A 0 cutoff means we don't care; if we do care, then try parsing out a timestamp. */ if (cutoff_timestamp != 0) { /* Hackish fast way to skip items created after our timestamp. This is the mechanism by which we avoid "seeing" commands from other sessions that started after we started. We try hard to ensure that our items are sorted by their timestamps, so in theory we could just break, but I don't think that works well if (for example) the clock changes. So we'll read all subsequent items. */ const char * const end = begin + mmap_length; /* Walk over lines that we think are interior. These lines are not null terminated, but are guaranteed to contain a newline. */ bool has_timestamp = false; time_t timestamp; const char *interior_line; for (interior_line = next_line(line_start, end - line_start); interior_line != NULL && ! has_timestamp; interior_line = next_line(interior_line, end - interior_line)) { /* If the first character is not a space, it's not an interior line, so we're done */ if (interior_line[0] != ' ') break; /* Hackish optimization: since we just stepped over some interior line, update the cursor so we don't have to look at these lines next time */ cursor = interior_line - begin; /* Try parsing a timestamp from this line. If we succeed, the loop will break. */ has_timestamp = parse_timestamp(interior_line, ×tamp); } /* Skip this item if the timestamp is at or after our cutoff. */ if (has_timestamp && timestamp >= cutoff_timestamp) { continue; } } /* We made it through the gauntlet. */ result = line_start - begin; break; } *inout_cursor = cursor; return result; }
TEST(timestamp, dec_date) { const std::string str = "Thu, 01 Dec 1970 00:00:00 GMT"; const time_t timestamp = parse_timestamp(str.data(), str.size()); EXPECT_EQ(28857600, timestamp); }
/* *************************************************************************** * Main entry to the sar program *************************************************************************** */ int main(int argc, char **argv) { int opt = 1, args_idx = 2; int fd[2]; char from_file[MAX_FILE_LEN], to_file[MAX_FILE_LEN]; char ltemp[20]; /* Get HZ */ get_HZ(); /* Compute page shift in kB */ get_kb_shift(); from_file[0] = to_file[0] = '\0'; #ifdef USE_NLS /* Init National Language Support */ init_nls(); #endif tm_start.use = tm_end.use = FALSE; /* Allocate and init activity bitmaps */ allocate_bitmaps(act); init_structures(); /* Process options */ while (opt < argc) { if (!strcmp(argv[opt], "-I")) { if (argv[++opt]) { /* Parse -I option */ if (parse_sar_I_opt(argv, &opt, act)) { usage(argv[0]); } } else { usage(argv[0]); } } else if (!strcmp(argv[opt], "-P")) { /* Parse -P option */ if (parse_sa_P_opt(argv, &opt, &flags, act)) { usage(argv[0]); } } else if (!strcmp(argv[opt], "-o")) { /* Save stats to a file */ if ((argv[++opt]) && strncmp(argv[opt], "-", 1) && (strspn(argv[opt], DIGITS) != strlen(argv[opt]))) { strncpy(to_file, argv[opt++], MAX_FILE_LEN); to_file[MAX_FILE_LEN - 1] = '\0'; } else { strcpy(to_file, "-"); } } else if (!strcmp(argv[opt], "-f")) { /* Read stats from a file */ if ((argv[++opt]) && strncmp(argv[opt], "-", 1) && (strspn(argv[opt], DIGITS) != strlen(argv[opt]))) { strncpy(from_file, argv[opt++], MAX_FILE_LEN); from_file[MAX_FILE_LEN - 1] = '\0'; } else { set_default_file(&rectime, from_file); } } else if (!strcmp(argv[opt], "-s")) { /* Get time start */ if (parse_timestamp(argv, &opt, &tm_start, DEF_TMSTART)) { usage(argv[0]); } } else if (!strcmp(argv[opt], "-e")) { /* Get time end */ if (parse_timestamp(argv, &opt, &tm_end, DEF_TMEND)) { usage(argv[0]); } } else if (!strcmp(argv[opt], "-i")) { if (!argv[++opt] || (strspn(argv[opt], DIGITS) != strlen(argv[opt]))) { usage(argv[0]); } interval = atol(argv[opt++]); if (interval < 1) { usage(argv[0]); } flags |= S_F_INTERVAL_SET; } else if (!strcmp(argv[opt], "-n")) { if (argv[++opt]) { /* Parse option -n */ if (parse_sar_n_opt(argv, &opt, act)) { usage(argv[0]); } } else { usage(argv[0]); } } else if (!strncmp(argv[opt], "-", 1)) { /* Other options not previously tested */ if (parse_sar_opt(argv, &opt, act, &flags, C_SAR)) { usage(argv[0]); } opt++; } else if (interval < 0) { /* Get interval */ if (strspn(argv[opt], DIGITS) != strlen(argv[opt])) { usage(argv[0]); } interval = atol(argv[opt++]); if (interval < 0) { usage(argv[0]); } } else { /* Get count value */ if ((strspn(argv[opt], DIGITS) != strlen(argv[opt])) || !interval) { usage(argv[0]); } if (count) { /* Count parameter already set */ usage(argv[0]); } count = atol(argv[opt++]); if (count < 1) { usage(argv[0]); } } } /* 'sar' is equivalent to 'sar -f' */ if ((argc == 1) || ((interval < 0) && !from_file[0] && !to_file[0])) { set_default_file(&rectime, from_file); } if (tm_start.use && tm_end.use && (tm_end.tm_hour < tm_start.tm_hour)) { tm_end.tm_hour += 24; } /* * Check option dependencies */ /* You read from a file OR you write to it... */ if (from_file[0] && to_file[0]) { fprintf(stderr, _("-f and -o options are mutually exclusive\n")); exit(1); } /* Use time start or option -i only when reading stats from a file */ if ((tm_start.use || INTERVAL_SET(flags)) && !from_file[0]) { fprintf(stderr, _("Not reading from a system activity file (use -f option)\n")); exit(1); } /* Don't print stats since boot time if -o or -f options are used */ if (!interval && (from_file[0] || to_file[0])) { usage(argv[0]); } if (!count) { /* * count parameter not set: Display all the contents of the file * or generate a report continuously. */ count = -1; } /* Default is CPU activity... */ select_default_activity(act); /* ---Reading stats from file */ if (from_file[0]) { if (interval < 0) { interval = 1; } /* Read stats from file */ read_stats_from_file(from_file); return 0; } /* ---Reading stats from sadc */ /* Create anonymous pipe */ if (pipe(fd) == -1) { perror("pipe"); exit(4); } switch (fork()) { case -1: perror("fork"); exit(4); break; case 0: /* Child */ if (dup2(fd[1], STDOUT_FILENO) < 0) { perror("dup2"); exit(4); } CLOSE_ALL(fd); /* * Prepare options for sadc */ /* Program name */ salloc(0, SADC); /* Interval value */ if (interval < 0) { usage(argv[0]); } else if (!interval) { strcpy(ltemp, "1"); } else { sprintf(ltemp, "%ld", interval); } salloc(1, ltemp); /* Count number */ if (count >= 0) { sprintf(ltemp, "%ld", count + 1); salloc(args_idx++, ltemp); } /* Flags to be passed to sadc */ salloc(args_idx++, "-z"); salloc(args_idx++, "-S"); salloc(args_idx++, K_ALL); /* Outfile arg */ if (to_file[0]) { salloc(args_idx++, to_file); } /* Last arg is NULL */ args[args_idx] = NULL; /* Call now the data collector */ execv(SADC_PATH, args); execvp(SADC, args); /* * Note: don't use execl/execlp since we don't have a fixed number of * args to give to sadc. */ fprintf(stderr, _("Cannot find the data collector (%s)\n"), SADC); perror("exec"); exit(4); break; default: /* Parent */ if (dup2(fd[0], STDIN_FILENO) < 0) { perror("dup2"); exit(4); } CLOSE_ALL(fd); /* Get now the statistics */ read_stats(); break; } return 0; }
TEST(timestamp, year2000_date) { const std::string str = "Wed, 01 Mar 2000 00:00:00 GMT"; const time_t timestamp = parse_timestamp(str.data(), str.size()); EXPECT_EQ(951868800, timestamp); }
/** * Overly complex function that builds a .deb file. */ int do_build(const char *const *argv) { struct compress_params control_compress_params; struct dpkg_error err; struct dpkg_ar *ar; time_t timestamp; const char *timestamp_str; const char *dir, *dest; char *ctrldir; char *debar; char *tfbuf; int gzfd; /* Decode our arguments. */ dir = *argv++; if (!dir) badusage(_("--%s needs a <directory> argument"), cipaction->olong); dest = *argv++; if (dest && *argv) badusage(_("--%s takes at most two arguments"), cipaction->olong); debar = gen_dest_pathname(dir, dest); ctrldir = str_fmt("%s/%s", dir, BUILDCONTROLDIR); /* Perform some sanity checks on the to-be-build package. */ if (nocheckflag) { if (debar == NULL) ohshit(_("target is directory - cannot skip control file check")); warning(_("not checking contents of control area")); info(_("building an unknown package in '%s'."), debar); } else { struct pkginfo *pkg; pkg = check_control_area(ctrldir, dir); if (debar == NULL) debar = gen_dest_pathname_from_pkg(dest, pkg); info(_("building package '%s' in '%s'."), pkg->set->name, debar); } m_output(stdout, _("<standard output>")); timestamp_str = getenv("SOURCE_DATE_EPOCH"); if (timestamp_str) timestamp = parse_timestamp(timestamp_str); else timestamp = time(NULL); /* Now that we have verified everything its time to actually * build something. Let's start by making the ar-wrapper. */ ar = dpkg_ar_create(debar, 0644); dpkg_ar_set_mtime(ar, timestamp); unsetenv("TAR_OPTIONS"); /* Create a temporary file to store the control data in. Immediately * unlink our temporary file so others can't mess with it. */ tfbuf = path_make_temp_template("dpkg-deb"); gzfd = mkstemp(tfbuf); if (gzfd == -1) ohshite(_("failed to make temporary file (%s)"), _("control member")); /* Make sure it's gone, the fd will remain until we close it. */ if (unlink(tfbuf)) ohshit(_("failed to unlink temporary file (%s), %s"), _("control member"), tfbuf); free(tfbuf); /* Select the compressor to use for our control archive. */ if (opt_uniform_compression) { control_compress_params = compress_params; } else { control_compress_params.type = COMPRESSOR_TYPE_GZIP; control_compress_params.strategy = COMPRESSOR_STRATEGY_NONE; control_compress_params.level = -1; if (!compressor_check_params(&control_compress_params, &err)) internerr("invalid control member compressor params: %s", err.str); } /* Fork a tar to package the control-section of the package. */ tarball_pack(ctrldir, control_treewalk_feed, timestamp, &control_compress_params, gzfd); free(ctrldir); if (lseek(gzfd, 0, SEEK_SET)) ohshite(_("failed to rewind temporary file (%s)"), _("control member")); /* We have our first file for the ar-archive. Write a header for it * to the package and insert it. */ if (deb_format.major == 0) { struct stat controlstab; char versionbuf[40]; if (fstat(gzfd, &controlstab)) ohshite(_("failed to stat temporary file (%s)"), _("control member")); sprintf(versionbuf, "%-8s\n%jd\n", OLDARCHIVEVERSION, (intmax_t)controlstab.st_size); if (fd_write(ar->fd, versionbuf, strlen(versionbuf)) < 0) ohshite(_("error writing '%s'"), debar); if (fd_fd_copy(gzfd, ar->fd, -1, &err) < 0) ohshit(_("cannot copy '%s' into archive '%s': %s"), _("control member"), ar->name, err.str); } else if (deb_format.major == 2) { const char deb_magic[] = ARCHIVEVERSION "\n"; char adminmember[16 + 1]; sprintf(adminmember, "%s%s", ADMINMEMBER, compressor_get_extension(control_compress_params.type)); dpkg_ar_put_magic(ar); dpkg_ar_member_put_mem(ar, DEBMAGIC, deb_magic, strlen(deb_magic)); dpkg_ar_member_put_file(ar, adminmember, gzfd, -1); } else { internerr("unknown deb format version %d.%d", deb_format.major, deb_format.minor); } close(gzfd); /* Control is done, now we need to archive the data. */ if (deb_format.major == 0) { /* In old format, the data member is just concatenated after the * control member, so we do not need a temporary file and can use * the compression file descriptor. */ gzfd = ar->fd; } else if (deb_format.major == 2) { /* Start by creating a new temporary file. Immediately unlink the * temporary file so others can't mess with it. */ tfbuf = path_make_temp_template("dpkg-deb"); gzfd = mkstemp(tfbuf); if (gzfd == -1) ohshite(_("failed to make temporary file (%s)"), _("data member")); /* Make sure it's gone, the fd will remain until we close it. */ if (unlink(tfbuf)) ohshit(_("failed to unlink temporary file (%s), %s"), _("data member"), tfbuf); free(tfbuf); } else { internerr("unknown deb format version %d.%d", deb_format.major, deb_format.minor); } /* Pack the directory into a tarball, feeding files from the callback. */ tarball_pack(dir, file_treewalk_feed, timestamp, &compress_params, gzfd); /* Okay, we have data.tar as well now, add it to the ar wrapper. */ if (deb_format.major == 2) { char datamember[16 + 1]; sprintf(datamember, "%s%s", DATAMEMBER, compressor_get_extension(compress_params.type)); if (lseek(gzfd, 0, SEEK_SET)) ohshite(_("failed to rewind temporary file (%s)"), _("data member")); dpkg_ar_member_put_file(ar, datamember, gzfd, -1); close(gzfd); } if (fsync(ar->fd)) ohshite(_("unable to sync file '%s'"), ar->name); dpkg_ar_close(ar); free(debar); return 0; }
TEST(timestamp, tab_before_date) { const std::string str = "\tSun, 06 Nov 1994 08:49:37 GMT"; const time_t timestamp = parse_timestamp(str.data(), str.size()); EXPECT_EQ(784111777, timestamp); }