source: ksyslog/trunk/ksyslog.c @ 264

Revision 264, 16.4 KB checked in by atzm, 11 years ago (diff)

fsnotify_open compat

RevLine 
[232]1/*
2 * ksyslog: In-kernel syslog receiver
3 * Copyright(C) 2013 Atzm WATANABE All rights reserved
4 * Distributed under the GPL
5 */
6
[246]7#include <linux/version.h>
[232]8#include <linux/module.h>
[243]9#include <linux/inet.h>
[232]10#include <linux/ip.h>
11#include <linux/udp.h>
12#include <linux/namei.h>
[263]13#include <linux/fsnotify.h>
[246]14#include <linux/proc_fs.h>
[250]15#include <linux/u64_stats_sync.h>
16#include <linux/percpu.h>
[232]17#include <net/udp.h>
[246]18#include "compat.h"
[232]19#include "ksyslog.h"
20
[242]21static struct ksyslog_queue ksyslog_queue;
[232]22static struct socket *ksyslog_rcv_sk = NULL;
23
24static struct delayed_work ksyslog_work;
25static struct workqueue_struct *ksyslog_wq = NULL;
26
27#ifdef CONFIG_PROC_FS
28static struct proc_dir_entry *ksyslog_procdir = NULL;
29static struct proc_dir_entry *ksyslog_proc_queue = NULL;
[250]30static struct proc_dir_entry *ksyslog_proc_size = NULL;
31static struct proc_dir_entry *ksyslog_proc_stats = NULL;
[232]32#endif
33
34static char *ksyslog_host = "0.0.0.0";
35static ushort ksyslog_port = 514;
36static char *ksyslog_path = "/var/log/ksyslog.log";
[250]37static ulong ksyslog_queue_size_max = 4096;
[232]38static ulong ksyslog_flush_interval = 45;  /* milliseconds */
39
40module_param(ksyslog_host, charp, 0444);
41module_param(ksyslog_port, ushort, 0444);
42module_param(ksyslog_path, charp, 0644);
[250]43module_param(ksyslog_queue_size_max, ulong, 0644);
[232]44module_param(ksyslog_flush_interval, ulong, 0644);
45
[250]46static int
[241]47ksyslog_queue_init(struct ksyslog_queue *queue)
48{
49        memset(queue, 0, sizeof(*queue));
50        INIT_LIST_HEAD(&queue->head);
[242]51        spin_lock_init(&queue->lock);
[250]52        atomic64_set(&queue->size, 0);
53        queue->stats = alloc_percpu(struct ksyslog_stats);
54        if (unlikely(queue->stats == NULL))
55                return -ENOMEM;
56        return 0;
[241]57}
58
[250]59static void
60ksyslog_queue_uninit(struct ksyslog_queue *queue)
61{
62        if (likely(queue->stats))
63                free_percpu(queue->stats);
64        queue->stats = NULL;
65}
66
[232]67static int
68ksyslog_close(struct file *file)
69{
[263]70        int err;
71        mm_segment_t oldfs;
72
73        oldfs = get_fs();
74        set_fs(get_ds());
75
76        err = filp_close(file, NULL);
77
78        set_fs(oldfs);
79        return err;
[232]80}
81
82static struct file *
83ksyslog_open(const char *path)
84{
85        struct file *file;
[243]86        struct path ppath;
[232]87        mm_segment_t oldfs;
88
89        oldfs = get_fs();
90        set_fs(get_ds());
91
[243]92        if (unlikely(kern_path(path, LOOKUP_OPEN|LOOKUP_FOLLOW, &ppath)))
[232]93                file = filp_open(path, O_CREAT|O_WRONLY|O_APPEND|O_LARGEFILE, 0600);
94        else
95                file = filp_open(path, O_WRONLY|O_APPEND|O_LARGEFILE, 0);
96
[234]97        if (unlikely(IS_ERR(file)))
[232]98                goto out;
99
[264]100        compat_fsnotify_open(file);
[263]101
[234]102        if (unlikely(S_ISDIR(file->f_path.dentry->d_inode->i_mode))) {
[232]103                ksyslog_close(file);
104                file = ERR_PTR(-EISDIR);
105                goto out;
106        }
107
[234]108        if (unlikely(file->f_pos < 0)) {
[232]109                ksyslog_close(file);
110                file = ERR_PTR(-EIO);
111                goto out;
112        }
113
114out:
115        set_fs(oldfs);
116        return file;
117}
118
119static int
120ksyslog_write(struct file *file, const char *buf, const size_t length)
121{
122        int err;
123        mm_segment_t oldfs;
124
125        oldfs = get_fs();
126        set_fs(get_ds());
127
128        err = vfs_write(file, (__force void __user *)buf, length, &file->f_pos);
129
130        set_fs(oldfs);
131        return err;
132}
133
134static void
[234]135ksyslog_drop_warning(const struct ksyslog_entry *entry)
[232]136{
[250]137        pr_warn("ksyslog: dropped: %llu %s.%s %u.%u.%u.%u %.*s\n",
[232]138                timeval_to_ns(&entry->tv) / 1000 / 1000 / 1000,
139                ksyslog_facility_str(entry->facility),
140                ksyslog_severity_str(entry->severity),
141                entry->saddr.addr8[0], entry->saddr.addr8[1],
142                entry->saddr.addr8[2], entry->saddr.addr8[3],
143                (int)entry->length, entry->data);
144}
145
146static int
[234]147ksyslog_format(char **buf, const struct ksyslog_entry *entry)
[232]148{
149        *buf = kzalloc(54 + entry->length + 2, GFP_ATOMIC);
[234]150        if (unlikely(*buf == NULL))
[232]151                return -ENOMEM;
152
153        return sprintf(*buf, "%llu %s.%s %u.%u.%u.%u %.*s\n",
154                       timeval_to_ns(&entry->tv) / 1000 / 1000 / 1000,
155                       ksyslog_facility_str(entry->facility),
156                       ksyslog_severity_str(entry->severity),
157                       entry->saddr.addr8[0], entry->saddr.addr8[1],
158                       entry->saddr.addr8[2], entry->saddr.addr8[3],
159                       (int)entry->length, entry->data);
160}
161
162static struct ksyslog_entry *
[234]163ksyslog_entry_create(const struct sk_buff *skb,
164                     const struct iphdr *iph, const struct udphdr *udph)
[232]165{
166        struct ksyslog_entry *entry;
[235]167        unsigned int priority, facility, severity, month, day, hour, minute, second;
168        unsigned char *start, month_s[4];
169        struct tm tm;
[232]170        int length, i;
171
[235]172        if (sscanf(skb->data, "<%3u>%3s %2u %2u:%2u:%2u ",
173                   &priority, month_s, &day, &hour, &minute, &second) != 6)
[232]174                return ERR_PTR(-EINVAL);
175
176        start = memchr(skb->data, '>', 5);
177        if (start == NULL)
178                return ERR_PTR(-EINVAL);
179        start++;
180
181        facility = priority >> 3;
182        severity = priority & 7;
183
184        if (facility >= __KSYSLOG_F_MAX)
185                return ERR_PTR(-EINVAL);
186        if (severity >= __KSYSLOG_S_MAX)
187                return ERR_PTR(-EINVAL);
188
[235]189        month = ksyslog_month_num(month_s);
190        if (!month)
191                return ERR_PTR(-EINVAL);
192        if (day > 31)
193                return ERR_PTR(-EINVAL);
194        if (hour > 23)
195                return ERR_PTR(-EINVAL);
196        if (minute > 59)
197                return ERR_PTR(-EINVAL);
198        if (second > 59)
199                return ERR_PTR(-EINVAL);
200
[232]201        entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
[234]202        if (unlikely(entry == NULL))
[232]203                return ERR_PTR(-ENOMEM);
204
205        length = skb->len - (start - skb->data);
206        entry->data = kzalloc(length, GFP_ATOMIC);
[234]207        if (unlikely(entry->data == NULL)) {
[232]208                kfree(entry);
209                return ERR_PTR(-ENOMEM);
210        }
211
212        if (skb->tstamp.tv64)
213                entry->tv = ktime_to_timeval(skb->tstamp);
214        else
215                do_gettimeofday(&entry->tv);
216
[235]217        time_to_tm(entry->tv.tv_sec, 0, &tm);
218        entry->time = mktime(tm.tm_year + 1900, month, day, hour, minute, second);
219
220        entry->priority = priority;
[234]221        entry->facility = facility;
222        entry->severity = severity;
223
[232]224        entry->daddr.addr32 = iph->daddr;
225        entry->saddr.addr32 = iph->saddr;
226
227        entry->dport = udph->dest;
228        entry->sport = udph->source;
229
230        entry->length = length;
231        memcpy(entry->data, start, length);
232
233        for (i = 0; i < length; i++)
[234]234                if (unlikely(entry->data[i] == '\n'))
[232]235                        entry->data[i] = ' ';
236
237        return entry;
238}
239
240static void
241ksyslog_entry_free(struct rcu_head *head)
242{
243        struct ksyslog_entry *entry = container_of(head, struct ksyslog_entry, rcu);
244        kfree(entry->data);
245        kfree(entry);
246}
247
248static int
249ksyslog_entry_add(struct ksyslog_queue *queue, struct ksyslog_entry *entry)
250{
[250]251        if (unlikely(atomic64_read(&queue->size) >= ksyslog_queue_size_max))
[232]252                return -ENOBUFS;
253        list_add_tail_rcu(&entry->list, &queue->head);
[250]254        WARN_ON(atomic64_inc_return(&queue->size) > ksyslog_queue_size_max);
[232]255        return 0;
256}
257
258static void
259ksyslog_entry_del(struct ksyslog_queue *queue, struct ksyslog_entry *entry, bool free)
260{
[250]261        WARN_ON(atomic64_dec_return(&queue->size) < 0);
[232]262        list_del_rcu(&entry->list);
263        if (free)
264                call_rcu(&entry->rcu, ksyslog_entry_free);
265}
266
267static void
268ksyslog_entry_destroy(struct ksyslog_queue *queue)
269{
270        struct ksyslog_entry *entry, *next;
271
272        list_for_each_entry_safe(entry, next, &queue->head, list)
273                ksyslog_entry_del(queue, entry, true);
274}
275
276static void
277ksyslog_entry_migrate(struct ksyslog_queue *from, struct ksyslog_queue *to)
278{
279        struct ksyslog_entry *entry, *next;
280
281        list_for_each_entry_safe(entry, next, &from->head, list) {
282                ksyslog_entry_del(from, entry, false);
[234]283                if (unlikely(ksyslog_entry_add(to, entry))) {
[250]284                        ksyslog_stats_add_drop(from, entry->length);
285                        ksyslog_stats_add_drop(to, entry->length);
[232]286                        ksyslog_drop_warning(entry);
287                        call_rcu(&entry->rcu, ksyslog_entry_free);
288                }
289        }
290}
291
292static void
293ksyslog_work_register(unsigned long timer)
294{
295        queue_delayed_work(ksyslog_wq, &ksyslog_work, timer * HZ / 1000);
296}
297
298static void
299ksyslog_work_unregister(void)
300{
301        cancel_delayed_work_sync(&ksyslog_work);
302}
303
304static void
305ksyslog_work_handler(struct work_struct *work)
306{
307        struct file *file = NULL;
308        struct ksyslog_entry *entry, *next;
309        struct ksyslog_queue write_queue;
310
[250]311        if (ksyslog_queue_init(&write_queue))
312                goto out;
[232]313
[242]314        spin_lock_bh(&ksyslog_queue.lock);
[232]315        ksyslog_entry_migrate(&ksyslog_queue, &write_queue);
[242]316        spin_unlock_bh(&ksyslog_queue.lock);
[232]317
[250]318        if (atomic64_read(&write_queue.size) <= 0)
[232]319                goto out;
320
321        file = ksyslog_open(ksyslog_path);
[234]322        if (unlikely(IS_ERR(file))) {
[242]323                spin_lock_bh(&ksyslog_queue.lock);
[232]324                ksyslog_entry_migrate(&write_queue, &ksyslog_queue);
[242]325                spin_unlock_bh(&ksyslog_queue.lock);
[232]326                goto out;
327        }
328
329        list_for_each_entry_safe(entry, next, &write_queue.head, list) {
330                int length;
331                char *buf;
332
333                ksyslog_entry_del(&write_queue, entry, false);
334
335                length = ksyslog_format(&buf, entry);
[234]336                if (unlikely(length < 0))
[232]337                        goto restore;
338
[244]339                if (unlikely(ksyslog_write(file, buf, length) != length)) {
[232]340                        kfree(buf);
341                        goto restore;
342                }
343
[250]344                ksyslog_stats_add_write(&ksyslog_queue, entry->length);
[232]345                kfree(buf);
346                call_rcu(&entry->rcu, ksyslog_entry_free);
347                continue;
348
349restore:
[242]350                spin_lock_bh(&ksyslog_queue.lock);
[234]351                if (unlikely(ksyslog_entry_add(&ksyslog_queue, entry))) {
[250]352                        ksyslog_stats_add_drop(&ksyslog_queue, entry->length);
[232]353                        ksyslog_drop_warning(entry);
354                        call_rcu(&entry->rcu, ksyslog_entry_free);
355                }
[242]356                spin_unlock_bh(&ksyslog_queue.lock);
[232]357        }
[234]358
[232]359        ksyslog_close(file);
360
361out:
[250]362        ksyslog_queue_uninit(&write_queue);
[232]363        ksyslog_work_register(ksyslog_flush_interval);
364}
365
366static int
367ksyslog_rcv(struct sock *sk, struct sk_buff *skb)
368{
369        int err;
370        struct iphdr *iph;
371        struct udphdr *udph;
372        struct ksyslog_entry *entry;
373
[250]374        if (unlikely(skb_linearize(skb))) {
375                ksyslog_stats_add_drop(&ksyslog_queue, skb->len);
376                goto out;
377        }
[232]378
379        iph = ip_hdr(skb);
380        udph = udp_hdr(skb);
381
[250]382        if (unlikely(!skb_pull(skb, sizeof(*udph)))) {
383                ksyslog_stats_add_drop(&ksyslog_queue, skb->len);
384                goto out;
385        }
[232]386
387        entry = ksyslog_entry_create(skb, iph, udph);
[250]388        if (unlikely(IS_ERR(entry))) {
389                if (PTR_ERR(entry) == -EINVAL) {
390                        ksyslog_stats_add_discard(&ksyslog_queue, skb->len);
391                        goto out;
392                }
[232]393
[250]394                ksyslog_stats_add_drop(&ksyslog_queue, skb->len);
395                goto out;
396        }
397
[242]398        spin_lock_bh(&ksyslog_queue.lock);
[232]399        err = ksyslog_entry_add(&ksyslog_queue, entry);
[242]400        spin_unlock_bh(&ksyslog_queue.lock);
[232]401
[241]402        if (unlikely(err)) {
[250]403                ksyslog_stats_add_drop(&ksyslog_queue, entry->length);
[241]404                ksyslog_drop_warning(entry);
[232]405                ksyslog_entry_free(&entry->rcu);
[250]406                goto out;
[241]407        }
[232]408
409out:
410        consume_skb(skb);
411        return 0;
412}
413
414#ifdef CONFIG_PROC_FS
415static void *
[240]416ksyslog_rculist_seq_start(struct seq_file *seq, loff_t *pos)
[232]417{
418        struct list_head *lh, *head = seq->private;
419        loff_t ppos = *pos;
420
421        rcu_read_lock();
422
423        __list_for_each_rcu(lh, head)
424                if (ppos-- == 0)
425                        return lh;
426
427        return NULL;
428}
429
430static void *
[240]431ksyslog_rculist_seq_next(struct seq_file *seq, void *v, loff_t *pos)
[232]432{
433        struct list_head *lh = rcu_dereference(((struct list_head *)v)->next);
434        ++(*pos);
435        return lh == seq->private ? NULL : lh;
436}
437
438static void
[240]439ksyslog_rculist_seq_stop(struct seq_file *seq, void *v)
[232]440{
441        rcu_read_unlock();
442}
443
444static int
445ksyslog_queue_seq_show(struct seq_file *seq, void *v)
446{
447        const struct ksyslog_entry *entry = list_entry_rcu(v, struct ksyslog_entry, list);
448
[233]449        seq_printf(seq, "%llu %s.%s %u.%u.%u.%u %.*s\n",
[232]450                   timeval_to_ns(&entry->tv) / 1000 / 1000 / 1000,
[233]451                   ksyslog_facility_str(entry->facility),
452                   ksyslog_severity_str(entry->severity),
[232]453                   entry->saddr.addr8[0], entry->saddr.addr8[1],
454                   entry->saddr.addr8[2], entry->saddr.addr8[3],
455                   (int)entry->length, entry->data);
456
457        return 0;
458}
459
460static struct seq_operations ksyslog_queue_seq_ops = {
[240]461        .start = ksyslog_rculist_seq_start,
462        .next  = ksyslog_rculist_seq_next,
463        .stop  = ksyslog_rculist_seq_stop,
[232]464        .show  = ksyslog_queue_seq_show,
465};
466
467static int
468ksyslog_queue_seq_open(struct inode *inode, struct file *file)
469{
470        int err = seq_open(file, &ksyslog_queue_seq_ops);
471
472        if (!err)
[246]473                ((struct seq_file *)file->private_data)->private = PDE_DATA(inode);
[232]474
475        return err;
476}
477
478static struct file_operations ksyslog_queue_fops = {
479        .owner   = THIS_MODULE,
480        .open    = ksyslog_queue_seq_open,
481        .read    = seq_read,
482        .llseek  = seq_lseek,
483        .release = seq_release,
484};
485
486static int
[250]487ksyslog_size_seq_show(struct seq_file *seq, void *v)
[240]488{
[250]489        seq_printf(seq, "%lu\n", atomic64_read(&ksyslog_queue.size));
[240]490        return 0;
491}
492
493static int
[250]494ksyslog_size_seq_open(struct inode *inode, struct file *file)
[240]495{
[250]496        return single_open(file, ksyslog_size_seq_show, PDE_DATA(inode));
[240]497}
498
[241]499static int
[250]500ksyslog_stats_seq_show(struct seq_file *seq, void *v)
[241]501{
[250]502        int i;
503        struct ksyslog_stats stats;
[241]504
[250]505        memset(&stats, 0, sizeof(stats));
[241]506
[250]507        for_each_possible_cpu(i) {
508                const struct ksyslog_stats *percpu_stats;
509                struct ksyslog_stats local_stats;
510                unsigned int start;
511
512                percpu_stats = per_cpu_ptr(ksyslog_queue.stats, i);
513
514                do {
515                        start = u64_stats_fetch_begin_bh(&percpu_stats->sync);
516                        local_stats = *percpu_stats;
517                } while (u64_stats_fetch_retry_bh(&percpu_stats->sync, start));
518
519                stats.write_bytes += local_stats.write_bytes;
520                stats.write_packets += local_stats.write_packets;
521                stats.drop_bytes += local_stats.drop_bytes;
522                stats.drop_packets += local_stats.drop_packets;
523                stats.discard_bytes += local_stats.discard_bytes;
524                stats.discard_packets += local_stats.discard_packets;
525        }
526
527        seq_puts(seq,   "{\n");
528        seq_puts(seq,   \"write\": {\n");
529        seq_printf(seq, "    \"bytes\":   \"%llu\",\n", stats.write_bytes);
530        seq_printf(seq, "    \"packets\": \"%llu\"\n", stats.write_packets);
531        seq_puts(seq,   "  },\n");
532        seq_puts(seq,   \"drop\": {\n");
533        seq_printf(seq, "    \"bytes\":   \"%llu\",\n", stats.drop_bytes);
534        seq_printf(seq, "    \"packets\": \"%llu\"\n", stats.drop_packets);
535        seq_puts(seq,   "  },\n");
536        seq_puts(seq,   \"discard\": {\n");
537        seq_printf(seq, "    \"bytes\":   \"%llu\",\n", stats.discard_bytes);
538        seq_printf(seq, "    \"packets\": \"%llu\"\n", stats.discard_packets);
539        seq_puts(seq,   "  }\n");
540        seq_puts(seq,   "}\n");
541
[241]542        return 0;
543}
544
545static int
[250]546ksyslog_stats_seq_open(struct inode *inode, struct file *file)
[241]547{
[250]548        return single_open(file, ksyslog_stats_seq_show, PDE_DATA(inode));
[241]549}
550
[250]551static struct file_operations ksyslog_size_fops = {
[240]552        .owner   = THIS_MODULE,
[250]553        .open    = ksyslog_size_seq_open,
[240]554        .read    = seq_read,
555        .llseek  = seq_lseek,
556        .release = single_release,
557};
558
[250]559static struct file_operations ksyslog_stats_fops = {
[241]560        .owner   = THIS_MODULE,
[250]561        .open    = ksyslog_stats_seq_open,
[241]562        .read    = seq_read,
563        .llseek  = seq_lseek,
564        .release = single_release,
565};
566
567static void
568ksyslog_proc_destroy(void)
569{
570        if (ksyslog_proc_queue)
[246]571                remove_proc_entry("queue", ksyslog_procdir);
[241]572        ksyslog_proc_queue = NULL;
573
[250]574        if (ksyslog_proc_size)
575                remove_proc_entry("size", ksyslog_procdir);
576        ksyslog_proc_size = NULL;
[241]577
[250]578        if (ksyslog_proc_stats)
579                remove_proc_entry("stats", ksyslog_procdir);
580        ksyslog_proc_stats = NULL;
[241]581
582        if (ksyslog_procdir)
[246]583                remove_proc_entry("ksyslog", NULL);
[241]584        ksyslog_procdir = NULL;
585}
586
[240]587static int
[232]588ksyslog_proc_init(void)
589{
590        ksyslog_procdir = proc_mkdir("ksyslog", NULL);
591        if (ksyslog_procdir == NULL) {
[250]592                pr_err("ksyslog: proc_mkdir failed\n");
[241]593                goto err;
[232]594        }
595
[239]596        ksyslog_proc_queue = proc_create_data("queue", S_IRUGO, ksyslog_procdir,
597                                              &ksyslog_queue_fops, &ksyslog_queue.head);
[232]598        if (ksyslog_proc_queue == NULL) {
[250]599                pr_err("ksyslog: proc_create(queue) failed\n");
[241]600                goto err;
[232]601        }
602
[250]603        ksyslog_proc_size = proc_create("size", S_IRUGO, ksyslog_procdir,
604                                        &ksyslog_size_fops);
605        if (ksyslog_proc_size == NULL) {
606                pr_err("ksyslog: proc_create(size) failed\n");
[241]607                goto err;
[240]608        }
609
[250]610        ksyslog_proc_stats = proc_create("stats", S_IRUGO, ksyslog_procdir,
611                                         &ksyslog_stats_fops);
612        if (ksyslog_proc_stats == NULL) {
613                pr_err("ksyslog: proc_create(stats) failed\n");
[241]614                goto err;
615        }
[232]616
[241]617        return 0;
[232]618
[241]619err:
620        ksyslog_proc_destroy();
621        return -ENOMEM;
[232]622}
623#endif
624
625static void
626ksyslog_finish(void)
627{
628        if (ksyslog_rcv_sk)
629                sock_release(ksyslog_rcv_sk);
630        ksyslog_rcv_sk = NULL;
631
632        if (ksyslog_wq) {
633                ksyslog_work_unregister();
634                destroy_workqueue(ksyslog_wq);
635        }
636        ksyslog_wq = NULL;
637
638#ifdef CONFIG_PROC_FS
639        ksyslog_proc_destroy();
640#endif
641
642        ksyslog_entry_destroy(&ksyslog_queue);
[237]643        rcu_barrier();
[250]644
645        ksyslog_queue_uninit(&ksyslog_queue);
[232]646}
647
648static int __init
649ksyslog_init(void)
650{
651        int err;
652        struct sockaddr_in sin;
653
[250]654        err = ksyslog_queue_init(&ksyslog_queue);
655        if (err)
656                goto err;
[232]657
658#ifdef CONFIG_PROC_FS
659        err = ksyslog_proc_init();
660        if (err)
661                goto err;
662#endif
663
664        ksyslog_wq = create_singlethread_workqueue("ksyslog");
665        if (ksyslog_wq == NULL) {
[250]666                pr_err("ksyslog: create_workqueue failed\n");
[232]667                err = -ENOMEM;
668                goto err;
669        }
670
671        INIT_DELAYED_WORK(&ksyslog_work, ksyslog_work_handler);
672
673        err = sock_create(AF_INET, SOCK_DGRAM, 0, &ksyslog_rcv_sk);
674        if (err) {
[250]675                pr_err("ksyslog: sock_create failed\n");
[232]676                goto err;
677        }
678
679        sin.sin_family = AF_INET;
680        sin.sin_addr.s_addr = in_aton(ksyslog_host);
681        sin.sin_port = htons(ksyslog_port);
682
683        err = kernel_bind(ksyslog_rcv_sk, (struct sockaddr *)&sin,
684                          sizeof(struct sockaddr_in));
685        if (err) {
[250]686                pr_err("ksyslog: kernel_bind failed\n");
[232]687                goto err;
688        }
689
[247]690        ksyslog_work_register(ksyslog_flush_interval);
691
[232]692        udp_sk(ksyslog_rcv_sk->sk)->encap_type = UDP_ENCAP_KSYSLOG;
693        udp_sk(ksyslog_rcv_sk->sk)->encap_rcv = ksyslog_rcv;
[247]694        udp_encap_enable();
[232]695
696        return 0;
697
698err:
699        ksyslog_finish();
700        return err;
701}
702
703static void __exit
704ksyslog_exit(void)
705{
706        ksyslog_finish();
707}
708
709module_init(ksyslog_init);
710module_exit(ksyslog_exit);
711
712MODULE_AUTHOR("Atzm WATANABE");
713MODULE_DESCRIPTION("In-kernel syslog receiver");
714MODULE_LICENSE("GPL");
Note: See TracBrowser for help on using the repository browser.