Russ Allbery: Review: Star Healer
| Series: | Sector General #6 |
| Publisher: | Orb |
| Copyright: | 1984 |
| Printing: | 2002 |
| ISBN: | 0-312-87770-6 |
| Format: | Trade paperback |
| Pages: | 206 |
| Series: | Sector General #6 |
| Publisher: | Orb |
| Copyright: | 1984 |
| Printing: | 2002 |
| ISBN: | 0-312-87770-6 |
| Format: | Trade paperback |
| Pages: | 206 |
| Series: | Species Imperative #2 |
| Publisher: | DAW |
| Copyright: | 2005 |
| ISBN: | 0-7564-0260-3 |
| Format: | Hardcover |
| Pages: | 453 |
$ curl https://ci.debian.net/data/packages/unstable/amd64/d/debci/latest.json
"run_id": "20170528_173652",
"package": "debci",
"version": "1.5.1",
"date": "2017-05-28 17:43:05",
"status": "pass",
"blame": [],
"previous_status": "pass",
"duration_seconds": "373",
"duration_human": "0h 6m 13s",
"message": "Tests passed, but at least one test skipped",
"last_pass_version": "1.5.1",
"last_pass_date": "2017-05-28 17:43:05"
Now, nothing in life is without compromises. One big disadvantage of the way
debci stored its data is that there were a lot of files, which ends up using
a large number of inodes in the filesystem. The current Debian CI master has
more than 10 million inodes in its filesystem, and almost all of them were
being used. This is clearly unsustainable.
You will notice that I said stored, because as of version 1.6, debci now
implements a data retention policy: log files and test artifacts will now only
be kept for a configurable amount of days (default: 180).
So there you have it: effective immediately, Debian CI will not provide logs
and test artifacts older than 180 days.
If you are reporting bugs based on logs from Debian CI, please don t hotlink
the log files. Instead, make sure you download the logs in question and attach
them to the bug report, because in 6 months they will be gone.
For quite some I'm happy user of Turris Omnia router. The router has quite good hardware, so I've decided to try if I can run Bitcoin node on that and ElectrumX server.
To make the things easier to manage, I've decided to use LXC and run all these in separate container. First of all you need LXC on the router. This is the default setup, but in case you've removed it, you can add it back in the Updater settings.
Now we will create Debian container. There is basic information on using in Turris Documentation on how to create the container, in latter documentation I assume it is called debian.
It's also good idea to enable LXC autostart, to do so add your container to cat /etc/config/lxc-auto on :
config container
option name debian
# Send SIGRTMIN+3 to shutdown systemd (37 on Turris Omnia)
lxc.haltsignal = SIGRTMIN+3
$ lxc-attach --name debian
$ sed -i s/jessie/stretch/ /etc/apt/sources.list
$ apt update
$ apt full-upgrade
$ adduser bitcoin
$ su - bitcoin
$ bitcoind -daemon
$ bitcoin-cli getinfo
"version": 140000,
"protocolversion": 70015,
"walletversion": 130000,
"balance": 0.00000000,
"blocks": 301242,
"timeoffset": -1,
"connections": 8,
"proxy": "",
"difficulty": 8853416309.1278,
"testnet": false,
"keypoololdest": 1490267950,
"keypoolsize": 100,
"paytxfee": 0.00000000,
"relayfee": 0.00001000,
"errors": ""
.bitcoin/bitcoin.conf, I've ended up with following settings:
par=1
dbcache=150
maxmempool=150
/etc/systemd/system/bitcoind.service):
[Unit]
Description=Bitcoind
After=network.target
[Service]
ExecStart=/opt/bitcoin/bin/bitcoind
User=bitcoin
TimeoutStopSec=30min
Restart=on-failure
RestartSec=30
[Install]
WantedBy=multi-user.target
systemctl enable bitcoind.service
I travelled (for three days only!) to Argentina, to be a part of the Open Source Symposium 2017, a co-located event of the International Conference on Software Engineering.
| Attachment | Size |
|---|---|
| oss2017_cover.png | 84.47 KB |
In this blog post, I ve described what started as simple migration of WordPress blog to AWS, ended up as automation project consisting of publishing multiple Ansible roles deploying and running multiple Docker images.
If you re not interested in reading about my entire journey, cognition gains and how this process came to be, please skim down to Birth of: containerized-wordpress-project (TL;DR) section.
Migrating WordPress blog to AWS (EC2, Lightsail?)
Since I ve been sold on Amazon s AWS idea of cloud computing services for couple of years now. I ve wanted, and been trying to migrate this (WordPress) blog to AWS, but somehow it never worked out.
Moving it to EC2 instance, with its own ELB volumes, AMI, EIP, Security Group it just seemed as an overkill.
When AWS Lightsail was first released, it seemed that was an answer to all my problems.
But it wasn t, disregarding its bit restrictive/dumbed down versions of original features. Living in Amsterdam, my main problem with it was that it was only available in a single US region.
Regardless, I thought it had everything I needed for WordPress site, and as a new service, it had great potential.
Its regional limitations were also good in a sense that they made me realize one important thing. And that s once I migrate my blog to AWS, I want to be able to seamlessly move/migrate it across different EC2 s and different regions once they were available.
If done properly, it meant I could even have it moved across different clouds (I m talking to you Google Cloud).
P.S: AWS Lightsail is now available in couple of different regions across Europe. Rollout which was almost smoothless.
Fundamental problem of every migration is migrationBirth of: containerized-wordpress-project (TL;DR)
After a lot of work, end result is project which allows you to automagically deploy & run containerized WordPress instance which consists of 3 separate containers running:
Once run, containerized-wordpress playbook will guide you through interactive setup of all 3 containers, after which it will run all Ansible roles created for this project. End result is that host you have never even SSH-ed to will be fully configured and running containerized WordPress instace out of box.
Most importantly, this whole process will be completed in <= 5 minutes and doesn t require any Docker or Ansible knowledge!
containerized-wordpress demo
Console output of running containerized-wordpress Ansible Playbook:
Accessing WordPress instance created from containerized-wordpress Ansible Playbook:
Did I end up migrating to AWS in the end?
You bet. Thanks to efforts made in containerized-wordpress-project, I m happy to report my whole WordPress migration to AWS was completed in matter of minutes and that this blog is now running on Docker and on AWS!
I hope this same project will help you take a leap in your migration.
Happy hacking!
I now have an XMPP setup which has all the features of the recent fancy chat systems, and on top of that it runs, client and server, on Free Software, which can be audited, it is federated and I can self-host my own server in my own VPS if I want to, with packages supported in Debian.
prosodyctl adduser alice@example.orgc2s_require_encryption = true
s2s_secure_auth = trues2s_insecure_domains = "gmail.com" VirtualHost "chat.example.org"
enabled = true
ssl =
key = "/etc/ssl/private/example.org-key.pem";
certificate = "/etc/ssl/public/example.org.pem";
Component "conference.chat.example.org" "muc"
restrict_room_creation = "local"Component "upload.chat.example.org" "http_upload""something";
We re coming closer to the Debian/stretch stable release and similar to what we had with #newinwheezy and #newinjessie it s time for #newinstretch!
Hideki Yamane already started the game by blogging about GitHub s Icon font, fonts-octicons and Arturo Borrero Gonzalez wrote a nice article about nftables in Debian/stretch.
One package that isn t new but its tools are used by many of us is util-linux, providing many essential system utilities. We have util-linux v2.25.2 in Debian/jessie and in Debian/stretch there will be util-linux >=v2.29.2. There are many new options available and we also have a few new tools available.
Tools that have been taken over from other packages
root@ff2713f55b36:/# lsipc RESOURCE DESCRIPTION LIMIT USED USE% MSGMNI Number of message queues 32000 0 0.00% MSGMAX Max size of message (bytes) 8192 - - MSGMNB Default max size of queue (bytes) 16384 - - SHMMNI Shared memory segments 4096 0 0.00% SHMALL Shared memory pages 18446744073692774399 0 0.00% SHMMAX Max size of shared memory segment (bytes) 18446744073692774399 - - SHMMIN Min size of shared memory segment (bytes) 1 - - SEMMNI Number of semaphore identifiers 32000 0 0.00% SEMMNS Total number of semaphores 1024000000 0 0.00% SEMMSL Max semaphores per semaphore set. 32000 - - SEMOPM Max number of operations per semop(2) 500 - - SEMVMX Semaphore max value 32767 - -
root@ff2713f55b36:/# lslogins
UID USER PROC PWD-LOCK PWD-DENY LAST-LOGIN GECOS
0 root 2 0 1 root
1 daemon 0 0 1 daemon
2 bin 0 0 1 bin
3 sys 0 0 1 sys
4 sync 0 0 1 sync
5 games 0 0 1 games
6 man 0 0 1 man
7 lp 0 0 1 lp
8 mail 0 0 1 mail
9 news 0 0 1 news
10 uucp 0 0 1 uucp
13 proxy 0 0 1 proxy
33 www-data 0 0 1 www-data
34 backup 0 0 1 backup
38 list 0 0 1 Mailing List Manager
39 irc 0 0 1 ircd
41 gnats 0 0 1 Gnats Bug-Reporting System (admin)
100 _apt 0 0 1
65534 nobody 0 0 1 nobody
root@ff2713f55b36:/# lsns
NS TYPE NPROCS PID USER COMMAND
4026531835 cgroup 2 1 root bash
4026531837 user 2 1 root bash
4026532473 mnt 2 1 root bash
4026532474 uts 2 1 root bash
4026532475 ipc 2 1 root bash
4026532476 pid 2 1 root bash
4026532478 net 2 1 root bash
--reload reload prompts on running agetty instancesblkdiscard (discard the content of sectors on a device):
-p, --step <num> size of the discard iterations within the offset -z, --zeroout zero-fill rather than discardchrt (show or change the real-time scheduling attributes of a process):
-d, --deadline set policy to SCHED_DEADLINE -T, --sched-runtime <ns> runtime parameter for DEADLINE -P, --sched-period <ns> period parameter for DEADLINE -D, --sched-deadline <ns> deadline parameter for DEADLINEfdformat (do a low-level formatting of a floppy disk):
-f, --from <N> start at the track N (default 0) -t, --to <N> stop at the track N -r, --repair <N> try to repair tracks failed during the verification (max N retries)fdisk (display or manipulate a disk partition table):
-B, --protect-boot don't erase bootbits when creating a new label
-o, --output <list> output columns
--bytes print SIZE in bytes rather than in human readable format
-w, --wipe <mode> wipe signatures (auto, always or never)
-W, --wipe-partitions <mode> wipe signatures from new partitions (auto, always or never)
New available columns (for -o):
gpt: Device Start End Sectors Size Type Type-UUID Attrs Name UUID
dos: Device Start End Sectors Cylinders Size Type Id Attrs Boot End-C/H/S Start-C/H/S
bsd: Slice Start End Sectors Cylinders Size Type Bsize Cpg Fsize
sgi: Device Start End Sectors Cylinders Size Type Id Attrs
sun: Device Start End Sectors Cylinders Size Type Id Flags
findmnt (find a (mounted) filesystem):
-J, --json use JSON output format
-M, --mountpoint <dir> the mountpoint directory
-x, --verify verify mount table content (default is fstab)
--verbose print more details
flock (manage file locks from shell scripts):
-F, --no-fork execute command without forking
--verbose increase verbosity
getty (open a terminal and set its mode):
--reload reload prompts on running agetty instanceshwclock (query or set the hardware clock):
--get read hardware clock and print drift corrected result --update-drift update drift factor in /etc/adjtime (requires --set or --systohc)ldattach (attach a line discipline to a serial line):
-c, --intro-command <string> intro sent before ldattach -p, --pause <seconds> pause between intro and ldattachlogger (enter messages into the system log):
-e, --skip-empty do not log empty lines when processing files
--no-act do everything except the write the log
--octet-count use rfc6587 octet counting
-S, --size <size> maximum size for a single message
--rfc3164 use the obsolete BSD syslog protocol
--rfc5424[=<snip>] use the syslog protocol (the default for remote);
<snip> can be notime, or notq, and/or nohost
--sd-id <id> rfc5424 structured data ID
--sd-param <data> rfc5424 structured data name=value
--msgid <msgid> set rfc5424 message id field
--socket-errors[=<on off auto>] print connection errors when using Unix sockets
losetup (set up and control loop devices):
-L, --nooverlap avoid possible conflict between devices
--direct-io[=<on off>] open backing file with O_DIRECT
-J, --json use JSON --list output format
New available --list column:
DIO access backing file with direct-io
lsblk (list information about block devices):
-J, --json use JSON output format New available columns (for --output): HOTPLUG removable or hotplug device (usb, pcmcia, ...) SUBSYSTEMS de-duplicated chain of subsystemslscpu (display information about the CPU architecture):
-y, --physical print physical instead of logical IDs New available column: DRAWER logical drawer numberlslocks (list local system locks):
-J, --json use JSON output format -i, --noinaccessible ignore locks without read permissionsnsenter (run a program with namespaces of other processes):
-C, --cgroup[=<file>] enter cgroup namespace
--preserve-credentials do not touch uids or gids
-Z, --follow-context set SELinux context according to --target PID
rtcwake (enter a system sleep state until a specified wakeup time):
--date <timestamp> date time of timestamp to wake --list-modes list available modes -r, --reorder <dev> fix partitions order (by start offset)sfdisk (display or manipulate a disk partition table):
New Commands:
-J, --json <dev> dump partition table in JSON format
-F, --list-free [<dev> ...] list unpartitioned free areas of each device
-r, --reorder <dev> fix partitions order (by start offset)
--delete <dev> [<part> ...] delete all or specified partitions
--part-label <dev> <part> [<str>] print or change partition label
--part-type <dev> <part> [<type>] print or change partition type
--part-uuid <dev> <part> [<uuid>] print or change partition uuid
--part-attrs <dev> <part> [<str>] print or change partition attributes
New Options:
-a, --append append partitions to existing partition table
-b, --backup backup partition table sectors (see -O)
--bytes print SIZE in bytes rather than in human readable format
--move-data[=<typescript>] move partition data after relocation (requires -N)
--color[=<when>] colorize output (auto, always or never)
colors are enabled by default
-N, --partno <num> specify partition number
-n, --no-act do everything except write to device
--no-tell-kernel do not tell kernel about changes
-O, --backup-file <path> override default backup file name
-o, --output <list> output columns
-w, --wipe <mode> wipe signatures (auto, always or never)
-W, --wipe-partitions <mode> wipe signatures from new partitions (auto, always or never)
-X, --label <name> specify label type (dos, gpt, ...)
-Y, --label-nested <name> specify nested label type (dos, bsd)
Available columns (for -o):
gpt: Device Start End Sectors Size Type Type-UUID Attrs Name UUID
dos: Device Start End Sectors Cylinders Size Type Id Attrs Boot End-C/H/S Start-C/H/S
bsd: Slice Start End Sectors Cylinders Size Type Bsize Cpg Fsize
sgi: Device Start End Sectors Cylinders Size Type Id Attrs
sun: Device Start End Sectors Cylinders Size Type Id Flags
swapon (enable devices and files for paging and swapping):
-o, --options <list> comma-separated list of swap options New available columns (for --show): UUID swap uuid LABEL swap labelunshare (run a program with some namespaces unshared from the parent):
-C, --cgroup[=<file>] unshare cgroup namespace
--propagation slave shared private unchanged modify mount propagation in mount namespace
-s, --setgroups allow deny control the setgroups syscall in user namespaces
Deprecated / removed options
sfdisk (display or manipulate a disk partition table):
-c, --id change or print partition Id
--change-id change Id
--print-id print Id
-C, --cylinders <number> set the number of cylinders to use
-H, --heads <number> set the number of heads to use
-S, --sectors <number> set the number of sectors to use
-G, --show-pt-geometry deprecated, alias to --show-geometry
-L, --Linux deprecated, only for backward compatibility
-u, --unit S deprecated, only sector unit is supported
Last week, we presented a new paper that describes how children are thinking through some of the implications of new forms of data collection and analysis. The presentation was given at the ACM CHI conference in Denver last week and the paper is open access and online.
Over the last couple years, we ve worked on a large project to support children in doing and not just learning about data science. We built a system, Scratch Community Blocks, that allows the 18 million users of the Scratch online community to write their own computer programs in Scratch of course to analyze data about their own learning and social interactions. An example of one of those programs to find how many of one s follower in Scratch are not from the United States is shown below.
Last year, we deployed Scratch Community Blocks to 2,500 active Scratch users who, over a period of several months, used the system to create more than 1,600 projects.
As children used the system, Samantha Hautea, a student in UW s Communication Leadership program, led a group of us in an online ethnography. We visited the projects children were creating and sharing. We followed the forums where users discussed the blocks. We read comment threads left on projects. We combined Samantha s detailed field notes with the text of comments and forum posts, with ethnographic interviews of several users, and with notes from two in-person workshops. We used a technique called grounded theory to analyze these data.
What we found surprised us. We expected children to reflect on being challenged by and hopefully overcoming the technical parts of doing data science. Although we certainly saw this happen, what emerged much more strongly from our analysis was detailed discussion among children about the social implications of data collection and analysis.
In our analysis, we grouped children s comments into five major themes that represented what we called critical data literacies. These literacies reflect things that children felt were important implications of social media data collection and analysis.
First, children reflected on the way that programmatic access to data even data that was technically public introduced privacy concerns. One user described the ability to analyze data as, creepy , but at the same time, very cool. Children expressed concern that programmatic access to data could lead to stalking and suggested that the system should ask for permission.
Second, children recognized that data analysis requires skepticism and interpretation. For example, Scratch Community Blocks introduced a bug where the block that returned data about followers included users with disabled accounts. One user, in an interview described to us how he managed to figure out the inconsistency:
At one point the follower blocks, it said I have slightly more followers than I do. And, that was kind of confusing when I was trying to make the project. [ ] I pulled up a second [browser] tab and compared the [data from Scratch Community Blocks and the data in my profile]. Third, children discussed the hidden assumptions and decisions that drive the construction of metrics. For example, the number of views received for each project in Scratch is counted using an algorithm that tries to minimize the impact of gaming the system (similar to, for example, Youtube). As children started to build programs with data, they started to uncover and speculate about the decisions behind metrics. For example, they guessed that the view count might only include unique views and that view counts may include users who do not have accounts on the website. Fourth, children building projects with Scratch Community Blocks realized that an algorithm driven by social data may cause certain users to be excluded. For example, a 13-year-old expressed concern that the system could be used to exclude users with few social connections saying:
I think this was a great idea! I am just a bit worried that people will make these projects and take it the wrong way, saying that followers are the most important thing in on Scratch. Kids conversations around Scratch Community Blocks are good news for educators who are starting to think about how to engage young learners in thinking critically about the implications of data. Although no kid using Scratch Community Blocks discussed each of the five literacies described above, the themes reflect starting points for educators designing ways to engage kids in thinking critically about data. Our work shows that if children are given opportunities to actively engage and build with social and behavioral data, they might not only learn how to do data analysis, but also reflect on its implications.
After the workshop on Saturday, members of the OSCAL team successfully reconstructed the SDR and antenna at the Debian info booth on Sunday and a wide range of shortwave and ham signals were detected:
Here is a close-up look at the laptop, RTL-SDR dongle (above laptop), Ham-It-Up converter (above water bottle) and MFJ-971 ATU (on right):
Buying the parts
| Component | Purpose, Notes | Price/link to source |
|---|---|---|
| RTL-SDR dongle | Converts radio signals (RF) into digital signals for reception through the USB port. It is essential to buy the dongles for SDR with TCXO, the generic RTL dongles for TV reception are not stable enough for anything other than TV. | ~ 25 |
| Enamelled copper wire, 25 meters or more | Loop antenna. Thicker wire provides better reception and is more suitable for transmitting (if you have a license) but it is heavier. The antenna I've demonstrated at recent events uses 1mm thick wire. | ~ 10 |
| 4 (or more) ceramic egg insulators | Attach the antenna to string or rope. Smaller insulators are better as they are lighter and less expensive. | ~ 10 |
| 4:1 balun | The actual ratio of the balun depends on the shape of the loop (square, rectangle or triangle) and the point where you attach the balun (middle, corner, etc). You may want to buy more than one balun, for example, a 4:1 balun and also a 1:1 balun to try alternative configurations. Make sure it is waterproof, has hooks for attaching a string or rope and an SO-239 socket. | from 20 |
| 5 meter RG-58 coaxial cable with male PL-259 plugs on both ends | If using more than 5 meters or if you want to use higher frequencies above 30MHz, use thicker, heavier and more expensive cables like RG-213. The cable must be 50 ohm. | ~ 10 |
| Antenna Tuning Unit (ATU) | I've been using the MFJ-971 for portable use and demos because of the weight. There are even lighter and cheaper alternatives if you only need to receive. | ~ 20 for receive only or second hand |
| PL-259 to SMA male pigtail, up to 50cm, RG58 | Joins the ATU to the upconverter. Cable must be RG58 or another 50 ohm cable | ~ 5 |
| Ham It Up v1.3 up-converter | Mixes the HF signal with a signal from a local oscillator to create a new signal in the spectrum covered by the RTL-SDR dongle | ~ 40 |
| SMA (male) to SMA (male) pigtail | Join the up-converter to the RTL-SDR dongle | ~ 2 |
| USB charger and USB type B cable | Used for power to the up-converter. A spare USB mobile phone charge plug may be suitable. | ~ 5 |
| String or rope | For mounting the antenna. A ligher and cheaper string is better for portable use while a stronger and weather-resistent rope is better for a fixed installation. | 5 |
Configuring gqrx for the up-converter and shortwave signals
Inspect the up-converter carefully. Look for the crystal and find the frequency written on the side of it. The frequency written on the specification sheet or web site may be wrong so looking at the crystal itself is the best way to be certain. On my Ham It Up, I found a crystal with 125.000 written on it, this is 125 MHz.
Launch gqrx, go to the File menu and select I/O devices. Change the LNB LO value to match the crystal frequency on the up-converter, with a minus sign. For my Ham It Up, I use the LNB LO value -125.000000 MHz.
Click OK to close the I/O devices window.
On the Input Controls tab, make sure Hardware AGC is enabled.
On the Receiver options tab, change the Mode value. Commercial shortwave broadcasts use AM and amateur transmission use single sideband: by convention, LSB is used for signals below 10MHz and USB is used for signals above 10MHz. To start exploring the 20 meter amateur band around 14.2 MHz, for example, use USB.
In the top of the window, enter the frequency, for example, 14.200 000 MHz.
Now choose the FFT Settings tab and adjust the Freq zoom slider. Zoom until the width of the display is about 100 kHZ, for example, from 14.15 on the left to 14.25 on the right.
Click the Play icon at the top left to start receiving. You may hear white noise. If you hear nothing, check the computer's volume controls, move the Gain slider (bottom right) to the maximum position and then lower the Squelch value on the Receiver options tab until you hear the white noise or a transmission.
Adjust the Antenna Tuner knobs
Now that gqrx is running, it is time to adjust the knobs on the antenna tuner (ATU). Reception improves dramatically when it is tuned correctly. Exact instructions depend on the type of ATU you have purchased, here I present instructions for the MFJ-971 that I have been using.
Turn the TRANSMITTER and ANTENNA knobs to the 12 o'clock position and leave them like that. Turn the INDUCTANCE knob while looking at the signals in the gqrx window. When you find the best position, the signal strength displayed on the screen will appear to increase (the animated white line should appear to move upwards and maybe some peaks will appear in the line).
When you feel you have found the best position for the INDUCTANCE knob, leave it in that position and begin turning the ANTENNA knob clockwise looking for any increase in signal strength on the chart. When you feel that is correct, begin turning the TRANSMITTER knob.
Listening to a transmission
At this point, if you are lucky, some transmissions may be visible on the gqrx screen. They will appear as darker colours in the waterfall chart. Try clicking on one of them, the vertical red line will jump to that position. For a USB transmission, try to place the vertical red line at the left hand side of the signal. Try dragging the vertical red line or changing the frequency value at the top of the screen by 100 Hz at a time until the station is tuned as well as possible.
Try and listen to the transmission and identify the station. Commercial shortwave broadcasts will usually identify themselves from time to time. Amateur transmissions will usually include a callsign spoken in the phonetic alphabet. For example, if you hear "CQ, this is Victor Kilo 3 Tango Quebec Romeo" then the station is VK3TQR. You may want to note down the callsign, time, frequency and mode in your log book. You may also find information about the callsign in a search engine.
The video demonstrates reception of a transmission from another country, can you identify the station's callsign and find his location?
If you have questions about this topic, please come and ask on the Debian Hams mailing list. The gqrx package is also available in Fedora and Ubuntu but it is known to crash on startup in Ubuntu 17.04. Users of other distributions may also want to try the Debian Ham Blend bootable ISO live image as a quick and easy way to get started.
Visiting the FSFE team in Berlin
Having recently joined the FSFE's General Assembly as the fellowship representative, I've been keen to get to know more about the organization. My visit to the FSFE office involved a wide-ranging discussion with Erik Albers about the fellowship program and FSFE in general.
Steak and SDR night
After a hard day of SIP hacking and a long afternoon at Kamailio World's open bar, a developer needs a decent meal and something previously unseen to hack on. A group of us settled at Escados, Alexanderplatz where my SDR kit emerged from my bag and other Debian users found out how easy it is to apt install the packages, attach the dongle and explore the radio spectrum.
Next stop OSCAL'17, Tirana
Having left Berlin, I'm now in Tirana, Albania where I'll give an SDR workshop and Free-RTC talk at OSCAL'17. The weather forecast is between 26 - 28 degrees celsius, the food is great and the weekend's schedule is full of interesting talks and workshops. The organizing team have already made me feel very welcome here, meeting me at the airport and leaving a very generous basket of gifts in my hotel room. OSCAL has emerged as a significant annual event in the free software world and if it's too late for you to come this year, don't miss it in 2018.
A week of typesetting, typography, bookbinding, bibliophily, not to forget long chats with good friends and loads of beer. That is BachoTeX, the best series of conferences I have ever been. This year BachoTeX was held for the 25th time, and was merged with the TUG Meeting for a firework of excellent presentations and long hours of brain storming, hacking, music making, dancing, and simply enjoying life!

(photo by Frans Goddijn)
Number of subscribers and moderators on /r/NoSleep over time.This blog post was written with Charlie Kiene. The paper and work this post describes is collaborative work with Charlie Kiene and Andr s Monroy-Hern ndez. The paper was published in the Proceedings of CHI 2016 and is released as open access so anyone can read the entire paper here. A version of this post was published on the Community Data Science Collective blog.
It's been a long time I did not write any new blog posts, and finally I got
something which is interesting enough for a new post and so here it is.
I actually wanted some bills from my ISP for some work and I could not find mail
from the ISP which had bills for some specific months in my mailbox. Problem
with my ISP is bills are accessible in their account which can be only accessed
from their own network. They do have a mobile app and that does not seem to work
especially for the billing section. I used mobile app and selected month for
which I did not have bill and clicked Send Mail button. App happily showed
message saying it sent the bill to my registered mail address but that was a
fancy lie. After trying several time I gave up and decided I will do it once I
get back home.
Fast forward few hours, I'm back home from office and then I sat in front of my
laptop and connected to ISP site, promptly downloaded the bills, then used
notmuch-emacs and fire up a mail composer, attach those HTML file (yeah they
produce bill in HTML file :-/) send it to my gmail and forget about it.
Fast forward few more days, I just remember I need those bills. I got hold of
mail I sent earlier in gmail inbox and clicked on attachment and when browser
opened the attachment I was shocked/surprised . Did you ask why?. See what I saw
when I opened attachment.
Well I was confused for moment on what happened, I tried downloading the file
and opened it an editor, and I see Chinese characters here also. After reaching
home I checked the Sent folder in my laptop where I keep copy of mails sent
using notmuch-emacs's notmuch-fcc-dirs variable. I open the file and open
the attachement and I see same character as I saw in browser!. I open the
original bills I downloaded and it looks fine. To check if I really attached the
correct files I again drafted a mail this time to my personal email and sent it.
Now I open the file from Sent folder and voila again there is different content
inside my attachment!. Same happens when I receive the mail and open the
attachment everything inside is Chinese characters!. Totally lost I finally
opened the original file using emacs, since I use spacemacs it asked me for
downloading of html layer and after which I was surprised because everything
inside the editor is in Chinese!. OK finally I've something now so I opened same
file at same time in nano from terminal and there it looks fine!. OK that is
weird again I read carefully content and saw this line in beginning of file
<?xml version="1.0" encoding="UTF-16" ?>
<html xmlns="http://www.w3.org/1999/xhtml>....
<?xml version="1.0" encoding="utf-8"?><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /><title> Something weird </title><body>blablablablablalabkabakba</body></html>
I made following observation from above experiments.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head><META http-equiv="Content-Type" content="text/html; charset=utf-8">
Content-Type: text/html; charset=utf-8
Content-Disposition: attachment;
filename=SOA-102012059675-FEBRUARY-2017.html
Content-Transfer-Encoding: base64
Content-Type: text/html
Content-Disposition: attachment;
filename=SOA-102012059675-DECEMBER-2016.html
Content-Transfer-Encoding: quoted-printable
As a workaround I am using now systemd, to disable WRITE SAME for all attached block devices in the guest. Simply run the following:WRITE SAME failed.Manually zeroing.
for i in find /sys/block/*/device/scsi_disk/*/max_write_same_blocks ; do echo w $i 0 ; done > /etc/tmpfiles.d/write_same.conf[0]: http://lists.linbit.com/pipermail/drbd-user/2017-January/022931.html Pacemaker failovers with DRBD+LVM do not work If you use a DRBD with a nested LVM, you already had to add the following lines to your /etc/lvm/lvm.conf in past Debian releases (assuming that sdb and sdc are DRBD devices):
filter = [ r /dev/sdb.* /dev/sdc.* ]Wit Debian Stretch this is not enough. Your failovers will result in a broken state on the second node, because it can not find your LVs and VGs. I found out, that killing lvmetad helps. So I also added a global_filter (it should be used for all LVM services):
write_cache_state = 0
global_filter = [ r /dev/sdb.* /dev/sdc.* ]But this also didn t helped.. My only solution was to disable lvmetad (which I am also not using at all). So adding this all in combination works now for me and failovers are as smooth as with Jessie:
filter = [ r /dev/sdb.* /dev/sdc.* ]Do not forget to update your initrd, so that the LVM configuration is updated on booting your server:
global_filter = [ r /dev/sdb.* /dev/sdc.* ]
write_cache_state = 0
use_lvmetad = 0
update-initramfs -k all -uReboot, that s it :)
VXLAN is an overlay network to encapsulate Ethernet traffic
over an existing (highly available and scalable, possibly the
Internet) IP network while accomodating a very large number of
tenants. It is defined in RFC 7348. For an uncut introduction on
its use with Linux, have a look at my VXLAN & Linux post.
203.0.113.254 configured as a loopback IP.
router bgp 65000 bgp router-id 203.0.113.254 bgp cluster-id 203.0.113.254 bgp log-neighbor-changes no bgp default ipv4-unicast neighbor fabric peer-group neighbor fabric remote-as 65000 neighbor fabric capability extended-nexthop neighbor fabric update-source 203.0.113.254 bgp listen range 203.0.113.0/24 peer-group fabric ! address-family evpn neighbor fabric activate neighbor fabric route-reflector-client exit-address-family ! exit !
fabric is defined and we leverage the dynamic neighbor
feature of Cumulus Quagga: we don t have to explicitely define each
neighbor. Any client from 203.0.113.0/24 and presenting itself as
part of AS 65000 can connect. All sent EVPN routes will be accepted
and reflected to the other clients.
You don t need to run Zebra, the route engine talking with the
kernel. Instead, start bgpd with the --no_kernel flag.
global: config: as: 65000 router-id: 203.0.113.254 local-address-list: - 203.0.113.254 neighbors: - config: neighbor-address: 203.0.113.1 peer-as: 65000 afi-safis: - config: afi-safi-name: l2vpn-evpn route-reflector: config: route-reflector-client: true route-reflector-cluster-id: 203.0.113.254
$ gobgp neighbor add 203.0.113.2 as 65000 \ > route-reflector-client 203.0.113.254 \ > --address-family evpn
interfaces lo0 unit 0 family inet address 203.0.113.254/32; protocols bgp group fabric family evpn signaling /* Do not try to install EVPN routes */ no-install; type internal; cluster 203.0.113.254; local-address 203.0.113.254; allow 203.0.113.0/24; routing-options router-id 203.0.113.254; autonomous-system 65000;
for vni in 100 200; do # Create VXLAN interface ip link add vxlan$ vni type vxlan id $ vni \ dstport 4789 \ local 203.0.113.2 \ nolearning # Create companion bridge brctl addbr br$ vni brctl addif br$ vni vxlan$ vni brctl stp br$ vni off ip link set up dev br$ vni ip link set up dev vxlan$ vni done # Attach each VM to the appropriate segment brctl addif br100 vnet10 brctl addif br100 vnet11 brctl addif br200 vnet12
advertise-all-vni directive to
publish all local VNIs.
router bgp 65000 bgp router-id 203.0.113.2 no bgp default ipv4-unicast neighbor fabric peer-group neighbor fabric remote-as 65000 neighbor fabric capability extended-nexthop neighbor fabric update-source dummy0 ! BGP sessions with route reflectors neighbor 203.0.113.253 peer-group fabric neighbor 203.0.113.254 peer-group fabric ! address-family evpn neighbor fabric activate advertise-all-vni exit-address-family ! exit !
ping command shows if everything is in order:
$ ping -c10 -w1 -t1 ff02::1%eth0 PING ff02::1%eth0(ff02::1%eth0) 56 data bytes 64 bytes from fe80::5254:33ff:fe00:8%eth0: icmp_seq=1 ttl=64 time=0.016 ms 64 bytes from fe80::5254:33ff:fe00:b%eth0: icmp_seq=1 ttl=64 time=4.98 ms (DUP!) 64 bytes from fe80::5254:33ff:fe00:9%eth0: icmp_seq=1 ttl=64 time=4.99 ms (DUP!) 64 bytes from fe80::5254:33ff:fe00:a%eth0: icmp_seq=1 ttl=64 time=4.99 ms (DUP!) --- ff02::1%eth0 ping statistics --- 1 packets transmitted, 1 received, +3 duplicates, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.016/3.745/4.991/2.152 ms
vtysh:
# show interface vxlan100 Interface vxlan100 is up, line protocol is up Link ups: 1 last: 2017/04/29 20:01:33.43 Link downs: 0 last: (never) PTM status: disabled vrf: Default-IP-Routing-Table index 11 metric 0 mtu 1500 flags: <UP,BROADCAST,RUNNING,MULTICAST> Type: Ethernet HWaddr: 62:42:7a:86:44:01 inet6 fe80::6042:7aff:fe86:4401/64 Interface Type Vxlan VxLAN Id 100 Access VLAN Id 1 Master (bridge) ifindex 9 ifp 0x56536e3f3470
# show evpn mac vni 100 Number of MACs (local and remote) known for this VNI: 2 MAC Type Intf/Remote VTEP VLAN 50:54:33:00:00:0a local eth1.100 50:54:33:00:00:0b local eth2.100
vtysh:
# show bgp neighbors 203.0.113.254 BGP neighbor is 203.0.113.254, remote AS 65000, local AS 65000, internal link Member of peer-group fabric for session parameters BGP version 4, remote router ID 203.0.113.254 BGP state = Established, up for 00:00:45 Neighbor capabilities: 4 Byte AS: advertised and received AddPath: L2VPN EVPN: RX advertised L2VPN EVPN Route refresh: advertised and received(new) Address family L2VPN EVPN: advertised and received Hostname Capability: advertised Graceful Restart Capabilty: advertised [...] For address family: L2VPN EVPN fabric peer-group member Update group 1, subgroup 1 Packet Queue length 0 Community attribute sent to this neighbor(both) 8 accepted prefixes Connections established 1; dropped 0 Last reset never Local host: 203.0.113.2, Local port: 37603 Foreign host: 203.0.113.254, Foreign port: 179
Established,L2VPN EVPN is correctly advertised, and# gobgp neighbor 203.0.113.2 BGP neighbor is 203.0.113.2, remote AS 65000, route-reflector-client BGP version 4, remote router ID 203.0.113.2 BGP state = established, up for 00:04:30 BGP OutQ = 0, Flops = 0 Hold time is 9, keepalive interval is 3 seconds Configured hold time is 90, keepalive interval is 30 seconds Neighbor capabilities: multiprotocol: l2vpn-evpn: advertised and received route-refresh: advertised and received graceful-restart: received 4-octet-as: advertised and received add-path: received UnknownCapability(73): received cisco-route-refresh: received [...] Route statistics: Advertised: 8 Received: 5 Accepted: 5
> show bgp neighbor 203.0.113.2 Peer: 203.0.113.2+38089 AS 65000 Local: 203.0.113.254+179 AS 65000 Group: fabric Routing-Instance: master Forwarding routing-instance: master Type: Internal State: Established Last State: OpenConfirm Last Event: RecvKeepAlive Last Error: None Options: <Preference LocalAddress Cluster AddressFamily Rib-group Refresh> Address families configured: evpn Local Address: 203.0.113.254 Holdtime: 90 Preference: 170 NLRI evpn: NoInstallForwarding Number of flaps: 0 Peer ID: 203.0.113.2 Local ID: 203.0.113.254 Active Holdtime: 9 Keepalive Interval: 3 Group index: 0 Peer index: 2 I/O Session Thread: bgpio-0 State: Enabled BFD: disabled, down NLRI for restart configured on peer: evpn NLRI advertised by peer: evpn NLRI for this session: evpn Peer supports Refresh capability (2) Stale routes from peer are kept for: 300 Peer does not support Restarter functionality NLRI that restart is negotiated for: evpn NLRI of received end-of-rib markers: evpn NLRI of all end-of-rib markers sent: evpn Peer does not support LLGR Restarter or Receiver functionality Peer supports 4 byte AS extension (peer-as 65000) NLRI's for which peer can receive multiple paths: evpn Table bgp.evpn.0 Bit: 20000 RIB State: BGP restart is complete RIB State: VPN restart is complete Send state: in sync Active prefixes: 5 Received prefixes: 5 Accepted prefixes: 5 Suppressed due to damping: 0 Advertised prefixes: 8 Last traffic (seconds): Received 276 Sent 170 Checked 276 Input messages: Total 61 Updates 3 Refreshes 0 Octets 1470 Output messages: Total 62 Updates 4 Refreshes 0 Octets 1775 Output Queue[1]: 0 (bgp.evpn.0, evpn)
> show route table bgp.evpn.0 receive-protocol bgp 203.0.113.2 bgp.evpn.0: 10 destinations, 10 routes (10 active, 0 holddown, 0 hidden) Prefix Nexthop MED Lclpref AS path 2:203.0.113.2:100::0::50:54:33:00:00:0a/304 MAC/IP * 203.0.113.2 100 I 2:203.0.113.2:100::0::50:54:33:00:00:0b/304 MAC/IP * 203.0.113.2 100 I 3:203.0.113.2:100::0::203.0.113.2/304 IM * 203.0.113.2 100 I 3:203.0.113.2:200::0::203.0.113.2/304 IM * 203.0.113.2 100 I
extensive. Here is a type 3 route advertising 203.0.113.2 as a
VTEP for VNI 1008:
> show route table bgp.evpn.0 receive-protocol bgp 203.0.113.2 extensive bgp.evpn.0: 11 destinations, 11 routes (11 active, 0 holddown, 0 hidden) * 3:203.0.113.2:100::0::203.0.113.2/304 IM (1 entry, 1 announced) Accepted Route Distinguisher: 203.0.113.2:100 Nexthop: 203.0.113.2 Localpref: 100 AS path: I Communities: target:65000:268435556 encapsulation:vxlan(0x8) [...]
50:54:33:00:00:0a MAC address for VNI 100:
> show route table bgp.evpn.0 receive-protocol bgp 203.0.113.2 extensive bgp.evpn.0: 11 destinations, 11 routes (11 active, 0 holddown, 0 hidden) * 2:203.0.113.2:100::0::50:54:33:00:00:0a/304 MAC/IP (1 entry, 1 announced) Accepted Route Distinguisher: 203.0.113.2:100 Route Label: 100 ESI: 00:00:00:00:00:00:00:00:00:00 Nexthop: 203.0.113.2 Localpref: 100 AS path: I Communities: target:65000:268435556 encapsulation:vxlan(0x8) [...]
vtysh:
# show bgp evpn route BGP table version is 0, local router ID is 203.0.113.1 Status codes: s suppressed, d damped, h history, * valid, > best, i - internal Origin codes: i - IGP, e - EGP, ? - incomplete EVPN type-2 prefix: [2]:[ESI]:[EthTag]:[MAClen]:[MAC] EVPN type-3 prefix: [3]:[EthTag]:[IPlen]:[OrigIP] Network Next Hop Metric LocPrf Weight Path Route Distinguisher: 203.0.113.2:100 *>i[2]:[0]:[0]:[48]:[50:54:33:00:00:0a] 203.0.113.2 100 0 i *>i[2]:[0]:[0]:[48]:[50:54:33:00:00:0b] 203.0.113.2 100 0 i *>i[3]:[0]:[32]:[203.0.113.2] 203.0.113.2 100 0 i Route Distinguisher: 203.0.113.2:200 *>i[3]:[0]:[32]:[203.0.113.2] 203.0.113.2 100 0 i [...]
# gobgp global rib -a evpn grep rd:203.0.113.2:200 Network Next Hop AS_PATH Age Attrs *> [type:macadv][rd:203.0.113.2:100][esi:single-homed][etag:0][mac:50:54:33:00:00:0a][ip:<nil>][labels:[100]]203.0.113.2 00:00:17 [ Origin: i LocalPref: 100 Extcomms: [VXLAN], [65000:268435556] ] *> [type:macadv][rd:203.0.113.2:100][esi:single-homed][etag:0][mac:50:54:33:00:00:0b][ip:<nil>][labels:[100]]203.0.113.2 00:00:17 [ Origin: i LocalPref: 100 Extcomms: [VXLAN], [65000:268435556] ] *> [type:macadv][rd:203.0.113.2:200][esi:single-homed][etag:0][mac:50:54:33:00:00:0a][ip:<nil>][labels:[200]]203.0.113.2 00:00:17 [ Origin: i LocalPref: 100 Extcomms: [VXLAN], [65000:268435656] ] *> [type:multicast][rd:203.0.113.2:100][etag:0][ip:203.0.113.2]203.0.113.2 00:00:17 [ Origin: i LocalPref: 100 Extcomms: [VXLAN], [65000:268435556] ] *> [type:multicast][rd:203.0.113.2:200][etag:0][ip:203.0.113.2]203.0.113.2 00:00:17 [ Origin: i LocalPref: 100 Extcomms: [VXLAN], [65000:268435656] ]
show bgp evpn route command of vtysh.
Does Quagga correctly understand the received routes? The type 3
routes are translated to an assocation between the remote VTEPs and
the VNIs:
# show evpn vni Number of VNIs: 2 VNI VxLAN IF VTEP IP # MACs # ARPs Remote VTEPs 100 vxlan100 203.0.113.2 4 0 203.0.113.3 203.0.113.1 200 vxlan200 203.0.113.2 3 0 203.0.113.3 203.0.113.1
# show evpn mac vni 100 Number of MACs (local and remote) known for this VNI: 4 MAC Type Intf/Remote VTEP VLAN 50:54:33:00:00:09 remote 203.0.113.1 50:54:33:00:00:0a local eth1.100 50:54:33:00:00:0b local eth2.100 50:54:33:00:00:0c remote 203.0.113.3
bridge command:
# bridge fdb show dev vxlan100 grep dst 00:00:00:00:00:00 dst 203.0.113.1 self permanent 00:00:00:00:00:00 dst 203.0.113.3 self permanent 50:54:33:00:00:0c dst 203.0.113.3 self 50:54:33:00:00:09 dst 203.0.113.1 self
203.0.113.1 and 203.0.113.3)
and the two last ones are the translation of the type 2 routes.
ip link and
brctl with Linux. We only configure one physical interface with two
old-school VLANs paired with matching VNIs.
interfaces ge-0/0/1 unit 0 family bridge interface-mode trunk; vlan-id-list [ 100 200 ]; routing-instances switch instance-type virtual-switch; interface ge-0/0/1.0; bridge-domains vlan100 domain-type bridge; vlan-id 100; vxlan vni 100; ingress-node-replication; vlan200 domain-type bridge; vlan-id 200; vxlan vni 200; ingress-node-replication;
protocols bgp group fabric type internal; multihop; family evpn signaling; local-address 203.0.113.3; neighbor 203.0.113.253; neighbor 203.0.113.254; routing-instances switch vtep-source-interface lo0.0; route-distinguisher 203.0.113.3:1; # vrf-import EVPN-VRF-VXLAN; vrf-target target:65000:1; auto; protocols evpn encapsulation vxlan; extended-vni-list all; multicast-mode ingress-replication; routing-options router-id 203.0.113.3; autonomous-system 65000; policy-options policy-statement EVPN-VRF-VXLAN then accept;
> show route table bgp.evpn.0 receive-protocol bgp 203.0.113.3 extensive bgp.evpn.0: 13 destinations, 13 routes (13 active, 0 holddown, 0 hidden) * 3:203.0.113.3:1::100::203.0.113.3/304 IM (1 entry, 1 announced) Accepted Route Distinguisher: 203.0.113.3:1 Nexthop: 203.0.113.3 Localpref: 100 AS path: I Communities: target:65000:268435556 encapsulation:vxlan(0x8) PMSI: Flags 0x0: Label 6: Type INGRESS-REPLICATION 203.0.113.3 [...]
> show route table bgp.evpn.0 receive-protocol bgp 203.0.113.3 extensive bgp.evpn.0: 13 destinations, 13 routes (13 active, 0 holddown, 0 hidden) * 2:203.0.113.3:1::200::50:54:33:00:00:0f/304 MAC/IP (1 entry, 1 announced) Accepted Route Distinguisher: 203.0.113.3:1 Route Label: 200 ESI: 00:00:00:00:00:00:00:00:00:00 Nexthop: 203.0.113.3 Localpref: 100 AS path: I Communities: target:65000:268435656 encapsulation:vxlan(0x8) [...]
> show evpn database l2-domain-id 100 Instance: switch VLAN DomainId MAC address Active source Timestamp IP address 100 50:54:33:00:00:0c 203.0.113.1 Apr 30 12:46:20 100 50:54:33:00:00:0d 203.0.113.2 Apr 30 12:32:42 100 50:54:33:00:00:0e 203.0.113.2 Apr 30 12:46:20 100 50:54:33:00:00:0f ge-0/0/1.0 Apr 30 12:45:55
# show evpn vni 100 VNI: 100 VxLAN interface: vxlan100 ifIndex: 9 VTEP IP: 203.0.113.1 Remote VTEPs for this VNI: 203.0.113.3 203.0.113.2 Number of MACs (local and remote) known for this VNI: 4 Number of ARPs (IPv4 and IPv6, local and remote) known for this VNI: 0 # show evpn mac vni 100 Number of MACs (local and remote) known for this VNI: 4 MAC Type Intf/Remote VTEP VLAN 50:54:33:00:00:0c local eth1.100 50:54:33:00:00:0d remote 203.0.113.2 50:54:33:00:00:0e remote 203.0.113.2 50:54:33:00:00:0f remote 203.0.113.3
203.0.113.2:100) is not the one used to encode the VNI. The VNI
is encoded in the route target (65000:268435556), in the 24
least signifiant bits (268435556 & 0xffffff equals 100). As
long as VNIs are unique, we don t have to understand those
details.
.rdb database format that contains the package's
definitions, plus a .rdx index file for easy lookup in the .rdb file.
Usually, there is a main rdb with the package contents, plus another rdb that
stores the help data. There is also a paths.rds (same format as .rdx) that
contains some more stuff.
One can actually read these files by hand using Rscript, see the diffoscope
code in
rdata.py.
If you run that, you can see that path.rds contains some obvious paths, but
the other files contain less obvious stuff, and in fact these scripts give
identical output for the .rdb files, even though they are bitwise different.
To get to the bottom of this, we'll have to use the R debugger.
Attached to this post is a script that
smooths this process. I ran this against Debian's R packages, but it probably
also works with other distros' R packages - try it and see.
You run it like ./r-mini-repro-test.sh $pkgdir $builddir and it will output
some hashes for you; make sure to install the build dependencies first. You
should manually vary both $pkgdir and $builddir to introduce the build-path
variations; $builddir can be an arbitrary string but $pkgdir should point
to the actual R package's source directory, so I just copy that to two
locations and point the script at each of them in turn.
Now, we can begin debugging. Before I did this, we had 478 unreproducible R
packages so the biggest problem was likely with R itself. I downloaded the
source code of both R and a small example package (r-cran-tensor), then figured
out how the R packages were actually being built. This resulted in me writing
the script above, to speed up debugging. You can read about R's debugger here
(no HTTPS), it's
a bit primitive but it supports the basic stuff (step, continue, where,
print/eval) and that was adequate for me.
Debugging R core
So let's take a small example with Debian R 3.4.0-1:
$ ../r-mini-repro-test.sh r-cran-tensor-1.5 123
[..]
* installing *source* package tensor ...
** package tensor successfully unpacked and MD5 sums checked
** R
** preparing package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded
* DONE (tensor)
[..]
c71a766429151a13e46039f3c37a14edc704004f410c34f8f37a2f098506421d ./debian/123/usr/lib/R/site-library/tensor/R/tensor.rdx
736b5b4a885db71fb3fe2a538faeefe43c500c4080dbf2c75b97135b98401acd ./debian/123/usr/lib/R/site-library/tensor/R/tensor.rdb
8a3f9616de7ee78a83b07395dd6ec43c5259d3f1b1b653d397808fc9fc5d96c2 ./debian/123/usr/lib/R/site-library/tensor/help/tensor.rdx
d1ac634987b24606a5da627ec073f45edce2bddf071391dd17c246a0a01eba63 ./debian/123/usr/lib/R/site-library/tensor/help/tensor.rdb
80796cc1a2cfcac40c394153f67617d575e103a405430b8483c2261a903db046 ./debian/123/usr/lib/R/site-library/tensor/help/paths.rds
$ ../r-mini-repro-test.sh r-cran-tensor-1.5 1234
[..]
5f081f4d6f9da1fbe06e374067e6636d926de4cdf09886058b15c5928c636c0d ./debian/1234/usr/lib/R/site-library/tensor/R/tensor.rdx
7145669891e1b766ca0d8d89fa9c317af716e61a62650abe3a11a848240f1d57 ./debian/1234/usr/lib/R/site-library/tensor/R/tensor.rdb
8a3f9616de7ee78a83b07395dd6ec43c5259d3f1b1b653d397808fc9fc5d96c2 ./debian/1234/usr/lib/R/site-library/tensor/help/tensor.rdx
d1ac634987b24606a5da627ec073f45edce2bddf071391dd17c246a0a01eba63 ./debian/1234/usr/lib/R/site-library/tensor/help/tensor.rdb
80796cc1a2cfcac40c394153f67617d575e103a405430b8483c2261a903db046 ./debian/1234/usr/lib/R/site-library/tensor/help/paths.rds
The files are created by the ** preparing package for lazy loading and **
help steps. In retrospect this seems somewhat obvious from the output, but I
had never done R before so I spent a while using strace to be sure; one can
see that those files are indeed written to after those strings are printed.
Then we can grep the R source code for these strings.
r-base-3.4.0$ grep -Ri "preparing package for lazy loading" src
src/library/tools/R/install.R: starsmsg(stars, "preparing package for lazy loading")
Reading the file, we see that this happens in the tools:::.install_packages
function, and reading it further we see that it calls makeLazyLoading then
code2LazyLoadDB then makeLazyLoadDB. Seems promising, let's confirm it
before chasing potential wild geese.
Important: In the rest of these command-line outputs I'll prepend what I
input with >>> but this doesn't actually get printed by Rscript. So don't
be surprised that you don't see these, when you're trying to recreate my steps.
Also I am a total R noob so possibly there are more elegant ways to do what I'm
about to show you; this is what I came up with after 2-3 hours of research.
$ DEBUG=1 ../r-mini-repro-test.sh r-cran-tensor-1.5 123
enter (some or all of) the following into R:
[.. helpful commands ..]
+ R_DEFAULT_PACKAGES= LC_COLLATE=C /usr/lib/R/bin/R --no-restore --slave --args nextArg-lnextArgdebian/123/usr/lib/R/site-librarynextArg-dnextArg.nextArg--built-timestamp="Thu, 01 Jan 1970 00:00:00 +0000"
>>> debug(tools:::makeLazyLoadDB)
>>> tools:::.install_packages()
processing .
[..]
** preparing package for lazy loading
debugging in: makeLazyLoadDB(ns, dbbase, compress = compress)
debug:
[.. source code of makeLazyLoadDB, not yet run ..]
OK so we just entered the function and it's paused, in a separate shell let's check what it's doing:
$ find r-cran-tensor-1.5 -name '*.rdb'
[ no output ]
So, no files have been written yet, which means none of the parent functions
did anything, we are in the right function (or it's in a child). If we continue
the function, we get:
>>> c
exiting from: makeLazyLoadDB(ns, dbbase, compress = compress)
** help
debugging in: makeLazyLoadDB(db, file.path(manOutDir, basename(outDir)))
debug:
[.. source code of makeLazyLoadDB, not yet run ..]
$ find r-cran-tensor-1.5 -name '*.rdb'
r-cran-tensor-1.5/debian/123/usr/lib/R/site-library/tensor/R/tensor.rdb
Then continuing again:
>>> c
exiting from: makeLazyLoadDB(db, file.path(manOutDir, basename(outDir)))
*** installing help indices
** building package indices
** testing if installed package can be loaded
* DONE (tensor)
$ find r-cran-tensor-1.5 -name '*.rdb'
r-cran-tensor-1.5/debian/123/usr/lib/R/site-library/tensor/help/tensor.rdb
r-cran-tensor-1.5/debian/123/usr/lib/R/site-library/tensor/R/tensor.rdb
So it seems likely this function is the correct one. After reading the source
code of makeLazyLoadDB, even though I don't understand the whole thing, it
looks like possibly this part is the one that does the actual writing:
for (i in seq_along(vars))
key <- if (is.null(from) is.environment(from))
lazyLoadDBinsertVariable(vars[i], from, datafile,
ascii, compress, envhook)
else lazyLoadDBinsertListElement(from, i, datafile, ascii,
compress, envhook)
assign(vars[i], key, envir = varenv)
So let's step through it and see if the data contains any paths.
$ DEBUG=1 ../r-mini-repro-test.sh r-cran-tensor-1.5 123
[..]
>>> debug(tools:::makeLazyLoadDB)
>>> tools:::.install_packages()
processing .
[..]
** preparing package for lazy loading
debugging in: makeLazyLoadDB(ns, dbbase, compress = compress)
debug:
[.. source code of makeLazyLoadDB, not yet run ..]
>>> # pressing <Enter> just means "step"
debug: ascii <- as.logical(ascii) # this is the first line of the function
>>> # keep stepping
[..]
>>>
debug: for (i in seq_along(vars))
[.. source code of the inside of the block, not yet run ..]
>>>
debug: key <- if (is.null(from) is.environment(from)) lazyLoadDBinsertVariable(vars[i],
from, datafile, ascii, compress, envhook) else lazyLoadDBinsertListElement(from,
i, datafile, ascii, compress, envhook)
>>>
debug: lazyLoadDBinsertVariable(vars[i], from, datafile, ascii, compress,
envhook) # not yet run
If we look at the source code we see that it will try to insert the value of
.Internal(getVarsFromFrame(vars[i], from, FALSE))[[1L]] into the file, so let's evaluate it:
>>> .Internal(getVarsFromFrame(vars[i], from, FALSE))[[1L]]
function (x, y)
tensor(x, y, 2, 2)
<environment: namespace:tensor>
>>> typeof(.Internal(getVarsFromFrame(vars[i], from, FALSE))[[1L]])
[1] "closure"
>>> environment(.Internal(getVarsFromFrame(vars[i], from, FALSE))[[1L]]) # get the environment of a closure
<environment: namespace:tensor>
>>> envlist(environment(.Internal(getVarsFromFrame(vars[i], from, FALSE))[[1L]])) # environment as an envlist, more detailed output
$ %*t%
function (x, y)
tensor(x, y, 2, 2)
<environment: namespace:tensor>
$ %t*%
function (x, y)
tensor(x, y, 1, 1)
<environment: namespace:tensor>
$ %t*t%
function (x, y)
tensor(x, y, 1, 2)
<environment: namespace:tensor>
$.__NAMESPACE__.
<environment: 0x55eb55d00be0>
$.__S3MethodsTable__.
<environment: 0x55eb55d166e8>
$.packageName
[1] "tensor"
$tensor
function (A, B, alongA = integer(0), alongB = integer(0))
[.. function definition ..]
<environment: namespace:tensor>
Nothing obviously containing paths so far, let's keep stepping and dumping the objects
>>>
debug: assign(vars[i], key, envir = varenv)
>>> # next iteration now
debug: key <- if (is.null(from) is.environment(from)) lazyLoadDBinsertVariable(vars[i],
from, datafile, ascii, compress, envhook) else lazyLoadDBinsertListElement(from,
i, datafile, ascii, compress, envhook)
>>>
debug: lazyLoadDBinsertVariable(vars[i], from, datafile, ascii, compress,
envhook)
>>> .Internal(getVarsFromFrame(vars[i], from, FALSE))[[1L]]
function (x, y)
tensor(x, y, 1, 1)
<environment: namespace:tensor>
>>>
[.. more stepping ..]
debug: lazyLoadDBinsertVariable(vars[i], from, datafile, ascii, compress,
envhook)
>>> .Internal(getVarsFromFrame(vars[i], from, FALSE))[[1L]]
<environment: 0x55eb55d00be0>
>>> envlist(.Internal(getVarsFromFrame(vars[i], from, FALSE))[[1L]])
$S3methods
[,1] [,2] [,3]
$dynlibs
NULL
$exports
<environment: 0x55eb55d0a4f8>
$imports
$imports$base
[1] TRUE
$lazydata
<environment: 0x55eb55d0a178>
attr(,"name")
[1] "lazydata:tensor"
$path
[1] "/mystupidbuildpath/r-tests/r-cran-tensor-1.5/debian/123/usr/lib/R/site-library/tensor"
$spec
name version
"tensor" "1.5"
Oh, here we go. (In fact we could have got this earlier, it was part of the
.__NAMESPACE__. key of the first environment that we examined.) Naturally,
you'll sometimes miss stuff, and sometimes go down dead ends when doing
something like this, perseverence is important.
The names are also a hint, after grepping the R source code for names like
"S3methods" and "lazydata" we see that src/library/base/R/namespace.R is the
only one that contains all of them, then reading that code in more depth
reveals this.
After patching it, rebuilding r-base, installing this patched version, then
running our tests again, we see that we've eliminated differences in the main
rdb file but not the help rdb file.
In fact, after some more time stepping through the loop repeatedly and printing
out all the objects, nothing obvious shows up. Time to re-read the source code
of makeLazyLoadDB. We notice that all the lazyLoadDBinsert* functions have
a hook parameter that we haven't been stepping through because it's in a
separate function. So let's do that. Since it's an inner function, one has to
call debug() inside makeLazyLoadDB:
$ DEBUG=1 ../r-mini-repro-test.sh r-cran-tensor-1.5 123
[..]
>>> debug(tools:::makeLazyLoadDB)
>>> tools:::.install_packages()
processing .
[..]
** preparing package for lazy loading
debugging in: makeLazyLoadDB(ns, dbbase, compress = compress)
debug:
[.. source code of makeLazyLoadDB, not yet run ..]
>>> c
exiting from: makeLazyLoadDB(ns, dbbase, compress = compress)
** help
debugging in: makeLazyLoadDB(db, file.path(manOutDir, basename(outDir)))
debug:
[.. source code of makeLazyLoadDB, not yet run ..]
[.. stepping through the function ..]
debug: envhook <- function(e)
[.. function definition ..]
>>> # step next, to define that function
[.. next statement, we don't care about it ..]
>>> debug(envhook)
[.. then keep stepping through makeLazyLoadDB ..]
>>>
debug: lazyLoadDBinsertVariable(vars[i], from, datafile, ascii, compress,
envhook)
[.. then keep stepping through makeLazyLoadDB ..]
debug: lazyLoadDBinsertVariable(vars[i], from, datafile, ascii, compress,
envhook)
[.. hook wasn't run for these previous iterations for some reason, but keep stepping ..]
[.. eventually we get ..]
debugging in: (function (e)
[.. function definition ..]
)(<environment>) # "(..)(<environment>)" is R's name for that function (actually a closure)
debug:
[.. source code, not yet run ..]
>>> e
/mystupidbuildpath/r-tests/r-cran-tensor-1.5/man/tensor.Rd
>>> typeof(e)
[1] "environment"
>>> envlist(e)
$Enc
[1] "UTF-8"
$encoding
[1] ""
$filename
[1] "/mystupidbuildpath/r-tests/r-cran-tensor-1.5/man/tensor.Rd"
$timestamp
[1] "2002-01-16 11:51:14 CET"
$wd
[1] "/mystupidbuildpath/r-tests/r-cran-tensor-1.5"
After doing the same thing as before, i.e. grepping the R source code for "Enc"
"timestamp" etc, we spot a few different places
that are setting the wd field.
Then after some experimenting, we find that overwriting this in a different
file (src/library/tools/R/parseRd.R) seems to work to get rid of this
irreproducibility. (This may not be the best; our exact strategy is still being
discussed with upstream, but at least we know which areas of the code are
responsible.)
Exercise for the reader to figure out how to get rid of the paths.rds
difference. After doing the previous two, this one is fairly easy.
These three issues allowed us to write a preliminary
patch that
enabled us to reproduce
r-cran-tensor.
$ ./r-mini-repro-test.sh r-cran-tensor-1.5 123
[..]
bca9de1351ab265475cf6f1af3f6aff49bde1d209e8fafb33954caa8d90f3462 ./debian/123/usr/lib/R/site-library/tensor/R/tensor.rdx
ac7fffeb751ffc2d13c5317704b19787a7078446d97d1c6f259c93f282e04cef ./debian/123/usr/lib/R/site-library/tensor/R/tensor.rdb
d989603340d1e8f14c35551ef379956653bf3b6e7b1868b4bf9a66d85820998e ./debian/123/usr/lib/R/site-library/tensor/help/tensor.rdx
30e543cda9f97c202dc9c0291933940dfe71b94d352f66d8ed6c035c1a722b41 ./debian/123/usr/lib/R/site-library/tensor/help/tensor.rdb
e9f78ba2cca39a6face1ed88fce4bb718d911d567d01db49bc00a3011720ac50 ./debian/123/usr/lib/R/site-library/tensor/help/paths.rds
$ ./r-mini-repro-test.sh r-cran-tensor-1.5 1234
[..]
bca9de1351ab265475cf6f1af3f6aff49bde1d209e8fafb33954caa8d90f3462 ./debian/1234/usr/lib/R/site-library/tensor/R/tensor.rdx
ac7fffeb751ffc2d13c5317704b19787a7078446d97d1c6f259c93f282e04cef ./debian/1234/usr/lib/R/site-library/tensor/R/tensor.rdb
d989603340d1e8f14c35551ef379956653bf3b6e7b1868b4bf9a66d85820998e ./debian/1234/usr/lib/R/site-library/tensor/help/tensor.rdx
30e543cda9f97c202dc9c0291933940dfe71b94d352f66d8ed6c035c1a722b41 ./debian/1234/usr/lib/R/site-library/tensor/help/tensor.rdb
e9f78ba2cca39a6face1ed88fce4bb718d911d567d01db49bc00a3011720ac50 ./debian/1234/usr/lib/R/site-library/tensor/help/paths.rds
$ ./r-mini-repro-test.sh r-cran-tensor 1234
[..]
bca9de1351ab265475cf6f1af3f6aff49bde1d209e8fafb33954caa8d90f3462 ./debian/1234/usr/lib/R/site-library/tensor/R/tensor.rdx
ac7fffeb751ffc2d13c5317704b19787a7078446d97d1c6f259c93f282e04cef ./debian/1234/usr/lib/R/site-library/tensor/R/tensor.rdb
d989603340d1e8f14c35551ef379956653bf3b6e7b1868b4bf9a66d85820998e ./debian/1234/usr/lib/R/site-library/tensor/help/tensor.rdx
30e543cda9f97c202dc9c0291933940dfe71b94d352f66d8ed6c035c1a722b41 ./debian/1234/usr/lib/R/site-library/tensor/help/tensor.rdb
e9f78ba2cca39a6face1ed88fce4bb718d911d567d01db49bc00a3011720ac50 ./debian/1234/usr/lib/R/site-library/tensor/help/paths.rds
Testing the patch
Of course r-cran-tensor is just 1 package, so then we tested this patch on all
478 tagged R
packages.
Before the patch, all of these were unreproducible. Now 463/478 are
reproducible, hurray!
The first version of the patch made 2 packages FTBFS ("fail to build from
source"), r-bioc-biobase and r-cran-shinybs; this was fixed
in a subsequent version of the patch. (Some other packages, r-cran-randomfields r-cran-randomfieldsutils, FTBFS even with an
unpatched r-base, due to differences between 3.3.3 and 3.4.0 (#861333),
and not because of our patch.)
Given the overwhelming proportion of packages that did reproduce, the other
14 packages that are still unreproducible, are quite probably due to issues in
those specific packages. Only 2 of these are certainly due to build-path
differences: r-cran-runit r-cran-rinside. This is because, we
currently see they are reproducible in Debian testing but not Debian unstable.
This is slightly misleading, the real reason is not testing vs unstable
directly; rather the fact that we (at the time of writing) use the same build
path when trying to reproduce Debian testing packages, and different paths for
unstable. The other 12 are unreproducible in both testing and unstable, so it
either suffers from a non-build-path issue as well as a build-path issue, or
only a non-build-path issue.
So, further investigation of each package is needed. This is where you can
help.
Debugging R packages
To investigate why (for example) r-cran-runit doesn't reproduce
despite our patches, we just do the above process again:
$ DEBUG=1 ../r-mini-repro-test.sh r-cran-runit
[..]
>>> debug(tools:::makeLazyLoadDB)
>>> tools:::.install_packages()
processing .
a directory
* build_help_types=
* DBG: 'R CMD INSTALL' now doing do_install()
* created lock directory /mystupidbuildpath/r-tests/r-cran-runit/debian/r-cran-runit/usr/lib/R/site-library/00LOCK-r-cran-runit
* installing *source* package RUnit ...
** package RUnit successfully unpacked and MD5 sums checked
** backing up earlier installation
** R
** inst
** preparing package for lazy loading
debugging in: makeLazyLoadDB(ns, dbbase, compress = compress)
debug:
[.. source code of makeLazyLoadDB ..]
We know our irreproducibility is with the help files and not the main package,
so c to skip this part:
>>> c
exiting from: makeLazyLoadDB(ns, dbbase, compress = compress)
** help
debugging in: makeLazyLoadDB(db, file.path(manOutDir, basename(outDir)))
debug:
[.. source code of makeLazyLoadDB ..]
Examine the "from" object, grep the output for our builddir
>>> from
$ RUnit-internal
[..]
$ RUnit-intro
[..]
[.. etc ..]
[..]
$checkFuncs
\title RUnit check [..]
[..]
For a simple example see the provided test cases in
/mystupidbuildpath/r-tests/r-cran-runit/debian/r-cran-runit/usr/lib/R/site-library/RUnit/examples/runitVirtualClassTest.r.
[..]
Found it, now we quit, patch the source code, and try again.
>>> Q
[..]
exit code 1
[.. hack hack hack ..]
$ ../r-mini-repro-test.sh r-cran-runit-0.4.31/ 123
[..]
01347305351a45bb88dab909c56942498e97f5edbe583cf6ab1327138914e315 ./debian/123/usr/lib/R/site-library/RUnit/R/RUnit.rdx
ecde40bdfac5b070acc30a0d5889d9d7f65418844d14312aceff6af5b9d0bf7a ./debian/123/usr/lib/R/site-library/RUnit/R/RUnit.rdb
182d38ac5adc160eb9edd40d5bd7e27b95b756b8f14cee7d912ba4745ae81bdc ./debian/123/usr/lib/R/site-library/RUnit/help/RUnit.rdx
f8a9f22acc9f937cb47a92f3979d619e83a791ad734796c2fcd9d0a34e1f11ca ./debian/123/usr/lib/R/site-library/RUnit/help/RUnit.rdb
5c37672fdc1f325b8a3846f4eafd2624b246ec70ce01d197134fa1b97a9ee849 ./debian/123/usr/lib/R/site-library/RUnit/help/paths.rds
$ ../r-mini-repro-test.sh r-cran-runit-0.4.31/ 1234
[..]
01347305351a45bb88dab909c56942498e97f5edbe583cf6ab1327138914e315 ./debian/1234/usr/lib/R/site-library/RUnit/R/RUnit.rdx
ecde40bdfac5b070acc30a0d5889d9d7f65418844d14312aceff6af5b9d0bf7a ./debian/1234/usr/lib/R/site-library/RUnit/R/RUnit.rdb
182d38ac5adc160eb9edd40d5bd7e27b95b756b8f14cee7d912ba4745ae81bdc ./debian/1234/usr/lib/R/site-library/RUnit/help/RUnit.rdx
f8a9f22acc9f937cb47a92f3979d619e83a791ad734796c2fcd9d0a34e1f11ca ./debian/1234/usr/lib/R/site-library/RUnit/help/RUnit.rdb
5c37672fdc1f325b8a3846f4eafd2624b246ec70ce01d197134fa1b97a9ee849 ./debian/1234/usr/lib/R/site-library/RUnit/help/paths.rds
Works! All finished.
If yours doesn't, just repeat the above loop; hopefully
eventually you'll get there.
Recently I had the opportunity to be a part of Ultrahack as a mentor which was held in Helsinki, Finland.
Another in the series of looking at the security of IoT type objects. This time I've gone for the Arlo network connected cameras produced by Netgear, specifically the stock Arlo base system with a single camera. The base station is based on a Broadcom 5358 SoC with an 802.11n radio, along with a single Broadcom gigabit ethernet interface. Other than it only having a single ethernet port, this looks pretty much like a standard Netgear router. There's a convenient unpopulated header on the board that turns out to be a serial console, so getting a shell is only a few minutes work.Next.