printk: convert byte-buffer to variable-length record buffer
[pandora-kernel.git] / drivers / char / mem.c
index d6e9d08..cf56614 100644 (file)
@@ -810,33 +810,54 @@ static const struct file_operations oldmem_fops = {
 static ssize_t kmsg_writev(struct kiocb *iocb, const struct iovec *iv,
                           unsigned long count, loff_t pos)
 {
-       char *line, *p;
+       char *buf, *line;
        int i;
-       ssize_t ret = -EFAULT;
+       int level = default_message_loglevel;
+       int facility = 1;       /* LOG_USER */
        size_t len = iov_length(iv, count);
+       ssize_t ret = len;
 
-       line = kmalloc(len + 1, GFP_KERNEL);
-       if (line == NULL)
+       if (len > 1024)
+               return -EINVAL;
+       buf = kmalloc(len+1, GFP_KERNEL);
+       if (buf == NULL)
                return -ENOMEM;
 
-       /*
-        * copy all vectors into a single string, to ensure we do
-        * not interleave our log line with other printk calls
-        */
-       p = line;
+       line = buf;
        for (i = 0; i < count; i++) {
-               if (copy_from_user(p, iv[i].iov_base, iv[i].iov_len))
+               if (copy_from_user(line, iv[i].iov_base, iv[i].iov_len))
                        goto out;
-               p += iv[i].iov_len;
+               line += iv[i].iov_len;
+       }
+
+       /*
+        * Extract and skip the syslog prefix <[0-9]*>. Coming from userspace
+        * the decimal value represents 32bit, the lower 3 bit are the log
+        * level, the rest are the log facility.
+        *
+        * If no prefix or no userspace facility is specified, we
+        * enforce LOG_USER, to be able to reliably distinguish
+        * kernel-generated messages from userspace-injected ones.
+        */
+       line = buf;
+       if (line[0] == '<') {
+               char *endp = NULL;
+
+               i = simple_strtoul(line+1, &endp, 10);
+               if (endp && endp[0] == '>') {
+                       level = i & 7;
+                       if (i >> 3)
+                               facility = i >> 3;
+                       endp++;
+                       len -= endp - line;
+                       line = endp;
+               }
        }
-       p[0] = '\0';
+       line[len] = '\0';
 
-       ret = printk("%s", line);
-       /* printk can add a prefix */
-       if (ret > len)
-               ret = len;
+       printk_emit(facility, level, NULL, 0, "%s", line);
 out:
-       kfree(line);
+       kfree(buf);
        return ret;
 }