1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (C) 2010-2017 B.A.T.M.A.N. contributors: 3 * 4 * Marek Lindner 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of version 2 of the GNU General Public 8 * License as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, but 11 * WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 #include "log.h" 20 #include "main.h" 21 22 #include <linux/compiler.h> 23 #include <linux/debugfs.h> 24 #include <linux/errno.h> 25 #include <linux/export.h> 26 #include <linux/fcntl.h> 27 #include <linux/fs.h> 28 #include <linux/gfp.h> 29 #include <linux/jiffies.h> 30 #include <linux/kernel.h> 31 #include <linux/module.h> 32 #include <linux/poll.h> 33 #include <linux/sched.h> /* for linux/wait.h */ 34 #include <linux/slab.h> 35 #include <linux/spinlock.h> 36 #include <linux/stddef.h> 37 #include <linux/types.h> 38 #include <linux/uaccess.h> 39 #include <linux/wait.h> 40 #include <stdarg.h> 41 42 #define BATADV_LOG_BUFF_MASK (batadv_log_buff_len - 1) 43 44 static const int batadv_log_buff_len = BATADV_LOG_BUF_LEN; 45 46 static char *batadv_log_char_addr(struct batadv_priv_debug_log *debug_log, 47 size_t idx) 48 { 49 return &debug_log->log_buff[idx & BATADV_LOG_BUFF_MASK]; 50 } 51 52 static void batadv_emit_log_char(struct batadv_priv_debug_log *debug_log, 53 char c) 54 { 55 char *char_addr; 56 57 char_addr = batadv_log_char_addr(debug_log, debug_log->log_end); 58 *char_addr = c; 59 debug_log->log_end++; 60 61 if (debug_log->log_end - debug_log->log_start > batadv_log_buff_len) 62 debug_log->log_start = debug_log->log_end - batadv_log_buff_len; 63 } 64 65 __printf(2, 3) 66 static int batadv_fdebug_log(struct batadv_priv_debug_log *debug_log, 67 const char *fmt, ...) 68 { 69 va_list args; 70 static char debug_log_buf[256]; 71 char *p; 72 73 if (!debug_log) 74 return 0; 75 76 spin_lock_bh(&debug_log->lock); 77 va_start(args, fmt); 78 vscnprintf(debug_log_buf, sizeof(debug_log_buf), fmt, args); 79 va_end(args); 80 81 for (p = debug_log_buf; *p != 0; p++) 82 batadv_emit_log_char(debug_log, *p); 83 84 spin_unlock_bh(&debug_log->lock); 85 86 wake_up(&debug_log->queue_wait); 87 88 return 0; 89 } 90 91 /** 92 * batadv_debug_log() - Add debug log entry 93 * @bat_priv: the bat priv with all the soft interface information 94 * @fmt: format string 95 * 96 * Return: 0 on success or negative error number in case of failure 97 */ 98 int batadv_debug_log(struct batadv_priv *bat_priv, const char *fmt, ...) 99 { 100 va_list args; 101 char tmp_log_buf[256]; 102 103 va_start(args, fmt); 104 vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args); 105 batadv_fdebug_log(bat_priv->debug_log, "[%10u] %s", 106 jiffies_to_msecs(jiffies), tmp_log_buf); 107 va_end(args); 108 109 return 0; 110 } 111 112 static int batadv_log_open(struct inode *inode, struct file *file) 113 { 114 if (!try_module_get(THIS_MODULE)) 115 return -EBUSY; 116 117 nonseekable_open(inode, file); 118 file->private_data = inode->i_private; 119 return 0; 120 } 121 122 static int batadv_log_release(struct inode *inode, struct file *file) 123 { 124 module_put(THIS_MODULE); 125 return 0; 126 } 127 128 static bool batadv_log_empty(struct batadv_priv_debug_log *debug_log) 129 { 130 return !(debug_log->log_start - debug_log->log_end); 131 } 132 133 static ssize_t batadv_log_read(struct file *file, char __user *buf, 134 size_t count, loff_t *ppos) 135 { 136 struct batadv_priv *bat_priv = file->private_data; 137 struct batadv_priv_debug_log *debug_log = bat_priv->debug_log; 138 int error, i = 0; 139 char *char_addr; 140 char c; 141 142 if ((file->f_flags & O_NONBLOCK) && batadv_log_empty(debug_log)) 143 return -EAGAIN; 144 145 if (!buf) 146 return -EINVAL; 147 148 if (count == 0) 149 return 0; 150 151 if (!access_ok(VERIFY_WRITE, buf, count)) 152 return -EFAULT; 153 154 error = wait_event_interruptible(debug_log->queue_wait, 155 (!batadv_log_empty(debug_log))); 156 157 if (error) 158 return error; 159 160 spin_lock_bh(&debug_log->lock); 161 162 while ((!error) && (i < count) && 163 (debug_log->log_start != debug_log->log_end)) { 164 char_addr = batadv_log_char_addr(debug_log, 165 debug_log->log_start); 166 c = *char_addr; 167 168 debug_log->log_start++; 169 170 spin_unlock_bh(&debug_log->lock); 171 172 error = __put_user(c, buf); 173 174 spin_lock_bh(&debug_log->lock); 175 176 buf++; 177 i++; 178 } 179 180 spin_unlock_bh(&debug_log->lock); 181 182 if (!error) 183 return i; 184 185 return error; 186 } 187 188 static __poll_t batadv_log_poll(struct file *file, poll_table *wait) 189 { 190 struct batadv_priv *bat_priv = file->private_data; 191 struct batadv_priv_debug_log *debug_log = bat_priv->debug_log; 192 193 poll_wait(file, &debug_log->queue_wait, wait); 194 195 if (!batadv_log_empty(debug_log)) 196 return EPOLLIN | EPOLLRDNORM; 197 198 return 0; 199 } 200 201 static const struct file_operations batadv_log_fops = { 202 .open = batadv_log_open, 203 .release = batadv_log_release, 204 .read = batadv_log_read, 205 .poll = batadv_log_poll, 206 .llseek = no_llseek, 207 }; 208 209 /** 210 * batadv_debug_log_setup() - Initialize debug log 211 * @bat_priv: the bat priv with all the soft interface information 212 * 213 * Return: 0 on success or negative error number in case of failure 214 */ 215 int batadv_debug_log_setup(struct batadv_priv *bat_priv) 216 { 217 struct dentry *d; 218 219 if (!bat_priv->debug_dir) 220 goto err; 221 222 bat_priv->debug_log = kzalloc(sizeof(*bat_priv->debug_log), GFP_ATOMIC); 223 if (!bat_priv->debug_log) 224 goto err; 225 226 spin_lock_init(&bat_priv->debug_log->lock); 227 init_waitqueue_head(&bat_priv->debug_log->queue_wait); 228 229 d = debugfs_create_file("log", 0400, bat_priv->debug_dir, bat_priv, 230 &batadv_log_fops); 231 if (!d) 232 goto err; 233 234 return 0; 235 236 err: 237 return -ENOMEM; 238 } 239 240 /** 241 * batadv_debug_log_cleanup() - Destroy debug log 242 * @bat_priv: the bat priv with all the soft interface information 243 */ 244 void batadv_debug_log_cleanup(struct batadv_priv *bat_priv) 245 { 246 kfree(bat_priv->debug_log); 247 bat_priv->debug_log = NULL; 248 } 249