~xnox/ubuntu/trusty/gcc-arm-linux-androideabi/dima

« back to all changes in this revision

Viewing changes to android/bionic/libc/unistd/syslog.c

  • Committer: Package Import Robot
  • Author(s): Dmitrijs Ledkovs
  • Date: 2013-07-05 10:12:24 UTC
  • Revision ID: package-import@ubuntu.com-20130705101224-6qo3e8jbz8p31aa1
Tags: upstream-0.20130705.1
ImportĀ upstreamĀ versionĀ 0.20130705.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*      $OpenBSD: syslog.c,v 1.28 2005/08/08 08:05:34 espie Exp $ */
 
2
/*
 
3
 * Copyright (c) 1983, 1988, 1993
 
4
 *      The Regents of the University of California.  All rights reserved.
 
5
 *
 
6
 * Redistribution and use in source and binary forms, with or without
 
7
 * modification, are permitted provided that the following conditions
 
8
 * are met:
 
9
 * 1. Redistributions of source code must retain the above copyright
 
10
 *    notice, this list of conditions and the following disclaimer.
 
11
 * 2. Redistributions in binary form must reproduce the above copyright
 
12
 *    notice, this list of conditions and the following disclaimer in the
 
13
 *    documentation and/or other materials provided with the distribution.
 
14
 * 3. Neither the name of the University nor the names of its contributors
 
15
 *    may be used to endorse or promote products derived from this software
 
16
 *    without specific prior written permission.
 
17
 *
 
18
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 
19
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
21
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 
22
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
23
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 
24
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
25
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
27
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
28
 * SUCH DAMAGE.
 
29
 */
 
30
 
 
31
#include <sys/types.h>
 
32
#include <sys/socket.h>
 
33
#include <sys/uio.h>
 
34
#include <syslog.h>
 
35
#include <sys/un.h>
 
36
#include <netdb.h>
 
37
 
 
38
#include <errno.h>
 
39
#include <fcntl.h>
 
40
#include <paths.h>
 
41
#include <stdio.h>
 
42
#include <string.h>
 
43
#include <time.h>
 
44
#include <unistd.h>
 
45
#include <stdarg.h>
 
46
 
 
47
static struct syslog_data sdata = SYSLOG_DATA_INIT;
 
48
 
 
49
extern char     *__progname;            /* Program name, from crt0. */
 
50
 
 
51
static void     disconnectlog_r(struct syslog_data *);  /* disconnect from syslogd */
 
52
static void     connectlog_r(struct syslog_data *);     /* (re)connect to syslogd */
 
53
 
 
54
/*
 
55
 * syslog, vsyslog --
 
56
 *      print message on log file; output is intended for syslogd(8).
 
57
 */
 
58
void
 
59
syslog(int pri, const char *fmt, ...)
 
60
{
 
61
        va_list ap;
 
62
 
 
63
        va_start(ap, fmt);
 
64
        vsyslog(pri, fmt, ap);
 
65
        va_end(ap);
 
66
}
 
67
 
 
68
void
 
69
vsyslog(int pri, const char *fmt, va_list ap)
 
70
{
 
71
        vsyslog_r(pri, &sdata, fmt, ap);
 
72
}
 
73
 
 
74
void
 
75
openlog(const char *ident, int logstat, int logfac)
 
76
{
 
77
        openlog_r(ident, logstat, logfac, &sdata);
 
78
}
 
79
 
 
80
void
 
81
closelog(void)
 
82
{
 
83
        closelog_r(&sdata);
 
84
}
 
85
 
 
86
/* setlogmask -- set the log mask level */
 
87
int
 
88
setlogmask(int pmask)
 
89
{
 
90
        return setlogmask_r(pmask, &sdata);
 
91
}
 
92
 
 
93
/* Reentrant version of syslog, i.e. syslog_r() */
 
94
 
 
95
void
 
96
syslog_r(int pri, struct syslog_data *data, const char *fmt, ...)
 
97
{
 
98
        va_list ap;
 
99
 
 
100
        va_start(ap, fmt);
 
101
        vsyslog_r(pri, data, fmt, ap);
 
102
        va_end(ap);
 
103
}
 
104
 
 
105
void
 
106
vsyslog_r(int pri, struct syslog_data *data, const char *fmt, va_list ap)
 
107
{
 
108
        int cnt;
 
109
        char ch, *p, *t;
 
110
        time_t now;
 
111
        int fd, saved_errno, error;
 
112
#define TBUF_LEN        2048
 
113
#define FMT_LEN         1024
 
114
        char *stdp = NULL, tbuf[TBUF_LEN], fmt_cpy[FMT_LEN];
 
115
        int tbuf_left, fmt_left, prlen;
 
116
 
 
117
#define INTERNALLOG     LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
 
118
        /* Check for invalid bits. */
 
119
        if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) {
 
120
                if (data == &sdata) {
 
121
                        syslog(INTERNALLOG,
 
122
                            "syslog: unknown facility/priority: %x", pri);
 
123
                } else {
 
124
                        syslog_r(INTERNALLOG, data,
 
125
                            "syslog_r: unknown facility/priority: %x", pri);
 
126
                }
 
127
                pri &= LOG_PRIMASK|LOG_FACMASK;
 
128
        }
 
129
 
 
130
        /* Check priority against setlogmask values. */
 
131
        if (!(LOG_MASK(LOG_PRI(pri)) & data->log_mask))
 
132
                return;
 
133
 
 
134
        saved_errno = errno;
 
135
 
 
136
        /* Set default facility if none specified. */
 
137
        if ((pri & LOG_FACMASK) == 0)
 
138
                pri |= data->log_fac;
 
139
 
 
140
        /* If we have been called through syslog(), no need for reentrancy. */
 
141
        if (data == &sdata)
 
142
                (void)time(&now);
 
143
 
 
144
        p = tbuf;
 
145
        tbuf_left = TBUF_LEN;
 
146
 
 
147
#define DEC()   \
 
148
        do {                                    \
 
149
                if (prlen < 0)                  \
 
150
                        prlen = 0;              \
 
151
                if (prlen >= tbuf_left)         \
 
152
                        prlen = tbuf_left - 1;  \
 
153
                p += prlen;                     \
 
154
                tbuf_left -= prlen;             \
 
155
        } while (0)
 
156
 
 
157
        prlen = snprintf(p, tbuf_left, "<%d>", pri);
 
158
        DEC();
 
159
 
 
160
        /* 
 
161
         * syslogd will expand time automagically for reentrant case, and
 
162
         * for normal case, just do like before
 
163
         */
 
164
        if (data == &sdata) {
 
165
                prlen = strftime(p, tbuf_left, "%h %e %T ", localtime(&now));
 
166
                DEC();
 
167
        }
 
168
 
 
169
        if (data->log_stat & LOG_PERROR)
 
170
                stdp = p;
 
171
        if (data->log_tag == NULL)
 
172
                data->log_tag = __progname;
 
173
        if (data->log_tag != NULL) {
 
174
                prlen = snprintf(p, tbuf_left, "%s", data->log_tag);
 
175
                DEC();
 
176
        }
 
177
        if (data->log_stat & LOG_PID) {
 
178
                prlen = snprintf(p, tbuf_left, "[%ld]", (long)getpid());
 
179
                DEC();
 
180
        }
 
181
        if (data->log_tag != NULL) {
 
182
                if (tbuf_left > 1) {
 
183
                        *p++ = ':';
 
184
                        tbuf_left--;
 
185
                }
 
186
                if (tbuf_left > 1) {
 
187
                        *p++ = ' ';
 
188
                        tbuf_left--;
 
189
                }
 
190
        }
 
191
 
 
192
        /* strerror() is not reentrant */
 
193
 
 
194
        for (t = fmt_cpy, fmt_left = FMT_LEN; (ch = *fmt); ++fmt) {
 
195
                if (ch == '%' && fmt[1] == 'm') {
 
196
                        ++fmt;
 
197
                        if (data == &sdata) {
 
198
                                prlen = snprintf(t, fmt_left, "%s",
 
199
                                    strerror(saved_errno)); 
 
200
                        } else {
 
201
                                prlen = snprintf(t, fmt_left, "Error %d",
 
202
                                    saved_errno); 
 
203
                        }
 
204
                        if (prlen < 0)
 
205
                                prlen = 0;
 
206
                        if (prlen >= fmt_left)
 
207
                                prlen = fmt_left - 1;
 
208
                        t += prlen;
 
209
                        fmt_left -= prlen;
 
210
                } else if (ch == '%' && fmt[1] == '%' && fmt_left > 2) {
 
211
                        *t++ = '%';
 
212
                        *t++ = '%';
 
213
                        fmt++;
 
214
                        fmt_left -= 2;
 
215
                } else {
 
216
                        if (fmt_left > 1) {
 
217
                                *t++ = ch;
 
218
                                fmt_left--;
 
219
                        }
 
220
                }
 
221
        }
 
222
        *t = '\0';
 
223
 
 
224
        prlen = vsnprintf(p, tbuf_left, fmt_cpy, ap);
 
225
        DEC();
 
226
        cnt = p - tbuf;
 
227
 
 
228
        /* Output to stderr if requested. */
 
229
        if (data->log_stat & LOG_PERROR) {
 
230
                struct iovec iov[2];
 
231
 
 
232
                iov[0].iov_base = stdp;
 
233
                iov[0].iov_len = cnt - (stdp - tbuf);
 
234
                iov[1].iov_base = "\n";
 
235
                iov[1].iov_len = 1;
 
236
                (void)writev(STDERR_FILENO, iov, 2);
 
237
        }
 
238
 
 
239
        /* Get connected, output the message to the local logger. */
 
240
        if (!data->opened)
 
241
                openlog_r(data->log_tag, data->log_stat, 0, data);
 
242
        connectlog_r(data);
 
243
 
 
244
        /*
 
245
         * If the send() failed, there are two likely scenarios:
 
246
         *  1) syslogd was restarted
 
247
         *  2) /dev/log is out of socket buffer space
 
248
         * We attempt to reconnect to /dev/log to take care of
 
249
         * case #1 and keep send()ing data to cover case #2
 
250
         * to give syslogd a chance to empty its socket buffer.
 
251
         */
 
252
        if ((error = send(data->log_file, tbuf, cnt, 0)) < 0) {
 
253
                if (errno != ENOBUFS) {
 
254
                        disconnectlog_r(data);
 
255
                        connectlog_r(data);
 
256
                }
 
257
                do {
 
258
                        usleep(1);
 
259
                        if ((error = send(data->log_file, tbuf, cnt, 0)) >= 0)
 
260
                                break;
 
261
                } while (errno == ENOBUFS);
 
262
        }
 
263
 
 
264
        /*
 
265
         * Output the message to the console; try not to block
 
266
         * as a blocking console should not stop other processes.
 
267
         * Make sure the error reported is the one from the syslogd failure.
 
268
         */
 
269
        if (error == -1 && (data->log_stat & LOG_CONS) &&
 
270
            (fd = open(_PATH_CONSOLE, O_WRONLY|O_NONBLOCK, 0)) >= 0) {
 
271
                struct iovec iov[2];
 
272
                
 
273
                p = strchr(tbuf, '>') + 1;
 
274
                iov[0].iov_base = p;
 
275
                iov[0].iov_len = cnt - (p - tbuf);
 
276
                iov[1].iov_base = "\r\n";
 
277
                iov[1].iov_len = 2;
 
278
                (void)writev(fd, iov, 2);
 
279
                (void)close(fd);
 
280
        }
 
281
 
 
282
        if (data != &sdata)
 
283
                closelog_r(data);
 
284
}
 
285
 
 
286
static void
 
287
disconnectlog_r(struct syslog_data *data)
 
288
{
 
289
        /*
 
290
         * If the user closed the FD and opened another in the same slot,
 
291
         * that's their problem.  They should close it before calling on
 
292
         * system services.
 
293
         */
 
294
        if (data->log_file != -1) {
 
295
                close(data->log_file);
 
296
                data->log_file = -1;
 
297
        }
 
298
        data->connected = 0;            /* retry connect */
 
299
}
 
300
 
 
301
static void
 
302
connectlog_r(struct syslog_data *data)
 
303
{
 
304
    union {
 
305
        struct sockaddr     syslogAddr;
 
306
        struct sockaddr_un  syslogAddrUn;
 
307
    } u;
 
308
 
 
309
#define SyslogAddr   u.syslogAddrUn
 
310
 
 
311
        if (data->log_file == -1) {
 
312
                if ((data->log_file = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1)
 
313
                        return;
 
314
                (void)fcntl(data->log_file, F_SETFD, 1);
 
315
        }
 
316
        if (data->log_file != -1 && !data->connected) {
 
317
                memset(&SyslogAddr, '\0', sizeof(SyslogAddr));
 
318
#if 0
 
319
                /* BIONIC: no sun_len field to fill on Linux */
 
320
                SyslogAddr.sun_len = sizeof(SyslogAddr);
 
321
#endif
 
322
                SyslogAddr.sun_family = AF_UNIX;
 
323
                strlcpy(SyslogAddr.sun_path, _PATH_LOG,
 
324
                    sizeof(SyslogAddr.sun_path));
 
325
                if (connect(data->log_file, &u.syslogAddr,
 
326
                    sizeof(SyslogAddr)) == -1) {
 
327
                        (void)close(data->log_file);
 
328
                        data->log_file = -1;
 
329
                } else
 
330
                        data->connected = 1;
 
331
        }
 
332
}
 
333
 
 
334
void
 
335
openlog_r(const char *ident, int logstat, int logfac, struct syslog_data *data)
 
336
{
 
337
        if (ident != NULL)
 
338
                data->log_tag = ident;
 
339
        data->log_stat = logstat;
 
340
        if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0)
 
341
                data->log_fac = logfac;
 
342
 
 
343
        if (data->log_stat & LOG_NDELAY)        /* open immediately */
 
344
                connectlog_r(data);
 
345
 
 
346
        data->opened = 1;       /* ident and facility has been set */
 
347
}
 
348
 
 
349
void
 
350
closelog_r(struct syslog_data *data)
 
351
{
 
352
        (void)close(data->log_file);
 
353
        data->log_file = -1;
 
354
        data->connected = 0;
 
355
        data->log_tag = NULL;
 
356
}
 
357
 
 
358
/* setlogmask -- set the log mask level */
 
359
int
 
360
setlogmask_r(int pmask, struct syslog_data *data)
 
361
{
 
362
        int omask;
 
363
 
 
364
        omask = data->log_mask;
 
365
        if (pmask != 0)
 
366
                data->log_mask = pmask;
 
367
        return (omask);
 
368
}