1
0
Fork 0
mirror of https://github.com/iiab/iiab.git synced 2025-03-09 15:40:17 +00:00

Compare commits

..

No commits in common. "master" and "release-8.2" have entirely different histories.

59 changed files with 313 additions and 1010 deletions

View file

@ -1,4 +1,4 @@
name: '"10 min" IIAB on Ubuntu 24.04 on x86-64'
name: '"10 min" IIAB test install'
# run-name: ${{ github.actor }} is testing out GitHub Actions 🚀
# https://michaelcurrin.github.io/dev-cheatsheets/cheatsheets/ci-cd/github-actions/triggers.html

View file

@ -1,4 +1,4 @@
name: '"30 min" IIAB on Debian 12 on RPi 3'
name: '"30 min" IIAB test install deb12 on rpi3'
# run-name: ${{ github.actor }} is testing out GitHub Actions 🚀
# https://michaelcurrin.github.io/dev-cheatsheets/cheatsheets/ci-cd/github-actions/triggers.html
@ -18,7 +18,7 @@ on: [push, pull_request, workflow_dispatch]
jobs:
test-install:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
strategy:
matrix:
arch: [debian12]

View file

@ -1,4 +1,4 @@
name: '"30 min" IIAB on RasPiOS on Zero 2 W'
name: '"30 min" IIAB test install raspios'
# run-name: ${{ github.actor }} is testing out GitHub Actions 🚀
# https://michaelcurrin.github.io/dev-cheatsheets/cheatsheets/ci-cd/github-actions/triggers.html
@ -18,7 +18,7 @@ on: [push, pull_request, workflow_dispatch]
jobs:
test-install:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
strategy:
matrix:
arch: [aarch64] #[zero_raspbian, zero_raspios, zero2_raspios, aarch64]
@ -65,13 +65,13 @@ jobs:
uname -a # uname -srm
whoami # Typically 'root' instead of 'runner'
pwd # /home/runner/work/iiab/iiab == $GITHUB_WORKSPACE == ${{ github.workspace }}
apt-get update -y --allow-releaseinfo-change
apt-get install --no-install-recommends -y git
sudo apt-get update -y --allow-releaseinfo-change
sudo apt-get install --no-install-recommends -y git
ls /opt/iiab/iiab
mkdir /etc/iiab
cp /opt/iiab/iiab/vars/local_vars_none.yml /etc/iiab/local_vars.yml
/opt/iiab/iiab/scripts/ansible
./iiab-install
sudo mkdir /etc/iiab
sudo cp /opt/iiab/iiab/vars/local_vars_none.yml /etc/iiab/local_vars.yml
sudo /opt/iiab/iiab/scripts/ansible
sudo ./iiab-install
cd /opt/iiab/iiab
iiab-summary
cat /etc/iiab/iiab_state.yml

View file

@ -15,6 +15,6 @@ this is to include the following two lines at the top of the file:
Licensed under the terms of the GNU GPL v2 or later; see LICENSE for details.
All files not containing an explicit copyright notice or terms of license in
the file are Copyright © 2015-2025, Unleash Kids, and are licensed under the
the file are Copyright © 2015-2024, Unleash Kids, and are licensed under the
terms of the GPLv2 license in the file named LICENSE in the root of the
repository.

View file

@ -5,4 +5,4 @@
# Disallowed by Ansible 2.11+ -- see https://docs.ansible.com/ansible/devel/porting_guides/porting_guide_2.7.html#using-a-loop-on-a-package-module-via-squash-actions
#squash_actions = apk, apt, dnf, homebrew, openbsd_pkg, pacman, pkgng, yum, zypper, package
[defaults]
interpreter_python=/usr/local/ansible/bin/python3
interpreter_python=/usr/bin/python3

View file

@ -42,7 +42,7 @@ fi
echo "Ansible will now run iiab-network.yml -- log file is iiab-network.log"
Start=`date`
ansible -m setup -i ansible_hosts localhost --connection=local | grep python
ansible-playbook -i ansible_hosts iiab-network.yml --extra-vars "{\"skip_role_on_error\":false}" --connection=local
ansible-playbook -i ansible_hosts iiab-network.yml --connection=local
End=`date`

View file

@ -8,7 +8,7 @@
# apache_interface: 127.0.0.1
# Make this False to disable http://box/common/services/power_off.php button:
# allow_www_data_poweroff: False
# allow_www_data_sudo: True
# All above are set in: github.com/iiab/iiab/blob/master/vars/default_vars.yml
# If nec, change them by editing /etc/iiab/local_vars.yml prior to installing!

View file

@ -60,7 +60,7 @@ else
echo -e " cd /opt/iiab/iiab"
echo -e " sudo iiab-hotspot-off # NO LONGER NEC? eg to restore 'wifi_up_down: True'"
echo -e " sudo ./runrole --reinstall firmware"
echo -e " sudo iiab-network # SOMETIMES NECESSARY"
echo -e " sudo ./iiab-network # SOMETIMES NECESSARY"
echo -e " sudo iiab-hotspot-on # NO LONGER NEC? eg to restore 'wifi_up_down: True'"
echo -e " sudo reboot\n"
#echo

View file

@ -17,11 +17,11 @@
shell: df -B1 --output=used / | tail -1
register: df1
# 2025-02-16
#- name: "Install package: python3-psutil"
# package:
# name: python3-psutil
# state: present
- name: "Install package: python3-psutil"
package:
name: python3-psutil
state: present
- name: Remove previous virtual environment {{ jupyterhub_venv }}
file:
@ -43,16 +43,15 @@
global: yes
state: latest
- name: "pip install 3 packages into virtual environment: {{ jupyterhub_venv }} (~316 MB total, after 2 Ansible calls)"
- name: "pip install 3 packages into virtual environment: {{ jupyterhub_venv }} (~326 MB total, after 2 Ansible calls)"
pip:
name:
- pip
- wheel
- jupyterhub
virtualenv: "{{ jupyterhub_venv }}" # /opt/iiab/jupyterhub
#virtualenv_site_packages: no
virtualenv_command: python3 -m venv "{{ jupyterhub_venv }}" # 2025-02-16
#virtualenv_command: python3 -m venv --system-site-packages "{{ jupyterhub_venv }}" # 2021-07-29: This works on RasPiOS 10, Debian 11, Ubuntu 20.04 and Mint 20 -- however if you absolutely must use the older Debian 10 -- you can work around errors "can't find Rust compiler" and "This package requires Rust >=1.41.0" if you (1) revert this line to 'virtualenv_command: virtualenv' AND (2) uncomment the line just below
virtualenv_site_packages: no
virtualenv_command: python3 -m venv --system-site-packages "{{ jupyterhub_venv }}" # 2021-07-29: This works on RasPiOS 10, Debian 11, Ubuntu 20.04 and Mint 20 -- however if you absolutely must use the older Debian 10 -- you can work around errors "can't find Rust compiler" and "This package requires Rust >=1.41.0" if you (1) revert this line to 'virtualenv_command: virtualenv' AND (2) uncomment the line just below
#virtualenv_python: python3 # 2021-07-29: Was needed when above line was 'virtualenv_command: virtualenv' (generally for Python 2)
extra_args: "--no-cache-dir --prefer-binary" # 2021-11-30, 2022-07-07: The "--pre" flag had earlier been needed, for beta-like pre-releases of JupyterHub 2.0.0
@ -68,9 +67,8 @@
- jupyterhub-systemdspawner
- ipywidgets
virtualenv: "{{ jupyterhub_venv }}"
#virtualenv_site_packages: no
virtualenv_command: python3 -m venv "{{ jupyterhub_venv }}" # 2025-02-16
#virtualenv_command: python3 -m venv --system-site-packages "{{ jupyterhub_venv }}"
virtualenv_site_packages: no
virtualenv_command: python3 -m venv --system-site-packages "{{ jupyterhub_venv }}"
extra_args: "--no-cache-dir --prefer-binary" # 2023-10-01: Lifesaver when recent wheels (e.g. piwheels.org) are inevitably not yet built! SEE #3560
- name: "Install from template: {{ jupyterhub_venv }}/etc/jupyterhub/jupyterhub_config.py"

View file

@ -9,7 +9,7 @@
name: net.ipv6.conf.all.disable_ipv6
value: 0
- name: "Install 4 packages: libcgi-fast-perl, munin, munin-node, munin-plugins-extra"
- name: "Install 5 packages: libcgi-fast-perl, munin, munin-node, munin-plugins-extra, python3-passlib"
package:
name:
#- libapache2-mod-fcgid
@ -17,15 +17,9 @@
- munin
- munin-node
- munin-plugins-extra
#- python3-passlib # For Ansible module 'htpasswd' in Ansible collection community.general -- used just below
- python3-passlib # For Ansible module 'htpasswd' in Ansible collection community.general -- used just below
state: present
- name: pip install 'passlib' into venv /usr/local/ansible -- for Ansible module 'htpasswd' in Ansible collection community.general -- used just below
pip:
name: passlib
virtualenv: /usr/local/ansible
extra_args: "--upgrade --no-cache-dir --prefer-binary" # 2023-10-01: Lifesaver when recent wheels (e.g. piwheels.org) are inevitably not yet built! SEE #3560
# SEE ALSO roles/network/tasks/install.yml
- name: RESTORE net.ipv6.conf.all.disable_ipv6 to 1 in /etc/sysctl.conf for #3434
sysctl:

View file

@ -3,22 +3,16 @@
register: df1
- name: 'Install MySQL packages: mariadb-server, mariadb-client, php{{ php_version }}-mysql'
- name: 'Install MySQL packages: mariadb-server, mariadb-client, php{{ php_version }}-mysql, python3-pymysql'
package:
name:
- mariadb-server
- mariadb-client
#- php{{ php_version }}-common # Auto-installed as an apt dependency. REGARDLESS: php{{ php_version }}-common superset php{{ php_version }}-cli is auto-installed by php{{ php_version }}-fpm in nginx/tasks/install.yml
- php{{ php_version }}-mysql # Likewise installed in nextcloud/tasks/install.yml, pbx/tasks/freepbx.yml, wordpress/tasks/install.yml
#- python3-pymysql # For Ansible modules {mysql_db, mysql_user} in Ansible collection community.mysql -- used in MySQL roles {mediawiki, nextcloud, wordpress} and possibly {elgg, pbx}
- python3-pymysql # For Ansible modules {mysql_db, mysql_user} in Ansible collection community.mysql -- used in MySQL roles {mediawiki, nextcloud, wordpress} and possibly {elgg, pbx}
state: present
- name: pip install 'PyMySQL' into venv /usr/local/ansible -- for Ansible modules {mysql_db, mysql_user} in Ansible collection community.mysql -- used in roles {mediawiki, nextcloud, wordpress, matomo, pbx}
pip:
name: PyMySQL
virtualenv: /usr/local/ansible
extra_args: "--upgrade --no-cache-dir --prefer-binary" # 2023-10-01: Lifesaver when recent wheels (e.g. piwheels.org) are inevitably not yet built! SEE #3560
# 2020-07-11: 10 PHP package installs moved to roles/www_base/tasks/main.yml
# php{{ php_version }}-sqlite3 install moved to roles/osm-vector-maps/tasks/install.yml

View file

@ -55,7 +55,7 @@ strict_networking: False
iiab_demo_mode: False
gui_static_wan: False
wan_cidr: ""
virtual_network_devices: "-e wwlan -e ppp -e ap0 -e lo -e br0 -e tun -e br- -e docker -e bridge0 -e veth -e tailscale0"
virtual_network_devices: "-e wwlan -e ppp -e ap0 -e lo -e br0 -e tun -e br- -e docker -e bridge0 -e veth"
# Set defaults for discovery process as strings
wifi1: "not found-1"
@ -71,8 +71,6 @@ iiab_lan_iface: none
discovered_lan_iface: none
discovered_wired_iface: none
discovered_wireless_iface: none
# use the same case as what `iw reg get` would return with 00 present
host_country_code_found: UNSET
# Red Hat
#iiab_wired_lan_iface: "none"

View file

@ -78,7 +78,7 @@
- name: Reload systemd
systemd:
daemon_reload: yes
when: not no_net_restart or not iiab_lan_iface == "br0"
when: not iiab_lan_iface == "br0"
- name: Restart the NetworkManager service
systemd:

View file

@ -239,41 +239,6 @@
iiab_lan_iface: "{{ iiab_wireless_lan_iface }}"
when: iiab_wireless_lan_iface is defined and nobridge is defined
- name: Detect WiFi country code in use
shell: iw reg get | grep country | grep -v UNSET | awk '{print $2}' | sed "s|:||"
register: REG_DOM
ignore_errors: True
- name: Set host_country_code_found
set_fact:
host_country_code_found: "{{ REG_DOM.stdout }}"
when: REG_DOM.stdout is defined and REG_DOM.stdout | length > 0
- name: Set Wifi Region country to {{ REG_DOM.stdout }} for hostapd when present
set_fact:
host_country_code: "{{ REG_DOM.stdout }}"
when: REG_DOM.stdout is defined and REG_DOM.stdout | length > 0 and wifi_up_down and can_be_ap and has_wifi_gateway is defined
- name: Detect current Wifi channel
shell: iw {{ discovered_wireless_iface }} info | grep channel | cut -d' ' -f2
register: current_client_channel
when: wifi_up_down and can_be_ap and has_wifi_gateway is defined
- name: Forcing wifi_up_down to False based on firmware selection "24"
set_fact:
wifi_up_down: False
when: rpi3bplus_rpi4_wifi_firmware == "24"
- name: Detect "Firmware rejected country setting" in dmesg (invert return code, for intentional red error)
shell: '! dmesg | grep ieee80211 | grep "Firmware rejected country setting"'
register: FW_rejected_country
ignore_errors: True
- name: Detect country code passed from cmdline in dmesg
shell: dmesg | grep -om1 'cfg80211\.ieee80211_regdom=\S*' | cut -d= -f2
register: cmdline_country_code
ignore_errors: True
- name: In VM disable LAN - needs local_vars entry to activate
set_fact:
iiab_lan_iface: none
@ -330,36 +295,6 @@
value: "{{ iiab_wan_iface }}"
- option: can_be_ap
value: "{{ can_be_ap }}"
- option: host_country_code_found
value: "{{ host_country_code_found }}"
- option: wifi_firmware_43430
value: "{{ rpizerow_rpi3_wifi_firmware }}"
- option: wifi_firmware_43455
value: "{{ rpi3bplus_rpi4_wifi_firmware }}"
- name: Add 'detected_network' variable 'current_client_channel_found' stdout value ({{ current_client_channel.stdout }}) if defined and non-empty, to {{ iiab_ini_file }}
ini_file:
dest: "{{ iiab_ini_file }}"
section: detected_network
option: client_wifi_channel_found
value: "{{ current_client_channel.stdout }}"
when: current_client_channel.stdout is defined and current_client_channel.stdout != ""
- name: Add 'detected_network' variable 'FW_rejected_country' stdout value ({{ FW_rejected_country.stdout }}) if defined and non-empty, to {{ iiab_ini_file }}
ini_file:
dest: "{{ iiab_ini_file }}"
section: detected_network
option: FW_rejected_country
value: "{{ FW_rejected_country.stdout }}"
when: FW_rejected_country.stdout is defined and FW_rejected_country.stdout != ""
- name: Add 'detected_network' variable 'cmdline_country_code' stdout value ({{ cmdline_country_code.stdout }}) if defined and non-empty, to {{ iiab_ini_file }}
ini_file:
dest: "{{ iiab_ini_file }}"
section: detected_network
option: cmdline_country_code
value: "{{ cmdline_country_code.stdout }}"
when: cmdline_country_code.stdout is defined and cmdline_country_code.stdout != ""
# well if there ever was a point to tell the user things are FUBAR this is it.
# limit 2 network adapters wifi wired

View file

@ -3,12 +3,28 @@
hostapd_enabled: False
when: (not wifi_up_down and discovered_wireless_iface == iiab_wan_iface) or discovered_wireless_iface == "none" or not can_be_ap
- name: Disable the Access Point 'hostapd' service if hostapd_enabled False
- name: Disable the Access Point 'hostapd' service
systemd:
name: hostapd
enabled: no
when: not hostapd_enabled
- name: Detect WiFi country code in use
shell: iw reg get | grep country | grep -v UNSET | awk '{print $2}' | sed "s|:||"
register: REG_DOM
ignore_errors: True
when: wifi_up_down and can_be_ap and has_wifi_gateway is defined
- name: Set Wifi Region country code for hostapd when present
set_fact:
host_country_code: "{{ REG_DOM.stdout }}"
when: REG_DOM.stdout is defined and REG_DOM.stdout | length > 0
- name: Detect current Wifi channel
shell: iw {{ discovered_wireless_iface }} info | grep channel | cut -d' ' -f2
register: current_client_channel
when: wifi_up_down and can_be_ap and has_wifi_gateway is defined
- name: Setting WiFi channel to {{ current_client_channel.stdout }}
set_fact:
host_channel: "{{ current_client_channel.stdout }}"
@ -115,3 +131,14 @@
value: "{{ host_country_code }}"
- option: host_channel
value: "{{ host_channel }}"
- name: Add 'network' variable 'current_client_channel' value if defined, to {{ iiab_ini_file }}
ini_file:
dest: "{{ iiab_ini_file }}"
section: network
option: "{{ item.option }}"
value: "{{ item.value | string }}"
with_items:
- option: client_wifi_channel
value: "{{ current_client_channel.stdout }}"
when: current_client_channel.stdout is defined

View file

@ -1,3 +1,8 @@
- name: Select RPi firmware mode
include_role:
name: firmware
when: rpi_model != "none"
- name: detected_network
include_tasks: detected_network.yml
@ -103,11 +108,6 @@
# end block
when: network_installed is defined and network_enabled
- name: Select RPi firmware mode
include_role:
name: firmware
when: rpi_model != "none"
- name: Create {{ iiab_etc_path }}/install-flags/iiab-network-complete on second pass of network role.
file:

View file

@ -12,7 +12,7 @@
state: restarted
with_items:
- wpa_supplicant
when: wifi_up_down and hostapd_enabled and not network_manager_active
when: wifi_up_down and hostapd_enabled
- name: Enable & Restart networkd-dispatcher.service
systemd:
@ -28,16 +28,12 @@
state: restarted
when: wifi_up_down and can_be_ap and ansible_ap0 is undefined
- name: Waiting {{ hostapd_wait }} seconds for network to stabilize for ap0
shell: sleep {{ hostapd_wait }}
when: ansible_ap0 is undefined
- name: Restart hostapd when WiFi is present but not when using WiFi as gateway
- name: Restart hostapd when WiFi is present but not when using WiFi as gateway with wifi_up_down False
systemd:
name: hostapd
state: restarted
daemon_reload: yes
when: hostapd_enabled and not no_net_restart
when: hostapd_enabled and (wifi_up_down or not no_net_restart)
# 2022-07-22: @jvonau suggests commenting this out as: "we really don't touch
# any of the config files... netplan.yml renames one file if it's a container
@ -111,7 +107,7 @@
systemd:
name: hostapd
state: restarted
when: hostapd_enabled and not no_net_restart and wifi_slave.stdout is defined and wifi_slave.stdout == 0
when: hostapd_enabled and wifi_slave.stdout is defined and wifi_slave.stdout == 0
#both interfaces.d and systemd-networkd should have br0 available and Appliance lacks br0
#keep an eye on legacy wifi installs where br0 is present but not 'online' with an ip address

View file

@ -14,7 +14,7 @@ echo " IIAB hotspot access point Disabled"
#exit 0
{% else %}
echo " IIAB hotspot access point Disabled"
{% if dhcpcd_result == "enabled" %}
{% if is_raspbian %}
# hotspot-off before ap0_updown
sed -i "s/^denyinterfaces/#denyinterfaces/" /etc/dhcpcd.conf
#systemctl disable dnsmasq
@ -37,7 +37,7 @@ fi
echo -e "\nIf you're enabling upstream WiFi, please reboot now.\n"
#exit 0
{% endif %}
#if dhcpcd_result == "enabled"
#is_raspbian
{% endif %}
#wifi_up_down
{% endif %}

View file

@ -16,7 +16,7 @@ systemctl enable hostapd
systemctl enable iiab-wifi-test.service
#exit 0
{% else %}
{% if dhcpcd_result == "enabled" %}
{% if is_raspbian %}
# just do what we have always done in hotspot-on
cp -f /etc/hostapd/hostapd.conf.iiab /etc/hostapd/hostapd.conf
sed -i "s/^#denyinterfaces/denyinterfaces/" /etc/dhcpcd.conf
@ -44,7 +44,7 @@ fi
systemctl enable hostapd
#exit 0
{% endif %}
#if dhcpcd_result == "enabled"
#is_raspbian
{% endif %}
#wifi_up_down
{% endif %}

View file

@ -131,7 +131,7 @@
# nextcloud_dl_url: https://download.nextcloud.com/server/releases/latest-25.tar.bz2
# when: php_version is version('8.0', '<')
- name: Unarchive {{ nextcloud_dl_url }} (~216 MB) to {{ nextcloud_root_dir }} (~844 MB initially, sometimes ~878 MB later, {{ apache_user }}:{{ apache_user }})
- name: Unarchive {{ nextcloud_dl_url }} (~180 MB) to {{ nextcloud_root_dir }} (~687 MB initially, sometimes ~721 MB later, {{ apache_user }}:{{ apache_user }})
unarchive:
remote_src: yes # Overwrite even if "already exists on the target"
src: "{{ nextcloud_dl_url }}"

View file

@ -5,25 +5,10 @@ location / {
location /usb {
alias /library/www/html/local_content/;
fancyindex on; # autoindex on;
add_before_body /upload2usb/button.html;
}
location ~ ^/upload2usb/(.*)\.php$ {
alias /library/www/html/upload2usb/$1.php;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
fastcgi_pass php;
fastcgi_index index.php;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
include fastcgi_params;
}
location /local_content/ {
fancyindex on; # autoindex on;
add_before_body /upload2usb/button.html;
}
location /info {

View file

@ -3,20 +3,14 @@
register: df1
- name: 'Install packages: postgresql, postgresql-client'
- name: 'Install packages: postgresql, postgresql-client, python3-psycopg2'
package:
name:
- postgresql
- postgresql-client
#- python3-psycopg2 # For Ansible modules {postgresql_db, postgresql_user} in Ansible collection community.postgresql -- used in moodle/tasks/install.yml
- python3-psycopg2 # For Ansible modules {postgresql_db, postgresql_user} in Ansible collection community.postgresql -- used in moodle/tasks/install.yml
state: present
- name: pip install 'psycopg' (NEW Psycopg 3) into venv /usr/local/ansible -- for Ansible modules {postgresql_db, postgresql_user} in Ansible collection community.postgresql -- used in moodle/tasks/install.yml
pip:
name: psycopg
virtualenv: /usr/local/ansible
extra_args: "--upgrade --no-cache-dir --prefer-binary" # 2023-10-01: Lifesaver when recent wheels (e.g. piwheels.org) are inevitably not yet built! SEE #3560
- name: Run shell command "pg_config --version" to extract MAJOR version number -- strip off MINOR/PATCH version number(s)
shell: pg_config --version | sed 's/^[^0-9]*//; s/[^0-9].*//'
register: pg_config_version

View file

@ -2,34 +2,30 @@
usb_lib README
==============
**PLEASE SEE** `"Can teachers display their own content?" <https://wiki.iiab.io/go/FAQ#Can_teachers_display_their_own_content?>`_ **AND** `"Can students upload their own work?" <https://wiki.iiab.io/go/FAQ#Can_students_upload_their_own_work?>`_ **WITHIN https://FAQ.IIAB.IO FOR UP-TO-DATE DOCUMENTATION!**
**PLEASE SEE "Can teachers display their own content?" WITHIN https://FAQ.IIAB.IO FOR UP-TO-DATE DOCUMENTATION.**
This role (1) implements functionality similar to LibraryBox, to mount "teacher content" from USB sticks / drives for students, and (2) allows students to upload their work to the teacher's USB stick / drive:
This role implements functionality similar to LibraryBox, to mount "teacher content" from USB drives.
#. Students should have nearly immediate access to "teacher content" (on all inserted USB sticks) by browsing to http://box/usb.
#. Students can also click the "Upload to USB" button on top of this same page (http://box/usb), to upload their work to the teacher's USB stick. (FYI student uploads appear in folders like ``UPLOADS.YYYY-MM-DD`` within the root of the teacher's USB stick).
Users should have nearly immediate access to this "teacher content" (on all inserted USB drives) by browsing to http://box/usb
As of January 2025, automount is handled by usbmount: (`devmon included with udevil <https://ignorantguru.github.io/udevil/>`_ might be considered in future)
Automount is handled by usbmount, and scripts in this role look in the root of the mounted drive for...
* A script in this role (/etc/usbmount/mount.d/70-usb-library) looks in the root of the mounted USB stick for folder /PUBLIC and if found, creates a symlink of the form /library/www/html/local_content/USBn pointing to /media/usbn/PUBLIC — where n is generally one of {0, 1, 2, 3, 4, 5, 6, 7}. *RESULT: Only documents within /PUBLIC are browsable by students.* This option is very useful to **prevent students from copying uploaded homework!**
* If however folder /PUBLIC is not found, the symlink is created to the root of the mounted USB stick. *RESULT: EVERYTHING on the USB stick is browsable by students — just like with a traditional community bulletin board.* This option is very useful when students are uploading artwork, photo essays, personal audio recordings and **science projects that are intended to be shared!**
* /usb
* /USB
* /share
* /Share
* /Piratebox/Share
Technical Details:
...and if found, creates a symlink of the form /library/www/html/local_content/USBn pointing to /media/usbn — where n is generally one of {0, 1, 2, 3, 4, 5, 6, 7}.
* USB sticks / drives must be formatted with one of the filesystems listed under "FILESYSTEMS=" at ``/etc/usbmount/usbmount.conf`` — these are specified on/around Line 17 of: `/opt/iiab/iiab/roles/usb_lib/files/usbmount/usbmount.conf <https://github.com/iiab/iiab/blob/master/roles/usb_lib/files/usbmount/usbmount.conf#L17>`_
USB drives must be formatted with one of the filesystems listed under "FILESYSTEMS=" at ``/etc/usbmount/usbmount.conf`` — these are specified on/around Line 76 of: `/opt/iiab/iiab/roles/usb_lib/tasks/install.yml <https://github.com/iiab/iiab/blob/master/roles/usb_lib/tasks/install.yml#L76>`_
* If your IIAB was built on a Graphical Desktop OS (instead of a headless OS, like Raspberry Pi OS Lite), USB sticks will problematically be mounted twice by default, once by usbmount and once by the desktop. You must disable the automount function in the Desktop in order to use the "Upload to USB" functionality, which allows students to upload their work to your USB stick.
IIAB will generally mount USB drives 'rw' allowing root to both read and write to them. In addition, in March 2021 (`PR #2715 <https://github.com/iiab/iiab/issues/2715>`_) Kolibri exports were enabled by also giving non-root users read and write access to VFAT/FAT32, NTFS and exFAT USB drives, using ``umask=0000`` (in /etc/usbmount/usbmount.conf) to override the ``umask=0022`` default. If however you prefer to restore usbmount's default, set ``usb_lib_umask0000_for_kolibri: False`` in `/etc/iiab/local_vars.yml <http://FAQ.IIAB.IO/#What_is_local_vars.yml_and_how_do_I_customize_it%3F>`_ (preferably do this prior to installing IIAB).
* EXAMPLE: To disable Desktop automount within "Raspberry Pi OS with desktop", go to File Manager (pcmanfm) → Edit → Preferences → Volume Management, and uncheck "Mount removable media automatically when they are inserted".
Official `usbmount 0.0.22 (2011-08-08) <https://github.com/rbrito/usbmount/tags>`_ documentation:
* IIAB will generally mount USB sticks / drives 'rw' allowing root to both read and write to them. In addition, in March 2021 (`PR #2715 <https://github.com/iiab/iiab/pull/2715>`_) Kolibri exports were enabled, by also giving non-root users read and write access to VFAT/FAT32, NTFS and exFAT USB sticks — using ``umask=0000`` (in /etc/usbmount/usbmount.conf) to override the ``umask=0022`` default. This ``umask=0000`` is also required for students to upload to the teachers's VFAT/FAT32, NTFS and exFAT USB sticks, as introduced in January 2025 (`PR #3875 <https://github.com/iiab/iiab/pull/3875>`_). If, however, you prefer to restore usbmount's default, set ``usb_lib_writable_sticks: False`` in `/etc/iiab/local_vars.yml <http://FAQ.IIAB.IO/#What_is_local_vars.yml_and_how_do_I_customize_it%3F>`_ — please do this prior to installing IIAB — so you don't have to run: ``cd /opt/iiab/iiab ; ./runrole --reinstall usb_lib``
* https://github.com/hfuchs/usbmount/blob/master/README (2010-08-11)
* https://github.com/rbrito/usbmount/blob/master/README.md (2018-08-10)
* https://github.com/rbrito/usbmount/blob/master/usbmount.conf (2010-04-25)
* Official `usbmount 0.0.22 (2011-08-08) <https://github.com/rbrito/usbmount/tags>`_ documentation:
* https://github.com/hfuchs/usbmount/blob/master/README (2010-08-11)
* https://github.com/rbrito/usbmount/blob/master/README.md (2018-08-10)
* https://github.com/rbrito/usbmount/blob/master/usbmount.conf (2010-04-25)
* Dev Notes at the top of: https://github.com/iiab/iiab/blob/master/roles/usb_lib/tasks/install.yml
* January 2025 work to improve automount reliability during boot: `PR #3916 <https://github.com/iiab/iiab/pull/3916>`_
Legacy warning: There is also a patch for problems with automount on Fedora 21+. Please note that as of 4.1.8-200.fc22.x86_64 not all USB drives will mount, even with this patch.

View file

@ -1,9 +1,12 @@
# usb_lib_install: True
# usb_lib_enabled: True
# Set umask=0000 for VFAT, NTFS and exFAT in /etc/usbmount/usbmount.conf for
# Kolibri exports, and student uploads to teacher's USB stick (http://box/usb)
# usb_lib_writable_sticks: True
# Show entire contents of USB sticks/drives (at http://box/usb)
# iiab_usb_lib_show_all: True
# Set umask=0000 for VFAT, NTFS and exFAT in /etc/usbmount/usbmount.conf so
# Kolibri can export & import channels to USB sticks/drive:
# usb_lib_umask0000_for_kolibri: True
# All above are set in: github.com/iiab/iiab/blob/master/vars/default_vars.yml
# If nec, change them by editing /etc/iiab/local_vars.yml prior to installing!

View file

@ -1,19 +0,0 @@
<style>
.button {
background-color: #343a40;
border: none;
border-radius:.25rem;
color: white;
padding: .5rem .75rem;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 1rem;
font-weight:bold;
float:right;
}
.button:hover {
color: #ddd;
}
</style>
<a class="button" href="/upload2usb/">Upload to USB</a>

View file

@ -1,15 +0,0 @@
<?php
/*
* error.php
* Upload2USB App error
*/
?>
ERROR: Please make sure <span style="color:red; font-weight:bold;"> one and ONLY one </span>(no more, no less) removable USB stick is plugged into your Internet-in-a-Box. Please see IIAB FAQ, "<a href="https://wiki.iiab.io/go/FAQ#Can_students_upload_their_own_work%3F" style="font-weight:bold;">Can students upload their own work?</a>", for additional support.
<br/><br/>
<pre><?php if (isset($exception)) {echo (string)$exception;} ?></pre>

View file

@ -1,14 +0,0 @@
<?php
/*
* footer.php
* Upload2USB App Footer for all User Facing Pages
*/
?>
</div>
</div>
</div>
</body>
</html>

View file

@ -1,32 +0,0 @@
<?php
/*
* header.php
* Upload2USB App Header for all User Facing Pages
*/
include("upload2usb.php");
?>
<!DOCTYPE html>
<html>
<head>
<title><?php echo $title ?></title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/common/css/bootstrap4.min.css"/>
<link rel="stylesheet" href="/common/css/fa.all.min.css"/>
<link rel="stylesheet" href="/common/css/font-faces.css"/>
<script src="/common/js/jquery.min.js"></script>
<script src="/common/js/bootstrap4.min.js"></script>
</head>
<body class="text-center" style="background-color:#f5f5f5;">
<div id="container" class="container">
<div class="row">
<div class="col-sm-6 offset-sm-3 text-center" style="padding:15px;">
<a href="/usb/"><img class="mb-4" src="uk-swing.png" alt="" width="75"></a>
<h1 class="h3 mb-3 font-weight-normal"><?php echo $title ?></h1>

View file

@ -1,24 +0,0 @@
<?php
/*
* index.php
* Upload2USB App Index Page
*/
$title = "Upload to USB";
include("header.php");
//Check if folder for today exists, and get file count if it does
$file_count = getFileCount(getTargetFolderPath(0));
?>
<form action="upload-file.php" id="upload2usb_form" method="post" enctype="multipart/form-data">
<label for="upload2usb" style="font-weight:bold;padding-bottom:10px;">Upload your file here!</label><br/>
<input type="file" name="uploaded_file" id="uploaded_file"><br/><br/>
<button class="btn btn-dark" name="submit" type="submit" style="width:150px;">Upload</button>
</form>
<br/>
<?php echo $file_count ?> files have been uploaded today!
<?php include ("footer.php"); ?>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

View file

@ -1,58 +0,0 @@
<?php
/*
* upload-file.php
* Upload2USB App - Process Submission
*/
$title = "Upload to USB Results";
include("header.php");
//get folder path where file will be stored
$target_folder_path = getTargetFolderPath(1);
$uploaded_filename = basename($_FILES["uploaded_file"]["name"]);
$target_file = $target_folder_path . "/" . $uploaded_filename;
$upload_ok = 1;
$upload_msg = "";
if(!isset($_POST["submit"]) || !is_uploaded_file($_FILES['uploaded_file']['tmp_name'])) {
$upload_msg = "No file uploaded!";
$upload_ok = 0;
} elseif (!isFileMimeTypeAcceptable($_FILES["uploaded_file"]["tmp_name"])) {
$upload_msg = "You cannot upload zips, executables, xml, or binary files!";
$upload_ok = 0;
} elseif (file_exists($target_file)) {
if (!isFileContentUnique($target_folder_path, $_FILES["uploaded_file"]["tmp_name"])) {
$upload_msg = "This file already exists!";
$upload_ok = 0;
} else {
// rename file so name is unique
$new_filename = getUniqueFileName($target_folder_path, $uploaded_filename);
$target_file = $target_folder_path . "/" . $new_filename;
}
}
// Check if $upload_ok is set to 0 by an error
if ($upload_ok == 0) {
$upload_msg = "&#x274C; Your file was not uploaded. " . $upload_msg;
// if everything is ok, try to upload file
} else {
if (move_uploaded_file($_FILES["uploaded_file"]["tmp_name"], $target_file)) {
$upload_msg = "&#x1F60A; &#x2705; Your file <span style=\"font-weight:bold; font-style:italic;\">". htmlspecialchars( $uploaded_filename ). "</span> was successfully uploaded!";
} else {
$upload_ok = 0;
throw new RuntimeException('There was an error uploading your file. <br/><br/>');
}
}
$file_count = getFileCount($target_folder_path);
?>
<?php echo $upload_msg ?> <br/>
<?php echo $file_count ?> files have been uploaded today!
<?php include ("footer.php"); ?>

View file

@ -1,101 +0,0 @@
<?php
/*
* upload2usb.php
* Upload2USB App Helper Functions
*/
set_exception_handler(function (Throwable $exception) {
error_log('UPLOAD2USB ERROR: ' . (string)$exception);
include ("error.php");
});
//return the first removable USB drive location
function getTargetUSBDriveLocation () {
// Get the count of storage mounted at /media, and error if there is <>1 otherwise return upload path
# error if 1<>usb sticks are installed
$rmv_usb_path_count = shell_exec('lsblk --output NAME,TRAN,RM,MOUNTPOINT --pairs | cut -d " " -f 4 | grep "^MOUNTPOINT=\"/media" | wc -l');
if ($rmv_usb_path_count == 0) {
throw new RuntimeException('0 USB sticks found. <br/><br/>');
} elseif ($rmv_usb_path_count > 1) {
throw new RuntimeException('More than 1 USB sticks installed. <br/><br/>');
}
$rmv_usb_path = trim(str_replace('"', '', shell_exec('lsblk --output NAME,TRAN,RM,MOUNTPOINT --pairs | cut -d " " -f 4 | grep "^MOUNTPOINT=\"/media" | cut -d "=" -f 2')));
if (empty($rmv_usb_path)) {
throw new RuntimeException('Not able to find USB stick. <br/><br/>');
} else {
return $rmv_usb_path . "/";
}
}
//returns folder path where file will be stored, if create_folder_p = 1, it will create the folder if it doesn't exist
function getTargetFolderPath ($create_folder_p) {
$parent_dir = getTargetUSBDriveLocation();
$today_folder_name = "UPLOADS." . date("Y-m-d");
$target_folder_path = $parent_dir . $today_folder_name;
if (!file_exists($target_folder_path) && $create_folder_p) {
mkdir($target_folder_path, 0777) or throw new RuntimeException("Not able to create upload directory. <br/>Make sure 'usb_lib_writable_sticks' is set to 'True'. <br/><br/>");
}
return $target_folder_path;
}
//return number of files within a specified folder
function getFileCount ($folder_path) {
return count(glob($folder_path . "/*"));
}
//check if file mimetype is acceptable for upload
function isFileMimeTypeAcceptable ($file) {
$mimetype = strtolower(mime_content_type($file));
$invalid_mimetypes_str = array ("compress", "image/svg+xml", "octet", "text/xml", "xhtml+xml");
foreach ($invalid_mimetypes_str as $invalid_mt_str) {
if (str_contains($mimetype, $invalid_mt_str)) {
error_log('UPLOAD2USB ERROR - MIMETYPE: ' . $mimetype);
return false;
}
}
return true;
}
//check file content to see if it's unique or not
function isFileContentUnique ($target_folder_path, $file) {
$file_to_upload_md5 = md5_file($file);
$usb_dir = array_diff(scandir($target_folder_path), array('..', '.'));
foreach ($usb_dir as $dir_file) {
$dir_file = $target_folder_path . "/" . $dir_file;
if (!is_dir($dir_file)) {
$dir_file_md5 = md5_file($dir_file);
if ($file_to_upload_md5 == $dir_file_md5) {
return false;
}
}
}
return true;
}
//return unique filename
function getUniqueFileName ($target_folder_path, $filename) {
$new_filename = $filename;
$counter = 1;
while (file_exists($target_folder_path . "/" . $new_filename)) {
$counter++;
$new_filename = pathinfo($filename,8) . '-'. $counter . "." . pathinfo($filename,4);
}
return $new_filename;
}
// Check file size - we are not going to check file size for now.
// elseif ($_FILES["uploaded_file"]["size"] > 5000000) {
// $upload_msg = "Your file is too large.";
// $upload_ok = 0;
// }
?>

View file

@ -1,17 +0,0 @@
Format: http://dep.debian.net/deps/dep5/
Upstream-Name: usbmount
Upstream-Contact: Martin Dickopp <martin@zero-based.org>, Rogério Brito <rbrito@ime.usp.br>
Source: git://git.debian.org/usbmount/usbmount.git
Files: *
Copyright: 2004-2007, Martin Dickopp <martin@zero-based.org>
2008-2011, Rogério Brito <rbrito@ime.usp.br>
License: BSD-2
This package is free software; the copyright holder gives unlimited
permission to copy and/or distribute it, with or without
modifications, as long as this notice is preserved.
.
This package is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY, to the extent permitted by law; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.

View file

@ -1,235 +0,0 @@
#!/bin/sh
# This script mounts USB mass storage devices when they are plugged in
# and unmounts them when they are removed.
# Copyright © 2004, 2005 Martin Dickopp
# Copyright © 2008, 2009, 2010 Rogério Theodoro de Brito
# Copyright © 2025, Jerry Vonau
#
# This file is free software; the copyright holder gives unlimited
# permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
#
# This file is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
# https://github.com/iiab/iiab/blob/master/roles/usb_lib/files/usbmount/copyright
# https://github.com/rbrito/usbmount/blob/master/debian/copyright
#set -e
exec > /dev/null 2>&1
######################################################################
# Auxiliary functions
# Log a string via the syslog facility.
log()
{
if [ $1 != debug ] || expr "$VERBOSE" : "[yY]" > /dev/null; then
logger -p user.$1 -t "usbmount[$$]" -- "$2"
fi
}
# Test if the first parameter is in the list given by the second
# parameter.
in_list()
{
for v in $2; do
[ "$1" != "$v" ] || return 0
done
return 1
}
######################################################################
# Main program
# Default values for configuration variables.
ENABLED=1
MOUNTPOINTS=
FILESYSTEMS=
MOUNTOPTIONS=
FS_MOUNTOPTIONS=
VERBOSE=no
if [ -r /etc/usbmount/usbmount.conf ]; then
. /etc/usbmount/usbmount.conf
log debug "loaded usbmount configurations"
fi
if [ "${ENABLED:-1}" -eq 0 ]; then
log info "usbmount is disabled, see /etc/usbmount/usbmount.conf"
exit 0
fi
if [ ! -x /sbin/blkid ]; then
log err "cannot execute /sbin/blkid"
exit 1
fi
if [ "$1" = add ]; then
# Per Policy 9.3.2, directories under /var/run have to be created
# after every reboot.
if [ ! -e /var/run/usbmount ]; then
mkdir -p /var/run/usbmount
log debug "creating /var/run/usbmount directory"
else
log debug "/var/run/usbmount exists"
fi
umask 022
# Acquire lock.
log debug "trying to acquire lock /var/run/usbmount/.mount.lock"
lockfile-create --retry 6 /var/run/usbmount/.mount || \
{ log err "cannot acquire lock /var/run/usbmount/.mount.lock"; exit 1; }
trap '( lockfile-remove /var/run/usbmount/.mount )' 0
log debug "acquired lock /var/run/usbmount/.mount.lock"
# Grab device information from device and "divide it"
# FIXME: improvement: implement mounting by label (notice that labels
# can contain spaces, which makes things a little bit less comfortable).
DEVINFO=$(/sbin/blkid -p $DEVNAME)
FSTYPE=$(echo "$DEVINFO" | sed 's/.*[[:blank:]]TYPE="\([^"]*\)".*/\1/g; s/[[:blank:]]*//g;')
UUID=$(echo "$DEVINFO" | sed 's/.*[[:blank:]]UUID="\([^"]*\)".*/\1/g; s/[[:blank:]]*//g;')
USAGE=$(echo "$DEVINFO" | sed 's/.*[[:blank:]]USAGE="\([^"]*\)".*/\1/g; s/[[:blank:]]*//g;')
if ! echo $USAGE | egrep -q "(filesystem|disklabel)"; then
log debug "/$DEVNAME does not contain a filesystem or disklabel"
lockfile-remove /var/run/usbmount/.mount
exit
fi
log debug "/$DEVNAME contains filesystem type $FSTYPE"
BOOTFW_DEV=$(/usr/bin/findmnt -no source /boot/firmware)
log debug "BOOTFW_DEV $BOOTFW_DEV"
ROOT_DEV=$(/usr/bin/findmnt -no source /)
log debug "ROOT_DEV $ROOT_DEV"
BOOT_DEV=$(/usr/bin/findmnt -no source /boot)
log debug "BOOT_DEV $BOOT_DEV"
if [ $BOOTFW_DEV = /$DEVNAME ]; then
log debug "skipping BOOTFS_DEV $BOOTFS_DEV mounted at /boot/firmware"
lockfile-remove /var/run/usbmount/.mount
exit
elif [ $ROOT_DEV = /$DEVNAME ]; then
log debug "skipping ROOT_DEV $ROOT_DEV mounted at /"
lockfile-remove /var/run/usbmount/.mount
exit
elif [ $BOOT_DEV = /$DEVNAME ]; then
log debug "skipping BOOT_DEV $BOOT_DEV mount as /boot"
lockfile-remove /var/run/usbmount/.mount
exit
fi
# Try to use specifications in /etc/fstab to skip.
if egrep -q "^[[:blank:]]*$DEVNAME" /etc/fstab; then
log debug "skipping /$DEVNAME exit"
lockfile-remove /var/run/usbmount/.mount
exit
elif grep -q "^[[:blank:]]*UUID=$UUID" /etc/fstab; then
log debug "skipping $UUID"
lockfile-remove /var/run/usbmount/.mount
exit
else
log debug "/$DEVNAME contains filesystem type $FSTYPE"
fstype=$FSTYPE
# Test if the filesystem type is in the list of filesystem
# types to mount.
if in_list "$fstype" "$FILESYSTEMS"; then
# Search an available mountpoint.
for v in $MOUNTPOINTS; do
if [ -d "$v" ] && ! grep -q "^[^ ][^ ]* *$v " /proc/mounts; then
mountpoint="$v"
log debug "mountpoint $mountpoint is available for /$DEVNAME"
break
fi
done
if [ -n "$mountpoint" ]; then
# Determine mount options.
options=
for v in $FS_MOUNTOPTIONS; do
if expr "$v" : "-fstype=$fstype,."; then
options="$(echo "$v" | sed 's/^[^,]*,//')"
break
fi
done
if [ -n "$MOUNTOPTIONS" ]; then
options="$MOUNTOPTIONS${options:+,$options}"
fi
# Mount the filesystem.
log info "executing command: mount -t$fstype ${options:+-o$options} $DEVNAME $mountpoint"
mount "-t$fstype" "${options:+-o$options}" "$DEVNAME" "$mountpoint"
# Determine vendor and model.
vendor=
if [ -r "/sys$DEVPATH/device/vendor" ]; then
vendor="`cat \"/sys$DEVPATH/device/vendor\"`"
elif [ -r "/sys$DEVPATH/../device/vendor" ]; then
vendor="`cat \"/sys$DEVPATH/../device/vendor\"`"
elif [ -r "/sys$DEVPATH/device/../manufacturer" ]; then
vendor="`cat \"/sys$DEVPATH/device/../manufacturer\"`"
elif [ -r "/sys$DEVPATH/../device/../manufacturer" ]; then
vendor="`cat \"/sys$DEVPATH/../device/../manufacturer\"`"
fi
vendor="$(echo "$vendor" | sed 's/^[[:blank:]]\+//; s/[[:blank:]]\+$//')"
model=
if [ -r "/sys$DEVPATH/device/model" ]; then
model="`cat \"/sys$DEVPATH/device/model\"`"
elif [ -r "/sys$DEVPATH/../device/model" ]; then
model="`cat \"/sys$DEVPATH/../device/model\"`"
elif [ -r "/sys$DEVPATH/device/../product" ]; then
model="`cat \"/sys$DEVPATH/device/../product\"`"
elif [ -r "/sys$DEVPATH/../device/../product" ]; then
model="`cat \"/sys$DEVPATH/../device/../product\"`"
fi
model="$(echo "$model" | sed 's/^[[:blank:]]\+//; s/[[:blank:]]\+$//')"
# Run hook scripts; ignore errors.
export UM_DEVICE="$DEVNAME"
export UM_MOUNTPOINT="$mountpoint"
export UM_FILESYSTEM="$fstype"
export UM_MOUNTOPTIONS="$options"
export UM_VENDOR="$vendor"
export UM_MODEL="$model"
log info "executing command: run-parts /etc/usbmount/mount.d"
run-parts /etc/usbmount/mount.d || :
else
# No suitable mount point found.
log warning "no mountpoint found for $DEVNAME"
exit 1
fi
fi
fi
elif [ "$1" = remove ]; then
# A block or partition device has been removed.
# Test if it is mounted.
while read device mountpoint fstype remainder; do
if [ "$DEVNAME" = "$device" ]; then
# If the mountpoint and filesystem type are maintained by
# this script, unmount the filesystem.
if in_list "$mountpoint" "$MOUNTPOINTS" &&
in_list "$fstype" "$FILESYSTEMS"; then
log info "executing command: umount -l $mountpoint"
umount -l "$mountpoint"
# Run hook scripts; ignore errors.
export UM_DEVICE="$DEVNAME"
export UM_MOUNTPOINT="$mountpoint"
export UM_FILESYSTEM="$fstype"
log info "executing command: run-parts /etc/usbmount/umount.d"
run-parts /etc/usbmount/umount.d || :
fi
break
fi
done < /proc/mounts
else
log err "unexpected: action '$1'"
exit 1
fi
log debug "usbmount execution finished"

View file

@ -1,53 +0,0 @@
# Configuration file for the usbmount package, which mounts removable
# storage devices when they are plugged in and unmounts them when they
# are removed.
# Change to zero to disable usbmount
ENABLED=1
# Mountpoints: These directories are eligible as mointpoints for
# removable storage devices. A newly plugged in device is mounted on
# the first directory in this list that exists and on which nothing is
# mounted yet.
MOUNTPOINTS="/media/usb0 /media/usb1 /media/usb2 /media/usb3
/media/usb4 /media/usb5 /media/usb6 /media/usb7"
# Filesystem types: removable storage devices are only mounted if they
# contain a filesystem type which is in this list.
FILESYSTEMS="vfat ext2 ext3 ext4 hfsplus exfat fuseblk ntfs"
#############################################################################
# WARNING! #
# #
# The "sync" option may not be a good choice to use with flash drives, as #
# it forces a greater amount of writing operating on the drive. This makes #
# the writing speed considerably lower and also leads to a faster wear out #
# of the disk. #
# #
# If you omit it, don't forget to use the command "sync" to synchronize the #
# data on your disk before removing the drive or you may experience data #
# loss. #
# #
# It is highly recommended that you use the pumount command (as a regular #
# user) before unplugging the device. It makes calling the "sync" command #
# and mounting with the sync option unnecessary---this is similar to other #
# operating system's "safely disconnect the device" option. #
#############################################################################
# Mount options: Options passed to the mount command with the -o flag.
# See the warning above regarding removing "sync" from the options.
MOUNTOPTIONS="sync,noexec,nodev,noatime,nodiratime"
# Filesystem type specific mount options: This variable contains a space
# separated list of strings, each which the form "-fstype=TYPE,OPTIONS".
#
# If a filesystem with a type listed here is mounted, the corresponding
# options are appended to those specificed in the MOUNTOPTIONS variable.
#
# For example, "-fstype=vfat,gid=floppy,dmask=0007,fmask=0117" would add
# the options "gid=floppy,dmask=0007,fmask=0117" when a vfat filesystem
# is mounted.
FS_MOUNTOPTIONS=""
# If set to "yes", more information will be logged via the syslog
# facility.
VERBOSE=yes

View file

@ -7,10 +7,6 @@
# https://github.com/rbrito/usbmount/blob/master/README.md (2018-08-10)
# https://github.com/rbrito/usbmount/blob/master/usbmount.conf (2010-04-25)
# The variable, usb_lib_writable_sticks (e.g., in /etc/iiab/local_vars.yml), must be set to true
# in order for non-root users to be able to write to VFAT/FAT32, NTFS and exFAT USB sticks.
# If you are still not able to write to a mounted USB stick, try unmounting the drive
# (sudo umount <mountpoint>) and then remount it setting umask to 0000 manually (sudo mount -o umask=0000 <device name> <mountpoint>).
- name: Record (initial) disk space used
shell: df -B1 --output=used / | tail -1
@ -48,53 +44,27 @@
when: udev_unit.stat.exists is defined and udev_unit.stat.exists
# http://raspbian.raspberrypi.org/raspbian/pool/main/u/usbmount/usbmount_0.0.22_all.deb
#- name: Install {{ iiab_download_url }}/usbmount_0.0.22_all.deb, no longer supported by {RasPiOS, Debian, Ubuntu}
# apt:
# deb: "{{ iiab_download_url }}/usbmount_0.0.22_all.deb"
# # when: is_debian
- name: Install {{ iiab_download_url }}/usbmount_0.0.22_all.deb, no longer supported by {RasPiOS, Debian, Ubuntu}
apt:
deb: "{{ iiab_download_url }}/usbmount_0.0.22_all.deb"
# when: is_debian
- name: Install lockfile-progs and util-linux (findmnt blkid) for usbmount from OS repo
package:
name:
- lockfile-progs
- util-linux
state: present
# check status of usbmount on mintlinux - should be ok Ubuntu variant
# - name: Install usbmount from OS repo for Ubuntu variants
# package:
# name: usbmount
# state: present
# when: is_ubuntu
- name: Add dir {{ doc_root }}/local_content, where USB drive links can appear (0775) owned by {{ apache_user }}:{{ apache_user }}
- name: Add dir {{ doc_root }}/local_content, where USB drive links can appear (0775)
file:
state: directory
path: "{{ doc_root }}/local_content" # /library/www/html
owner: "{{ apache_user }}" # www-data
path: "{{ doc_root }}/local_content"
owner: "{{ apache_user }}"
group: "{{ apache_user }}" # 2020-02-13: changed from iiab_admin_user, after discussion on weekly call (#1228, #2222)
mode: 0775
- name: Set up dirs /etc/usbmount/mount.d, /etc/usbmount/umount.d, /media/usb0-7
file:
state: directory
path: "{{ item }}"
mode: 0755
with_items:
- /etc/usbmount/mount.d
- /etc/usbmount/umount.d
- /media/usb0
- /media/usb1
- /media/usb2
- /media/usb3
- /media/usb4
- /media/usb5
- /media/usb6
- /media/usb7
- name: Copy files from files/usbmount to filesystem
copy:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
mode: "{{ item.mode }}"
with_items:
- { src: 'usbmount/usbmount.conf', dest: '/etc/usbmount/', mode: '0644' }
- { src: 'usbmount/usbmount', dest: '/usr/local/sbin/', mode: '0755' }
- name: 'Install from template: /etc/udev/rules.d/usbmount.rules, /etc/systemd/system/usbmount@.service, /usr/local/sbin/iiab-clean-usb.sh'
- name: 'Install from template: /etc/udev/rules.d/usbmount.rules, /etc/systemd/system/usbmount@.service, /usr/bin/iiab-usb_lib-show-all-on, /usr/bin/iiab-usb_lib-show-all-off, /usr/sbin/iiab-clean-usb.sh'
template:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
@ -102,36 +72,23 @@
with_items:
- { src: 'usbmount.rules.j2', dest: '/etc/udev/rules.d/usbmount.rules', mode: '0644' }
- { src: 'usbmount@.service.j2', dest: '/etc/systemd/system/usbmount@.service', mode: '0644' }
- { src: 'iiab-clean-usb.sh', dest: '/usr/local/sbin/', mode: '0755' }
- name: Add dir {{ doc_root }}/upload2usb (0775) owned by {{ apache_user }}:{{ apache_user }}
file:
state: directory
path: "{{ doc_root }}/upload2usb"
owner: "{{ apache_user }}"
group: "{{ apache_user }}"
mode: 0755
- name: Copy files from files/upload2usb/ into {{ doc_root }}/upload2usb/
copy:
src: "{{ item }}"
dest: "{{ doc_root }}/upload2usb/"
with_fileglob:
- upload2usb/*
- { src: 'iiab-usb_lib-show-all-on', dest: '/usr/bin/', mode: '0755' }
- { src: 'iiab-usb_lib-show-all-off', dest: '/usr/bin/', mode: '0755' }
- { src: 'iiab-clean-usb.sh', dest: '/usr/sbin/', mode: '0755' }
# 2021-03-21: If usbmount is repackaged by apt as a result of Linux kernel 5.4+
# supporting exFAT, the stanza below (might) in future no longer be needed...
# SEE ALSO: https://github.com/iiab/iiab/blob/586bfc5cb1abf6b4333a21d3fa89695f115432dc/roles/2-common/tasks/packages.yml#L11-L12
#- name: Add ' exfat fuseblk ntfs' to FILESYSTEMS var in /etc/usbmount/usbmount.conf
# lineinfile:
# regexp: '^FILESYSTEMS=.*'
# line: 'FILESYSTEMS="vfat ext2 ext3 ext4 hfsplus exfat fuseblk ntfs"'
# path: /etc/usbmount/usbmount.conf
- name: Add ' exfat fuseblk ntfs' to FILESYSTEMS var in /etc/usbmount/usbmount.conf
lineinfile:
regexp: '^FILESYSTEMS=.*'
line: 'FILESYSTEMS="vfat ext2 ext3 ext4 hfsplus exfat fuseblk ntfs"'
path: /etc/usbmount/usbmount.conf
#- name: Remove /etc/usbmount/mount.d/00_create_model_symlink
# file:
# path: /etc/usbmount/mount.d/00_create_model_symlink
# state: absent
- name: Remove /etc/usbmount/mount.d/00_create_model_symlink
file:
path: /etc/usbmount/mount.d/00_create_model_symlink
state: absent
# RECORD 'USB_LIB' AS INSTALLED

View file

@ -1,7 +1,7 @@
# TO DO: (2020-02-13)
# - Look at analogous NGINX logic for http://box/usb in
# nginx/templates/iiab.conf.j2 and make that visually meaningful for teachers:
# https://github.com/iiab/iiab/blob/master/roles/nginx/templates/iiab.conf.j2#L5-L9
# https://github.com/iiab/iiab/blob/master/roles/nginx/templates/iiab.conf.j2#L5-L8
# "How do i fail a task in Ansible if the variable contains a boolean value?
@ -32,12 +32,12 @@
# If setup.yml becomes the norm in future, put the 2-3 stanzas below in there:
- name: "Set 'umask=0000' for {VFAT/FAT32, NTFS, exFAT} using var FS_MOUNTOPTIONS in /etc/usbmount/usbmount.conf -- for Kolibri exports AND student uploads to teacher's USB stick (using http://box/usb)"
- name: "Set 'umask=0000' for {VFAT/FAT32, NTFS, exFAT} using var FS_MOUNTOPTIONS in /etc/usbmount/usbmount.conf, so Kolibri exports work"
lineinfile:
regexp: '^FS_MOUNTOPTIONS=.*'
line: 'FS_MOUNTOPTIONS="-fstype=vfat,umask=0000 -fstype=ntfs,umask=0000 -fstype=exfat,umask=0000"'
path: /etc/usbmount/usbmount.conf
when: usb_lib_writable_sticks
when: usb_lib_umask0000_for_kolibri
# Setting 'umask=0000' for all filesystems: (much the same thing as above, as
# the mount command does not use this umask setting for filesystems like ext4)
@ -46,14 +46,14 @@
# regexp: '^MOUNTOPTIONS=.*'
# line: 'MOUNTOPTIONS="sync,noexec,nodev,noatime,nodiratime,umask=0000"'
# path: /etc/usbmount/usbmount.conf
# when: usb_lib_writable_sticks
# when: usb_lib_umask0000_for_kolibri
- name: 'Set FS_MOUNTOPTIONS="" in /etc/usbmount/usbmount.conf -- e.g. if Kolibri exports AND student uploads to teacher USB stick are not needed'
- name: 'Set FS_MOUNTOPTIONS="" in /etc/usbmount/usbmount.conf, e.g. if Kolibri will not be used'
lineinfile:
regexp: '^FS_MOUNTOPTIONS=.*'
line: 'FS_MOUNTOPTIONS=""' # Restore apt pkg default, e.g. for runrole
path: /etc/usbmount/usbmount.conf
when: not usb_lib_writable_sticks
when: not usb_lib_umask0000_for_kolibri
- name: Enable/Disable/Restart NGINX
@ -66,6 +66,12 @@
path: /etc/usbmount/mount.d/00_create_model_symlink
state: absent
- name: Put variable in iiab.env that enables display of content at root of USB
lineinfile:
path: "{{ iiab_env_file }}"
regexp: "^IIAB_USB_LIB_SHOW_ALL.*"
line: "IIAB_USB_LIB_SHOW_ALL={{ iiab_usb_lib_show_all }}"
- name: Add 'usb_lib' variable values to {{ iiab_ini_file }}
ini_file:
@ -77,10 +83,10 @@
- option: name
value: USB_LIB
- option: description
value: '"USB_LIB (1) automounts teacher content on USB sticks to /library/www/html/local_content, so students can browse the USB; AND (2) allows students to upload their work to USB sticks / drives, all from http://box/usb"'
value: '"USB_LIB automounts Teacher Content on USB drives to /library/www/html/local_content, so students can browse it almost immediately at http://box/usb"'
- option: usb_lib_install
value: "{{ usb_lib_install }}"
- option: usb_lib_enabled
value: "{{ usb_lib_enabled }}"
- option: usb_lib_writable_sticks
value: "{{ usb_lib_writable_sticks }}"
- option: usb_lib_umask0000_for_kolibri
value: "{{ usb_lib_umask0000_for_kolibri }}"

View file

@ -1,21 +1,20 @@
- name: Install /etc/usbmount/mount.d/70-usb-library from template, if usb_lib_enabled
template:
src: mount.d/70-usb-library.j2
dest: /etc/usbmount/mount.d/70-usb-library
src: mount.d/70-usb-library
dest: /etc/usbmount/mount.d/
owner: root
group: root
mode: '0751'
when: usb_lib_enabled
# 20250125: commenting out stale file, superseded by iiab-clean-usb.sh
# - name: Install /etc/usbmount/umount.d/70-usb-library from template, if usb_lib_enabled
# template:
# src: umount.d/70-usb-library
# dest: /etc/usbmount/umount.d
# owner: root
# group: root
# mode: '0751'
# when: usb_lib_enabled
- name: Install /etc/usbmount/umount.d/70-usb-library from template, if usb_lib_enabled
template:
src: umount.d/70-usb-library
dest: /etc/usbmount/umount.d
owner: root
group: root
mode: '0751'
when: usb_lib_enabled
- name: Remove /etc/usbmount/mount.d/70-usb-library if not usb_lib_enabled
file:
@ -23,12 +22,11 @@
state: absent
when: not usb_lib_enabled
# 20250125: commenting out stale file, superseded by iiab-clean-usb.sh
# - name: Remove /etc/usbmount/umount.d/70-usb-library if not usb_lib_enabled
# file:
# path: /etc/usbmount/umount.d/70-usb-library
# state: absent
# when: not usb_lib_enabled
- name: Remove /etc/usbmount/umount.d/70-usb-library if not usb_lib_enabled
file:
path: /etc/usbmount/umount.d/70-usb-library
state: absent
when: not usb_lib_enabled
- name: Restart 'nginx' systemd service
systemd:

View file

@ -1,14 +1,14 @@
#!/bin/bash
# Remove symlink in /library/www/html/local_content to automounted USB drive
DEVICE="/$(echo $1 | sed 's|-|/|')"
MNT_POINT=$(findmnt -no target $DEVICE)
CONTENT_LINK_USB=$(basename $MNT_POINT | awk '{print toupper($0)}')
# Remove symlink in /library/content to automounted usb drive
#
DEVICE=`echo $@ | sed -s 's|-|/|'`
MNT_POINT=`findmnt -n /$DEVICE | awk '{print $1}'`
CONTENT_LINK_USB=`basename $MNT_POINT | awk '{print toupper($0)}'`
CONTENT_LINK="/library/www/html/local_content/$CONTENT_LINK_USB"
logger -t "usb_lib (iiab-clean-usb.sh)" "Attempting to remove symlink $CONTENT_LINK, as auto-created earlier by usbmount."
logger -p user.notice -t "usbmount" -- "Attempting to remove link $CONTENT_LINK."
if [ -L $CONTENT_LINK ]; then
/usr/bin/rm $CONTENT_LINK
logger -t "usb_lib (iiab-clean-usb.sh)" "Symlink $CONTENT_LINK removed, as auto-created earlier by usbmount."
/bin/rm $CONTENT_LINK
logger -p user.notice -t "usbmount" -- "$CONTENT_LINK removed."
fi

View file

@ -0,0 +1,72 @@
#!/bin/bash
# Create symlink in DocumentRoot/content to autmounted usb drive
#
# based on a similar script in the xs-rsync package
# by Martin Langhoff <martin@laptop.org>
#
# and the adaptation for xs-activity-server by Douglas Bagnall
# <douglas@paradise.net.nz>
#
# by Tim Moody tim@timmoody.com
source {{ iiab_env_file }}
case $IIAB_USB_LIB_SHOW_ALL in
'True'|'true'|'TRUE')
logger -p user.notice -t "70-usb-library" -- "Display entire USB drive is True. Checking for rootfs or /library on $UM_MOUNTPOINT."
# regularize the variable
IIAB_USB_LIB_SHOW_ALL=True
;;
*)
logger -p user.notice -t "70-usb-library" -- "Looking for /share, /Share, /Piratebox/Share, /USB, or /usb on $UM_MOUNTPOINT."
;;
esac
VERBOSE=yes
SHARE_DIR=""
# Only show content if in these directories
if [ -d $UM_MOUNTPOINT/share ]; then
SHARE_DIR="$UM_MOUNTPOINT/share"
fi
if [ -d $UM_MOUNTPOINT/Share ]; then
SHARE_DIR="$UM_MOUNTPOINT/Share"
fi
if [ -d $UM_MOUNTPOINT/Piratebox/Share ]; then
SHARE_DIR="$UM_MOUNTPOINT/Piratebox/Share"
fi
if [ -d $UM_MOUNTPOINT/USB ]; then
SHARE_DIR="$UM_MOUNTPOINT/USB"
fi
if [ -d $UM_MOUNTPOINT/usb ]; then
SHARE_DIR="$UM_MOUNTPOINT/usb"
fi
if [ "$IIAB_USB_LIB_SHOW_ALL" == "True" ]; then
UM_DEV=`findmnt $UM_MOUNTPOINT | grep / | awk '{print $2}'`
LIB_DEV=`findmnt /library | grep / | awk '{print $2}' |awk -F '[' '{print $1}'`
ROOT_DEV=`findmnt / | grep / | awk '{print $2}'`
if [ "$UM_DEV" == "$LIB_DEV" ]; then
logger -p user.notice -t "70-usb-library" -- "skipping $UM_MOUNTPOINT containing /library"
#echo "lib on dev"
elif [ "$UM_DEV" == "$ROOT_DEV" ]; then
logger -p user.notice -t "70-usb-library" -- "skipping $UM_MOUNTPOINT containing rootfs"
#echo "rootfs on dev"
else
SHARE_DIR="$UM_MOUNTPOINT"
fi
fi
if [ ! -z "$SHARE_DIR" ]; then
logger -p user.notice -t "70-usb-library" -- "Found Share Directory $SHARE_DIR."
else
logger -p user.notice -t "70-usb-library" -- "did not find /share, /Share, /Piratebox/Share, /USB, or /usb on USB"
fi
if [ "$SHARE_DIR" != "" ];then
CONTENT_LINK_USB=`basename $UM_MOUNTPOINT | awk '{print toupper($0)}'`
CONTENT_LINK="{{ doc_root }}/local_content/$CONTENT_LINK_USB"
logger -p user.notice -t "70-usb-library" -- "Creating link to $CONTENT_LINK."
ln -s $SHARE_DIR $CONTENT_LINK
fi

View file

@ -1,67 +0,0 @@
#!/bin/bash
# Create symlink in DocumentRoot/content to automounted usb drive
#
# based on a similar script in the xs-rsync package
# by Martin Langhoff <martin@laptop.org>
#
# and the adaptation for xs-activity-server by Douglas Bagnall
# <douglas@paradise.net.nz>
#
# by Tim Moody tim@timmoody.com
# Better to set this in /etc/usbmount/usbmount.conf
# VERBOSE=yes
# UM_MOUNTPOINT is documented at: https://github.com/rbrito/usbmount#hook-scripts
UM_DEV=$(findmnt -no source $UM_MOUNTPOINT)
# 2022-06-16 better security thanks to @tim-moody and @jvonau:
# https://github.com/iiab/iiab/pull/3254
LIB_DEV=$(findmnt -no source /library | cut -d '[' -f 1)
ROOT_DEV=$(findmnt -no source /)
BOOT_DEV=$(findmnt -no source /boot)
BOOTFW_DEV=$(findmnt -no source /boot/firmware)
# Verbose logging to illuminate occasional boot bugginess:
logger -t "usb_lib (70-usb-library)" "UM_DEV is: $UM_DEV"
logger -t "usb_lib (70-usb-library)" "LIB_DEV is: $LIB_DEV"
logger -t "usb_lib (70-usb-library)" "ROOT_DEV is: $ROOT_DEV"
logger -t "usb_lib (70-usb-library)" "BOOT_DEV is: $BOOT_DEV"
logger -t "usb_lib (70-usb-library)" "BOOTFW_DEV is: $BOOTFW_DEV"
if [ "$UM_DEV" == "$LIB_DEV" ]; then
logger -t "usb_lib (70-usb-library)" "Skipping $UM_MOUNTPOINT containing /library"
exit 1
elif [ "$UM_DEV" == "$ROOT_DEV" ]; then
logger -t "usb_lib (70-usb-library)" "Skipping $UM_MOUNTPOINT containing rootfs"
exit 1
elif [ "$UM_DEV" == "$BOOT_DEV" ]; then
logger -t "usb_lib (70-usb-library)" "Skipping $UM_MOUNTPOINT containing /boot"
exit 1
elif [ "$UM_DEV" == "$BOOTFW_DEV" ]; then
logger -t "usb_lib (70-usb-library)" "Skipping $UM_MOUNTPOINT containing /boot/firmware"
exit 1
fi
# 2025-01-25: Check for existence of folder PUBLIC on USB stick: if found, the stick will not be completely browsable.
# Teachers can set their stick for 1 of 2 two "personalities" — students can either upload "confidential homework" or
# "public artwork" — as summarized here: https://github.com/iiab/iiab/blob/master/roles/usb_lib/README.rst
if [ -d $UM_MOUNTPOINT/PUBLIC ]; then
SHARE_DIR=$UM_MOUNTPOINT/PUBLIC
logger -t "usb_lib (70-usb-library)" "Found /PUBLIC on $UM_MOUNTPOINT"
else
SHARE_DIR=$UM_MOUNTPOINT
logger -t "usb_lib (70-usb-library)" "Did not find /PUBLIC on $UM_MOUNTPOINT"
fi
CONTENT_LINK_USB=$(basename $UM_MOUNTPOINT | awk '{print toupper($0)}')
if [ -z "$CONTENT_LINK_USB" ]; then
logger -t "usb_lib (70-usb-library)" 'ERROR: Var CONTENT_LINK_USB is empty ("rm -rf /library/www/html/local_content/" would be dangerous!)'
exit 1
fi
CONTENT_LINK="{{ doc_root }}/local_content/$CONTENT_LINK_USB"
# 'rm -rf' even stronger than 'ln -nsf' and 'ln -Tsf'
# https://serverfault.com/questions/147787/how-to-update-a-symbolic-link-target-ln-f-s-not-working/522483#522483
logger -t "usb_lib (70-usb-library)" "Creating link from $CONTENT_LINK to $SHARE_DIR"
rm -rf $CONTENT_LINK
ln -s $SHARE_DIR $CONTENT_LINK

View file

@ -12,7 +12,7 @@
CONTENT_LINK_USB=`basename $UM_MOUNTPOINT | awk '{print toupper($0)}'`
CONTENT_LINK="{{ doc_root }}/local_content/$CONTENT_LINK_USB"
logger -p user.notice -t "usb_lib (70-usb-library)" -- "Attempting to remove link $CONTENT_LINK."
logger -p user.notice -t "70-usb-library" -- "Attempting to remove link $CONTENT_LINK."
if [ -L $CONTENT_LINK ]; then
{% if is_debuntu %}
@ -20,5 +20,5 @@ if [ -L $CONTENT_LINK ]; then
{% else %}
/usr/bin/rm -f $CONTENT_LINK
{% endif %}
logger -p user.notice -t "usb_lib (70-usb-library)" -- "$CONTENT_LINK removed."
logger -p user.notice -t "70-usb-library" -- "$CONTENT_LINK removed."
fi

View file

@ -1,3 +1,5 @@
ACTION=="add", SUBSYSTEMS=="usb", SUBSYSTEM=="block", ENV{ID_FS_USAGE}=="filesystem" PROGRAM="/bin/systemd-escape -p --template=usbmount@.service $env{DEVNAME}", ENV{SYSTEMD_WANTS}+="%c"
ACTION=="remove", SUBSYSTEMS=="usb", SUBSYSTEM=="block", ENV{ID_FS_USAGE}=="filesystem" PROGRAM="/bin/systemd-escape -p /usr/share/usbmount/usbmount remove"
KERNEL=="sd*", DRIVERS=="sbp2", ACTION=="add", PROGRAM="/bin/systemd-escape -p --template=usbmount@.service $env{DEVNAME}", ENV{SYSTEMD_WANTS}+="%c"
KERNEL=="sd*", SUBSYSTEMS=="usb", ACTION=="add", PROGRAM="/bin/systemd-escape -p --template=usbmount@.service $env{DEVNAME}", ENV{SYSTEMD_WANTS}+="%c"
KERNEL=="ub*", SUBSYSTEMS=="usb", ACTION=="add", PROGRAM="/bin/systemd-escape -p --template=usbmount@.service $env{DEVNAME}", ENV{SYSTEMD_WANTS}+="%c"
KERNEL=="sd*", SUBSYSTEMS=="usb", ACTION=="remove", PROGRAM="/usr/share/usbmount/usbmount remove"

View file

@ -1,15 +1,14 @@
[Unit]
BindTo=%i.device
After=%i.device
After=systemd-udev-trigger.service
ConditionPathExists=/var/run
After=rc-local.service
[Service]
#Type=oneshot
TimeoutStartSec=0
Environment=DEVNAME=%I
ExecStart=/usr/local/sbin/usbmount add
ExecStop=/usr/local/sbin/iiab-clean-usb.sh %I
ExecStart=/usr/share/usbmount/usbmount add
ExecStop=/usr/sbin/iiab-clean-usb.sh %I
ExecStopPost=/bin/umount /%I
RemainAfterExit=yes
RuntimeDirectory=usbmount

View file

@ -69,8 +69,7 @@
# WordPress) so './runrole <ROLE>' and similar are fully self-sufficient!
- name: "Run php-settings.yml -- allows post-install toggling of nginx_high_php_limits in /etc/iiab/local_vars.yml -- if you run './runrole www_options'"
include_tasks: php-settings.yml
# 2025-01-29: PHP's own defaults (presumably from the 1990s?) were Way Too Low -- for usb-lib's upload2usb, and in general -- so let's run php-settings.yml every time!
# when: nginx_high_php_limits or matomo_install or moodle_install or nextcloud_install or pbx_install or wordpress_install
when: nginx_high_php_limits or matomo_install or moodle_install or nextcloud_install or pbx_install or wordpress_install
# 'Is a "Rapid Power Off" button possible for low-electricity environments?'
@ -78,22 +77,22 @@
# COMPARE nginx_high_php_limits further above.
# 2020-03-08: DOES THE FLAG BELOW (allow_www_data_poweroff) PRESUMABLY WORK
# 2020-03-08: DOES THE FLAG BELOW (allow_www_data_sudo) PRESUMABLY WORK
# WITH NGINX TOO ? (The single-click poweroff button on IIAB's home
# page certainly does still work with NGINX.)
- name: Give {{ apache_user }} (per variable apache_user) permission to poweroff, installing /etc/sudoers.d/020_www_data_poweroff from template
- name: Give {{ apache_user }} (per variable apache_user) permission to poweroff, installing /etc/sudoers.d/020_apache_poweroff from template
template:
src: 020_www_data_poweroff.j2
dest: /etc/sudoers.d/020_www_data_poweroff
src: 020_apache_poweroff.j2
dest: /etc/sudoers.d/020_apache_poweroff
mode: '0440'
when: allow_www_data_poweroff
when: allow_www_data_sudo
- name: Remove {{ apache_user }} (per variable apache_user) permission to poweroff, removing /etc/sudoers.d/020_www_data_poweroff
- name: Remove {{ apache_user }} (per variable apache_user) permission to poweroff, removing /etc/sudoers.d/020_apache_poweroff
file:
path: /etc/sudoers.d/020_www_data_poweroff
path: /etc/sudoers.d/020_apache_poweroff
state: absent
when: not allow_www_data_poweroff
when: not allow_www_data_sudo
# 2022-06-30: internet_available var removed

View file

@ -21,19 +21,11 @@
#
# This takes care of essentially everything (e.g. output "America/New_York")
# by checking (1) symlink /etc/localtime then (2) text file /etc/timezone if
# nec, then (3) if neither exist, "UTC" is declared (correctly!) Potential
# nec, then (3) if neither exist, "UTC" is declated (correctly!) Potential
# drawback: timedatectl is not easily usable within chroot environments.
# 2025-01-29: Current GitHub Actions chroot environments for RPi (using guyot/arm-runner-action@v2) surface this error, after PR #3927 mainlined php-settings.yml...
# "System has not been booted with systemd as init system (PID 1). Can't operate.\nFailed to connect to bus: Host is down"
# ...which might be mitigated in 2 ways:
# 1) Try spawning these "guyot/arm-runner-action@v2" GHA workflows with... use_systemd_nspawn: true
# 2) Weaken timedatectl command just below, trying this instead... shell: readlink /etc/localtime | sed 's#^/usr/share/zoneinfo/##'
- name: Extract Time Zone from symlink /etc/localtime, text file /etc/timezone, or if all else fails declare Etc/UTC
# command: timedatectl show -p Timezone --value
# 2025-02-01: "guyot/arm-runner-action@v2" GHA workflows don't seem to work with "use_systemd_nspawn: true", so hack in the equivalent of timedatectl...
shell: tmp=$(readlink /etc/localtime) && echo $tmp | sed 's|^/usr/share/zoneinfo/||' || cat /etc/timezone || echo Etc/UTC
- name: Extract Time Zone from symlink /etc/localtime &/or text file /etc/timezone (or lack thereof!)
command: timedatectl show -p Timezone --value
register: tz_cli
- name: Store 'date.timezone = {{ tz_cli.stdout }}' (from above) in /etc/php/{{ php_version }}/fpm/php.ini and /etc/php/{{ php_version }}/cli/php.ini
@ -215,4 +207,4 @@
# name: php{{ php_version }}-fpm
# state: restarted
# when: matomo_install or moodle_install or nextcloud_install or pbx_install or wordpress_install # 5-STANZA BLOCK ENDS. COMPARE allow_www_data_poweroff conditionals below.
# when: matomo_install or moodle_install or nextcloud_install or pbx_install or wordpress_install # 5-STANZA BLOCK ENDS. COMPARE allow_www_data_sudo conditionals below.

View file

@ -7,8 +7,8 @@
# https://github.com/iiab/iiab/wiki/Technical-Contributors-Guide#female_detective-understanding-ansible
APT_PATH=/usr/bin # Avoids problematic /usr/local/bin/apt on Linux Mint
CURR_VER=undefined # Ansible version you have installed, e.g. [core 2.18.3]
GOOD_VER=2.18.3 # Orig for 'yum install [rpm]' & XO laptops (pip install)
CURR_VER=undefined # Ansible version you have installed, e.g. [core 2.18.1]
GOOD_VER=2.18.1 # Orig for 'yum install [rpm]' & XO laptops (pip install)
# 2021-06-22: The apt approach (with PPA source in /etc/apt/sources.list.d/ and
# .gpg key etc) are commented out with ### below. Associated guidance/comments

View file

@ -101,18 +101,10 @@ function cat_cmd() { # $1 = command + params, $2 = explanation
spc_params=$(echo "$1" | sed 's/^\s*\S\S*\s*/ /;s/\s*$//') # Drop command on left; Keep a single space + params on right; RTrim
#spc_params=$(echo "$1" | sed 's/^\s*\S*//;s/\s*$//;s/^\s\s*/ /') # LTrim + drop original path + command on left; RTrim; Compress whitespace in between
#spc_params=$(echo "$1" | sed 's/^[[:blank:]]*[^[:blank:]]*//;s/[[:blank:]]*$//;s/^[[:blank:]][[:blank:]]*/ /') # Equivalent (POSIX compliant)
if [[ $path_cmd == "" ]]; then
if [[ $2 == "" ]]; then
echo "COMMAND: $1" >> $outfile
else
echo "COMMAND: $1 # $2" >> $outfile
fi
if [[ $2 == "" ]]; then
echo "COMMAND: $path_cmd$spc_params" >> $outfile
else
if [[ $2 == "" ]]; then
echo "COMMAND: $path_cmd$spc_params" >> $outfile
else
echo "COMMAND: $path_cmd$spc_params # $2" >> $outfile
fi
echo "COMMAND: $path_cmd$spc_params # $2" >> $outfile
fi
echo >> $outfile
if [[ $path_cmd == "" ]]; then
@ -162,24 +154,20 @@ for f in "$@"; do
done
if [ $# -eq 0 ]; then
echo -e " 2. Regular Files etc:\n"
echo -e " 2. Regular Files:\n"
else
echo -e "\n 2. Regular Files etc:\n"
echo -e "\n 2. Regular Files:\n"
fi
echo -e "\n\n\n2. REGULAR FILES ETC\n" >> $outfile
echo -e "\n\n\n2. REGULAR FILES\n" >> $outfile
#cat_file /dev/sda # Device "file" test
#cat_file /nonsense # Non-existence test
#cat_file /opt/iiab/iiab # Directory test
#cat_file /tmp/empty-file # Empty file test
#cat_file /usr/bin/iiab-support-on # Symlink test
cat_file /.iiab-image
cat_file /etc/default/locale # e.g. on Debian 12
cat_file /etc/locale.conf # e.g. on Debian 13+ and Ubuntu
cat_cmd 'localectl' 'Locale settings'
cat_cmd 'locale -a' 'Available locales'
cat_file /etc/iiab/iiab.env
cat_file /etc/iiab/iiab.ini
cat_file /etc/iiab/local_vars.yml # Redacts most passwords above
cat_file /etc/iiab/local_vars.yml # Redacts most passwords above
cat_file /etc/iiab/iiab_state.yml
cat_file /etc/resolv.conf
cat_file /etc/network/interfaces
@ -205,10 +193,8 @@ cat_dir /etc/netplan # Redacts most passwords above
echo -e "\n 4. Output of Commands:\n"
echo -e "\n\n\n\n4. OUTPUT OF COMMANDS\n" >> $outfile
cat_cmd 'uname -a' 'Linux kernel'
cat_cmd 'sudo dmesg | grep -i "command line:"' 'Kernel boot parameters'
cat_cmd 'free' 'RAM memory'
cat_cmd 'lscpu' 'CPU details'
cat_cmd 'rpi-eeprom-update' 'RPi Bootloader EEPROM'
cat_cmd 'df -h' 'Disk usage'
cat_cmd 'df -ah' 'Disk usage detail'
cat_cmd 'lsblk' 'Partition mount points'
@ -233,14 +219,11 @@ cat_cmd 'iw list' 'List capabilities of all wireless devices'
cat_cmd 'systemctl status hostapd' 'Downstream Wi-Fi: Is hostapd running?'
cat_cmd 'ls -l /etc/wpa_supplicant' 'Upstream Wi-Fi'
cat_cmd 'ps -AH' 'Process hierarchy: staging of hostapd & wpa_supplicant?'
cat_cmd 'sudo journalctl -b | grep wpa_supplicant' 'wpa_supplicant log since boot'
cat_cmd 'sudo journalctl -b | grep NetworkManager | head -100' 'NetworkManager log since boot'
#cat_cmd 'sudo dmesg | grep brcm' 'Diagnostic messages: RPi Wi-Fi firmware'
cat_cmd 'sudo dmesg | grep Firmware:' '(Wi-Fi) firmware boot diagnostics'
cat_cmd 'ls -l /lib/firmware/cypress/*43430*' 'WiFi firmware for: RPi Zero W, Zero 2 W & 3'
cat_cmd 'ls -l /lib/firmware/cypress/*43455*' 'WiFi firmware for: RPi 3 B+, 4, 5 & 500'
cat_cmd 'sudo dmesg | grep -i -e 80211 -e 802\.11 -e wireless -e wifi -e wlan -e broadcom -e brcm -e bcm -e realtek | head -100' 'Wi-Fi firmware/driver msgs'
#cat_cmd 'dmesg | grep brcm' 'Diagnostic messages: RPi Wi-Fi firmware'
cat_cmd 'dmesg | grep -i -e 80211 -e 802\.11 -e wireless -e wifi -e wlan -e broadcom -e brcm -e bcm -e realtek | head -100' 'Wi-Fi firmware/driver msgs'
cat_cmd 'lspci -nn' 'Devices on PCI buses'
cat_cmd 'ls -l /lib/firmware/cypress/*43430*' 'RPi Zero W & 3 WiFi firmware'
cat_cmd 'ls -l /lib/firmware/cypress/*43455*' 'RPi 3 B+ & 4 WiFi firmware'
cat_cmd 'env' 'Environment variables'
cat_cmd 'node -v' 'Node.js version'
cat_cmd 'npm -v' 'npm version'
@ -249,10 +232,10 @@ cat_cmd 'cd /usr/local/calibre-web-py3; sudo git log --graph --oneline --decorat
cat_cmd 'sudo lb --version' 'xklb version'
cat_cmd 'sudo yt-dlp --version' 'yt-dlp version'
cat_cmd 'systemctl status calibre-web' 'Is Calibre-Web running?'
cat_cmd 'sudo journalctl -u calibre-web | tail -100' 'Calibre-Web systemd log'
cat_cmd 'journalctl -u calibre-web | tail -100' 'Calibre-Web systemd log'
cat_tail /var/log/calibre-web.log 100
cat_tail /var/log/xklb.log 300
cat_cmd 'sudo journalctl -t IIAB-CMDSRV' 'Admin Console CMDSRV log'
cat_cmd 'journalctl -t IIAB-CMDSRV' 'Admin Console CMDSRV log'
#cat_cmd 'ansible localhost -m setup 2>/dev/null' 'All Ansible facts' # For cleaner scraping of Ansible vars, consider "./runrole all-vars /tmp/all-ansible-vars" 27-31 lines above?
echo -e "\n 5. Firewall Rules:\n"

View file

@ -66,4 +66,4 @@ But first off, the file is compiled by harvesting 1 + 6 kinds of things:
## Source Code
Please look over the bottom of [iiab-diagnostics](iiab-diagnostics) (lines 135-273 especially) to learn more about which common IIAB files and commands make this rapid troubleshooting possible.
Please look over the bottom of [iiab-diagnostics](iiab-diagnostics) (lines 127-256 especially) to learn more about which common IIAB files and commands make this rapid troubleshooting possible.

View file

@ -13,7 +13,7 @@
# IIAB (PRE-)release version number, for {{ iiab_env_file }}
iiab_base_ver: 8.3
iiab_base_ver: 8.2
iiab_revision: 0
# 2022-06-23: ./iiab-install (with 'sudo iiab') follow the traditional linear
@ -274,7 +274,7 @@ nginx_port: 80
nginx_interface: 0.0.0.0
nginx_conf_dir: /etc/nginx/conf.d
nginx_log_dir: /var/log/nginx
# SEE BELOW: nginx_high_php_limits, allow_www_data_poweroff
# SEE BELOW: nginx_high_php_limits, allow_www_data_sudo
# roles/www_base runs here (mandatory)
@ -307,9 +307,11 @@ bluetooth_term_enabled: False
# USB_LIB
usb_lib_install: True
usb_lib_enabled: True
# Set umask=0000 for VFAT, NTFS and exFAT in /etc/usbmount/usbmount.conf for
# Kolibri exports, and student uploads to teacher's USB stick (http://box/usb)
usb_lib_writable_sticks: True
# Show entire contents of USB sticks/drives (at http://box/usb)
iiab_usb_lib_show_all: True
# Set umask=0000 for VFAT, NTFS and exFAT in /etc/usbmount/usbmount.conf so
# Kolibri can export & import channels to USB sticks/drive:
usb_lib_umask0000_for_kolibri: True
systemd_location: /lib/systemd/system # 2-common iiab-startup also uses
# Common UNIX Printing System (CUPS)
@ -339,7 +341,7 @@ nginx_high_php_limits: False
# ALSO: ADJUST "client_max_body_size 10000M;" AS NEC, IN: /etc/nginx/server.conf
# Make this True to enable http://box/js-menu/menu-files/services/power_off.php and set-server-time.php
allow_www_data_poweroff: False
allow_www_data_sudo: True
apache_service: apache2
apache_user: www-data # Admin Console uses

View file

@ -172,7 +172,7 @@ pi_swap_file_size: 1024
# roles/nginx runs here (mandatory)
# roles/www_base runs here (mandatory)
# SEE BELOW: nginx_high_php_limits, allow_www_data_poweroff
# SEE BELOW: nginx_high_php_limits, allow_www_data_sudo
# 4-SERVER-OPTIONS
@ -192,9 +192,11 @@ bluetooth_install: True
bluetooth_enabled: False
bluetooth_term_enabled: False
# Set umask=0000 for VFAT, NTFS and exFAT in /etc/usbmount/usbmount.conf for
# Kolibri exports, and student uploads to teacher's USB stick (http://box/usb)
usb_lib_writable_sticks: True
# Show entire contents of USB sticks/drives (at http://box/usb)
iiab_usb_lib_show_all: True
# Set umask=0000 for VFAT, NTFS and exFAT in /etc/usbmount/usbmount.conf so
# Kolibri can export & import channels to USB sticks/drive:
usb_lib_umask0000_for_kolibri: True
# Common UNIX Printing System (CUPS)
cups_install: True
@ -217,7 +219,7 @@ nginx_high_php_limits: False
# ALSO: ADJUST "client_max_body_size 10000M;" AS NEC, IN: /etc/nginx/server.conf
# Make this True to enable http://box/js-menu/menu-files/services/power_off.php and set-server-time.php
allow_www_data_poweroff: False
allow_www_data_sudo: True
# Toggle iiab-refresh-wiki-docs scraping for offline docs (http://box/info)
nodocs: False

View file

@ -12,8 +12,8 @@ munin_install: True
munin_enabled: True
vnstat_install: True
vnstat_enabled: True
usb_lib_writable_sticks: False
allow_www_data_poweroff: False
usb_lib_umask0000_for_kolibri: False
allow_www_data_sudo: True
# By default
# kiwix
# awstats

View file

@ -172,7 +172,7 @@ pi_swap_file_size: 1024
# roles/nginx runs here (mandatory)
# roles/www_base runs here (mandatory)
# SEE BELOW: nginx_high_php_limits, allow_www_data_poweroff
# SEE BELOW: nginx_high_php_limits, allow_www_data_sudo
# 4-SERVER-OPTIONS
@ -192,9 +192,11 @@ bluetooth_install: True
bluetooth_enabled: False
bluetooth_term_enabled: False
# Set umask=0000 for VFAT, NTFS and exFAT in /etc/usbmount/usbmount.conf for
# Kolibri exports, and student uploads to teacher's USB stick (http://box/usb)
usb_lib_writable_sticks: True
# Show entire contents of USB sticks/drives (at http://box/usb)
iiab_usb_lib_show_all: True
# Set umask=0000 for VFAT, NTFS and exFAT in /etc/usbmount/usbmount.conf so
# Kolibri can export & import channels to USB sticks/drive:
usb_lib_umask0000_for_kolibri: True
# Common UNIX Printing System (CUPS)
cups_install: False
@ -217,7 +219,7 @@ nginx_high_php_limits: False
# ALSO: ADJUST "client_max_body_size 10000M;" AS NEC, IN: /etc/nginx/server.conf
# Make this True to enable http://box/js-menu/menu-files/services/power_off.php and set-server-time.php
allow_www_data_poweroff: False
allow_www_data_sudo: True
# Toggle iiab-refresh-wiki-docs scraping for offline docs (http://box/info)
nodocs: False

View file

@ -172,7 +172,7 @@ pi_swap_file_size: 1024
# roles/nginx runs here (mandatory)
# roles/www_base runs here (mandatory)
# SEE BELOW: nginx_high_php_limits, allow_www_data_poweroff
# SEE BELOW: nginx_high_php_limits, allow_www_data_sudo
# 4-SERVER-OPTIONS
@ -192,9 +192,11 @@ bluetooth_install: True
bluetooth_enabled: False
bluetooth_term_enabled: False
# Set umask=0000 for VFAT, NTFS and exFAT in /etc/usbmount/usbmount.conf for
# Kolibri exports, and student uploads to teacher's USB stick (http://box/usb)
usb_lib_writable_sticks: True
# Show entire contents of USB sticks/drives (at http://box/usb)
iiab_usb_lib_show_all: True
# Set umask=0000 for VFAT, NTFS and exFAT in /etc/usbmount/usbmount.conf so
# Kolibri can export & import channels to USB sticks/drive:
usb_lib_umask0000_for_kolibri: True
# Common UNIX Printing System (CUPS)
cups_install: False
@ -217,7 +219,7 @@ nginx_high_php_limits: False
# ALSO: ADJUST "client_max_body_size 10000M;" AS NEC, IN: /etc/nginx/server.conf
# Make this True to enable http://box/js-menu/menu-files/services/power_off.php and set-server-time.php
allow_www_data_poweroff: False
allow_www_data_sudo: True
# Toggle iiab-refresh-wiki-docs scraping for offline docs (http://box/info)
nodocs: False

View file

@ -178,7 +178,7 @@ pi_swap_file_size: 1024
# roles/nginx runs here (mandatory)
# roles/www_base runs here (mandatory)
# SEE BELOW: nginx_high_php_limits, allow_www_data_poweroff
# SEE BELOW: nginx_high_php_limits, allow_www_data_sudo
# 4-SERVER-OPTIONS
@ -198,9 +198,11 @@ bluetooth_install: False
bluetooth_enabled: False
bluetooth_term_enabled: False
# Set umask=0000 for VFAT, NTFS and exFAT in /etc/usbmount/usbmount.conf for
# Kolibri exports, and student uploads to teacher's USB stick (http://box/usb)
usb_lib_writable_sticks: True
# Show entire contents of USB sticks/drives (at http://box/usb)
iiab_usb_lib_show_all: True
# Set umask=0000 for VFAT, NTFS and exFAT in /etc/usbmount/usbmount.conf so
# Kolibri can export & import channels to USB sticks/drive:
usb_lib_umask0000_for_kolibri: True
# Common UNIX Printing System (CUPS)
cups_install: False
@ -223,7 +225,7 @@ nginx_high_php_limits: False
# ALSO: ADJUST "client_max_body_size 10000M;" AS NEC, IN: /etc/nginx/server.conf
# Make this True to enable http://box/js-menu/menu-files/services/power_off.php and set-server-time.php
allow_www_data_poweroff: False
allow_www_data_sudo: True
# Toggle iiab-refresh-wiki-docs scraping for offline docs (http://box/info)
nodocs: True