--- /dev/null
+/*
+ * A tail-like command working on pcap files
+ *
+ * (c) 2012 Martin Mares <mj@ucw.cz>
+ */
+
+#define _LARGEFILE_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+struct pcap_header {
+ uint32_t magic;
+ uint16_t major, minor;
+ uint32_t tz_offset;
+ uint32_t time_accuracy;
+ uint32_t snaplen;
+ uint32_t ll_type;
+};
+
+struct pcap_packet {
+ uint32_t time_sec;
+ uint32_t time_us;
+ uint32_t captured_len;
+ uint32_t orig_len;
+};
+
+int main(int argc, char **argv)
+{
+ if (argc != 3) {
+ fprintf(stderr, "Usage: pcap-tail <num-packets> <file>\n");
+ return 1;
+ }
+
+ uint64_t num = atoi(argv[1]);
+ uint64_t *ring = malloc(num * sizeof(uint64_t));
+ if (!ring) {
+ fprintf(stderr, "Out of memory\n");
+ return 1;
+ }
+
+ FILE *in = fopen(argv[2], "r");
+ if (!in) {
+ fprintf(stderr, "Cannot open %s: %m\n", argv[2]);
+ return 1;
+ }
+
+ struct pcap_header hdr;
+ if (fread(&hdr, sizeof(hdr), 1, in) < 1) {
+ fprintf(stderr, "Cannot read header\n");
+ return 1;
+ }
+ if (hdr.magic != 0xa1b2c3d4) {
+ fprintf(stderr, "Bad (black?) magic\n");
+ return 1;
+ }
+
+ struct pcap_packet pkt;
+ int ring_pos = 0;
+ uint64_t count = 0;
+ for (;;) {
+ uint64_t pos = ftell(in);
+ if (fread(&pkt, sizeof(pkt), 1, in) < 1)
+ break;
+ // printf("@%d len=%d\n", (int)pos, pkt.captured_len);
+ ring[ring_pos] = pos;
+ ring_pos = (ring_pos + 1) % num;
+ fseek(in, pkt.captured_len, SEEK_CUR);
+ count++;
+ }
+
+ fwrite(&hdr, sizeof(hdr), 1, stdout);
+ if (count > num) {
+ fseek(in, ring[ring_pos], SEEK_SET);
+ } else {
+ fseek(in, ring[0], SEEK_SET);
+ }
+
+ char buf[4096];
+ int n;
+ while ((n = fread(buf, 1, sizeof(buf), in)) > 0)
+ fwrite(buf, 1, n, stdout);
+
+ return 0;
+}