├── Images
├── iphone-rpi-backup-blinkt-crop.png
├── rpi-iphone-diagnostics.png
└── rpi-iphone-trust.jpg
├── README.md
├── etc
├── motd
├── rc.local
└── udev
│ └── rules.d
│ └── lol.rules
└── home
└── pi
├── backup-iphone.py
├── backup-iphone.sh
├── blinkt.sh
├── iphone-backups
└── iphone files are rsyncd here.txt
├── log.txt
├── monitor.sh
├── udev-runs-this.sh
└── usr
├── src
└── this is where you should git clone libimobiledevice and friends.txt
└── the script backup-iphone.sh mounts the iphone in here.txt
/Images/iphone-rpi-backup-blinkt-crop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/justinpearson/Raspberry-Pi-for-iPhone-Backup/c9089e9c7b0276a50c9a4b214558484b78dc1aa5/Images/iphone-rpi-backup-blinkt-crop.png
--------------------------------------------------------------------------------
/Images/rpi-iphone-diagnostics.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/justinpearson/Raspberry-Pi-for-iPhone-Backup/c9089e9c7b0276a50c9a4b214558484b78dc1aa5/Images/rpi-iphone-diagnostics.png
--------------------------------------------------------------------------------
/Images/rpi-iphone-trust.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/justinpearson/Raspberry-Pi-for-iPhone-Backup/c9089e9c7b0276a50c9a4b214558484b78dc1aa5/Images/rpi-iphone-trust.jpg
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Raspberry Pi for iPhone backup
2 |
3 | You can use a Raspberry Pi (even a tiny RPi Zero) to backup your iphone. You plug the phone into the RPi at night, and the RPi charges it and copies its photos, music, etc onto the RPi's micro-SD card.
4 |
5 | (Note: Consider having your router disallow the RPi on the WAN, since you're just using it for iphone backup.)
6 |
7 |
8 |
9 | You can show backup progress with a [Blinkt LED strip](https://www.adafruit.com/product/3195):
10 |
11 |
12 |
13 | **Note:** This project requires Python version 3.6 or later, because it uses f-strings for easy string formatting when printing messages.
14 |
15 | ## Table of Contents
16 |
17 | - [Introduction](#introduction)
18 | - [Troubleshooting tip](#troubleshooting-tip)
19 | - [0. Install files from this repo](#0-install-files-from-this-repo)
20 | - [1. Install `libimobiledevice` from source](#1-install-libimobiledevice-from-source)
21 | - [2. Plug, pair, and mount iPhone](#2-plug-pair-and-mount-iphone)
22 | - [2a. Plug in phone](#2a-plug-in-phone)
23 | - [2b. Pair phone to RPi](#2b-pair-phone-to-rpi)
24 | - [2c. Mount phone's files on RPi](#2c-mount-phones-files-on-rpi)
25 | - [2d. Back up phone to RPi](#2d-back-up-phone-to-rpi)
26 | - [2e. Unmount, Unpair, Unplug](#2e-unmount-unpair-unplug)
27 | - [3. Run the backup script](#3-run-the-backup-script)
28 | - [4. Configure udev to run the backup script upon the phone plug-in event](#4-configure-udev-to-run-the-backup-script-upon-the-phone-plug-in-event)
29 | - [4a. udev example](#4a-udev-example)
30 | - [4b. Set up our own udev rule to run backup script upon plug-in](#4b-set-up-our-own-udev-rule-to-run-backup-script-upon-plug-in)
31 | - [5. Ensuring `udev` is configured correctly at boot](#5-ensuring-udev-is-configured-correctly-at-boot)
32 | - [6. Indicate progress with Blinkt LEDs](#6-indicate-progress-with-blinkt-leds)
33 | - [Appendix: Troubleshooting](#appendix-troubleshooting)
34 | - [Appendix: Notes / Resources](#appendix-notes-and-resources)
35 |
36 |
37 | # Introduction
38 |
39 | Accessing an iPhone's data from a Raspberry Pi is harder than you'd expect. The Raspbian OS doesn't seem to support it by default: the `apt-get install` versions of the iPhone-mounting software `libimobiledevice6` and `ifuse` did not work for my phone running iOS 11.4. So I followed [samrocketman's instructions](https://gist.github.com/samrocketman/70dff6ebb18004fc37dc5e33c259a0fc) for installing `libimobiledevice` and `ifuse` from source. Here are his instructions with my additions.
40 |
41 | Also, I wanted the RPi to download the iPhone's data as soon as I plugged it in. I did not want to have to ssh into the RPi to initiate the backup. This required setting up a `udev` rule. It was hard to get it configured just right.
42 |
43 | Lastly, there is one lingering problem I haven't solved:
44 |
45 | In order to pair the phone to the RPi, the `backup-iphone.py` script (from this repo) uses the command `$ idevicepair pair`. It seems that for this command to succeed, it requires two things:
46 |
47 | 1. the phone must be unlocked
48 | 2. the phone must "Trust" the RPi
49 |
50 | So, each time you plug in the iPhone to the RPi, you should:
51 |
52 | 1. unlock the phone,
53 | 2. wait for the "Trust this computer?" dialog to appear on the phone (sometimes takes 20 seconds to appear),
54 | 3. click "Trust" and enter passcode.
55 | 4. Keep the screen unlocked for 15 seconds.
56 |
57 | After you click "Trust", it is okay for the phone to re-lock and turn off its display.
58 |
59 | For some reason the phone doesn't remember the RPi, so you must do this each time.
60 |
61 | If everything is set up correctly, the `backup-iphone.py` script will start to run as soon as you plug in the phone. It tries to pair for about 30 seconds before it gives up, so you've got 30 seconds to remember to unlock the phone and click "Trust".
62 |
63 |
64 | ## Troubleshooting tip
65 |
66 | To help debug problems, try running `monitor.sh` on a Mac that can ssh into the Pi. It opens several terminal windows on the Mac that monitor various aspects of the USB-device manager and whether the phone is plugged in and paired.
67 |
68 | (The script `monitor.sh` assumes your `~/.ssh/config` file defines an ssh alias `rpi42` for sshing into the Pi.)
69 |
70 | - `watch -d -t lsusb` tells you when the phone is plugged in
71 | - `dmesg -w` gives you kernel messages
72 | - `tail -f /var/log/syslog` watches the syslog
73 | - `journalctl -f` watches the `systemd` journal
74 | - `udevadm monitor -kup` tells you what `udev` does when you plug in the phone
75 | - `watch -d -t /home/pi/usr/bin/idevicepair list` tells you when the phone is paired
76 | - `tail -f /home/pi/log.txt` shows the log that the `/home/pi/backup-iphone.sh` script writes to
77 |
78 |
79 |
80 | If `monitor.sh` doesn't work for you, consider using this bash snippet (for Mac). It runs each of these commands in its own terminal window on the RPi over ssh.
81 |
82 | The snippet assumes your `~/.ssh/config` file defines the alias `rpi01` to let you ssh into the RPi.
83 |
84 | REPLACE_STRINGS=( \
85 | '' \
86 | 'dmesg -w' \
87 | 'watch -d -t lsusb' \
88 | 'watch -d -t /home/pi/usr/bin/idevicepair list' \
89 | 'tail -f /var/log/syslog' \
90 | 'tail -f /home/pi/log.txt' \
91 | 'journalctl -f' \
92 | 'udevadm monitor -kup' ) # no trailing newline.
93 | for cmd in "${REPLACE_STRINGS[@]}"
94 | {
95 | osascript -e "tell application \"Terminal\" to do script \"ssh -t rpi01 $cmd\""
96 | }
97 |
98 |
99 | # 0. Install files from this repo
100 |
101 | sudo ln -s /home/pi/Raspberry-Pi-for-iPhone-Backup/etc/udev/rules.d/lol.rules /etc/udev/rules.d/lol.rules
102 | ln -s /home/pi/Raspberry-Pi-for-iPhone-Backup/home/pi/udev-runs-this.sh /home/pi/udev-runs-this.sh
103 | ln -s /home/pi/Raspberry-Pi-for-iPhone-Backup/home/pi/backup-iphone.sh /home/pi/backup-iphone.sh
104 | ln -s /home/pi/Raspberry-Pi-for-iPhone-Backup/home/pi/backup-iphone.py /home/pi/backup-iphone.py
105 | ln -s /home/pi/Raspberry-Pi-for-iPhone-Backup/home/pi/leds.pickle /home/pi/leds.pickle
106 | ln -s /home/pi/Raspberry-Pi-for-iPhone-Backup/home/pi/leds_OFF.pickle /home/pi/leds_OFF.pickle
107 |
108 |
109 | - `lol.rules` tells `udev` to run `udev-runs-this.sh` when the iPhone is plugged in
110 | - `udev.runs.this.sh` runs `backup-iphone.sh`
111 | - `backup-iphone.sh` sets up some environment variables and calls the main script `backup-iphone.py`.
112 | - `backup-iphone.py` uses `idevicepair`, `ifuse`, and `rsync` to pair with, mount, and backup the iPhone.
113 |
114 | In the next section, we build `idevicepair` and friends from source.
115 |
116 |
117 |
118 |
119 | # 1. Install `libimobiledevice` from source
120 |
121 | In this section we `git clone` the `libimobiledevice` software and friends.
122 |
123 | However, before we do that, we do a little hack to install a user named `usbmux` that is required by a subsystem within `libimobiledevice`.
124 |
125 | The `usbmuxd` daemon is part of `libimobiledevice`; it multiplexes connections over USB to an iOS device. For safety, it runs as a user named `usbmux` with certain (limited?) permissions. It expects the `usbmux` user to exist or it will fail to start. Unfortunately, when you build `usbmuxd` from source, it doesn't create the `usbmux` user. However, `apt-get install`ing the `usbmuxd` package *does* create the `usbmux` user, and `apt-get remove`ing `usbmuxd` removes the package but doesn't delete the `usbmux` user. (However, we can't simply use `apt-get`'s version of `usbmux` because the Raspbian repos have old versions of `usbmuxd` and `libimobiledevice` that won't work with iOS 11). So before we build `usbmux` from source, we use `apt-get install` then `apt-get remove` to create the `usbmux` user.
126 |
127 | See if you have the `usbmux` user:
128 |
129 | grep usb /etc/passwd
130 |
131 | If not, install `usbmuxd` with `apt-get` to force the creation of the `usbmux` user:
132 |
133 | sudo apt-get install usbmuxd
134 |
135 | Now you should have the `usbmux` user:
136 |
137 | grep usb /etc/passwd
138 |
139 | usbmux:x:112:46:usbmux daemon,,,:/var/lib/usbmux:/bin/false
140 |
141 | Remove packages that we're going to build from source:
142 |
143 | sudo apt-get remove libimobiledevice6 ifuse usbmuxd
144 |
145 | Verify you still have the `usbmux` user.
146 |
147 | **REBOOT**
148 |
149 | Now we are ready to install `libimobiledevice` and friends from source.
150 |
151 | Add to your `.bashrc` some config that lets us build code in `~/usr` :
152 |
153 |
154 | [ ! -d "$HOME/usr/src" ] && mkdir -p "$HOME/usr/src"
155 | export PKG_CONFIG_PATH="${HOME}/usr/lib/pkgconfig:${PKG_CONFIG_PATH}"
156 | export CPATH="${HOME}/usr/include:${CPATH}"
157 |
158 | export MANPATH="${HOME}/usr/share/man:${MANPATH}"
159 |
160 | export PATH="${HOME}/usr/bin:${PATH}"
161 | export LD_LIBRARY_PATH="${HOME}/usr/lib:${LD_LIBRARY_PATH}"
162 |
163 | Don't forget to
164 |
165 | source ~/.bashrc
166 |
167 | to take effect.
168 |
169 | Install packages:
170 |
171 | sudo apt-get install -y build-essential git
172 |
173 | sudo apt-get install automake libtool pkg-config libplist-dev libplist++-dev python-dev libssl-dev libusb-1.0-0-dev libfuse-dev
174 |
175 | Get source:
176 |
177 | mkdir -p ~/usr/src
178 | cd ~/usr/src
179 | for x in libplist libusbmuxd usbmuxd libimobiledevice ifuse; do git clone https://github.com/libimobiledevice/${x}.git;done
180 |
181 | Build sources (order matters):
182 |
183 | cd ~/usr/src/libplist
184 | ./autogen.sh --prefix="$HOME/usr"
185 | make && make install
186 | cd ~/usr/src/libusbmuxd
187 | ./autogen.sh --prefix="$HOME/usr"
188 | make && make install
189 | cd ~/usr/src/libimobiledevice
190 | ./autogen.sh --prefix="$HOME/usr"
191 | make && make install
192 | cd ~/usr/src/usbmuxd
193 | ./autogen.sh --prefix="$HOME/usr"
194 | make && sudo make install
195 |
196 | Can't paste subsequent lines with the first block because it'll give subsequent lines as pw attempts to `sudo`.
197 |
198 | cd ~/usr/src/ifuse
199 | ./autogen.sh --prefix="$HOME/usr"
200 | make && make install
201 |
202 | Verify `ifuse` and `idevicepair` resolve to your new versions in `~/usr/bin/`:
203 |
204 | type -P ifuse # should be /home/pi/usr/bin/ifuse
205 | type -P idevicepair # should be /home/pi/usr/bin/idevicepair
206 |
207 |
208 | **REBOOT**
209 |
210 | We're finished installing the necessary software.
211 |
212 |
213 | # 2. Plug, pair, and mount iPhone
214 |
215 | Tips:
216 |
217 | - If any of these steps fail, consider restarting `usbmuxd` and `udev` like so:
218 |
219 | sudo service usbmuxd restart
220 | sudo service udev restart
221 |
222 | - Normally, the `usbmuxd` service isn't started on boot: `sudo service usbmuxd status` shows `Active: inactive (dead)`. However, once you plug in the phone, `sudo service usbmuxd status` will show
223 |
224 | (python3) pi@rpi01:~ $ sudo service usbmuxd status
225 | ● usbmuxd.service - Socket daemon for the usbmux protocol used by Apple devices
226 | Loaded: loaded (/lib/systemd/system/usbmuxd.service; static; vendor preset: enabled)
227 | Active: active (running) since Wed 2018-07-04 07:40:06 PDT; 4s ago
228 | Docs: man:usbmuxd(8)
229 | Main PID: 968 (usbmuxd)
230 | CGroup: /system.slice/usbmuxd.service
231 | └─968 /home/pi/usr/sbin/usbmuxd --user usbmux --systemd
232 |
233 |
234 |
235 | ## 2a. Plug in phone
236 |
237 | Plug the iPhone into the RPi's USB port. (Note the RPi Zero has micro-USB ports for both power and data; plug the phone into the data port.)
238 |
239 | Running `dmesg` shows the USB driver at least recognizes it:
240 |
241 | (python3) pi@rpi01:~ $ dmesg -wH
242 | [Jul 4 07:43] dwc_otg_handle_wakeup_detected_intr lxstate = 2
243 | [ +0.506597] usb 1-1.3: new high-speed USB device number 3 using dwc_otg
244 | [ +0.133126] usb 1-1.3: New USB device found, idVendor=05ac, idProduct=12a8
245 | [ +0.000025] usb 1-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
246 | [ +0.000012] usb 1-1.3: Product: iPhone
247 | [ +0.000010] usb 1-1.3: Manufacturer: Apple Inc.
248 | [ +0.000010] usb 1-1.3: SerialNumber: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
249 | [ +0.258682] ipheth 1-1.3:4.2: Apple iPhone USB Ethernet device attached
250 | [ +0.011945] usbcore: registered new interface driver ipheth
251 | [ +0.348555] IPv6: ADDRCONF(NETDEV_UP): eth0: link is not ready
252 |
253 | Unlock the phone and wait 10-20 secs for the phone to ask you to Trust the computer. Click "Trust" on the phone and enter passcode (or `idevicepair pair` will fail).
254 |
255 | ## 2b. Pair phone to RPi
256 |
257 | (python3) pi@rpi01:~ $ idevicepair pair
258 | SUCCESS: Paired with device XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
259 |
260 | ## 2c. Mount phone's files on RPi
261 |
262 | We'll mount the iphone at `~/usr/mnt`.
263 |
264 | mkdir -p ~/usr/mnt
265 | ifuse ~/usr/mnt
266 |
267 | Now the iPhone's files are mounted:
268 |
269 | (python3) pi@rpi01:~ $ ls ~/usr/mnt
270 | AirFair CloudAssets Downloads LoFiCloudAssets PhotoData Podcasts Purchases Recordings Vibrations
271 | Books DCIM iTunes_Control MediaAnalysis Photos PublicStaging Radio Safari
272 |
273 | ## 2d. Back up phone to RPi
274 |
275 | mkdir ~/iphone-backups
276 | rsync -v -a ~/usr/mnt ~/iphone-backups
277 |
278 | ## 2e. Unmount, Unpair, Unplug
279 |
280 | fusermount -u ~/usr/mnt
281 | idevicepair --debug unpair
282 |
283 |
284 |
285 |
286 |
287 | # 3. Run the backup script
288 |
289 | The file `/home/pi/backup-iphone.py` contains a Python3 script that detects the phone with `lsusb`, pairs the phone to the RPi with `idevicepair pair`, mounts it with `ifuse` to `/home/pi/usr/mnt/`, and copies everything (or, everything that `libimobiledevice` makes availble) to the RPi's micro-SD card at `/home/pi/iphone-backups/` with `rsync`.
290 |
291 | (Verify `backup-iphone.py` is executable.)
292 |
293 | Run `/home/pi/backup-iphone.sh`, which calls the Python script `backup-iphone.py`, and watch its logfile with `tail -f /home/pi/log.txt`.
294 |
295 |
296 | # 4. Configure udev to run the backup script upon the phone plug-in event
297 |
298 | Now we configure the RPi to run the `backup-iphone.sh` script whenever the phone plugs into the RPi.
299 |
300 | Raspbian Linux currently (July 2018) uses the `udev` system (a part of the `systemd` init system) to run user scripts when users plug in hardware devices.
301 |
302 |
303 | ## 4a. udev example
304 |
305 | When you plug in the phone, the `udev` system runs all its "rule" files in `/lib/udev/rules.d` (for system rules) and `/etc/udev/rules.d` (for user-supplied rules) and finds the file
306 |
307 | /lib/udev/rules.d/39-usbmuxd.rules
308 |
309 | which contains the line
310 |
311 | SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*", ACTION=="add", ENV{USBMUX_SUPPORTED}="1", ATTR{bConfigurationValue}="0", OWNER="usbmux", ENV{SYSTEMD_WANTS}="usbmuxd.service"
312 |
313 | which specifes that when the iPhone's product number is added (`lsusb` shows the phone's `vendorId:productId` as `05ac:12a8`), `systemd` should execute the file
314 |
315 | /lib/systemd/system/usbmuxd.service
316 |
317 | which contains the line
318 |
319 | ExecStart=/home/pi/usr/sbin/usbmuxd --user usbmux --systemd
320 |
321 | which is the command to run the `usbmuxd` daemon. Wow!
322 |
323 |
324 | ## 4b. Set up our own udev rule to run backup script upon plug-in
325 |
326 | Make a new `udev` rules file
327 |
328 | /etc/udev/rules.d/lol.rules
329 |
330 | that contains
331 |
332 | SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*", ACTION=="add", RUN+="/bin/bash /home/pi/udev-runs-this.sh"
333 |
334 | Ensure `/home/pi/udev-runs-this.sh` is executable.
335 |
336 | Restart the `udev` daemon so it picks up your new script:
337 |
338 | sudo service udev restart
339 | sudo service usbmuxd restart # for good measure
340 |
341 | Now, when the phone is plugged in, `udev` runs `/home/pi/udev-runs-this.sh`, which contains the line
342 |
343 | echo "/bin/su -c '/home/pi/backup-iphone.sh >> /home/pi/log.txt 2>&1' pi" | at now
344 |
345 | which runs the `backup-iphone.sh` script as the `pi` user.
346 |
347 |
348 | Notes:
349 |
350 | - By default the udev task is run w/ some weird user/group, so we use `su` to run `backup-iphone.sh` as the normal user `pi`. If you forget this, rsync will give weird user/group permissions to your backed-up files and even the mount folder `~/usr/mnt` will have weird permissions.
351 |
352 | - The `| at now` is a workaround for the requirement that `udev` jobs must exit quickly so as not to slow down the `udev` system. Since our backup script may run a long time, we disconnect it from `udev` by piping it to `at` which starts it in a separate (non-child?) process.
353 |
354 | - **Important**: `at` isn't in Raspbian by default so you should install it:
355 |
356 | sudo apt-get install at
357 |
358 |
359 |
360 | # 5. Ensuring `udev` is configured correctly at boot
361 |
362 | There is some problem with `usbmuxd` and `udev` not initializing after a reboot: you have to `sudo service udev restart` or the udev script `/etc/udev/rules.d/lol.rules` will fail when you plug your phone in, logging to `journalctl -f` the error
363 |
364 | Jul 07 12:34:53 rpi01 systemd-udevd[1078]: Process '/bin/bash /home/pi/udev-runs-this.sh' failed with exit code 1.
365 |
366 | To get around this, add the line
367 |
368 | service udev restart
369 | service usbmuxd restart
370 |
371 | to
372 |
373 | /etc/rc.local
374 |
375 | which causes `systemd` to restart `udev` and `usbmuxd` after every change in runlevel. This is probably overkill, but it ensures `udev` and `usbmuxd` are running correctly after a reboot. The alternative is sshing in and running `sudo service udev restart` (and also for `usbmuxd`) after a reboot manually -- ugh.
376 |
377 |
378 |
379 | # 6. Indicate progress with Blinkt LEDs
380 |
381 |
382 |
383 | Buy LED strip from Adafruit:
384 |
385 | Install Blinkt: run `home/pi/blinkt.sh` from this repo, or download it yourself:
386 |
387 | curl https://get.pimoroni.com/blinkt | bash
388 |
389 | Test: Set 0th LED to white (RGB=255,255,255), brightness=.1 (0 to 1)
390 |
391 | python2 -c 'from blinkt import set_pixel, show, clear ; import time ; set_pixel(0,255,255,255,.1) ; show() ; time.sleep(2) ; clear()'
392 |
393 | Note: Brightness has only 32 possible values, so setting brightness to anything below `1/32 = 0.03125` rounds it to 0 and turns it off.
394 |
395 |
396 |
397 |
398 |
399 | # Appendix: Troubleshooting
400 |
401 | ## Build error "No package 'libusbmuxd-2.0' found" (or libplist) when building idevicepair
402 |
403 | Running
404 |
405 | pi@rpi42:~/usr/src/libusbmuxd $ ./autogen.sh
406 |
407 | produces error:
408 |
409 | configure: error: Package requirements (libusbmuxd-2.0 >= 2.0.2) were not met:
410 |
411 | No package 'libusbmuxd-2.0' found
412 |
413 | Consider adjusting the PKG_CONFIG_PATH environment variable if you
414 | installed software in a non-standard prefix.
415 |
416 |
417 | This doesn't fix it:
418 |
419 | PKG_CONFIG_PATH=/home/pi/usr/lib/pkgconfig:/usr/lib/arm-linux-gnueabihf/pkgconfig: ./autogen.sh --prefix="$HOME/usr"
420 |
421 | This fixes it (was missing `libplist`!)
422 |
423 | for x in libplist libusbmuxd usbmuxd libimobiledevice ifuse; do git clone https://github.com/libimobiledevice/${x}.git;done
424 |
425 | Then later, build `libplist`:
426 |
427 | cd ~/usr/src/libplist
428 | ./autogen.sh --prefix="$HOME/usr"
429 | make && make install
430 |
431 |
432 | ## usbmuxd should've installed these
433 |
434 | The `.rules` file that `udev` runs upon iphone plug-in:
435 |
436 | (python3) pi@rpi01:~ $ cat /lib/udev/rules.d/39-usbmuxd.rules
437 | # usbmuxd (Apple Mobile Device Muxer listening on /var/run/usbmuxd)
438 |
439 | # systemd should receive all events relating to device
440 | SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*", TAG+="systemd"
441 |
442 | # Initialize iOS devices into "deactivated" USB configuration state and activate usbmuxd
443 | SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*", ACTION=="add", ENV{USBMUX_SUPPORTED}="1", ATTR{bConfigurationValue}="0", OWNER="usbmux", ENV{SYSTEMD_WANTS}="usbmuxd.service"
444 |
445 | # Make sure properties don't get lost when bind action is called
446 | SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*", ACTION=="bind", ENV{USBMUX_SUPPORTED}="1", OWNER="usbmux", ENV{SYSTEMD_WANTS}="usbmuxd.service"
447 |
448 | # Exit usbmuxd when the last device is removed
449 | SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*", ACTION=="remove", RUN+="/home/pi/usr/sbin/usbmuxd -x"
450 |
451 | Note the line `ENV{SYSTEMD_WANTS}="usbmuxd.service"`, which tells `systemd` to run:
452 |
453 | (python3) pi@rpi01:~ $ cat /lib/systemd/system/usbmuxd.service
454 | [Unit]
455 | Description=Socket daemon for the usbmux protocol used by Apple devices
456 | Documentation=man:usbmuxd(8)
457 |
458 | [Service]
459 | ExecStart=/home/pi/usr/sbin/usbmuxd --user usbmux --systemd
460 | PIDFile=/home/pi/usr/var/run/usbmuxd.pid
461 |
462 |
463 |
464 | ## debug usbmuxd with -vvv
465 |
466 |
467 |
468 | sudo /usr/local/sbin/usbmuxd -u -U usbmux -vvv -f
469 |
470 | Or: add `-vvv` to the `systemd` service that runs `usbmuxd`:
471 |
472 |
473 | (python3) pi@rpi01:~ $ cat /lib/systemd/system/usbmuxd.service
474 | [Unit]
475 | Description=Socket daemon for the usbmux protocol used by Apple devices
476 | Documentation=man:usbmuxd(8)
477 |
478 | [Service]
479 | ExecStart=/home/pi/usr/sbin/usbmuxd --user usbmux --systemd -vvv
480 | PIDFile=/home/pi/usr/var/run/usbmuxd.pid
481 |
482 | Now `usbmuxd` runs verbosely:
483 |
484 |
485 | (python3) pi@rpi01:~ $ sudo service usbmuxd start
486 | (python3) pi@rpi01:~ $ service usbmuxd status
487 | ● usbmuxd.service - Socket daemon for the usbmux protocol used by Apple devices
488 | Loaded: loaded (/lib/systemd/system/usbmuxd.service; static; vendor preset: enabled)
489 | Active: active (running) since Sat 2018-07-07 10:09:00 PDT; 6s ago
490 | Docs: man:usbmuxd(8)
491 | Main PID: 2291 (usbmuxd)
492 | CGroup: /system.slice/usbmuxd.service
493 | └─2291 /home/pi/usr/sbin/usbmuxd --user usbmux --systemd -vvv
494 |
495 |
496 | ## "libimobiledevice.so not found" error
497 |
498 | The `LD_LIBRARY_PATH` environment variable should include `/home/pi/usr/lib/`. I fixed this by putting the line
499 |
500 | export LD_LIBRARY_PATH=/home/pi/usr/lib
501 |
502 | in `backup-iphone.sh`.
503 |
504 |
505 | ## "idevicepair: command not found" error
506 |
507 | Probably `/home/pi/usr/bin` is not in the `PATH`. I fixed this by putting
508 |
509 | export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/home/pi/usr/bin
510 |
511 | in `backup-iphone.sh`.
512 |
513 | I suspect the problem occurred because my `udev-runs-this.sh` wasn't using `su pi` to run the script. Also I think there's an option to `su` to run the cmd from a login shell, which should execute `pi`'s `.bashrc` file, which we defined the env vars in earlier.
514 |
515 | ## Other "not found" or "no device or filename" errors
516 |
517 | Debug tip: in `backup-iphone.sh` and `udev-runs-this.sh`, dump ENV to log, see what user, `PATH`, `LD_LIBRARY_PATH` you have:
518 |
519 | env >> /home/pi/log.txt
520 |
521 |
522 | ## Phone doesn't charge when plugged in to RPi
523 |
524 | Problem: iphone buzzes twice and appears to not be charging. It's like it tries to negotiate with the rpi but fails so disconnects entirely.
525 |
526 | Solution: from `sudo service usbmuxd status`, it said it couldn't find a usbmux user. I apt-get installed usbmuxd to force the creation of the user, then apt-get removed it and built it again from source.
527 |
528 |
529 | ## test that udev would run `udev-runs-this.sh`
530 |
531 | Check that udev will run the `udev-runs-this.sh` script:
532 |
533 | Plug in phone
534 |
535 | sudo udevadm test --action="add" /sys/devices/platform/soc/20980000.usb/usb1/1-1/
536 |
537 | Note: look at `journalctl -f` or `udevadm monitor -kup` when you plug in the phone to find this weird `/sys/devices/...` location where the sysfs entry for the phone lives.
538 |
539 | Verify your udev rule appears:
540 |
541 | Reading rules file: /lib/udev/rules.d/10-local-rpi.rules
542 | ...
543 | Reading rules file: /etc/udev/rules.d/lol.rules <-------- this line should be there
544 | ...
545 | run: '/bin/bash /home/pi/udev-runs-this.sh' <------ this too
546 | ...
547 |
548 | If these are present, `udev` should execute the `udev-runs-this.sh` script.
549 |
550 |
551 | ## Lots of usbmuxd clients?
552 |
553 | Seems like lots clients connecting to usbmuxd. Can't tell which one is pairing w phone after my script stops.
554 |
555 |
556 |
557 | # Appendix: Notes and Resources
558 |
559 |
560 | - https://hackaday.com/2009/09/18/how-to-write-udev-rules/
561 | - https://askubuntu.com/questions/581810/iphone-does-not-unmount-properly-when-unplugged
562 | - https://github.com/libimobiledevice/usbmuxd/issues/26
563 | - https://raspberrypi.stackexchange.com/questions/19600/is-there-a-way-to-automatically-activate-a-script-when-a-usb-device-connects
564 | - https://unix.stackexchange.com/questions/28548/how-to-run-custom-scripts-upon-usb-device-plug-in
565 |
566 |
567 |
568 |
569 |
570 |
571 |
572 |
573 | "Usbmuxd do not start when iOS device connected to USB port (udev rule added as 39-usbmuxd.rules in /lib/udev/rules.d)
574 | usbmuxd recompiled with --without-systemd fixed the issue"
575 |
576 |
577 | Let's see if that's the case for us.
578 |
579 |
580 | looks like `service usbmuxd status` shows it running after plugin phone.
581 |
582 |
583 |
584 |
585 | "1.Script was not running because it needed sudo rights to run.."
586 |
587 | pi ALL=(ALL) NOPASSWD: /home/pi/my_script.sh
588 |
589 |
590 |
591 |
592 | You'll need 5 (five) files for such a USB device as follows, simply filling in respective values :
593 |
594 | /etc/udev/rules.d/00-usb-.rules
595 |
596 | ACTION=="add", ATTRS{idVendor}=="", ATTRS{idProduct}=="", ENV{XAUTHORITY}="/home//.Xauthority", ENV{DISPLAY}=":0", OWNER="", RUN+="/usr/local/bin/usb--in_udev"
597 | ACTION=="remove", ATTRS{idVendor}=="", ATTRS{idProduct}=="", ENV{XAUTHORITY}="/home//.Xauthority", ENV{DISPLAY}=":0", OWNER="", RUN+="/usr/local/bin/usb--out_udev"
598 |
599 | (... 4 other files)
600 |
601 |
602 |
603 |
604 | Start by finding your device in lsusb. Note the ID (eg 0a81:0101)
605 |
606 | Create a new udev rules file in /etc/udev/rules.d/ via sudoedit /etc/udev/rules.d/100-mount-videos.rulesand plonk a new rule in there like this:
607 |
608 | ACTION=="add", ATTRS{idVendor}=="0a81", ATTRS{idProduct}=="0101", RUN+="/home/your_username/bin/mount_videos.sh"
609 |
610 | A simple mount command should work. You might need a sleep 5 command in there to wait for the filesystem to initialize
611 |
612 | Addition from Allan: Long running scripts might block "all further events for this or a dependent device". My Mint man page further states "Long running tasks need to be immediately detached from the event process itself." No tip is given on where to gain the skill to do this.
613 |
614 |
615 | Or `systemd`:
616 |
617 |
618 | There's much nicer solution with systemd now. You create a service which depends and is wanted by you media e.g.: /etc/systemd/system/your.service
619 |
620 | [Unit]
621 | Description=My flashdrive script trigger
622 | Requires=media-YourMediaLabel.mount
623 | After=media-YourMediaLabel.mount
624 |
625 | [Service]
626 | ExecStart=/home/you/bin/triggerScript.sh
627 |
628 | [Install]
629 | WantedBy=media-YourMediaLabel.mount
630 |
631 | Then you have to start/enable the service:
632 |
633 | sudo systemctl start your.service
634 | sudo systemctl enable your.service
635 |
636 | After mount systemd fires your trigger script. The advantage over udev rule is that the script really fires after mount, not after adding system device.
637 |
638 | Use case: I have a crypted partition which I want to backup automatically. After adding the device I have to type-in password. If I hooked the backup script to udev, the script attempts to run at the time when I'm typing password, which will fail.
639 |
640 | Resource: Scripting with udev
641 |
642 | Note: You can find your device unit with:
643 |
644 | sudo systemctl list-units -t mount
645 |
646 |
647 |
648 |
649 |
650 | These udev rules seem to have been installed in my own system in
651 |
652 | /lib/udev/rules.d/39-usbmuxd.rules
653 |
654 |
655 | # usbmuxd (Apple Mobile Device Muxer listening on /var/run/usbmuxd)
656 |
657 | # systemd should receive all events relating to device
658 | SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*", TAG+="systemd"
659 |
660 | # Initialize iOS devices into "deactivated" USB configuration state and activate usbmuxd
661 | SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*", ACTION=="add", ENV{USBMUX_SUPPORTED}="1", ATTR{bConfigurationValue}="0", OWNER="usbmux", @udev_activation_rule@
662 |
663 | # Make sure properties don't get lost when bind action is called
664 | SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*", ACTION=="bind", ENV{USBMUX_SUPPORTED}="1", OWNER="usbmux", @udev_activation_rule@
665 |
666 | # Exit usbmuxd when the last device is removed
667 | SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*", ACTION=="remove", RUN+="@sbindir@/usbmuxd -x"
668 |
669 |
670 |
671 |
672 |
673 | - this post was written before systemd took over
674 |
675 | Ok, I have a workaround/fix. On line 206, right before the usb_discover call, I insert sleep(5):
676 | http://cgit.sukimashita.com/usbmuxd.git/tree/src/main.c?id=1dc5437d7c25df26368dcce8db75785eb48ec6aa#n206
677 |
678 | This delays usb_discover until after the new client is detected, and everything works. This doesn't feel like the "proper" fix, but it works for now.
679 |
680 | My distribution: Ubuntu 14.04 LTS (Trusty)
681 |
682 |
683 | FYI: even a sleep(1) appears to be sufficient.
684 |
685 | someone else:
686 |
687 | I'm using systemd (required by gnome 3). On gentoo the usbmuxd package does not install any .service files.
688 |
689 |
690 | - this is strange because the install process claimed it would install systemd service rules:
691 |
692 |
693 |
694 | "Unfortunately, sudo make install is required because it needs to write to /lib/udev/rules.d and /lib/systemd/system."
695 |
696 |
697 |
698 |
699 |
700 | Tutorial:
701 |
702 | We will write our rule in the /etc/udev/rules.d/99-togglemouse.rules file with the help of our favorite text editor. A rule definition can span over multiple lines, but if that's the case, a backslash must be used before the newline character, as a line continuation, just as in shell scripts. Here is our rule:
703 |
704 | ACTION=="add" \
705 | , ATTRS{idProduct}=="c52f" \
706 | , ATTRS{idVendor}=="046d" \
707 | , ENV{DISPLAY}=":0" \
708 | , ENV{XAUTHORITY}="/run/user/1000/gdm/Xauthority" \
709 | , RUN+="/usr/bin/xinput --disable 16"
710 |
711 |
712 |
713 | systemd docs:
714 |
715 |
716 |
717 |
718 |
719 |
720 | This guy did it with systemd:
721 |
722 |
723 |
724 |
725 | A udev issue with usbmuxd:
726 |
727 |
728 |
729 |
730 |
731 |
732 |
733 | use `at now` because udev scripts are supposed to exit quickly; udev may kill them otherwise
734 |
735 |
736 |
737 | **Todo**
738 |
739 | - Light up LEDs to show me the status or errors during backup.
740 | - https://www.raspberrypi.org/forums/viewtopic.php?t=127336
741 | - https://www.jeffgeerling.com/blogs/jeff-geerling/controlling-pwr-act-leds-raspberry-pi
742 |
743 |
--------------------------------------------------------------------------------
/etc/motd:
--------------------------------------------------------------------------------
1 | ===================================
2 | ------------ HEY BUDDY ------------
3 |
4 | The RPi's time is not set right because I don't let it on the WAN.
5 |
6 | I added the command `service udev restart` to `/etc/rc.local` so that
7 | it runs after every change in runlevel, because I wanted it to run at
8 | reboot to avoid having to restart it myself upon bootup.
9 |
10 | Here was my previous solution (restart udev on reboot):
11 |
12 | After reboot, you have to `sudo service udev restart` or the udev
13 | script `/etc/udev/rules.d/lol.rules` will fail when you plug your
14 | phone in, logging the error
15 |
16 | Jul 07 12:34:53 rpi01 systemd-udevd[1078]: Process '/bin/bash
17 | /home/pi/udev-runs-this.sh' failed with exit code 1.
18 |
19 | to `journalctl -f` .
20 |
21 |
22 | --------- HAVE A NICE DAY ----------
23 | ====================================
24 |
25 |
--------------------------------------------------------------------------------
/etc/rc.local:
--------------------------------------------------------------------------------
1 | #!/bin/sh -e
2 | #
3 | # rc.local
4 | #
5 | # This script is executed at the end of each multiuser runlevel.
6 | # Make sure that the script will "exit 0" on success or any other
7 | # value on error.
8 | #
9 | # In order to enable or disable this script just change the execution
10 | # bits.
11 | #
12 | # By default this script does nothing.
13 |
14 | # Print the IP address
15 | _IP=$(hostname -I) || true
16 | if [ "$_IP" ]; then
17 | printf "My IP address is %s\n" "$_IP"
18 | fi
19 |
20 | service udev restart
21 |
22 | exit 0
23 |
--------------------------------------------------------------------------------
/etc/udev/rules.d/lol.rules:
--------------------------------------------------------------------------------
1 | # run a short little program when iphone plugged in
2 | SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*", ACTION=="add", ENV{SYSTEMD_WANTS}="usbmuxd.service", RUN+="/bin/bash /home/pi/udev-runs-this.sh"
3 |
4 | # Same, for when its unplugged:
5 | SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*", ACTION=="remove", ENV{SYSTEMD_WANTS}="usbmuxd.service", RUN+="/usr/bin/python3 -c 'from blinkt import set_all, show, clear; from time import sleep; set_all(255,255,255) ; show() ; sleep(1) ; clear() ; show()'"
6 |
--------------------------------------------------------------------------------
/home/pi/backup-iphone.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | print('Hello from backup-iphone.py!')
4 |
5 | import blinkt
6 | blinkt.set_clear_on_exit(False)
7 |
8 | import os, time, subprocess
9 | from datetime import datetime
10 |
11 | MOUNT_DIR = '/home/pi/usr/mnt' # Phone's filesystem appears here
12 | BACKUP_DIR_BASE = '/home/pi/iphone-backups' # We backup the phone to here
13 |
14 | ##############################################
15 |
16 | def main():
17 | print(f'{datetime.now()}: Welcome to backup-iphone.py!')
18 |
19 | if not os.path.isdir(BACKUP_DIR_BASE):
20 | print(f'No backup dir exists, creating {BACKUP_DIR_BASE} ...')
21 | os.mkdir(BACKUP_DIR_BASE)
22 |
23 | leds = LEDs()
24 | leds.test()
25 |
26 | print('Plugged in?')
27 | leds.run_task_with_lights(task = lambda: run_repeatedly(plug_in, is_plugged_in), led = 0)
28 |
29 | # Note: takes 10 sec upon plug-in for iOS to prompt for "Trust".
30 | print('Pairing...')
31 | leds.run_task_with_lights(task = lambda: run_repeatedly(pair, is_paired), led = 1)
32 |
33 | print('Mounting...')
34 | leds.run_task_with_lights(task = lambda: run_repeatedly(mount, is_mounted), led = 2)
35 |
36 | print('Backing up...')
37 | leds.run_task_with_lights(task = lambda: backup(), led = 3)
38 |
39 | print('Unmounting...')
40 | leds.run_task_with_lights(task = lambda: run_repeatedly(unmount, is_unmounted), led = 4)
41 |
42 | print('Unpairing...')
43 | leds.run_task_with_lights(task = lambda: run_repeatedly(unpair, is_unpaired), led = 5)
44 |
45 | print(f'{datetime.now()}: Bye from backup-iphone.sh!')
46 |
47 |
48 | #############################################
49 |
50 | def run(arg_list):
51 | print('Running:')
52 | print(arg_list)
53 | p = subprocess.run(
54 | arg_list,
55 | capture_output=True,
56 | universal_newlines=True
57 | )
58 | print(f'returncode: "{p.returncode}"')
59 | print(f'stdout: "{p.stdout}"')
60 | print(f'stderr: "{p.stderr}"')
61 |
62 | return p
63 |
64 | def run_repeatedly(f, check, imax=100, twait=2):
65 | '''
66 | Gonna run f() until check() returns true,
67 | up to imax times, pausing twait secs after each failure.
68 | '''
69 |
70 | if check():
71 | print(f'Check={check.__name__} succeeded without even running f={f.__name__} once!')
72 | return
73 |
74 | i=0
75 | while i <= imax:
76 | i += 1
77 | print(f'Running f={f.__name__}, attempt {i}/{imax}...')
78 | f()
79 | print(f'Checking {check.__name__}...')
80 | if check():
81 | print('Success!')
82 | return
83 | else:
84 | if i == imax:
85 | raise RuntimeError(f'{f.__name__} failed {imax} times! Bailing.')
86 | else:
87 | print(f'Failed. Sleeping for {twait} secs...')
88 | time.sleep(twait)
89 | raise RuntimeError("Exceeded imax! Shouldn't get here!")
90 |
91 | def plug_in():
92 | print('Please plug in your phone!')
93 |
94 | def is_plugged_in():
95 | p = run(['/usr/bin/lsusb'])
96 | return 'iPad' in p.stdout or 'iPhone' in p.stdout
97 |
98 | def pair():
99 | print('Pairing...')
100 | run(['/home/pi/usr/bin/idevicepair','pair'])
101 |
102 | def is_paired():
103 | return len(paired_devices()) > 0
104 |
105 | def paired_devices():
106 | p = run(['/home/pi/usr/bin/idevicepair','list'])
107 | devs = [d.strip() for d in p.stdout.split() if len(d.strip())>0]
108 | return devs
109 |
110 | def backup():
111 | sn = phone_serial_number()
112 | print(f'Found phone serial number: {sn}')
113 | backup_dir = os.path.join(BACKUP_DIR_BASE, sn)
114 | if not os.path.isdir(backup_dir):
115 | print(f'No backup path exists, creating {backup_dir} ...')
116 | os.mkdir(backup_dir)
117 | run(['/usr/bin/rsync', '-v', '-a', MOUNT_DIR, backup_dir])
118 |
119 | def mount():
120 | run(['/home/pi/usr/bin/ifuse', MOUNT_DIR])
121 |
122 | def is_mounted():
123 | return any(MOUNT_DIR+' ' in m for m in open('/proc/mounts','r').readlines())
124 |
125 | def unmount():
126 | run(['/bin/fusermount', '-u', MOUNT_DIR])
127 |
128 | def is_unmounted():
129 | return not is_mounted()
130 |
131 | def unpair():
132 | run(['/home/pi/usr/bin/idevicepair','unpair'])
133 |
134 | def is_unpaired():
135 | return not is_paired()
136 |
137 | def phone_serial_number():
138 | if not is_paired():
139 | raise RuntimeError("Uh oh - there's no paired devices, so I can't get the phone serial #!")
140 |
141 | devs = paired_devices()
142 |
143 | if len(devs) > 1:
144 | raise RuntimeError(f'Uh oh - multiple paired devices!: {devs}')
145 |
146 | return devs[0]
147 |
148 | ########################################
149 |
150 | class LEDs:
151 | '''
152 | When a task begins, set to BLUE.
153 | When a task completes, set to GREEN.
154 | If a task errors, set to RED.
155 | '''
156 |
157 | def run_task_with_lights(self, task, led):
158 | if led < 0 or led > 7:
159 | raise RuntimeError(f'Blinkt LED strip has only 8 LEDs, so led={led} should be 0,1,...,7!')
160 |
161 | self._begin_task(led)
162 | task()
163 | self._task_completed(led)
164 |
165 | def all_off(self):
166 | blinkt.clear()
167 | blinkt.show()
168 |
169 | def test(self):
170 | self.all_off()
171 | n_leds = 8
172 | colors = ['red', 'green', 'blue', 'white']
173 | for l in range(n_leds):
174 | for c in colors:
175 | if c == 'red':
176 | r = 255
177 | g = 0
178 | b = 0
179 | elif c == 'green':
180 | r = 0
181 | g = 255
182 | b = 0
183 | elif c == 'blue':
184 | r = 0
185 | g = 0
186 | b = 255
187 | elif c == 'white':
188 | r = 255
189 | g = 255
190 | b = 255
191 | print(f'LED: {l}, color: {c}')
192 | blinkt.set_pixel(l, r, g, b, 0.07)
193 | blinkt.show()
194 | time.sleep(.01)
195 |
196 | for _ in range(3):
197 | blinkt.set_all(255,255,255)
198 | blinkt.show()
199 | time.sleep(.05)
200 | blinkt.set_all(0,0,0)
201 | blinkt.show()
202 | time.sleep(.05)
203 |
204 | self.all_off()
205 |
206 | def _begin_task(self,i):
207 | blinkt.set_pixel(i, 0, 0, 255, 0.07)
208 | blinkt.show()
209 |
210 | def _task_completed(self,i):
211 | blinkt.set_pixel(i, 0, 255, 0, 0.07)
212 | blinkt.show()
213 |
214 | def _task_errored(self,i):
215 | blinkt.set_pixel(i, 255, 0, 0, 0.07)
216 | blinkt.show()
217 |
218 |
219 | if __name__ == '__main__':
220 | main()
221 |
--------------------------------------------------------------------------------
/home/pi/backup-iphone.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | echo "$(date) : Welcome to backup-iphone.sh"
4 |
5 | export SHELL=/bin/bash
6 | export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/home/pi/usr/bin
7 | export LD_LIBRARY_PATH=/home/pi/usr/lib
8 |
9 | echo "Running backup-iphone.py..."
10 |
11 | # -u: stdout & stderr are unbuffered. Else our tail -f isn't real-time.
12 | python3 -u /home/pi/backup-iphone.py >> /home/pi/log.txt 2>&1
13 |
14 | echo "$(date) : goodbye from backup-iphone.sh"
15 |
--------------------------------------------------------------------------------
/home/pi/blinkt.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | : <<'DISCLAIMER'
4 |
5 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
6 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
7 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
8 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
9 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
10 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
11 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
12 | OTHER DEALINGS IN THE SOFTWARE.
13 |
14 | This script is licensed under the terms of the MIT license.
15 | Unless otherwise noted, code reproduced herein
16 | was written for this script.
17 |
18 | - The Pimoroni Crew -
19 |
20 | DISCLAIMER
21 |
22 | # script control variables
23 |
24 | productname="Blinkt!" # the name of the product to install
25 | scriptname="blinkt" # the name of this script
26 | spacereq=50 # minimum size required on root partition in MB
27 | debugmode="no" # whether the script should use debug routines
28 | debuguser="none" # optional test git user to use in debug mode
29 | debugpoint="none" # optional git repo branch or tag to checkout
30 | forcesudo="no" # whether the script requires to be ran with root privileges
31 | promptreboot="no" # whether the script should always prompt user to reboot
32 | mininstall="no" # whether the script enforces minimum install routine
33 | customcmd="no" # whether to execute commands specified before exit
34 | gpioreq="yes" # whether low-level gpio access is required
35 | i2creq="no" # whether the i2c interface is required
36 | i2sreq="no" # whether the i2s interface is required
37 | spireq="no" # whether the spi interface is required
38 | uartreq="no" # whether uart communication is required
39 | armhfonly="yes" # whether the script is allowed to run on other arch
40 | armv6="yes" # whether armv6 processors are supported
41 | armv7="yes" # whether armv7 processors are supported
42 | armv8="yes" # whether armv8 processors are supported
43 | raspbianonly="no" # whether the script is allowed to run on other OSes
44 | osreleases=( "Raspbian" "Kano" "Mate" "PiTop" "RetroPie" ) # list os-releases supported
45 | oswarning=( "Kali" "OSMC" "Volumio" ) # list experimental os-releases
46 | osdeny=( "Darwin" "Debian" "Linaro" "Ubuntu" ) # list os-releases specifically disallowed
47 | debpackage="blinkt" # the name of the package in apt repo
48 | piplibname="blinkt" # the name of the lib in pip repo
49 | pipoverride="no" # whether the script should give priority to pip repo
50 | pip2support="yes" # whether python2 is supported
51 | pip3support="yes" # whether python3 is supported
52 | topdir="Pimoroni" # the name of the top level directory
53 | localdir="blinkt" # the name of the dir for copy of resources
54 | gitreponame="blinkt" # the name of the git project repo
55 | gitusername="pimoroni" # the name of the git user to fetch repo from
56 | gitrepobranch="master" # repo branch to checkout
57 | gitrepotop="root" # the name of the dir to base repo from
58 | gitrepoclone="no" # whether the git repo is to be cloned locally
59 | gitclonedir="source" # the name of the local dir for repo
60 | repoclean="no" # whether any git repo clone found should be cleaned up
61 | repoinstall="no" # whether the library should be installed from repo
62 | libdir="library" # subdirectory of library in repo
63 | copydir=( "documentation" "examples" ) # subdirectories to copy from repo
64 | copyhead="no" # whether to use the latest repo commit or release tag
65 | pkgremove=() # list of conflicting packages to remove
66 | coredeplist=() # list of core dependencies
67 | pythondep=() # list of python dependencies
68 | pipdeplist=() # list of dependencies to source from pypi
69 | examplesdep=( "numpy" "psutil" "requests" "tweepy" ) # list of python modules required by examples
70 | somemoredep=() # list of additional dependencies
71 | xdisplaydep=() # list of dependencies requiring X server
72 |
73 | # template 1712181300
74 |
75 | FORCE=$1
76 | ASK_TO_REBOOT=false
77 | CURRENT_SETTING=false
78 | MIN_INSTALL=false
79 | FAILED_PKG=false
80 | REMOVE_PKG=false
81 | UPDATE_DB=false
82 |
83 | AUTOSTART=~/.config/lxsession/LXDE-pi/autostart
84 | BOOTCMD=/boot/cmdline.txt
85 | CONFIG=/boot/config.txt
86 | DTBODIR=/boot/overlays
87 | APTSRC=/etc/apt/sources.list
88 | INITABCONF=/etc/inittab
89 | BLACKLIST=/etc/modprobe.d/raspi-blacklist.conf
90 | LOADMOD=/etc/modules
91 |
92 | RASPOOL="http://mirrordirector.raspbian.org/raspbian/pool"
93 | RPIPOOL="http://archive.raspberrypi.org/debian/pool"
94 | DEBPOOL="http://ftp.debian.org/debian/pool"
95 | GETPOOL="https://get.pimoroni.com"
96 |
97 | SMBUS2="python-smbus_3.1.1+svn-2_armhf.deb"
98 | SMBUS3="python3-smbus_3.1.1+svn-2_armhf.deb"
99 | SMBUS35="python3-smbus1_1.1+35dbg-1_armhf.deb"
100 |
101 | SPIDEV2="python-spidev_2.0~git20150907_armhf.deb"
102 | SPIDEV3="python3-spidev_2.0~git20150907_armhf.deb"
103 |
104 | RPIGPIO1="raspi-gpio_0.20170105_armhf.deb"
105 | RPIGPIO2="python-rpi.gpio_0.6.3~jessie-1_armhf.deb"
106 | RPIGPIO3="python3-rpi.gpio_0.6.3~jessie-1_armhf.deb"
107 |
108 | export PIP_FORMAT=legacy
109 |
110 | # function define
111 |
112 | confirm() {
113 | if [ "$FORCE" == '-y' ]; then
114 | true
115 | else
116 | read -r -p "$1 [y/N] " response < /dev/tty
117 | if [[ $response =~ ^(yes|y|Y)$ ]]; then
118 | true
119 | else
120 | false
121 | fi
122 | fi
123 | }
124 |
125 | prompt() {
126 | read -r -p "$1 [y/N] " response < /dev/tty
127 | if [[ $response =~ ^(yes|y|Y)$ ]]; then
128 | true
129 | else
130 | false
131 | fi
132 | }
133 |
134 | success() {
135 | echo -e "$(tput setaf 2)$1$(tput sgr0)"
136 | }
137 |
138 | inform() {
139 | echo -e "$(tput setaf 6)$1$(tput sgr0)"
140 | }
141 |
142 | warning() {
143 | echo -e "$(tput setaf 1)$1$(tput sgr0)"
144 | }
145 |
146 | newline() {
147 | echo ""
148 | }
149 |
150 | progress() {
151 | count=0
152 | until [ $count -eq 7 ]; do
153 | echo -n "..." && sleep 1
154 | ((count++))
155 | done;
156 | if ps -C $1 > /dev/null; then
157 | echo -en "\r\e[K" && progress $1
158 | fi
159 | }
160 |
161 | sudocheck() {
162 | if [ $(id -u) -ne 0 ]; then
163 | echo -e "Install must be run as root. Try 'sudo ./$scriptname'\n"
164 | exit 1
165 | fi
166 | }
167 |
168 | sysclean() {
169 | sudo apt-get clean && sudo apt-get autoclean
170 | sudo apt-get -y autoremove &> /dev/null
171 | }
172 |
173 | sysupdate() {
174 | if ! $UPDATE_DB; then
175 | echo "Updating apt indexes..." && progress apt-get &
176 | sudo apt-get update 1> /dev/null || { warning "Apt failed to update indexes!" && exit 1; }
177 | sleep 3 && UPDATE_DB=true
178 | fi
179 | }
180 |
181 | sysupgrade() {
182 | sudo apt-get upgrade
183 | sudo apt-get clean && sudo apt-get autoclean
184 | sudo apt-get -y autoremove &> /dev/null
185 | }
186 |
187 | sysreboot() {
188 | warning "Some changes made to your system require"
189 | warning "your computer to reboot to take effect."
190 | echo
191 | if prompt "Would you like to reboot now?"; then
192 | sync && sudo reboot
193 | fi
194 | }
195 |
196 | arch_check() {
197 | IS_ARMHF=false
198 | IS_ARMv6=false
199 |
200 | if uname -m | grep -q "armv.l"; then
201 | IS_ARMHF=true
202 | if uname -m | grep -q "armv6l"; then
203 | IS_ARMv6=true
204 | fi
205 | fi
206 | }
207 |
208 | os_check() {
209 | IS_MACOSX=false
210 | IS_RASPBIAN=false
211 | IS_SUPPORTED=false
212 | IS_EXPERIMENTAL=false
213 | OS_NAME="Unknown"
214 |
215 | if uname -s | grep -q "Darwin"; then
216 | OS_NAME="Darwin" && IS_MACOSX=true
217 | elif cat /etc/os-release | grep -q "Kali"; then
218 | OS_NAME="Kali"
219 | elif [ -d ~/.kano-settings ] || [ -d ~/.kanoprofile ]; then
220 | OS_NAME="Kano"
221 | elif whoami | grep -q "linaro"; then
222 | OS_NAME="Linaro"
223 | elif [ -d ~/.config/ubuntu-mate ];then
224 | OS_NAME="Mate"
225 | elif [ -d ~/.pt-os-dashboard ] || [ -d ~/.pt-dashboard ] || [ -f ~/.pt-dashboard-config ]; then
226 | OS_NAME="PiTop"
227 | elif command -v emulationstation > /dev/null; then
228 | OS_NAME="RetroPie"
229 | elif cat /etc/os-release | grep -q "OSMC"; then
230 | OS_NAME="OSMC"
231 | elif cat /etc/os-release | grep -q "volumio"; then
232 | OS_NAME="Volumio"
233 | elif cat /etc/os-release | grep -q "Raspbian"; then
234 | OS_NAME="Raspbian" && IS_RASPBIAN=true
235 | elif cat /etc/os-release | grep -q "Debian"; then
236 | OS_NAME="Debian"
237 | elif cat /etc/os-release | grep -q "Ubuntu"; then
238 | OS_NAME="Ubuntu"
239 | fi
240 |
241 | if [[ " ${osreleases[@]} " =~ " ${OS_NAME} " ]]; then
242 | IS_SUPPORTED=true
243 | fi
244 | if [[ " ${oswarning[@]} " =~ " ${OS_NAME} " ]]; then
245 | IS_EXPERIMENTAL=true
246 | fi
247 | }
248 |
249 | raspbian_check() {
250 | IS_SUPPORTED=false
251 | IS_EXPERIMENTAL=false
252 |
253 | if [ -f /etc/os-release ]; then
254 | if cat /etc/os-release | grep -q "/sid"; then
255 | IS_SUPPORTED=false && IS_EXPERIMENTAL=true
256 | elif cat /etc/os-release | grep -q "stretch"; then
257 | IS_SUPPORTED=true && IS_EXPERIMENTAL=false
258 | elif cat /etc/os-release | grep -q "jessie"; then
259 | IS_SUPPORTED=true && IS_EXPERIMENTAL=false
260 | elif cat /etc/os-release | grep -q "wheezy"; then
261 | IS_SUPPORTED=true && IS_EXPERIMENTAL=false
262 | else
263 | IS_SUPPORTED=false && IS_EXPERIMENTAL=false
264 | fi
265 | fi
266 | }
267 |
268 | home_dir() {
269 | if [ $EUID -ne 0 ]; then
270 | if $IS_MACOSX; then
271 | USER_HOME=$(dscl . -read /Users/$USER NFSHomeDirectory | cut -d: -f2)
272 | else
273 | USER_HOME=$(getent passwd $USER | cut -d: -f6)
274 | fi
275 | else
276 | warning "Running as root, please log in as a regular user with sudo rights!"
277 | echo && exit 1
278 | fi
279 | }
280 |
281 | space_chk() {
282 | if command -v stat > /dev/null && ! $IS_MACOSX; then
283 | if [ $spacereq -gt $(($(stat -f -c "%a*%S" /)/10**6)) ];then
284 | echo
285 | warning "There is not enough space left to proceed with installation"
286 | if confirm "Would you like to attempt to expand your filesystem?"; then
287 | curl -sS $GETPOOL/expandfs | sudo bash && exit 1
288 | else
289 | echo && exit 1
290 | fi
291 | fi
292 | fi
293 | }
294 |
295 | timestamp() {
296 | date +%Y%m%d-%H%M
297 | }
298 |
299 | check_network() {
300 | sudo ping -q -w 10 -c 1 8.8.8.8 | grep "received, 0" &> /dev/null && return 0 || return 1
301 | }
302 |
303 | launch_url() {
304 | check_network || (error_box "You don't appear to be connected to the internet, please check your connection and try again!" && exit 1)
305 | if command -v xdg-open > /dev/null; then
306 | xdg-open "$1" && return 0
307 | else
308 | error_box "There was an error attempting to launch your browser!"
309 | fi
310 | }
311 |
312 | get_install() {
313 | check_network || (error_box "You don't appear to be connected to the internet, please check your connection and try again!" && exit 1)
314 | if [ "$1" != diagnostic ];then
315 | sysupdate && UPDATE_DB=true
316 | fi
317 | if ! command -v curl > /dev/null; then
318 | apt_pkg_install "curl"
319 | fi
320 | curl -sS https://get.pimoroni.com/$1 | bash -s - "-y" $2
321 | read -p "Press Enter to continue..." < /dev/tty
322 | }
323 |
324 | apt_pkg_req() {
325 | APT_CHK=$(dpkg-query -W -f='${Status}\n' "$1" 2> /dev/null | grep "install ok installed")
326 |
327 | if [ "" == "$APT_CHK" ]; then
328 | echo "$1 is required"
329 | true
330 | else
331 | echo "$1 is already installed"
332 | false
333 | fi
334 | }
335 |
336 | apt_pkg_install() {
337 | echo "Installing $1..."
338 | sudo apt-get --yes install "$1" 1> /dev/null || { inform "Apt failed to install $1!\nFalling back on pypi..." && return 1; }
339 | }
340 |
341 | apt_deb_chk() {
342 | BEFORE=$(dpkg-query -W "$1" 2> /dev/null)
343 | sudo apt-get --yes install "$1" &> /dev/null || return 1
344 | AFTER=$(dpkg-query -W "$1" 2> /dev/null)
345 | if [ "$BEFORE" == "$AFTER" ]; then
346 | echo "$1 is already the newest version"
347 | else
348 | echo "$1 was successfully upgraded"
349 | fi
350 | }
351 |
352 | apt_deb_install() {
353 | echo "Installing $1..."
354 | if [[ "$1" != *".deb"* ]]; then
355 | sudo apt-get --yes install "$1" &> /dev/null || inform "Apt failed to install $1!\nFalling back on pypi..."
356 | dpkg-query -W -f='${Status}\n' "$1" 2> /dev/null | grep "install ok installed"
357 | else
358 | DEBDIR=`mktemp -d /tmp/pimoroni.XXXXXX`
359 | cd $DEBDIR
360 | wget "$GETPOOL/resources/$1" &> /dev/null
361 | sudo dpkg -i "$DEBDIR/$1" | grep "Installing $1"
362 | fi
363 | }
364 |
365 | pip_cmd_chk() {
366 | if command -v pip2 > /dev/null; then
367 | PIP2_BIN="pip2"
368 | elif command -v pip-2.7 > /dev/null; then
369 | PIP2_BIN="pip-2.7"
370 | elif command -v pip-2.6 > /dev/null; then
371 | PIP2_BIN="pip-2.6"
372 | else
373 | PIP2_BIN="pip"
374 | fi
375 | if command -v pip3 > /dev/null; then
376 | PIP3_BIN="pip3"
377 | elif command -v pip-3.3 > /dev/null; then
378 | PIP3_BIN="pip-3.3"
379 | elif command -v pip-3.2 > /dev/null; then
380 | PIP3_BIN="pip-3.2"
381 | fi
382 | }
383 |
384 | pip2_lib_req() {
385 | PIP2_CHK=$($PIP2_BIN list 2> /dev/null | grep -i "$1")
386 |
387 | if [ -z "$PIP2_CHK" ]; then
388 | true
389 | else
390 | false
391 | fi
392 | }
393 |
394 | pip3_lib_req() {
395 | PIP3_CHK=$($PIP3_BIN list 2> /dev/null | grep -i "$1")
396 |
397 | if [ -z "$PIP3_CHK" ]; then
398 | true
399 | else
400 | false
401 | fi
402 | }
403 |
404 | usb_max_power() {
405 | if grep -q "^max_usb_current=1$" $CONFIG; then
406 | echo -e "\nMax USB current setting already active"
407 | else
408 | echo -e "\nAdjusting USB current setting in $CONFIG"
409 | echo "max_usb_current=1" | sudo tee -a $CONFIG &> /dev/null
410 | fi
411 | }
412 |
413 | add_dtoverlay() {
414 | if grep -q "^dtoverlay=$1" $CONFIG; then
415 | echo -e "\n$1 overlay already active"
416 | elif grep -q "^#dtoverlay=$1" $CONFIG; then
417 | sudo sed -i "/^#dtoverlay=$1$/ s|#||" $CONFIG
418 | echo -e "\nAdding $1 overlay to $CONFIG"
419 | ASK_TO_REBOOT=true
420 | else
421 | echo "dtoverlay=$1" | sudo tee -a $CONFIG &> /dev/null
422 | echo -e "\nAdding $1 overlay to $CONFIG"
423 | ASK_TO_REBOOT=true
424 | fi
425 | }
426 |
427 | remove_dtoverlay() {
428 | sudo sed -i "/^dtoverlay=$1$/ s|^|#|" $CONFIG
429 | ASK_TO_REBOOT=true
430 | }
431 |
432 | enable_pi_audio() {
433 | if grep -q "#dtparam=audio=on" $CONFIG; then
434 | sudo sed -i "/^#dtparam=audio=on$/ s|#||" $CONFIG
435 | echo -e "\nsnd_bcm2835 loaded (on-board audio enabled)"
436 | ASK_TO_REBOOT=true
437 | fi
438 | }
439 |
440 | disable_pi_audio() {
441 | if grep -q "^dtparam=audio=on" $CONFIG; then
442 | sudo sed -i "/^dtparam=audio=on$/ s|^|#|" $CONFIG
443 | echo -e "\nsnd_bcm2835 unloaded (on-board audio disabled)"
444 | ASK_TO_REBOOT=true
445 | fi
446 | }
447 |
448 | test_audio() {
449 | echo
450 | if confirm "Do you wish to test your system now?"; then
451 | echo -e "\nTesting..."
452 | speaker-test -l5 -c2 -t wav
453 | fi
454 | }
455 |
456 | disable_pulseaudio() {
457 | sudo mv /etc/xdg/autostart/pulseaudio.desktop /etc/xdg/autostart/pulseaudio.disabled &> /dev/null
458 | pulseaudio -k &> /dev/null
459 | }
460 |
461 | kill_volumealsa() {
462 | sed -i "s|type=volumealsa|type=space|" $HOME/.config/lxpanel/LXDE/panels/panel &> /dev/null
463 | sed -i "s|type=volumealsa|type=space|" $HOME/.config/lxpanel/LXDE-pi/panels/panel &> /dev/null
464 | }
465 |
466 | basic_asound() {
467 | sudo echo -e "pcm.\041default {\n type hw\n card 1\n}" > $HOME/.asoundrc
468 | sudo echo -e "ctl.\041default {\n type hw\n card 1\n}" >> $HOME/.asoundrc
469 | sudo mv $HOME/.asoundrc /etc/asound.conf
470 | }
471 |
472 | config_set() {
473 | if [ -n $defaultconf ]; then
474 | sudo sed -i "s|$1=.*$|$1=$2|" $defaultconf
475 | else
476 | sudo sed -i "s|$1=.*$|$1=$2|" $3
477 | fi
478 | }
479 |
480 | servd_trig() {
481 | if command -v service > /dev/null; then
482 | sudo service $1 $2
483 | fi
484 | }
485 |
486 | get_init_sys() {
487 | if command -v systemctl > /dev/null && systemctl | grep -q '\-\.mount'; then
488 | SYSTEMD=1
489 | elif [ -f /etc/init.d/cron ] && [ ! -h /etc/init.d/cron ]; then
490 | SYSTEMD=0
491 | else
492 | echo "Unrecognised init system" && exit 1
493 | fi
494 | }
495 |
496 | i2c_vc_dtparam() {
497 | if [ -e $CONFIG ] && grep -q "^dtparam=i2c_vc=on$" $CONFIG; then
498 | echo -e "\ni2c0 bus already active"
499 | else
500 | echo -e "\nEnabling i2c0 bus in $CONFIG"
501 | echo "dtparam=i2c_vc=on" | sudo tee -a $CONFIG && echo
502 | fi
503 | }
504 |
505 | : <<'MAINSTART'
506 |
507 | Perform all variables declarations as well as function definition
508 | above this section for clarity, thanks!
509 |
510 | MAINSTART
511 |
512 | # intro message
513 |
514 | if [ $debugmode != "no" ]; then
515 | if [ $debuguser != "none" ]; then
516 | gitusername="$debuguser"
517 | fi
518 | if [ $debugpoint != "none" ]; then
519 | gitrepobranch="$debugpoint"
520 | fi
521 | inform "\nDEBUG MODE ENABLED"
522 | echo -e "git user $gitusername and $gitrepobranch branch/tag will be used\n"
523 | else
524 | echo -e "\nThis script will install everything needed to use\n$productname"
525 | if [ "$FORCE" != '-y' ]; then
526 | inform "\nAlways be careful when running scripts and commands copied"
527 | inform "from the internet. Ensure they are from a trusted source.\n"
528 | echo -e "If you want to see what this script does before running it,"
529 | echo -e "you should run: 'curl $GETPOOL/$scriptname'\n"
530 | fi
531 | fi
532 |
533 | # checks and init
534 |
535 | arch_check
536 | os_check
537 | space_chk
538 | home_dir
539 |
540 | if [ $debugmode != "no" ]; then
541 | echo "USER_HOME is $USER_HOME"
542 | echo "OS_NAME is $OS_NAME"
543 | echo "IS_SUPPORTED is $IS_SUPPORTED"
544 | echo "IS_EXPERIMENTAL is $IS_EXPERIMENTAL"
545 | echo
546 | fi
547 |
548 | if ! $IS_ARMHF; then
549 | warning "This hardware is not supported, sorry!"
550 | warning "Config files have been left untouched\n"
551 | exit 1
552 | fi
553 |
554 | if $IS_ARMv8 && [ $armv8 == "no" ]; then
555 | warning "Sorry, your CPU is not supported by this installer\n"
556 | exit 1
557 | elif $IS_ARMv7 && [ $armv7 == "no" ]; then
558 | warning "Sorry, your CPU is not supported by this installer\n"
559 | exit 1
560 | elif $IS_ARMv6 && [ $armv6 == "no" ]; then
561 | warning "Sorry, your CPU is not supported by this installer\n"
562 | exit 1
563 | fi
564 |
565 | if [ $raspbianonly == "yes" ] && ! $IS_RASPBIAN;then
566 | warning "This script is intended for Raspbian on a Raspberry Pi!\n"
567 | exit 1
568 | fi
569 |
570 | if $IS_RASPBIAN; then
571 | raspbian_check
572 | if ! $IS_SUPPORTED && ! $IS_EXPERIMENTAL; then
573 | warning "\n--- Warning ---\n"
574 | echo "The $productname installer"
575 | echo "does not work on this version of Raspbian."
576 | echo "Check https://github.com/$gitusername/$gitreponame"
577 | echo "for additional information and support" && echo
578 | exit 1
579 | fi
580 | fi
581 |
582 | if ! $IS_SUPPORTED && ! $IS_EXPERIMENTAL; then
583 | warning "Your operating system is not supported, sorry!\n"
584 | exit 1
585 | fi
586 |
587 | if $IS_EXPERIMENTAL; then
588 | warning "\nSupport for your operating system is experimental. Please visit"
589 | warning "forums.pimoroni.com if you experience issues with this product.\n"
590 | fi
591 |
592 | if [ $forcesudo == "yes" ]; then
593 | sudocheck
594 | fi
595 |
596 | if [ $uartreq == "yes" ]; then
597 | echo "Note: $productname requires UART communication"
598 | warning "The serial console will be disabled if you proceed!"
599 | fi
600 | if [ $spireq == "yes" ]; then
601 | echo -e "Note: $productname requires SPI communication"
602 | fi
603 | if [ $i2creq == "yes" ]; then
604 | echo -e "Note: $productname requires I2C communication"
605 | fi
606 | if [ $i2sreq == "yes" ]; then
607 | echo -e "Note: $productname uses the I2S interface"
608 | if [ $OS_NAME != "Volumio" ]; then
609 | warning "The on-board audio chip will be disabled if you proceed!"
610 | fi
611 | fi
612 |
613 | newline
614 | if confirm "Do you wish to continue?"; then
615 |
616 | # basic environment preparation
617 |
618 | echo -e "\nChecking environment..."
619 |
620 | if [ "$FORCE" != '-y' ]; then
621 | if ! check_network; then
622 | warning "We can't connect to the Internet, check your network!" && exit 1
623 | fi
624 | sysupdate && newline
625 | fi
626 |
627 | if apt_pkg_req "apt-utils" &> /dev/null; then
628 | apt_pkg_install "apt-utils"
629 | fi
630 | if ! command -v curl > /dev/null; then
631 | apt_pkg_install "curl"
632 | fi
633 | if ! command -v wget > /dev/null; then
634 | apt_pkg_install "wget"
635 | fi
636 |
637 | if [ "$pip2support" == "yes" ]; then
638 | if ! [ -f "$(which python2)" ]; then
639 | if confirm "Python 2 is not installed. Would like to install it?"; then
640 | progress apt-get &
641 | apt_pkg_install "python-pip"
642 | else
643 | pip2support="na"
644 | fi
645 | elif apt_pkg_req "python-pip" &> /dev/null; then
646 | progress apt-get &
647 | apt_pkg_install "python-pip"
648 | fi
649 | fi
650 | if [ "$pip3support" == "yes" ]; then
651 | if ! [ -f "$(which python3)" ]; then
652 | if prompt "Python 3 is not installed. Would like to install it?"; then
653 | progress apt-get &
654 | apt_pkg_install "python3-pip"
655 | else
656 | pip3support="na"
657 | fi
658 | elif apt_pkg_req "python3-pip" &> /dev/null; then
659 | progress apt-get &
660 | apt_pkg_install "python3-pip"
661 | fi
662 | fi
663 | pip_cmd_chk
664 |
665 | # hardware setup
666 |
667 | echo -e "\nChecking hardware requirements..."
668 |
669 | if [ $uartreq == "yes" ]; then
670 | echo -e "\nThe serial console must be disabled for $productname to work"
671 | curl -sS $GETPOOL/uarton | sudo bash -s - "-y" && ASK_TO_REBOOT=true
672 | fi
673 |
674 | if [ $gpioreq == "yes" ]; then
675 | echo -e "\nChecking for packages required for GPIO control..."
676 | if ! apt_pkg_install "raspi-gpio" &> /dev/null; then
677 | echo "package raspi-gpio can't be found, fetching from alternative location..."
678 | DEBDIR=`mktemp -d /tmp/pimoroni.XXXXXX` && cd $DEBDIR
679 | wget $RPIPOOL/main/r/raspi-gpio/$RPIGPIO1 &> /dev/null
680 | sudo dpkg -i $DEBDIR/$RPIGPIO1 && FAILED_PKG=false
681 | fi
682 | if [ "$pip2support" == "yes" ] && ! apt_pkg_install "python-rpi.gpio" &> /dev/null; then
683 | if [ -n $(python --version 2>&1 | grep -q "2.7") ]; then
684 | echo "package python-rpi.gpio can't be found, fetching from alternative location..."
685 | DEBDIR=`mktemp -d /tmp/pimoroni.XXXXXX` && cd $DEBDIR
686 | wget $RPIPOOL/main/r/rpi.gpio/$RPIGPIO2 &> /dev/null
687 | sudo dpkg -i $DEBDIR/$RPIGPIO2 && FAILED_PKG=false
688 | else
689 | sudo $PIP2_BIN install RPi.GPIO && FAILED_PKG=false
690 | fi
691 | fi
692 | if [ "$pip3support" == "yes" ] && ! apt_pkg_install "python3-rpi.gpio" &> /dev/null; then
693 | if [ -n $(python3 --version 2>&1 | grep -q "3.4") ]; then
694 | echo "package python3-rpi.gpio can't be found, fetching from alternative location..."
695 | DEBDIR=`mktemp -d /tmp/pimoroni.XXXXXX` && cd $DEBDIR
696 | wget $RPIPOOL/main/r/rpi.gpio/$RPIGPIO3 &> /dev/null
697 | sudo dpkg -i $DEBDIR/$RPIGPIO3 && FAILED_PKG=false
698 | else
699 | sudo $PIP3_BIN install RPi.GPIO && FAILED_PKG=false
700 | fi
701 | fi
702 | if [ "$pip2support" == "yes" ] && [ -f "$(which python2)" ]; then
703 | if ! $PIP2_BIN list | grep "RPi.GPIO" &> /dev/null; then
704 | warning "Unable to install RPi.GPIO for python 2!" && FAILED_PKG=true
705 | else
706 | RPIGPIO2="install ok installed"
707 | fi
708 | fi
709 | if [ "$pip3support" == "yes" ] && [ -f "$(which python3)" ]; then
710 | if ! $PIP3_BIN list | grep "RPi.GPIO" &> /dev/null; then
711 | warning "Unable to install RPi.GPIO for python 3!" && FAILED_PKG=true
712 | else
713 | RPIGPIO3="install ok installed"
714 | fi
715 | fi
716 | if [ "$RPIGPIO2" == "install ok installed" ] || [ "$RPIGPIO3" == "install ok installed" ]; then
717 | if ! $FAILED_PKG; then
718 | echo -e "RPi.GPIO installed and up-to-date"
719 | fi
720 | fi
721 | fi
722 |
723 | if [ $spireq == "yes" ]; then
724 | newline
725 | if ls /dev/spi* &> /dev/null; then
726 | inform "SPI already enabled"
727 | else
728 | echo "SPI must be enabled for $productname to work"
729 | if command -v raspi-config > /dev/null && sudo raspi-config nonint get_spi | grep -q "1"; then
730 | sudo raspi-config nonint do_spi 0
731 | inform "SPI is now enabled"
732 | else
733 | curl -sS $GETPOOL/spi | sudo bash -s - "-y" && ASK_TO_REBOOT=true
734 | fi
735 | fi
736 | echo -e "\nChecking packages required by SPI interface..."
737 | if [ "$pip2support" == "yes" ] && ! apt_pkg_install "python-spidev" &> /dev/null; then
738 | if [ -n $(python --version 2>&1 | grep -q "2.7") ]; then
739 | echo "package python-spidev can't be found, fetching from alternative location..."
740 | DEBDIR=`mktemp -d /tmp/pimoroni.XXXXXX` && cd $DEBDIR
741 | wget $RPIPOOL/main/s/spidev/$SPIDEV2 &> /dev/null
742 | sudo dpkg -i $DEBDIR/$SPIDEV2 && FAILED_PKG=false
743 | else
744 | sudo $PIP2_BIN install spidev && FAILED_PKG=false
745 | fi
746 | fi
747 | if [ "$pip3support" == "yes" ] && ! apt_pkg_install "python3-spidev" &> /dev/null; then
748 | if [ -n $(python3 --version 2>&1 | grep -q "3.4") ]; then
749 | echo "package python3-spidev can't be found, fetching from alternative location..."
750 | DEBDIR=`mktemp -d /tmp/pimoroni.XXXXXX` && cd $DEBDIR
751 | wget $RPIPOOL/main/s/spidev/$SPIDEV3 &> /dev/null
752 | sudo dpkg -i $DEBDIR/$SPIDEV3 && FAILED_PKG=false
753 | else
754 | sudo $PIP3_BIN install spidev && FAILED_PKG=false
755 | fi
756 | fi
757 | if [ "$pip2support" == "yes" ] && [ -f "$(which python2)" ]; then
758 | if ! $PIP2_BIN list | grep "spidev" &> /dev/null; then
759 | warning "Unable to install spidev for python 2!" && FAILED_PKG=true
760 | else
761 | SPIDEV2="install ok installed"
762 | fi
763 | fi
764 | if [ "$pip3support" == "yes" ] && [ -f "$(which python3)" ]; then
765 | if ! $PIP3_BIN list | grep "spidev" &> /dev/null; then
766 | warning "Unable to install spidev for python 3!" && FAILED_PKG=true
767 | else
768 | SPIDEV3="install ok installed"
769 | fi
770 | fi
771 | if [ "$SPIDEV2" == "install ok installed" ] || [ "$SPIDEV3" == "install ok installed" ]; then
772 | if ! $FAILED_PKG; then
773 | echo -e "spidev installed and up-to-date"
774 | fi
775 | fi
776 | fi
777 |
778 | if [ $i2creq == "yes" ]; then
779 | newline
780 | if ls /dev/i2c* &> /dev/null; then
781 | inform "I2C already enabled"
782 | else
783 | echo "I2C must be enabled for $productname to work"
784 | if command -v raspi-config > /dev/null && sudo raspi-config nonint get_i2c | grep -q "1"; then
785 | sudo raspi-config nonint do_i2c 0
786 | inform "I2C is now enabled"
787 | else
788 | curl -sS $GETPOOL/i2c | sudo bash -s - "-y" && ASK_TO_REBOOT=true
789 | fi
790 | fi
791 | echo -e "\nChecking packages required by I2C interface..."
792 | if [ "$pip2support" == "yes" ] && ! apt_pkg_install "python-smbus" &> /dev/null; then
793 | if [ -n $(python --version 2>&1 | grep -q "2.7") ]; then
794 | echo "package python-smbus can't be found, fetching from alternative location..."
795 | DEBDIR=`mktemp -d /tmp/pimoroni.XXXXXX` && cd $DEBDIR
796 | wget $RPIPOOL/main/i/i2c-tools/$SMBUS2 &> /dev/null
797 | sudo dpkg -i $DEBDIR/$SMBUS2 && FAILED_PKG=false
798 | fi
799 | fi
800 | if [ "$pip3support" == "yes" ] && ! apt_pkg_install "python3-smbus" &> /dev/null; then
801 | if [ -n $(python3 --version 2>&1 | grep -q "3.4") ]; then
802 | echo "package python3-smbus can't be found, fetching from alternative location..."
803 | DEBDIR=`mktemp -d /tmp/pimoroni.XXXXXX` && cd $DEBDIR
804 | wget $RPIPOOL/main/i/i2c-tools/$SMBUS3 &> /dev/null
805 | sudo dpkg -i $DEBDIR/$SMBUS3 && FAILED_PKG=false
806 | elif [ -n $(python3 --version 2>&1 | grep -q "3.5") ]; then
807 | if apt_pkg_req "python3-smbus1" &> /dev/null; then
808 | echo "package python3-smbus can't be found, fetching from alternative location..."
809 | DEBDIR=`mktemp -d /tmp/pimoroni.XXXXXX` && cd $DEBDIR
810 | wget $GETPOOL/resources/$SMBUS35 &> /dev/null
811 | sudo dpkg -i $DEBDIR/$SMBUS35 && FAILED_PKG=false
812 | fi
813 | fi
814 | fi
815 | if [ "$pip2support" == "yes" ] && [ -f "$(which python2)" ]; then
816 | if ! $PIP2_BIN list | grep "smbus" &> /dev/null; then
817 | warning "Unable to install smbus for python 2!" && FAILED_PKG=true
818 | else
819 | SMBUS2="install ok installed"
820 | fi
821 | fi
822 | if [ "$pip3support" == "yes" ] && [ -f "$(which python3)" ]; then
823 | if ! $PIP3_BIN list | grep "smbus" &> /dev/null; then
824 | warning "Unable to install smbus for python 3!" && FAILED_PKG=true
825 | else
826 | SMBUS3="install ok installed"
827 | fi
828 | fi
829 | if [ "$SMBUS2" == "install ok installed" ] || [ "$SMBUS3" == "install ok installed" ]; then
830 | if ! $FAILED_PKG; then
831 | echo -e "smbus installed and up-to-date"
832 | fi
833 | fi
834 | fi
835 |
836 | if [ $i2sreq == "yes" ]; then
837 | if [ -f /etc/asound.conf ]; then
838 | sudo rm -f /etc/asound.conf.backup &> /dev/null
839 | sudo mv /etc/asound.conf /etc/asound.conf.backup
840 | inform "existing config backed up to /etc/asound.conf.backup"
841 | fi
842 | if [ -f $HOME/.asoundrc ]; then
843 | sudo rm -f $HOME/.asoundrc.backup &> /dev/null
844 | sudo mv $HOME/.asoundrc $HOME/.asoundrc.backup
845 | inform "existing config backed up to ~/.asound.conf.backup"
846 | fi
847 | fi
848 |
849 | # minimum install routine
850 |
851 | if [ $mininstall != "yes" ] && [ $gitrepoclone != "yes" ]; then
852 | newline
853 | echo "$productname comes with examples and documentation that you may wish to install."
854 | echo "Performing a full install will ensure those resources are installed,"
855 | echo "along with all required dependencies. It may however take a while!"
856 | newline
857 | if ! confirm "Do you wish to perform a full install?"; then
858 | MIN_INSTALL=true
859 | fi
860 | else
861 | MIN_INSTALL=true
862 | fi
863 |
864 | if [ $localdir != "na" ]; then
865 | installdir="$USER_HOME/$topdir/$localdir"
866 | else
867 | installdir="$USER_HOME/$topdir"
868 | fi
869 |
870 | if ! $MIN_INSTALL || [ $gitrepoclone == "yes" ]; then
871 | [ -d $installdir ] || mkdir -p $installdir
872 | fi
873 |
874 | if [ $debugmode != "no" ]; then
875 | echo "INSTALLDIR is $installdir"
876 | fi
877 |
878 | # apt repo install
879 |
880 | echo -e "\nChecking for dependencies..."
881 |
882 | if $REMOVE_PKG; then
883 | for pkgrm in ${pkgremove[@]}; do
884 | warning "Installed package conflicts with requirements"
885 | sudo apt-get remove "$pkgrm"
886 | done
887 | fi
888 |
889 | for pkgdep in ${coredeplist[@]}; do
890 | if apt_pkg_req "$pkgdep"; then
891 | apt_pkg_install "$pkgdep"
892 | fi
893 | done
894 |
895 | for pkgdep in ${pythondep[@]}; do
896 | if [ -f "$(which python2)" ] && [ $pip2support == "yes" ]; then
897 | if apt_pkg_req "python-$pkgdep"; then
898 | apt_pkg_install "python-$pkgdep"
899 | fi
900 | fi
901 | if [ -f "$(which python3)" ] && [ $pip3support == "yes" ]; then
902 | if apt_pkg_req "python3-$pkgdep"; then
903 | apt_pkg_install "python3-$pkgdep"
904 | fi
905 | fi
906 | done
907 |
908 | if [ $pipoverride != "yes" ] && [ $debpackage != "na" ]; then
909 | newline
910 | if [ $pip2support != "yes" ] && [ $pip3support != "yes" ]; then
911 | apt_deb_install "$debpackage"
912 | fi
913 | if [ -f "$(which python2)" ] && [ $pip2support == "yes" ]; then
914 | apt_deb_install "python-$debpackage"
915 | if ! apt_pkg_req "python-$debpackage" &> /dev/null; then
916 | sudo $PIP2_BIN uninstall -y "$piplibname" &> /dev/null
917 | fi
918 | fi
919 | if [ -f "$(which python3)" ] && [ $pip3support == "yes" ]; then
920 | apt_deb_install "python3-$debpackage"
921 | if ! apt_pkg_req "python3-$debpackage" &> /dev/null; then
922 | sudo $PIP3_BIN uninstall -y "$piplibname" &> /dev/null
923 | fi
924 | fi
925 | if apt_pkg_req "python-$debpackage" &> /dev/null || apt_pkg_req "python3-$debpackage" &> /dev/null; then
926 | debpackage="na"
927 | fi
928 | else
929 | debpackage="na"
930 | fi
931 |
932 | # pypi repo install
933 |
934 | if [ -f "$(which python2)" ] && [ $pip2support == "yes" ] && apt_pkg_req "python-$debpackage" &> /dev/null; then
935 | if [ $piplibname != "na" ] && [ $debpackage == "na" ]; then
936 | newline && echo "Installing $productname library for Python 2..." && newline
937 | if ! sudo -H $PIP2_BIN install "$piplibname"; then
938 | warning "Python 2 library install failed!"
939 | echo "If problems persist, visit forums.pimoroni.com for support"
940 | exit 1
941 | fi
942 | fi
943 | fi
944 |
945 | if [ -f "$(which python3)" ] && [ $pip3support == "yes" ] && apt_pkg_req "python3-$debpackage" &> /dev/null; then
946 | if [ $piplibname != "na" ] && [ $debpackage == "na" ]; then
947 | newline && echo "Installing $productname library for Python 3..." && newline
948 | if ! sudo -H $PIP3_BIN install "$piplibname"; then
949 | warning "Python 3 library install failed!"
950 | echo "If problems persist, visit forums.pimoroni.com for support"
951 | exit 1
952 | fi
953 | fi
954 | fi
955 |
956 | # git repo install
957 |
958 | if [ $gitrepoclone == "yes" ]; then
959 | if ! command -v git > /dev/null; then
960 | apt_pkg_install git
961 | fi
962 | if [ $gitclonedir == "source" ]; then
963 | gitclonedir=$gitreponame
964 | fi
965 | if [ $repoclean == "yes" ]; then
966 | rm -Rf $installdir/$gitclonedir
967 | fi
968 | if [ -d $installdir/$gitclonedir ]; then
969 | newline && echo "Github repo already present. Updating..."
970 | cd $installdir/$gitclonedir && git pull
971 | else
972 | newline && echo "Cloning Github repo locally..."
973 | cd $installdir
974 | if [ $debugmode != "no" ]; then
975 | echo "git user name is $gitusername"
976 | echo "git repo name is $gitreponame"
977 | fi
978 | if [ $gitrepobranch != "master" ]; then
979 | git clone https://github.com/$gitusername/$gitreponame $gitclonedir -b $gitrepobranch
980 | else
981 | git clone --depth=1 https://github.com/$gitusername/$gitreponame $gitclonedir
982 | fi
983 | fi
984 | fi
985 |
986 | if [ $repoinstall == "yes" ]; then
987 | newline && echo "Installing library..." && newline
988 | cd $installdir/$gitreponame/$libdir
989 | if [ -f "$(which python2)" ] && [ $pip2support == "yes" ]; then
990 | sudo python2 ./setup.py install
991 | fi
992 | if [ -f "$(which python3)" ] && [ $pip3support == "yes" ]; then
993 | sudo python3 ./setup.py install
994 | fi
995 | newline
996 | fi
997 |
998 | # additional install
999 |
1000 | if ! $MIN_INSTALL; then
1001 | echo -e "\nChecking for additional software..."
1002 | for moredep in ${examplesdep[@]}; do
1003 | if [ -f "$(which python2)" ] && apt_pkg_req "python-$moredep"; then
1004 | if ! apt_pkg_install "python-$moredep"; then
1005 | sudo -H $PIP2_BIN install "$moredep"
1006 | if pip2_lib_req "$moredep"; then
1007 | FAILED_PKG=true
1008 | fi
1009 | fi
1010 | fi
1011 | if [ -f "$(which python3)" ] && apt_pkg_req "python3-$moredep"; then
1012 | if ! apt_pkg_install "python3-$moredep"; then
1013 | sudo -H $PIP3_BIN install "$moredep"
1014 | if pip3_lib_req "$moredep"; then
1015 | FAILED_PKG=true
1016 | fi
1017 | fi
1018 | fi
1019 | done
1020 | for pipdep in ${pipdeplist[@]}; do
1021 | if [ -f "$(which python2)" ] && pip2_lib_req "$pipdep"; then
1022 | sudo -H $PIP2_BIN install "$pipdep"
1023 | fi
1024 | if [ -f "$(which python3)" ] && pip3_lib_req "$pipdep"; then
1025 | sudo -H $PIP3_BIN install "$pipdep"
1026 | fi
1027 | done
1028 | for moredep in ${somemoredep[@]}; do
1029 | if apt_pkg_req "$moredep"; then
1030 | apt_pkg_install "$moredep"
1031 | fi
1032 | done
1033 | if [ -n "$DISPLAY" ]; then
1034 | for x11dep in ${xdisplaydep[@]}; do
1035 | if apt_pkg_req "$x11dep"; then
1036 | apt_pkg_install "$x11dep"
1037 | fi
1038 | done
1039 | fi
1040 | fi
1041 |
1042 | # resources install
1043 |
1044 | if ! $MIN_INSTALL && [ -n "$copydir" ]; then
1045 | if ! command -v git > /dev/null; then
1046 | apt_pkg_install git
1047 | fi
1048 | echo -e "\nDownloading examples and documentation..."
1049 | TMPDIR=`mktemp -d /tmp/pimoroni.XXXXXX`
1050 | cd $TMPDIR
1051 | if [ $copyhead != "yes" ]; then
1052 | GITTAG=$(git ls-remote -t https://github.com/$gitusername/$gitreponame v\?.?.? | tail -n 1 | rev | cut -c -6 | rev)
1053 | fi
1054 | if [ -n "$GITTAG" ]; then
1055 | git clone https://github.com/$gitusername/$gitreponame -b $GITTAG &> /dev/null
1056 | else
1057 | git clone --depth=1 https://github.com/$gitusername/$gitreponame &> /dev/null
1058 | fi
1059 | cd $installdir
1060 | for repodir in ${copydir[@]}; do
1061 | if [ -d $repodir ] && [ $repodir != "documentation" ]; then
1062 | newline
1063 | if [ -d $installdir/$repodir-backup ]; then
1064 | rm -R $installdir/$repodir-old &> /dev/null
1065 | mv $installdir/$repodir-backup $installdir/$repodir-old &> /dev/null
1066 | fi
1067 | mv $installdir/$repodir $installdir/$repodir-backup &> /dev/null
1068 | if [ $gitrepotop != "root" ]; then
1069 | cp -R $TMPDIR/$gitreponame/$gitrepotop/$repodir $installdir/$repodir &> /dev/null
1070 | else
1071 | cp -R $TMPDIR/$gitreponame/$repodir $installdir/$repodir &> /dev/null
1072 | fi
1073 | inform "The $repodir directory already exists on your system!"
1074 | echo -e "We've backed them up as $repodir-backup, just in case you've changed anything!\n"
1075 | else
1076 | rm -R $installdir/$repodir &> /dev/null
1077 | if [ $gitrepotop != "root" ]; then
1078 | cp -R $TMPDIR/$gitreponame/$gitrepotop/$repodir $installdir/$repodir &> /dev/null
1079 | else
1080 | cp -R $TMPDIR/$gitreponame/$repodir $installdir/$repodir &> /dev/null
1081 | fi
1082 | fi
1083 | done
1084 | echo "Resources for your $productname were copied to"
1085 | inform "$installdir"
1086 | rm -rf $TMPDIR
1087 | fi
1088 |
1089 | # script custom routines
1090 |
1091 | if [ $customcmd == "no" ]; then
1092 | if [ -n "$pkgremove" ]; then
1093 | echo -e "\nFinalising Install...\n"
1094 | sysclean && newline
1095 | fi
1096 | echo -e "\nAll done. Enjoy your $productname!\n"
1097 | else # custom block starts here
1098 | echo -e "\nFinalising Install...\n"
1099 | # place all custom commands in this scope
1100 | fi
1101 |
1102 | if $FAILED_PKG; then
1103 | warning "\nSome packages could not be installed, review the output for details!\n"
1104 | fi
1105 | if $IS_EXPERIMENTAL; then
1106 | warning "\nSupport for your operating system is experimental. Please visit"
1107 | warning "forums.pimoroni.com if you experience issues with this product.\n"
1108 | fi
1109 |
1110 | if [ "$FORCE" != '-y' ]; then
1111 | if [ $promptreboot == "yes" ] || $ASK_TO_REBOOT; then
1112 | sysreboot && newline
1113 | fi
1114 | fi
1115 | else
1116 | echo -e "\nAborting...\n"
1117 | fi
1118 |
1119 | exit 0
1120 |
--------------------------------------------------------------------------------
/home/pi/iphone-backups/iphone files are rsyncd here.txt:
--------------------------------------------------------------------------------
1 | iphone backups will appear here
2 |
--------------------------------------------------------------------------------
/home/pi/log.txt:
--------------------------------------------------------------------------------
1 | here's where udev-runs-this.sh and backup-iphone.sh will dump their logs.
2 |
3 | lol.
4 |
5 |
--------------------------------------------------------------------------------
/home/pi/monitor.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # osascript -e 'tell application "Terminal"' -e 'set the bounds of the front window to {24, 96, 524, 396}' -e 'end tell'
4 | # 1. horiz dist from left side of screen to upper-left corner of window
5 | # 2. vert dist from top of screen to upper-left corner of window
6 | # 3. horiz dist from LHS of screen to lower-right corner of window
7 | # 4. vert dist from RHS of screen to lower-right corner of window
8 |
9 |
10 | osascript -e 'tell app "Terminal" to do script "ssh -t rpi42 watch -d -t lsusb"'
11 | osascript -e 'tell application "Terminal"' -e 'set the bounds of the front window to {1, 1, 500, 500}' -e 'end tell'
12 | osascript -e 'tell app "Terminal" to do script "ssh -t rpi42 dmesg -w"'
13 | osascript -e 'tell application "Terminal"' -e 'set the bounds of the front window to {500, 1, 1000, 500}' -e 'end tell'
14 | osascript -e 'tell app "Terminal" to do script "ssh -t rpi42 tail -f /var/log/syslog"'
15 | osascript -e 'tell application "Terminal"' -e 'set the bounds of the front window to {1000, 1, 1500, 500}' -e 'end tell'
16 | osascript -e 'tell app "Terminal" to do script "ssh -t rpi42 journalctl -f"'
17 | osascript -e 'tell application "Terminal"' -e 'set the bounds of the front window to {1, 550, 500, 1000}' -e 'end tell'
18 | osascript -e 'tell app "Terminal" to do script "ssh -t rpi42 udevadm monitor -kup"'
19 | osascript -e 'tell application "Terminal"' -e 'set the bounds of the front window to {500, 550, 1000, 1000}' -e 'end tell'
20 | osascript -e 'tell app "Terminal" to do script "ssh -t rpi42 watch -d -t /home/pi/usr/bin/idevicepair list "'
21 | osascript -e 'tell application "Terminal"' -e 'set the bounds of the front window to {1000, 550, 1500, 750}' -e 'end tell'
22 | osascript -e 'tell app "Terminal" to do script "ssh -t rpi42 tail -f /home/pi/log.txt "'
23 | osascript -e 'tell application "Terminal"' -e 'set the bounds of the front window to {1000, 750, 1500, 1000}' -e 'end tell'
--------------------------------------------------------------------------------
/home/pi/udev-runs-this.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | sleep 3
4 |
5 | echo "$(date +%Y-%m-%d-%H-%M-%S) /home/pi/udev-runs-this.sh : about to start backup-iphone.sh | at now." >> "/home/pi/log.txt" 2>&1
6 |
7 | echo "/bin/su -c '/home/pi/backup-iphone.sh >> /home/pi/log.txt 2>&1' pi" | at now
8 |
9 |
10 | echo "$(date +%Y-%m-%d-%H-%M-%S) /home/pi/udev-runs-this.sh : exiting udev-runs-this." >> "/home/pi/log.txt" 2>&1
11 |
--------------------------------------------------------------------------------
/home/pi/usr/src/this is where you should git clone libimobiledevice and friends.txt:
--------------------------------------------------------------------------------
1 | this is where you should git clone libimobiledevice and friends
2 |
--------------------------------------------------------------------------------
/home/pi/usr/the script backup-iphone.sh mounts the iphone in here.txt:
--------------------------------------------------------------------------------
1 | the script backup-iphone.sh mounts the iphone here
2 |
--------------------------------------------------------------------------------