All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andrew Cooper <andrew.cooper3@citrix.com>
To: xen-devel@lists.xen.org
Subject: Re: [PATCH] mini-os: enable compiler check for printk format types
Date: Wed, 06 Aug 2014 17:29:44 +0100	[thread overview]
Message-ID: <53E257F8.2090509@citrix.com> (raw)
In-Reply-To: <1407318240-1799-1-git-send-email-talex5@gmail.com>

On 06/08/2014 10:44, Thomas Leonard wrote:
> Signed-off-by: Thomas Leonard <talex5@gmail.com>
> ---
>
> I tried compiling mini-os and stubdom on x86 and x86_64 and fixed all the
> warnings reported in the most obvious way I could see.
>
>  extras/mini-os/arch/x86/mm.c     | 22 +++++++++++-----------
>  extras/mini-os/arch/x86/sched.c  |  4 ++--
>  extras/mini-os/arch/x86/traps.c  | 18 +++++++++---------
>  extras/mini-os/blkfront.c        |  2 +-
>  extras/mini-os/include/console.h |  4 ++--
>  extras/mini-os/lib/sys.c         |  4 ++--
>  extras/mini-os/lwip-arch.c       |  2 +-
>  extras/mini-os/minios.mk         |  2 +-
>  extras/mini-os/mm.c              |  6 +++++-
>  extras/mini-os/netfront.c        |  4 ++--
>  extras/mini-os/sched.c           |  2 +-
>  extras/mini-os/test.c            |  6 ++++--
>  extras/mini-os/tpm_tis.c         |  8 ++++----
>  extras/mini-os/xenbus/xenbus.c   |  4 ++--
>  stubdom/vtpmmgr/disk_read.c      |  2 +-
>  15 files changed, 48 insertions(+), 42 deletions(-)
>
> diff --git a/extras/mini-os/arch/x86/mm.c b/extras/mini-os/arch/x86/mm.c
> index 9c6d1b8..186659d 100644
> --- a/extras/mini-os/arch/x86/mm.c
> +++ b/extras/mini-os/arch/x86/mm.c
> @@ -94,7 +94,7 @@ static void new_pt_frame(unsigned long *pt_pfn, unsigned long prev_l_mfn,
>          break;
>  #endif
>      default:
> -        printk("new_pt_frame() called with invalid level number %d\n", level);
> +        printk("new_pt_frame() called with invalid level number %lu\n", level);
>          do_exit();
>          break;
>      }
> @@ -181,7 +181,7 @@ static int need_pt_frame(unsigned long va, int level)
>          if ( level == L1_FRAME )
>              return 1;
>  
> -    printk("ERROR: Unknown frame level %d, hypervisor %llx,%llx\n", 
> +    printk("ERROR: Unknown frame level %d, hypervisor %lx,%lx\n", 
>             level, hyp_virt_start, hyp_virt_end);
>      return -1;
>  }
> @@ -206,11 +206,11 @@ static void build_pagetable(unsigned long *start_pfn, unsigned long *max_pfn)
>      if ( *max_pfn >= virt_to_pfn(HYPERVISOR_VIRT_START) )
>      {
>          printk("WARNING: Mini-OS trying to use Xen virtual space. "
> -               "Truncating memory from %dMB to ",
> +               "Truncating memory from %luMB to ",
>                 ((unsigned long)pfn_to_virt(*max_pfn) -
>                  (unsigned long)&_text)>>20);
>          *max_pfn = virt_to_pfn(HYPERVISOR_VIRT_START - PAGE_SIZE);
> -        printk("%dMB\n",
> +        printk("%luMB\n",
>                 ((unsigned long)pfn_to_virt(*max_pfn) - 
>                  (unsigned long)&_text)>>20);
>      }
> @@ -326,7 +326,7 @@ static void set_readonly(void *text, void *etext)
>              count++;
>          }
>          else
> -            printk("skipped %p\n", start_address);
> +            printk("skipped %lx\n", start_address);
>  
>          start_address += PAGE_SIZE;
>  
> @@ -369,21 +369,21 @@ int mem_test(unsigned long *start_va, unsigned long *end_va, int verbose)
>      /* write values and print page walks */
>      if ( verbose && (((unsigned long)start_va) & 0xfffff) )
>      {
> -        printk("MemTest Start: 0x%lx\n", start_va);
> +        printk("MemTest Start: 0x%p\n", start_va);
>          page_walk((unsigned long)start_va);
>      }
>      for ( pointer = start_va; pointer < end_va; pointer++ )
>      {
>          if ( verbose && !(((unsigned long)pointer) & 0xfffff) )
>          {
> -            printk("Writing to %lx\n", pointer);
> +            printk("Writing to %p\n", pointer);
>              page_walk((unsigned long)pointer);
>          }
>          *pointer = (unsigned long)pointer & ~mask;
>      }
>      if ( verbose && (((unsigned long)end_va) & 0xfffff) )
>      {
> -        printk("MemTest End: %lx\n", end_va-1);
> +        printk("MemTest End: %p\n", end_va-1);
>          page_walk((unsigned long)end_va-1);
>      }
>   
> @@ -516,7 +516,7 @@ void arch_init_demand_mapping_area(unsigned long cur_pfn)
>  
>      demand_map_area_start = (unsigned long) pfn_to_virt(cur_pfn);
>      cur_pfn += DEMAND_MAP_PAGES;
> -    printk("Demand map pfns at %lx-%lx.\n", 
> +    printk("Demand map pfns at %lx-%p.\n", 
>             demand_map_area_start, pfn_to_virt(cur_pfn));
>  
>  #ifdef HAVE_LIBC
> @@ -619,7 +619,7 @@ void do_map_frames(unsigned long va,
>                  if (err)
>                      err[done * stride] = rc;
>                  else {
> -                    printk("Map %ld (%lx, ...) at %p failed: %d.\n",
> +                    printk("Map %ld (%lx, ...) at %lx failed: %d.\n",
>                             todo, mfns[done * stride] + done * incr, va, rc);
>                      do_exit();
>                  }
> @@ -793,7 +793,7 @@ unsigned long alloc_contig_pages(int order, unsigned int addr_bits)
>      out_frames = virt_to_pfn(in_va); /* PFNs to populate */
>      ret = HYPERVISOR_memory_op(XENMEM_exchange, &exchange);
>      if ( ret ) {
> -        printk("mem exchanged order=0x%x failed with rc=%d, nr_exchanged=%d\n", 
> +        printk("mem exchanged order=0x%x failed with rc=%d, nr_exchanged=%lu\n",
>                 order, ret, exchange.nr_exchanged);
>          /* we still need to return the allocated pages above to the pool
>           * ie. map them back into the 1:1 mapping etc. so we continue but 
> diff --git a/extras/mini-os/arch/x86/sched.c b/extras/mini-os/arch/x86/sched.c
> index e4a3dc2..ec13694 100644
> --- a/extras/mini-os/arch/x86/sched.c
> +++ b/extras/mini-os/arch/x86/sched.c
> @@ -73,7 +73,7 @@ void dump_stack(struct thread *thread)
>      printk("The stack for \"%s\"\n", thread->name);
>      for(count = 0; count < 25 && pointer < bottom; count ++)
>      {
> -        printk("[0x%lx] 0x%lx\n", pointer, *pointer);
> +        printk("[0x%p] 0x%lx\n", pointer, *pointer);
>          pointer++;
>      }
>      
> @@ -101,7 +101,7 @@ struct thread* arch_create_thread(char *name, void (*function)(void *),
>      /* We can't use lazy allocation here since the trap handler runs on the stack */
>      thread->stack = (char *)alloc_pages(STACK_SIZE_PAGE_ORDER);
>      thread->name = name;
> -    printk("Thread \"%s\": pointer: 0x%lx, stack: 0x%lx\n", name, thread, 
> +    printk("Thread \"%s\": pointer: 0x%p, stack: 0x%p\n", name, thread, 
>              thread->stack);
>      
>      thread->sp = (unsigned long)thread->stack + STACK_SIZE;
> diff --git a/extras/mini-os/arch/x86/traps.c b/extras/mini-os/arch/x86/traps.c
> index 516d133..6353718 100644
> --- a/extras/mini-os/arch/x86/traps.c
> +++ b/extras/mini-os/arch/x86/traps.c
> @@ -34,14 +34,14 @@ void dump_regs(struct pt_regs *regs)
>  {
>      printk("Thread: %s\n", current->name);
>  #ifdef __i386__    
> -    printk("EIP: %x, EFLAGS %x.\n", regs->eip, regs->eflags);
> -    printk("EBX: %08x ECX: %08x EDX: %08x\n",
> +    printk("EIP: %lx, EFLAGS %lx.\n", regs->eip, regs->eflags);
> +    printk("EBX: %08lx ECX: %08lx EDX: %08lx\n",
>  	   regs->ebx, regs->ecx, regs->edx);
> -    printk("ESI: %08x EDI: %08x EBP: %08x EAX: %08x\n",
> +    printk("ESI: %08lx EDI: %08lx EBP: %08lx EAX: %08lx\n",
>  	   regs->esi, regs->edi, regs->ebp, regs->eax);
> -    printk("DS: %04x ES: %04x orig_eax: %08x, eip: %08x\n",
> +    printk("DS: %04x ES: %04x orig_eax: %08lx, eip: %08lx\n",
>  	   regs->xds, regs->xes, regs->orig_eax, regs->eip);
> -    printk("CS: %04x EFLAGS: %08x esp: %08x ss: %04x\n",
> +    printk("CS: %04x EFLAGS: %08lx esp: %08lx ss: %04x\n",
>  	   regs->xcs, regs->eflags, regs->esp, regs->xss);
>  #else
>      printk("RIP: %04lx:[<%016lx>] ", regs->cs & 0xffff, regs->rip);
> @@ -214,10 +214,10 @@ void do_page_fault(struct pt_regs *regs, unsigned long error_code)
>      barrier();
>  
>  #if defined(__x86_64__)
> -    printk("Page fault at linear address %p, rip %p, regs %p, sp %p, our_sp %p, code %lx\n",
> +    printk("Page fault at linear address %lx, rip %lx, regs %p, sp %lx, our_sp %p, code %lx\n",
>             addr, regs->rip, regs, regs->rsp, &addr, error_code);
>  #else
> -    printk("Page fault at linear address %p, eip %p, regs %p, sp %p, our_sp %p, code %lx\n",
> +    printk("Page fault at linear address %lx, eip %lx, regs %p, sp %lx, our_sp %p, code %lx\n",
>             addr, regs->eip, regs, regs->esp, &addr, error_code);
>  #endif
>  
> @@ -243,9 +243,9 @@ void do_general_protection(struct pt_regs *regs, long error_code)
>  {
>      struct sched_shutdown sched_shutdown = { .reason = SHUTDOWN_crash };
>  #ifdef __i386__
> -    printk("GPF eip: %p, error_code=%lx\n", regs->eip, error_code);
> +    printk("GPF eip: %lx, error_code=%lx\n", regs->eip, error_code);
>  #else    
> -    printk("GPF rip: %p, error_code=%lx\n", regs->rip, error_code);
> +    printk("GPF rip: %lx, error_code=%lx\n", regs->rip, error_code);
>  #endif
>      dump_regs(regs);
>  #if defined(__x86_64__)
> diff --git a/extras/mini-os/blkfront.c b/extras/mini-os/blkfront.c
> index 59e576f..bdb7765 100644
> --- a/extras/mini-os/blkfront.c
> +++ b/extras/mini-os/blkfront.c
> @@ -236,7 +236,7 @@ done:
>      }
>      unmask_evtchn(dev->evtchn);
>  
> -    printk("%u sectors of %u bytes\n", dev->info.sectors, dev->info.sector_size);
> +    printk("%lu sectors of %u bytes\n", (unsigned long) dev->info.sectors, dev->info.sector_size);

Use PRIu64 and no cast, or you will trucate the sector count for 32bit
builds.  In general you should never need to cast (unless you have
something which isn't a long but changes size between builds)

>      printk("**************************\n");
>  
>      return dev;
> diff --git a/extras/mini-os/include/console.h b/extras/mini-os/include/console.h
> index 3755b66..a77f47f 100644
> --- a/extras/mini-os/include/console.h
> +++ b/extras/mini-os/include/console.h
> @@ -64,8 +64,8 @@ struct consfront_dev {
>  
>  
>  void print(int direct, const char *fmt, va_list args);

What about a printf notation for this print function?

> -void printk(const char *fmt, ...);
> -void xprintk(const char *fmt, ...);
> +void printk(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
> +void xprintk(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
>  
>  #define tprintk(_fmt, _args...) printk("[%s] " _fmt, current->name, ##_args) 
>  
> diff --git a/extras/mini-os/lib/sys.c b/extras/mini-os/lib/sys.c
> index 13e7e59..1e9bddc 100644
> --- a/extras/mini-os/lib/sys.c
> +++ b/extras/mini-os/lib/sys.c
> @@ -1319,7 +1319,7 @@ int clock_gettime(clockid_t clk_id, struct timespec *tp)
>  	    break;
>  	}
>  	default:
> -	    print_unsupported("clock_gettime(%d)", clk_id);
> +	    print_unsupported("clock_gettime(%ld)", (long) clk_id);

I am failing to locate a type declaration for clockid_t, but I feel that
is is likely you can get away without a cast.

>  	    errno = EINVAL;
>  	    return -1;
>      }
> @@ -1421,7 +1421,7 @@ void sparse(unsigned long data, size_t size)
>          mfns[i] = virtual_to_mfn(data + i * PAGE_SIZE);
>      }
>  
> -    printk("sparsing %ldMB at %lx\n", size >> 20, data);
> +    printk("sparsing %ldMB at %lx\n", (long) size >> 20, data);

%zu is the correct format for a size_t.

>  
>      munmap((void *) data, size);
>      free_physical_pages(mfns, n);
> diff --git a/extras/mini-os/lwip-arch.c b/extras/mini-os/lwip-arch.c
> index e634ef4..e2476d4 100644
> --- a/extras/mini-os/lwip-arch.c
> +++ b/extras/mini-os/lwip-arch.c
> @@ -236,7 +236,7 @@ sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, i
>  {
>      struct thread *t;
>      if (stacksize > STACK_SIZE) {
> -	printk("Can't start lwIP thread: stack size %d is too large for our %d\n", stacksize, STACK_SIZE);
> +	printk("Can't start lwIP thread: stack size %d is too large for our %d\n", stacksize, (int) STACK_SIZE);

STACK_SIZE is an unsigned long.

>  	do_exit();
>      }
>      lwip_thread = t = create_thread(name, thread, arg);
> diff --git a/extras/mini-os/minios.mk b/extras/mini-os/minios.mk
> index f42f48b..20ba64b 100644
> --- a/extras/mini-os/minios.mk
> +++ b/extras/mini-os/minios.mk
> @@ -6,7 +6,7 @@ debug = y
>  
>  # Define some default flags.
>  # NB. '-Wcast-qual' is nasty, so I omitted it.
> -DEF_CFLAGS += -fno-builtin -Wall -Werror -Wredundant-decls -Wno-format -Wno-redundant-decls
> +DEF_CFLAGS += -fno-builtin -Wall -Werror -Wredundant-decls -Wno-format -Wno-redundant-decls -Wformat

Please don't add overrides while leaving the previous still present. 
Drop both the -Wno-format and -Wformat

(Unrelated to your patch, A -Wredundat-decls followed by
-Wno-redundant-decls seems silly)

~Andrew


>  DEF_CFLAGS += $(call cc-option,$(CC),-fno-stack-protector,)
>  DEF_CFLAGS += $(call cc-option,$(CC),-fgnu89-inline)
>  DEF_CFLAGS += -Wstrict-prototypes -Wnested-externs -Wpointer-arith -Winline
> diff --git a/extras/mini-os/mm.c b/extras/mini-os/mm.c
> index 64b3292..31aaf83 100644
> --- a/extras/mini-os/mm.c
> +++ b/extras/mini-os/mm.c
> @@ -379,7 +379,11 @@ void *sbrk(ptrdiff_t increment)
>      unsigned long new_brk = old_brk + increment;
>  
>      if (new_brk > heap_end) {
> -	printk("Heap exhausted: %p + %lx = %p > %p\n", old_brk, increment, new_brk, heap_end);
> +	printk("Heap exhausted: %lx + %lx = %p > %p\n",
> +			old_brk,
> +			(unsigned long) increment,
> +			(void *) new_brk,
> +			(void *) heap_end);
>  	return NULL;
>      }
>      
> diff --git a/extras/mini-os/netfront.c b/extras/mini-os/netfront.c
> index 44c3995..6f335fe 100644
> --- a/extras/mini-os/netfront.c
> +++ b/extras/mini-os/netfront.c
> @@ -327,8 +327,8 @@ struct netfront_dev *init_netfront(char *_nodename, void (*thenetif_rx)(unsigned
>      dev->fd = -1;
>  #endif
>  
> -    printk("net TX ring size %d\n", NET_TX_RING_SIZE);
> -    printk("net RX ring size %d\n", NET_RX_RING_SIZE);
> +    printk("net TX ring size %llu\n", (unsigned long long) NET_TX_RING_SIZE);
> +    printk("net RX ring size %llu\n", (unsigned long long) NET_RX_RING_SIZE);
>      init_SEMAPHORE(&dev->tx_sem, NET_TX_RING_SIZE);
>      for(i=0;i<NET_TX_RING_SIZE;i++)
>      {
> diff --git a/extras/mini-os/sched.c b/extras/mini-os/sched.c
> index d0c607e..1e843d9 100644
> --- a/extras/mini-os/sched.c
> +++ b/extras/mini-os/sched.c
> @@ -276,7 +276,7 @@ void th_f2(void *data)
>  {
>      for(;;)
>      {
> -        printk("Thread OTHER executing, data 0x%lx\n", data);
> +        printk("Thread OTHER executing, data 0x%p\n", data);
>          schedule();
>      }
>  }
> diff --git a/extras/mini-os/test.c b/extras/mini-os/test.c
> index 20d372b..64a4057 100644
> --- a/extras/mini-os/test.c
> +++ b/extras/mini-os/test.c
> @@ -116,7 +116,7 @@ static void blk_read_completed(struct blkfront_aiocb *aiocb, int ret)
>  {
>      struct blk_req *req = aiocb->data;
>      if (ret)
> -        printk("got error code %d when reading at offset %ld\n", ret, aiocb->aio_offset);
> +        printk("got error code %d when reading at offset %ld\n", ret, (long) aiocb->aio_offset);
>      else
>          blk_size_read += blk_info.sector_size;
>      free(aiocb->aio_buf);
> @@ -237,7 +237,9 @@ static void blkfront_thread(void *p)
>          blkfront_aio_poll(blk_dev);
>          gettimeofday(&tv, NULL);
>          if (tv.tv_sec > lasttime + 10) {
> -            printk("%llu read, %llu write\n", blk_size_read, blk_size_write);
> +            printk("%llu read, %llu write\n",
> +                    (unsigned long long) blk_size_read,
> +                    (unsigned long long) blk_size_write);
>              lasttime = tv.tv_sec;
>          }
>  
> diff --git a/extras/mini-os/tpm_tis.c b/extras/mini-os/tpm_tis.c
> index dc4134a..936e854 100644
> --- a/extras/mini-os/tpm_tis.c
> +++ b/extras/mini-os/tpm_tis.c
> @@ -906,7 +906,7 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const uint8_t *buf,
>     //down(&chip->tpm_mutex);
>  
>     if ((rc = tpm_tis_send(chip, (uint8_t *) buf, count)) < 0) {
> -      printk("tpm_transmit: tpm_send: error %ld\n", rc);
> +      printk("tpm_transmit: tpm_send: error %ld\n", (long) rc);
>        goto out;
>     }
>  
> @@ -938,7 +938,7 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const uint8_t *buf,
>  
>  out_recv:
>     if((rc = tpm_tis_recv(chip, (uint8_t *) buf, bufsiz)) < 0) {
> -      printk("tpm_transmit: tpm_recv: error %d\n", rc);
> +      printk("tpm_transmit: tpm_recv: error %d\n", (int) rc);
>     }
>  out:
>     //up(&chip->tpm_mutex);
> @@ -977,7 +977,7 @@ int tpm_get_timeouts(struct tpm_chip *chip)
>  
>     if((rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
>  	 "attempting to determine the timeouts")) != 0) {
> -      printk("transmit failed %d\n", rc);
> +      printk("transmit failed %d\n", (int) rc);
>        goto duration;
>     }
>  
> @@ -1132,7 +1132,7 @@ struct tpm_chip* init_tpm_tis(unsigned long baseaddr, int localities, unsigned i
>        if(locality_enabled(tpm, i)) {
>  	 /* Map the page in now */
>  	 if((tpm->pages[i] = ioremap_nocache(addr, PAGE_SIZE)) == NULL) {
> -	    printk("Unable to map iomem page a address %p\n", addr);
> +	    printk("Unable to map iomem page a address %lx\n", addr);
>  	    goto abort_egress;
>  	 }
>  
> diff --git a/extras/mini-os/xenbus/xenbus.c b/extras/mini-os/xenbus/xenbus.c
> index 934f23b..4613ed6 100644
> --- a/extras/mini-os/xenbus/xenbus.c
> +++ b/extras/mini-os/xenbus/xenbus.c
> @@ -337,8 +337,8 @@ void init_xenbus(void)
>  		      xenbus_evtchn_handler,
>                NULL);
>      unmask_evtchn(start_info.store_evtchn);
> -    printk("xenbus initialised on irq %d mfn %#lx\n",
> -	   err, start_info.store_mfn);
> +    printk("xenbus initialised on irq %d mfn %#llx\n",
> +	   err, (unsigned long long) start_info.store_mfn);
>  }
>  
>  void fini_xenbus(void)
> diff --git a/stubdom/vtpmmgr/disk_read.c b/stubdom/vtpmmgr/disk_read.c
> index 33aacdd..a4c63c8 100644
> --- a/stubdom/vtpmmgr/disk_read.c
> +++ b/stubdom/vtpmmgr/disk_read.c
> @@ -538,7 +538,7 @@ int vtpm_load_disk(void)
>  	printk(" root seal: %lu; sector of %d: %lu\n",
>  		sizeof(struct disk_root_sealed_data), SEALS_PER_ROOT_SEAL_LIST, sizeof(struct disk_seal_list));
>  	printk(" root: %lu v=%lu\n", sizeof(root1), sizeof(root1.v));
> -	printk(" itree: %lu; sector of %d: %lu\n",
> +	printk(" itree: %u; sector of %d: %lu\n",
>  		4 + 32, NR_ENTRIES_PER_ITREE, sizeof(struct disk_itree_sector));
>  	printk(" group: %lu v=%lu id=%lu md=%lu\n",
>  		sizeof(struct disk_group_sector), sizeof(struct disk_group_sector_mac3_area),

  reply	other threads:[~2014-08-06 16:29 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-08-06  9:44 [PATCH] mini-os: enable compiler check for printk format types Thomas Leonard
2014-08-06 16:29 ` Andrew Cooper [this message]
2014-08-07  6:33   ` Jan Beulich
2014-08-07 14:55 ` Samuel Thibault
2014-08-08  8:50   ` Thomas Leonard
2014-08-08 14:28   ` Thomas Leonard
2014-08-08 14:32     ` Samuel Thibault
2014-10-03  8:44       ` Thomas Leonard
2014-10-03  8:55         ` Ian Campbell
2014-10-05 19:30           ` Samuel Thibault
2014-10-06 13:28             ` Ian Campbell
2014-10-07 16:04               ` Samuel Thibault
2014-10-08 11:12               ` Thomas Leonard
2014-10-08 11:16                 ` Andrew Cooper
2014-10-08 11:25                 ` Ian Campbell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=53E257F8.2090509@citrix.com \
    --to=andrew.cooper3@citrix.com \
    --cc=xen-devel@lists.xen.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.