chiark / gitweb /
lib/dpkg/tarfn.c: Kludge `tar_header_decode' to handle spurious `errno'.
[dpkg] / lib / compat / vsnprintf.c
1 /*
2  * libcompat - system compatibility library
3  *
4  * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
5  * Copyright © 2008-2012 Guillem Jover <guillem@debian.org>
6  *
7  * This is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22
23 #include <sys/types.h>
24
25 #include <unistd.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28
29 #include "compat.h"
30
31 int
32 vsnprintf(char *buf, size_t maxsize, const char *fmt, va_list args)
33 {
34         static FILE *file = NULL;
35         static pid_t file_pid;
36
37         size_t want, nr;
38         int total;
39
40         if (maxsize != 0 && buf == NULL)
41                 return -1;
42
43         /* Avoid race conditions from children after a fork(2). */
44         if (file_pid > 0 && file_pid != getpid()) {
45                 fclose(file);
46                 file = NULL;
47         }
48
49         if (!file) {
50                 file = tmpfile();
51                 if (!file)
52                         return -1;
53                 file_pid = getpid();
54         } else {
55                 if (fseek(file, 0, 0))
56                         return -1;
57                 if (ftruncate(fileno(file), 0))
58                         return -1;
59         }
60
61         total = vfprintf(file, fmt, args);
62         if (total < 0)
63                 return -1;
64         if (maxsize == 0)
65                 return total;
66         if (total >= (int)maxsize)
67                 want = maxsize - 1;
68         else
69                 want = total;
70         if (fflush(file))
71                 return -1;
72         if (fseek(file, 0, SEEK_SET))
73                 return -1;
74
75         nr = fread(buf, 1, want, file);
76         if (nr != want)
77                 return -1;
78         buf[want] = '\0';
79
80         return total;
81 }