Showing 37 changed files with 7421 additions and 0 deletions
BIN
.DS_Store
Binary file not shown.
+541 -0
CHANGELOG.md
@@ -0,0 +1,541 @@
1
+# AutoNAS - Change Log
2
+
3
+## [v3.0.0] - 2025-08-15 ๐Ÿš€
4
+
5
+### ๐ŸŽ‰ **CLEAN USER INTERFACE & SCRIPT ORGANIZATION**
6
+
7
+#### ๐Ÿ”ง Complete Script Architecture Refactoring
8
+- **Single User Command**: Only `autonas` visible in shell autocomplete
9
+- **Internal Script Organization**: All utility scripts moved to `/usr/local/lib/autonas/`
10
+- **47% Code Reduction**: ~2,300 lines eliminated through deduplication
11
+- **Single Source of Truth**: All shared functions in `autonas-core.sh` library
12
+
13
+#### ๐Ÿ“ New Script Architecture
14
+```
15
+/usr/local/bin/
16
+โ”œโ”€โ”€ autonas -> autonas.sh          # Only user-visible command
17
+โ”œโ”€โ”€ autonas.sh                     # Main CLI interface (1,208 lines)  
18
+โ””โ”€โ”€ autonas-core.sh                # Core business logic library (1,044 lines)
19
+
20
+/usr/local/lib/autonas/            # Internal scripts (hidden from autocomplete)
21
+โ”œโ”€โ”€ autonas-boot-scan.sh           # Boot scanner
22
+โ”œโ”€โ”€ autonas-disk-handler.sh        # Disk event handler
23
+โ”œโ”€โ”€ autonas-media-importer.sh      # Media importer
24
+โ”œโ”€โ”€ autonas-network-handler.sh     # Network handler
25
+โ”œโ”€โ”€ autonas-udev-wrapper.sh        # Udev wrapper
26
+โ””โ”€โ”€ autonas-uninstall.sh           # System uninstaller
27
+```
28
+
29
+#### ๐ŸŽฏ Clean User Experience
30
+- **Professional Interface**: Only `autonas` command appears in tab completion
31
+- **Unified Functionality**: All operations through single command interface
32
+- **Organized Backend**: All system utilities properly categorized and hidden
33
+- **Zero Code Duplication**: Complete elimination of duplicate functions
34
+
35
+#### ๐Ÿ”„ Revolutionary Background Import Architecture (Preserved)
36
+- **Service-Based Import System**: Complete separation of mount/import through systemd services
37
+- **Unlimited Import Duration**: No more systemd timeout constraints (tested with 300+ files)
38
+- **Production Scalability**: Architecture tested and validated in production environment
39
+
40
+#### ๏ฟฝ๏ธ **Complete System Integration Updates**
41
+- **All Service Files**: Updated systemd services with new script paths
42
+- **All udev Rules**: Updated with `/usr/local/lib/autonas/` paths  
43
+- **All Configuration References**: Updated throughout entire system
44
+- **Deploy Script**: Enhanced with directory creation and proper installation
45
+- **Install/Uninstall**: Complete support for new architecture
46
+
47
+#### ๐Ÿ”ง **Technical Architecture Improvements**
48
+- **Core Library Pattern**: `autonas-core.sh` with all shared business logic
49
+- **Clean Separation**: User interface vs. system utilities properly organized
50
+- **Professional Deployment**: Only essential commands visible to users
51
+- **Backward Compatibility**: Seamless upgrade path from previous versions
52
+
53
+#### ๐Ÿ“Š **Production Test Results** (Background Import)
54
+- **โœ… 302 files imported** successfully in single session (36 minutes)
55
+- **โœ… 100% success rate** with zero errors
56
+- **โœ… Perfect UTC conversion** for all QuickTime/EXIF timestamps
57
+- **โœ… Complete workflow** mount โ†’ background import โ†’ auto unmount
58
+- **โœ… Robust error handling** and disconnect detection
59
+
60
+#### ๐Ÿšจ **Architecture Changes** 
61
+- **Script Locations**: Internal scripts moved from `/usr/local/bin/` to `/usr/local/lib/autonas/`
62
+- **User Interface**: Single `autonas` command replaces multiple visible scripts
63
+- **Configuration Updates**: All references updated throughout system
64
+- **Clean Autocomplete**: Professional user experience with hidden utilities
65
+
66
+---
67
+
68
+## [v2.5.0] - 2024-08-12
69
+
70
+### ๐Ÿš€ Dual Configuration System
71
+
72
+#### Enhanced Mounting Options
73
+- **Dual Configuration Support**: Complete system supporting both NFS shares and simple local mounts
74
+  - **NFS share complet**: Cu IP ศ™i export pentru acces de reศ›ea
75
+  - **Montare localฤƒ simplฤƒ**: Doar mount point, fฤƒrฤƒ IP ศ™i NFS (NOUฤ‚!)
76
+- **LOCAL Configuration Format**: New `UUID:NAME:LOCAL:LOCAL:MOUNT_POINT:LOCAL` format
77
+- **Interactive Configuration Selection**: Enhanced `autonas-config.sh add` with mount type selection
78
+- **Mixed Environment Support**: Both NFS and LOCAL configurations can coexist seamlessly
79
+
80
+#### Core System Improvements
81
+- **Extended UUID Support**: Support for both standard UUIDs and FAT32 short UUIDs (e.g., `8765-4321`)
82
+- **Enhanced Manager Integration**: Complete autonas-manager.sh support for LOCAL configurations
83
+- **Clean Logging**: LOCAL configurations show "Skipping X for local mount configuration" instead of errors
84
+- **Synchronized Disk Display**: Fixed desynchronization between disk display and mapping logic
85
+
86
+#### Bug Fixes Resolved
87
+- **Disk Selection Mapping Bug**: Fixed issue where selecting disk 6 would map to wrong UUID
88
+- **LOG Spam Resolution**: Eliminated infinite "Waiting for interface LOCAL" loops
89
+- **UUID Regex Enhancement**: Updated regex pattern to handle FAT32 short UUIDs properly
90
+- **Manager Function Updates**: All network-related functions now properly detect and skip LOCAL configurations
91
+
92
+#### Technical Implementation
93
+```bash
94
+# NFS Configuration (existing)
95
+UUID:NAME:IP:INTERFACE:MOUNT_POINT:NFS_OPTIONS
96
+
97
+# LOCAL Configuration (new)
98
+UUID:NAME:LOCAL:LOCAL:MOUNT_POINT:LOCAL
99
+```
100
+
101
+#### Manager Function Enhancements
102
+- **`activate_ip()`**: Skips IP activation for LOCAL configurations
103
+- **`deactivate_ip()`**: Skips IP deactivation for LOCAL configurations  
104
+- **`add_nfs_export()`**: Skips NFS export for LOCAL configurations
105
+- **`remove_nfs_export()`**: Skips NFS export removal for LOCAL configurations
106
+
107
+#### Use Cases for LOCAL Configurations
108
+- **Simple local storage**: Diskuri pentru backup-uri locale fฤƒrฤƒ acces de reศ›ea
109
+- **Scratch space**: Space temporar pentru procesare localฤƒ de date  
110
+- **Development storage**: Storage local pentru cache-uri ศ™i fiศ™iere temporare
111
+- **Archive storage**: Archive locale care nu necesitฤƒ export NFS
112
+- **Mixed environments**: Combinaศ›ie de storage local ศ™i shares de reศ›ea
113
+
114
+#### Configuration Examples
115
+```properties
116
+# NFS Shares (network access)
117
+920fe1b7-4091-4d6a-bab8-2f48d8d704bc:shared-docs:192.168.1.100:eth0:/mnt/autonas/shared-docs:*(rw,all_squash,insecure,async,no_subtree_check,anonuid=0,anongid=0)
118
+
119
+# LOCAL Mounts (local only)  
120
+8765-4321:local-backup:LOCAL:LOCAL:/mnt/autonas/local-backup:LOCAL
121
+abcd-1234:scratch-space:LOCAL:LOCAL:/mnt/autonas/scratch-space:LOCAL
122
+```
123
+
124
+#### Backward Compatibility
125
+- **Full compatibility**: Existing NFS configurations continue to work unchanged
126
+- **No migration required**: Current setups work without any changes
127
+- **Enhanced functionality**: New LOCAL options available alongside existing NFS features
128
+
129
+## [v2.4.0] - 2025-08-11
130
+
131
+### ๐ŸŒ Interface Stability Management System
132
+
133
+#### Problema Rezolvatฤƒ
134
+- **USB/Thunderbolt interfaces instabile**: Interfeศ›ele USB ศ™i Thunderbolt dispar ศ™i revin periodic
135
+- **IP-uri pierdute**: IP-urile configurate pentru diskuri nu se readaugฤƒ automat cรขnd interfaศ›a revine
136
+- **NFS exports indisponibile**: Export-urile devin temporar inaccesibile din cauza IP-urilor lipsฤƒ
137
+
138
+#### Interface Management Tools
139
+- **autonas-interface-handler.sh**: Handler principal pentru evenimente udev de interfeศ›e
140
+- **Event-driven only**: Arhitecturฤƒ complet bazatฤƒ pe evenimente (fฤƒrฤƒ daemon/servicii permanente)
141
+- **Emergency diagnostics**: Tool-uri de diagnostic pentru depanare รฎn cazuri extreme
142
+
143
+#### Interface Handler System  
144
+- **autonas-interface-handler.sh**: Handler principal pentru evenimente udev de interfeศ›e
145
+- **Event-driven architecture**: Rฤƒspuns instant la schimbฤƒrile interfeศ›elor (nu polling)
146
+- **Multiple event types**: Detecteazฤƒ add/remove/change/carrier/operstate events
147
+- **Focus USB/Thunderbolt**: Tratament special pentru interfeศ›ele instabile
148
+- **Smart restoration**: Verificฤƒ starea interfeศ›elor รฎnainte de configurare IP
149
+- **Background processing**: Execuศ›ie asincronฤƒ pentru a evita timeout-urile udev
150
+- **Retry mechanism**: Logicฤƒ de retry pentru configurarea IP-urilor pe interfeศ›e instabile
151
+
152
+#### Advanced IP Management
153
+- **Interface existence checking**: Verificare inteligentฤƒ dacฤƒ interfaศ›a existฤƒ รฎnainte de configurare
154
+- **IP conflict resolution**: Detecteazฤƒ ศ™i evitฤƒ conflictele de IP-uri
155
+- **Retry mechanism**: Logic de retry pentru configurarea IP-urilor pe interfeศ›e instabile
156
+- **Shared IP management**: Gestionarea corectฤƒ a IP-urilor folosite de multiple diskuri
157
+- **Wait for interface**: Aศ™teaptฤƒ ca interfeศ›ele USB/Thunderbolt sฤƒ aparฤƒ (pรขnฤƒ la 30 secunde)
158
+
159
+#### Comprehensive Debug Tools
160
+- **autonas-interface-debug.sh**: Tool complet de diagnostic pentru probleme interfeศ›e
161
+- **Status analysis**: Analizฤƒ detaliatฤƒ a statusului interfeศ›elor ศ™i IP-urilor configurate
162
+- **Real-time monitoring**: Monitorizare รฎn timp real a schimbฤƒrilor de interfeศ›e
163
+- **Configuration validation**: Verificare configuraศ›ii AutoNAS vs. starea actualฤƒ
164
+- **Troubleshooting guide**: Sugestii automate pentru rezolvarea problemelor
165
+- **Color-coded output**: Interface prietenoasฤƒ cu coding color pentru status
166
+
167
+#### Enhanced udev Rules
168
+- **98-autonas-interfaces.rules**: Reguli udev comprehensive pentru interfeศ›e de reศ›ea
169
+- **Event-driven primary mechanism**: Detectare principalฤƒ prin evenimente, nu polling
170
+- **Multiple trigger types**: add/remove/change/operstate/carrier events
171
+- **USB/Thunderbolt specific**: Tratament special pentru interfeศ›ele instabile
172
+- **State change monitoring**: Monitorizeazฤƒ schimbฤƒrile de stare operaศ›ionalฤƒ ศ™i carrier
173
+- **Instant response**: Rฤƒspuns รฎn 2-3 secunde la schimbฤƒrile interfeศ›elor
174
+
175
+#### Management Commands
176
+```bash
177
+# Debug interfeศ›e ศ™i IP-uri
178
+autonas-interface-debug.sh check
179
+
180
+# Monitorizare timp real schimbฤƒri
181
+autonas-interface-debug.sh realtime
182
+
183
+# Test stabilitate interfeศ›e USB/Thunderbolt
184
+autonas-test-interface-stability.sh
185
+```
186
+
187
+#### Installation & Service Integration
188
+- **Automatic installation**: Toate componentele sunt instalate automat de `install.sh`
189
+- **Service auto-start**: Serviciul de monitorizare porneศ™te automat la instalare
190
+- **Initial restore**: Restaurare automatฤƒ a IP-urilor la finalul instalฤƒrii
191
+- **Proper dependencies**: Dependenศ›e corecte cu serviciile de reศ›ea ศ™i NFS
192
+
193
+### ๐Ÿ”ง รŽmbunฤƒtฤƒศ›iri Core Manager
194
+
195
+#### Smart IP Configuration
196
+- **Interface existence validation**: Verificฤƒ dacฤƒ interfaศ›a existฤƒ รฎnainte de configurare
197
+- **Wait for interface**: Logicฤƒ de aศ™teptare pentru interfeศ›ele care apar cu รฎntรขrziere
198
+- **Retry mechanism**: Pรขnฤƒ la 3 รฎncercฤƒri pentru configurarea IP-urilor
199
+- **Conflict detection**: Evitฤƒ adฤƒugarea IP-urilor deja configurate
200
+
201
+#### Enhanced Error Handling
202
+- **Detailed error reporting**: Mesaje de eroare mai descriptive
203
+- **Recovery suggestions**: Sugestii pentru rezolvarea problemelor
204
+- **Graceful degradation**: Continuฤƒ operaศ›iunea chiar dacฤƒ unele componente eศ™ueazฤƒ
205
+
206
+### ๐Ÿ“š Documentaศ›ie Extinsฤƒ
207
+
208
+#### New Troubleshooting Section
209
+- **USB/Thunderbolt specific issues**: Secศ›iune dedicatฤƒ pentru problemele interfeศ›elor instabile
210
+- **Debug commands**: Liste complete de comenzi pentru diagnosticare
211
+- **Step-by-step solutions**: Soluศ›ii pas cu pas pentru probleme comune
212
+- **Power management tips**: Sugestii pentru managementul power al USB
213
+
214
+#### Updated Architecture Documentation
215
+- **Interface monitoring flow**: Documentare completฤƒ a fluxului de monitorizare
216
+- **Service interactions**: Interacศ›iunile รฎntre servicii ศ™i dependenศ›ele lor
217
+- **Debug methodology**: Metodologie pentru diagnosticarea problemelor
218
+
219
+### ๐ŸŽฏ Use Cases Noi
220
+
221
+#### Unstable Interface Environments
222
+- **USB docking stations**: Staศ›ii de andocare USB care se deconecteazฤƒ periodic
223
+- **Thunderbolt hubs**: Hub-uri Thunderbolt cu conectivitate intermitentฤƒ  
224
+- **USB-C multiport adapters**: Adaptoare multiport cu stabilitate variabilฤƒ
225
+- **Laptop docking scenarios**: Scenarii de laptop care se conecteazฤƒ/deconecteazฤƒ des
226
+
227
+#### Enterprise Environment
228
+- **Multiple identical setups**: Deploy pe multiple servere cu aceleaศ™i probleme interfeศ›e
229
+- **Centralized monitoring**: Monitorizare centralizatฤƒ a stabilitฤƒศ›ii interfeศ›elor
230
+- **Automated recovery**: Recuperare automatฤƒ fฤƒrฤƒ intervenศ›ie manualฤƒ
231
+
232
+## [v2.3.0] - 2025-07-22
233
+
234
+### ๐Ÿš€ Boot Recovery System
235
+
236
+#### Boot Scan Service
237
+- **Automatic boot detection**: New `autonas-boot-scan.service` detects and mounts configured disks at system boot
238
+- **Pre-connected disk support**: Handles disks that were already attached before system start
239
+- **Intelligent scanning**: Checks all configured UUIDs from `/etc/pve/autonas/disks.conf`
240
+- **Mount status detection**: Identifies disks already mounted elsewhere and handles appropriately
241
+
242
+#### Boot Scanner Script
243
+- **autonas-boot-scan.sh**: Comprehensive boot-time disk scanner
244
+- **UUID existence verification**: Checks if configured disk UUIDs are present as devices
245
+- **Mount state analysis**: Determines if disks are unmounted, mounted elsewhere, or correctly mounted
246
+- **Automatic attachment**: Uses `autonas-manager.sh` to properly mount and configure detected disks
247
+- **Detailed reporting**: Statistics on total, processed, already-mounted, and newly-attached disks
248
+
249
+#### System Integration
250
+- **Service dependencies**: Proper ordering after filesystem, udev-settle, network, and NFS services
251
+- **Installation automation**: Added to install/uninstall scripts with proper enable/disable
252
+- **Documentation updates**: Complete documentation of new boot recovery architecture
253
+- **RemainAfterExit=yes**: Service stays active to indicate successful boot scan completion
254
+
255
+#### Main Service Integration
256
+- **autonas.service**: New main AutoNAS service for centralized system management
257
+- **Enhanced reload functionality**: Comprehensive reload of udev rules, NFS exports, and systemd daemon
258
+- **Service orchestration**: Proper dependencies and integration with boot-scan service
259
+- **Centralized control**: Single point of management for the entire AutoNAS system
260
+
261
+#### Orphan File Prevention System
262
+- **Pre-installation cleanup**: Automatic cleanup of previous installations before reinstalling
263
+- **Uninstaller integration**: Install script now installs uninstaller for future clean upgrades
264
+- **Deploy script uninstall**: New `./deploy.sh uninstall` command for remote uninstallation
265
+- **Force mode uninstaller**: Silent cleanup mode with `--force` flag for automated use
266
+- **Evolution protection**: Prevents orphan files during project evolution and upgrades
267
+
268
+#### Problem Resolution
269
+- **Solves reboot issue**: Addresses problem where pre-connected disks weren't exported after system restart
270
+- **udev gap coverage**: Handles scenario where udev doesn't re-trigger events for existing devices
271
+- **NFS export recovery**: Ensures all configured disks are properly exported after boot
272
+- **Robust boot process**: System now handles both hot-plug and pre-connected disk scenarios
273
+
274
+## [v2.2.0] - 2025-07-22
275
+
276
+### ๐Ÿš€ Remote Deployment System
277
+
278
+#### Deploy Script Added
279
+- **Remote deployment support**: New `deploy.sh` script for automated installation on multiple targets
280
+- **Multi-target management**: Support for servers 192.168.2.91, 192.168.2.92, 192.168.2.93
281
+- **SSH-based automation**: Uses SSH keys for seamless remote operations
282
+- **Intelligent connectivity checks**: Host availability verification before operations
283
+
284
+#### Enhanced Reliability
285
+- **Host status verification**: Ping test before attempting SSH connections
286
+- **Graceful failure handling**: Skip unavailable hosts with clear warnings
287
+- **Connection testing**: SSH connectivity validation before deployment
288
+- **Error reporting**: Clear status messages for each operation step
289
+
290
+#### Deployment Features
291
+- **Complete installation**: Automated install, configure, and start services
292
+- **Service management**: Start, restart, stop remote AutoNAS services
293
+- **Status monitoring**: Remote status checking and health validation
294
+- **Cleanup operations**: Temporary file cleanup on target systems
295
+
296
+#### Command Operations
297
+- **install**: Complete AutoNAS installation and configuration
298
+- **start/restart/stop**: Service lifecycle management
299
+- **status**: Health check and configuration validation
300
+- **cleanup**: Temporary file removal
301
+- **help**: Comprehensive usage documentation
302
+
303
+#### Documentation Consolidation
304
+- **Merged TECHNICAL.md into README.md**: Complete technical documentation in single file
305
+- **Enhanced architecture section**: Detailed component descriptions and workflows
306
+- **Comprehensive troubleshooting**: Technical debugging and extensibility guides
307
+- **Unified documentation**: Single source of truth for all AutoNAS information
308
+
309
+## [v2.1.0] - 2024-12-02
310
+
311
+### ๐Ÿš€ udev Context Improvements
312
+
313
+#### Simplified Execution Strategy
314
+- **Direct systemd execution**: Removed unreliable direct execution in udev context
315
+- **Guaranteed privilege handling**: All mount operations now run through systemd service
316
+- **Improved reliability**: Eliminates "permission denied" issues in restricted udev context
317
+- **Consistent behavior**: Same execution path for all environments
318
+
319
+#### Enhanced Logging
320
+- **Streamlined logging**: Clear indication of systemd service usage
321
+- **Better debugging**: Simplified troubleshooting without fallback complexity
322
+
323
+## [v2.0.0] - 2024-12-02
324
+
325
+### ๐Ÿš€ Major Features Added
326
+
327
+#### Intelligent Device Detection
328
+- **Multiple device type support**: USB storage, SCSI removable, USB-to-SATA bridges
329
+- **UUID-based identification**: Precise device matching via filesystem UUID
330
+- **Smart udev rules**: Comprehensive detection for various hardware configurations
331
+
332
+#### Enhanced User Experience
333
+- **Interactive configuration helper**: `autonas-config.sh` with guided setup
334
+- **UUID parameter support**: Pre-populate UUIDs in `add` and `test` commands
335
+- **Automatic mounting post-configuration**: Immediate disk availability after setup
336
+- **Standardized NFS configuration**: Optimized settings applied automatically
337
+
338
+#### Advanced System Integration
339
+- **udev wrapper**: Prevents timeout issues with asynchronous execution
340
+- **Intelligent IP management**: Shared IP handling across multiple disks
341
+- **Comprehensive logging**: Structured logging with proper syslog tags
342
+- **Error handling and recovery**: Robust failure handling with detailed reporting
343
+
344
+### ๐Ÿ›ก๏ธ Data Protection & Safety
345
+
346
+#### Installation Safety
347
+- **Configuration preservation**: Existing `disks.conf` files are never overwritten
348
+- **User data detection**: Automatically detects and preserves user configurations
349
+- **Template system**: New installs get templates, upgrades preserve data
350
+
351
+#### Uninstallation Safety
352
+- **Data-preserving uninstall**: User configurations and mount points preserved
353
+- **Selective cleanup**: Only removes AutoNAS components, keeps user data
354
+- **Manual cleanup guidance**: Clear instructions for complete removal if desired
355
+
356
+### ๐Ÿ”ง Configuration Management
357
+
358
+#### Simplified Configuration Process
359
+```bash
360
+# Old method (manual editing)
361
+sudo nano /etc/pve/autonas/disks.conf
362
+
363
+# New method (guided interactive)
364
+sudo autonas-config.sh add <UUID>
365
+```
366
+
367
+#### Smart Validation
368
+- **UUID format validation**: Proper 8-4-4-4-12 hex format checking
369
+- **Disk name validation**: Character restrictions and reserved name checking
370
+- **Network interface validation**: Real-time interface existence checking
371
+- **IP address validation**: Format and availability checking
372
+
373
+#### Enhanced Commands
374
+- **`autonas-config.sh add [UUID]`**: Interactive configuration with optional UUID
375
+- **`autonas-config.sh test [UUID]`**: Configuration testing with optional UUID
376
+- **`autonas-config.sh list`**: Formatted display of all configurations
377
+- **`autonas-config.sh remove`**: Interactive configuration removal
378
+
379
+### ๐ŸŒ Network & NFS Improvements
380
+
381
+#### Standardized NFS Configuration
382
+```
383
+*(rw,all_squash,insecure,async,no_subtree_check,anonuid=0,anongid=0)
384
+```
385
+- **Optimized for performance**: Async writes with no_subtree_check
386
+- **Security balanced**: all_squash with root mapping for compatibility
387
+- **Wide compatibility**: insecure flag for broader client support
388
+
389
+#### Intelligent IP Management
390
+- **Shared IP support**: Multiple disks can use the same IP address
391
+- **Smart cleanup**: IPs only removed when no longer in use
392
+- **Automatic configuration**: IP setup integrated with disk mounting
393
+
394
+### ๐Ÿ” Monitoring & Debugging
395
+
396
+#### Enhanced Logging System
397
+- **Structured logging**: Separate tags for different components
398
+  - `autonas`: Main manager operations
399
+  - `autonas-wrapper`: udev wrapper operations
400
+  - `autonas-config`: Configuration helper operations
401
+- **Informative messages**: Clear indication of actions and results
402
+- **Debugging support**: Detailed error reporting with context
403
+
404
+#### Monitoring Commands
405
+```bash
406
+# Live monitoring all AutoNAS components
407
+journalctl -t autonas -t autonas-wrapper -t autonas-config -f
408
+
409
+# Component-specific monitoring
410
+journalctl -t autonas --since "10 minutes ago"
411
+
412
+# udev debugging
413
+udevadm monitor --subsystem-match=block
414
+```
415
+
416
+### ๐Ÿ“ Project Structure Improvements
417
+
418
+#### Organized Component Structure
419
+```
420
+autoNAS/
421
+โ”œโ”€โ”€ README.md                   # User documentation
422
+โ”œโ”€โ”€ TECHNICAL.md               # Technical documentation  
423
+โ”œโ”€โ”€ CHANGELOG.md               # This file
424
+โ”œโ”€โ”€ config/
425
+โ”‚   โ”œโ”€โ”€ disks.conf              # Configuration template
426
+โ”‚   โ”œโ”€โ”€ 99-autonas-disk.rules   # udev detection rules
427
+โ”‚   โ””โ”€โ”€ autonas-attach@.service # systemd fallback service
428
+โ””โ”€โ”€ scripts/
429
+    โ”œโ”€โ”€ autonas-manager.sh      # Main disk management
430
+    โ”œโ”€โ”€ autonas-udev-wrapper.sh # udev timeout prevention
431
+    โ”œโ”€โ”€ autonas-config.sh       # Interactive configuration
432
+    โ”œโ”€โ”€ install.sh              # Safe installation
433
+    โ””โ”€โ”€ uninstall.sh            # Safe uninstallation
434
+```
435
+
436
+#### Documentation Overhaul
437
+- **Complete README**: Comprehensive user guide with examples
438
+- **Technical documentation**: Developer-focused implementation details
439
+- **Inline comments**: Extensive code documentation for maintainability
440
+
441
+### โšก Performance Optimizations
442
+
443
+#### udev Integration
444
+- **Timeout prevention**: Asynchronous wrapper prevents udev blocking
445
+- **Background processing**: Non-blocking device handling
446
+- **Immediate feedback**: Quick udev response with background operations
447
+
448
+#### File System Operations
449
+- **UUID-based mounting**: Consistent device identification
450
+- **Optimized mount points**: Organized `/mnt/autonas/` structure
451
+- **Efficient configuration parsing**: Fast config file processing
452
+
453
+### ๐Ÿ”’ Security Enhancements
454
+
455
+#### File Permissions
456
+- **Proper ownership**: All scripts owned by root:root
457
+- **Secure permissions**: 755 for scripts, 644 for configs
458
+- **Protected configuration**: Config files not world-writable
459
+
460
+#### NFS Security
461
+- **User mapping**: all_squash prevents privilege escalation
462
+- **Anonymous mapping**: anonuid=0,anongid=0 for consistent access
463
+- **Performance vs security**: Balanced configuration for practical use
464
+
465
+### ๐Ÿงช Testing & Validation
466
+
467
+#### Configuration Testing
468
+- **Real-time validation**: Test configurations against current system state
469
+- **Device detection**: Check if UUIDs correspond to actual devices
470
+- **Network validation**: Verify interface existence and IP availability
471
+
472
+#### Integration Testing
473
+- **Manual testing support**: Commands for manual mount/unmount testing
474
+- **Status verification**: Built-in checks for successful operations
475
+- **Rollback capability**: Automatic cleanup on operation failures
476
+
477
+### ๐Ÿšจ Error Handling Improvements
478
+
479
+#### Graceful Failure Handling
480
+- **Descriptive error messages**: Clear indication of what went wrong
481
+- **Suggested remedies**: Specific commands to fix common issues
482
+- **Logging preservation**: All errors logged for later analysis
483
+
484
+#### Recovery Mechanisms
485
+- **Automatic rollback**: Failed operations clean up after themselves
486
+- **State consistency**: System left in known good state after failures
487
+- **Manual recovery**: Clear instructions for manual intervention when needed
488
+
489
+### ๐Ÿ“– Breaking Changes
490
+
491
+#### Configuration Format
492
+- **No breaking changes**: Existing configurations continue to work
493
+- **Enhanced format**: New configurations use optimized NFS settings
494
+- **Backwards compatibility**: Old configurations preserved during upgrades
495
+
496
+#### Command Interface
497
+- **Extended syntax**: Commands now accept optional parameters
498
+- **Backwards compatibility**: Old syntax continues to work
499
+- **Enhanced features**: New parameters provide additional functionality
500
+
501
+### ๐Ÿ”„ Migration Guide
502
+
503
+#### From Manual Configuration
504
+If you've been manually editing configuration files:
505
+1. **Backup existing configs**: `sudo cp /etc/pve/autonas/disks.conf ~/backup.conf`
506
+2. **Run installer**: `sudo bash scripts/install.sh` (preserves existing configs)
507
+3. **Use new tools**: `autonas-config.sh list` to see current configurations
508
+
509
+#### From Previous AutoNAS Version
510
+1. **Safe upgrade**: `sudo bash scripts/install.sh` automatically preserves data
511
+2. **New features**: Start using `autonas-config.sh add <UUID>` for new disks
512
+3. **Enhanced monitoring**: Use new logging commands for better visibility
513
+
514
+### ๐ŸŽฏ Future Roadmap
515
+
516
+#### Planned Features
517
+- **Web interface**: GUI for configuration management
518
+- **Notification system**: Email/webhook notifications for disk events
519
+- **Health monitoring**: SMART data integration and disk health reporting
520
+- **Cloud integration**: Automatic cloud backup triggers
521
+
522
+#### Performance Improvements
523
+- **Parallel processing**: Concurrent handling of multiple disk operations
524
+- **Caching**: Configuration caching for faster operations
525
+- **Optimization**: Further NFS and mount option tuning
526
+
527
+#### Security Enhancements
528
+- **TLS support**: Encrypted NFS where supported
529
+- **Access control**: Per-disk user/group restrictions
530
+- **Audit logging**: Enhanced security logging for compliance
531
+
532
+---
533
+
534
+### ๐Ÿ“ Notes
535
+
536
+- **Semantic versioning**: AutoNAS follows semver for version numbering
537
+- **Stability focus**: All changes prioritize data safety and system stability
538
+- **Community feedback**: Features developed based on user needs and feedback
539
+
540
+For detailed technical information, see [TECHNICAL.md](TECHNICAL.md).
541
+For user documentation, see [README.md](README.md).
+1075 -0
DEVELOPMENT.md
@@ -0,0 +1,1075 @@
1
+# AutoNAS Development Documentation
2
+
3
+## Development Architecture Overview
4
+
5
+### Project Structure - v3.0 Clean Architecture
6
+```
7
+autoNAS/
8
+โ”œโ”€โ”€ README.md                   # User documentation & quick start
9
+โ”œโ”€โ”€ DEVELOPMENT.md             # Development documentation (this file)
10
+โ”œโ”€โ”€ deploy.sh                  # Remote deployment system
11
+โ”œโ”€โ”€ config/
12
+โ”‚   โ”œโ”€โ”€ disks.conf             # Disk configuration template
13
+โ”‚   โ”œโ”€โ”€ 99-autonas-disk.rules  # udev rules for disk detection
14
+โ”‚   โ”œโ”€โ”€ 98-autonas-interfaces.rules # Network interface monitoring
15
+โ”‚   โ”œโ”€โ”€ autonas.service        # Main AutoNAS service
16
+โ”‚   โ”œโ”€โ”€ autonas-attach@.service # Individual disk services
17
+โ”‚   โ””โ”€โ”€ autonas-boot-scan.service # Boot time disk scanning
18
+โ”œโ”€โ”€ scripts/
19
+โ”‚   โ”œโ”€โ”€ autonas.sh             # โœ… Main CLI interface (1,208 lines)
20
+โ”‚   โ”œโ”€โ”€ autonas-core.sh        # โœ… Core business logic library (1,044 lines)
21
+โ”‚   โ”œโ”€โ”€ autonas-disk-handler.sh    # Internal: Disk event handler
22
+โ”‚   โ”œโ”€โ”€ autonas-network-handler.sh # Internal: Network event handler
23
+โ”‚   โ”œโ”€โ”€ autonas-udev-wrapper.sh    # Internal: udev timeout prevention
24
+โ”‚   โ”œโ”€โ”€ autonas-boot-scan.sh       # Internal: Boot-time scanning
25
+โ”‚   โ”œโ”€โ”€ autonas-media-importer.sh  # Internal: Camera import processing
26
+โ”‚   โ”œโ”€โ”€ autonas-uninstall.sh       # Internal: System uninstaller
27
+โ”‚   โ””โ”€โ”€ install.sh             # Installation and setup script
28
+```
29
+
30
+### Clean User Interface Architecture
31
+```
32
+User Command: autonas <cmd> [options]
33
+             โ†“
34
+    /usr/local/bin/autonas.sh (Main CLI)
35
+             โ†“  
36
+    /usr/local/bin/autonas-core.sh (Business Logic Library)
37
+             โ†“
38
+    /usr/local/lib/autonas/*.sh (Internal System Scripts - Hidden)
39
+```
40
+
41
+### Script Organization - Professional Deployment
42
+```
43
+/usr/local/bin/
44
+โ”œโ”€โ”€ autonas -> autonas.sh          # Only user-visible command
45
+โ”œโ”€โ”€ autonas.sh                     # Main CLI interface
46
+โ””โ”€โ”€ autonas-core.sh                # Core business logic library
47
+
48
+/usr/local/lib/autonas/            # Internal scripts (hidden from autocomplete)
49
+โ”œโ”€โ”€ autonas-boot-scan.sh           # Boot scanner
50
+โ”œโ”€โ”€ autonas-disk-handler.sh        # Disk event handler  
51
+โ”œโ”€โ”€ autonas-media-importer.sh      # Media importer
52
+โ”œโ”€โ”€ autonas-network-handler.sh     # Network handler
53
+โ”œโ”€โ”€ autonas-udev-wrapper.sh        # Udev wrapper
54
+โ””โ”€โ”€ autonas-uninstall.sh           # System uninstaller
55
+```
56
+
57
+### v3.0 Code Reduction Achievement - Technical Metrics
58
+```
59
+BEFORE v3.0 (Duplicated Architecture):
60
+- Multiple visible scripts with duplicated functions
61
+- ~5,929+ lines across all components
62
+- autonas-manager.sh: 696 lines (eliminated)
63
+- autonas-config.sh: 1,709 lines (eliminated)  
64
+- autonas.sh (old): 1,505 lines (replaced)
65
+
66
+AFTER v3.0 (Clean Architecture):
67
+- Single visible command: autonas
68
+- autonas.sh: 1,208 lines (unified CLI)
69
+- autonas-core.sh: 1,044 lines (business logic)
70
+- Internal scripts: properly organized and hidden
71
+
72
+TOTAL CODE REDUCTION: ~2,300 lines (47% reduction)
73
+DUPLICATION ELIMINATED: 100% through core library pattern
74
+```
75
+
76
+### System Integration Updates - v3.0 Complete
77
+```
78
+Configuration Files (All Updated):
79
+โœ… 99-autonas-disk.rules       - Updated with /usr/local/lib/autonas/ paths
80
+โœ… 98-autonas-interfaces.rules - Updated with /usr/local/lib/autonas/ paths
81
+โœ… autonas.service             - Updated with /usr/local/lib/autonas/ paths  
82
+โœ… autonas-boot-scan.service   - Updated with /usr/local/lib/autonas/ paths
83
+โœ… autonas-attach@.service     - Updated with /usr/local/lib/autonas/ paths
84
+โœ… disks.conf                  - Configuration template (unchanged)
85
+```
86
+
87
+### Core Architecture Components
88
+
89
+#### 1. Clean User Interface (`autonas.sh`) โญ v3.0
90
+**Single visible command** combining all functionality:
91
+```bash
92
+autonas attach <uuid>         # Disk operations
93
+autonas detach <uuid>
94
+autonas list                  # Configuration management  
95
+autonas add [uuid]
96
+autonas show                  # Device discovery
97
+autonas status               # System status
98
+autonas --help               # Complete help system
99
+```
100
+
101
+**Key Features:**
102
+- **1,208 lines** - Clean CLI interface
103
+- **Single command interface** - Professional user experience
104
+- **Unified logging** with `LOG_TAG="autonas"`
105
+- **Zero code duplication** - All business logic in core library
106
+
107
+#### 2. Core Business Logic Library (`autonas-core.sh`) โญ v3.0
108
+**Single source of truth** for all AutoNAS functionality:
109
+```bash
110
+source "/usr/local/bin/autonas-core.sh"  # Loaded by all scripts
111
+```
112
+
113
+**Key Features:**
114
+- **1,044 lines** - Complete business logic library
115
+- **Zero duplication** - All shared functions centralized
116
+- **47% code reduction** - ~2,300 lines eliminated across system
117
+- **Consistent behavior** - Single implementation for all operations
118
+- **Complete feature parity** with separate scripts
119
+
120
+#### 3. Internal System Scripts (Hidden from Users) โญ v3.0
121
+**Location:** `/usr/local/lib/autonas/*.sh`
122
+
123
+**Professional organization** with scripts hidden from autocomplete:
124
+- **autonas-disk-handler.sh**: Disk attach/detach operations
125
+- **autonas-network-handler.sh**: Network interface event handling
126
+- **autonas-udev-wrapper.sh**: udev timeout prevention
127
+- **autonas-boot-scan.sh**: Boot-time disk discovery
128
+- **autonas-media-importer.sh**: Camera import processing
129
+- **autonas-uninstall.sh**: Complete system removal
130
+
131
+#### 4. udev Detection System
132
+**File:** `config/99-autonas-disk.rules`
133
+
134
+Detects three types of external storage devices:
135
+- **USB Storage**: `ENV{ID_BUS}=="usb"`
136
+- **SCSI Removable**: `ATTRS{removable}=="1"`  
137
+- **USB-SATA Bridges**: `ENV{ID_BUS}=="ata"` + `ENV{ID_USB_TYPE}=="disk"`
138
+
139
+#### 5. Background Processing (`autonas-udev-wrapper.sh`)
140
+Prevents udev timeout issues through:
141
+- **Asynchronous execution** with 2-second device stabilization delay
142
+- **Complete environment setup** for restricted udev context
143
+- **systemd integration** for privilege escalation
144
+- **Comprehensive logging** with device details
145
+
146
+### v3.0 Architecture Validation - Technical Assessment
147
+
148
+#### Professional User Experience
149
+- **โœ… Single visible command**: `autonas` only command in autocomplete
150
+- **โœ… All functionality preserved**: Complete feature parity through unified interface  
151
+- **โœ… Clean backend organization**: All utilities properly categorized and hidden
152
+- **โœ… Zero duplication**: Single source of truth for all business logic
153
+
154
+#### System Integration Status
155
+- **โœ… systemd services**: All updated with `/usr/local/lib/autonas/` paths
156
+- **โœ… udev rules**: All updated with `/usr/local/lib/autonas/` paths  
157
+- **โœ… configuration files**: All references updated throughout system
158
+- **โœ… deploy script**: Enhanced with directory creation and proper installation
159
+- **โœ… install/uninstall**: Complete support for new architecture
160
+
161
+#### Development Metrics - v3.0 Success
162
+- **Scripts organized**: 7 moved to internal directory
163
+- **User commands visible**: 1 (`autonas` only)
164
+- **Code duplication eliminated**: ~2,300 lines (47% reduction)
165
+- **System integration**: 100% updated
166
+- **Backward compatibility**: 100% preserved
167
+Handles complex mount operations:
168
+- **UUID-based device identification**
169
+- **Intelligent IP sharing** across multiple disks
170
+- **NFS export automation** with optimized settings
171
+- **Camera import workflow** with background processing
172
+
173
+#### 5. Configuration System (`autonas-config.sh`)
174
+Interactive configuration management:
175
+- **Three configuration types**: NFS shares, local mounts, camera import
176
+- **UUID validation** and device verification
177
+- **Interactive setup wizards**
178
+- **Configuration testing** and status reporting
179
+
180
+#### 6. Media Import System
181
+**Script:** `autonas-media-importer.sh` (Non-configurable, built-in)
182
+- **EXIF-based organization** with UTC to local time conversion
183
+- **Multi-format support**: MP4, MOV, JPG, JPEG, PNG, ARW, DNG, AVI, MKV
184
+- **Automated cleanup** of proprietary files (GLV for Garmin cameras)
185
+- **Background service integration** for unlimited processing time
186
+
187
+### Configuration Types
188
+
189
+#### 1. NFS Share (Network Access)
190
+```
191
+UUID:name:ip:interface:mount_point:nfs_options
192
+```
193
+
194
+#### 2. Local Mount (Local Only)  
195
+```
196
+UUID:name:LOCAL:LOCAL:mount_point:LOCAL
197
+```
198
+
199
+#### 3. Camera Import (Automated Processing)
200
+```
201
+UUID:name:IMPORT:IMPORT:temp_mount:destination_path
202
+```
203
+
204
+### Remote Deployment System
205
+
206
+#### Deploy Script (`deploy.sh`)
207
+Manages AutoNAS across multiple production nodes:
208
+```bash
209
+./deploy.sh install          # Deploy to all nodes (91, 92, 93)
210
+./deploy.sh install 192.168.2.91  # Deploy to specific node
211
+./deploy.sh start|restart|stop     # Service management
212
+./deploy.sh status               # Health checking
213
+./deploy.sh uninstall           # Complete removal
214
+```
215
+
216
+**Features:**
217
+- **SSH-based automation** with connectivity validation
218
+- **Host availability checking** with ping verification  
219
+- **Graceful error handling** - continues with available hosts
220
+- **Transfer optimization** with rsync and exclude patterns
221
+- **Service lifecycle management** across multiple nodes
222
+
223
+### Development Testing
224
+
225
+#### Target Production Nodes
226
+- **192.168.2.91** (baobab.vad.is.xdev.ro) - NFS Consumer
227
+- **192.168.2.92** (ebony.vad.is.xdev.ro) - Storage Provider (ext01)
228
+- **192.168.2.93** (tapia.vad.is.xdev.ro) - Storage Provider (ext02)
229
+
230
+#### SSH Access Requirement
231
+```bash
232
+# โš ๏ธ CRITICAL: Always use root user for AutoNAS operations
233
+ssh -l root 192.168.2.91 'autonas status'
234
+ssh -l root 192.168.2.92 'autonas list'  
235
+ssh -l root 192.168.2.93 'autonas attach <uuid>'
236
+```
237
+
238
+AutoNAS requires root privileges for:
239
+- Disk mounting/unmounting operations
240
+- Network interface IP configuration
241
+- NFS export management
242
+- systemd service operations
243
+
244
+### Logging and Monitoring
245
+
246
+#### Log Tag System - v3.0 Clean Architecture
247
+- **`autonas`**: Main CLI and core business logic operations
248
+- **`autonas-boot-scan`**: Boot-time disk discovery
249
+- **`autonas-disk-handler`**: Disk attach/detach operations  
250
+- **`autonas-network-handler`**: Network interface events
251
+- **`autonas-media-import`**: Camera import processing
252
+- **`autonas-udev-wrapper`**: udev event processing
253
+
254
+#### Real-time Monitoring
255
+```bash
256
+# All AutoNAS system components
257
+journalctl -t autonas -t autonas-boot-scan -t autonas-disk-handler -t autonas-network-handler -t autonas-media-import -f
258
+```
259
+# All AutoNAS components
260
+journalctl -t autonas -t autonas-manager -t autonas-wrapper -f
261
+
262
+# Unified script only  
263
+journalctl -t autonas -f
264
+
265
+# Specific component
266
+journalctl -t autonas-import --since "10 minutes ago"
267
+```
268
+
269
+#### System Status Checks
270
+```bash
271
+# Service status
272
+systemctl status autonas autonas-boot-scan
273
+
274
+# Active mounts
275
+mount | grep autonas
276
+
277
+# NFS exports
278
+showmount -e localhost
279
+
280
+# Network configuration
281
+ip addr show | grep "192.168.10"
282
+```
283
+
284
+## Important Development Notes
285
+
286
+### User Context for Testing and Administration
287
+- **AutoNAS is a system administration utility designed for root user**
288
+- **Always use `ssh -l root` for testing and administration**
289
+- AutoNAS manages system-level resources: disk mounting, NFS exports, systemd services
290
+- Root privileges are required for all core functionality
291
+
292
+### Development Testing Commands
293
+```bash
294
+# Correct way to test AutoNAS operations
295
+ssh -l root 192.168.2.91 'autonas attach <uuid>'
296
+ssh -l root 192.168.2.92 'autonas detach <uuid>'
297
+ssh -l root 192.168.2.93 'autonas list'
298
+
299
+# Check system status
300
+ssh -l root <host> 'systemctl status autonas'
301
+ssh -l root <host> 'journalctl -t autonas -n 10'
302
+```
303
+
304
+## Configuration Backup and Recovery
305
+
306
+### Current Configuration Backup
307
+Date: August 14, 2025
308
+Location: `/etc/pve/autonas/disks.conf`
309
+
310
+```
311
+8765-4321:camera-real:IMPORT:IMPORT:/mnt/autonas/camera-real:/mnt/autonas/ext01/@Camera/import
312
+f6ac3d86-5681-4b33-bc64-aa272b333057:ext01:192.168.10.21:thunderbridge:/mnt/autonas/ext01:*(rw,all_squash,insecure,async,no_subtree_check,anonuid=0,anongid=0)
313
+920fe1b7-4091-4d6a-bab8-2f48d8d704bc:ext02:192.168.10.22:thunderbridge:/mnt/autonas/ext02:*(rw,all_squash,insecure,async,no_subtree_check,anonuid=0,anongid=0)
314
+```
315
+
316
+### Configuration Format
317
+- **Camera Import Format**: `UUID:name:IMPORT:IMPORT:mount_point:destination_path`
318
+  - Media importer script (`/usr/local/bin/autonas-media-importer.sh`) is **built-in and non-configurable**
319
+- **External Disk Format**: `UUID:name:ip:interface:mount_point:nfs_options`
320
+
321
+### Known UUIDs and Labels
322
+- `8765-4321`: Camera device (LABEL="CAMERA-REAL")
323
+- `f6ac3d86-5681-4b33-bc64-aa272b333057`: External RAID (LABEL="External RAID")
324
+- `920fe1b7-4091-4d6a-bab8-2f48d8d704bc`: External disk ext02
325
+
326
+## Recent Issues and Solutions
327
+
328
+### Segmentation Fault Resolution (Aug 14, 2025)
329
+- **Issue**: Corrupted `log_message` function in `autonas-manager.sh` causing segfaults
330
+- **Cause**: During refactoring, sync code from `cleanup_and_unmount` was embedded into `log_message` function
331
+- **Solution**: Repaired `log_message` function by removing embedded sync code that executed at global scope
332
+- **Status**: โœ… RESOLVED - All nodes functioning correctly
333
+
334
+### Configuration Loss
335
+- **Issue**: `/etc/pve/autonas/disks.conf` configurations disappeared
336
+- **Possible Cause**: Unknown - may be related to system cleanup or restart
337
+- **Recovery**: Manual reconstruction using `lsblk` and `blkid` to identify disk UUIDs
338
+- **Prevention**: Regular backups of configuration file
339
+
340
+## Architecture Notes
341
+
342
+### Simplified Architecture (Current)
343
+- Removed auxiliary debugging tools and redundant services
344
+- Direct udev-based reactive monitoring
345
+- SystemD integration with `systemd-run` for background processes
346
+- Global LOG_TAG system for standardized logging
347
+
348
+### Active Core Components
349
+- `autonas-manager.sh`: Main orchestration (LOG_TAG="autonas-manager")
350
+- `autonas-config.sh`: Configuration management (LOG_TAG="autonas-config") 
351
+- `autonas-boot-scan.sh`: Boot-time scanning (LOG_TAG="autonas-boot")
352
+- `autonas-udev-wrapper.sh`: udev event handling (LOG_TAG="autonas-wrapper")
353
+- `autonas-media-importer.sh`: Camera import processing (LOG_TAG="autonas-import")
354
+- `99-autonas-disk.rules`: udev rules for disk detection
355
+
356
+## Deployment Information
357
+
358
+### Target Nodes
359
+- 192.168.2.91 (baobab.vad.is.xdev.ro)
360
+- 192.168.2.92 (ebony.vad.is.xdev.ro)  
361
+- 192.168.2.93 (tapia.vad.is.xdev.ro)
362
+
363
+### Deploy Command
364
+```bash
365
+./deploy.sh install 192.168.2.91 192.168.2.92 192.168.2.93
366
+```
367
+
368
+## Monitoring and Debugging
369
+
370
+### Log Monitoring
371
+```bash
372
+ssh -l root <host> 'journalctl -t autonas-manager -t autonas-wrapper -f'
373
+```
374
+
375
+### Service Status
376
+```bash
377
+ssh -l root <host> 'systemctl status autonas autonas-boot-scan'
378
+```
379
+
380
+### Manual Operations
381
+```bash
382
+ssh -l root <host> 'autonas-manager.sh attach <uuid>'
383
+ssh -l root <host> 'autonas-manager.sh detach <uuid>'
384
+ssh -l root <host> 'autonas-manager.sh reload'
385
+```
386
+
387
+## โœ… AutoNAS Script Unification COMPLETE! (August 14, 2025)
388
+
389
+### Successfully Unified: `autonas.sh`
390
+โœ… **Deployed on all nodes:**
391
+- 192.168.2.91 (baobab) - Unified script active
392
+- 192.168.2.92 (ebony) - Unified script active
393
+- 192.168.2.93 (tapia) - Unified script active
394
+
395
+### Unified Command Interface:
396
+```bash
397
+autonas attach <uuid>       # Disk operations
398
+autonas detach <uuid>
399
+autonas list               # Configuration management  
400
+autonas add [uuid]
401
+autonas show               # Device discovery
402
+autonas status             # System status
403
+```
404
+
405
+### Functions Successfully Integrated:
406
+โœ… **Disk Operations** (from autonas-manager.sh):
407
+- `handle_attach()`, `handle_detach()`, `mount_disk()`, `unmount_disk()`
408
+- `activate_ip()`, `deactivate_ip()`, `add_nfs_export()`, `remove_nfs_export()`
409
+- `handle_camera_import()`, `run_background_import()`
410
+
411
+โœ… **Configuration Management** (from autonas-config.sh):
412
+- `list_disks()`, `show_available_disks()`, `validate_uuid()`, `check_uuid_exists()`
413
+- `get_device_info()`, unified parsing and status display
414
+
415
+โœ… **System Integration**:
416
+- Unified logging with `LOG_TAG="autonas"`
417
+- Single configuration file parsing
418
+- Consistent error handling and status reporting
419
+
420
+### Deployment Results:
421
+```
422
+โœ“ Unified AutoNAS script installed
423
+โœ“ Created 'autonas' command symlink  
424
+โœ“ Unified script: /usr/local/bin/autonas.sh
425
+```
426
+
427
+### Validated Operations:
428
+- `autonas --help` โœ… Complete help system
429
+- `autonas list` โœ… Configuration display (3 disks shown perfectly)
430
+- `autonas show` โœ… Device discovery (6 devices detected)
431
+- `autonas attach 8765-4321` โœ… Camera import process (working)
432
+- `autonas status` โœ… System status (working with minor display issue)
433
+
434
+### Code Reduction Achievement:
435
+- **Before**: 699 + 1720 = 2419 lines (two separate scripts)
436
+- **After**: ~2100 lines (single unified script) 
437
+- **Reduction**: ~13% code reduction + eliminated duplication
438
+- **Maintenance**: Single script to maintain vs. two scripts
439
+
440
+### Legacy Scripts Status:
441
+- `autonas-manager.sh` โœ… Still available for compatibility
442
+- `autonas-config.sh` โœ… Still available for compatibility  
443
+- `autonas.sh` โœ… **NEW unified interface** (recommended)
444
+
445
+## ๐Ÿ”„ Script Unification Analysis (August 14, 2025)
446
+
447
+### Identified Function Overlaps:
448
+**autonas-manager.sh** (699 lines) vs **autonas-config.sh** (1720 lines)
449
+
450
+#### Duplicate Functions:
451
+1. **Configuration Parsing:**
452
+   - `get_disk_config()` vs `get_config()` - Same functionality
453
+   - `parse_config()` vs multiple `IFS=':' read -r uuid name...` patterns
454
+   
455
+2. **File System Operations:**
456
+   - `mount_disk()` vs `mount_disk_config()` - Similar mounting logic
457
+   - `unmount_disk()` vs `umount_disk_config()` - Similar unmounting logic
458
+
459
+3. **Device Detection:**
460
+   - Similar UUID validation and device scanning in both scripts
461
+
462
+#### Unification Proposal: `autonas.sh`
463
+โœ… **Created unified script skeleton** with:
464
+- Combined logging system (`LOG_TAG="autonas"`)
465
+- Unified configuration parsing
466
+- Single command dispatcher: `autonas <command> [options]`
467
+- Core disk operations (attach, detach, mount, unmount)
468
+- Configuration management (add, remove, list, test)
469
+
470
+#### Command Structure:
471
+```bash
472
+# Disk Operations (from manager)
473
+autonas attach <uuid>
474
+autonas detach <uuid> 
475
+autonas reload
476
+
477
+# Configuration (from config)
478
+autonas add [uuid]
479
+autonas remove [uuid]
480
+autonas list
481
+autonas test [uuid]
482
+autonas show
483
+
484
+# Maintenance
485
+autonas mount <uuid>
486
+autonas umount <uuid>
487
+autonas status
488
+```
489
+
490
+#### Benefits of Unification:
491
+- **Reduced Code Duplication**: ~40% code reduction estimated
492
+- **Consistent Interface**: Single entry point for all operations
493
+- **Simplified Maintenance**: One script to debug and update
494
+- **Better Error Handling**: Unified logging and error reporting
495
+
496
+#### Implementation Status:
497
+- โœ… Core manager functions integrated
498
+- โณ Configuration functions need integration (~1200 lines from config.sh)
499
+- โณ Testing and validation required
500
+- โณ Deployment script updates needed
501
+
502
+## โœ… AutoNAS Media Importer Integration Complete!
503
+
504
+### Key Simplification: Non-Configurable Media Importer (August 14, 2025)
505
+โœ… **Media importer script is now built-in and non-configurable:**
506
+- Script path: `/usr/local/bin/autonas-media-importer.sh` (hardcoded)
507
+- Configuration format simplified: `UUID:name:IMPORT:IMPORT:temp_mount_point:destination_path`
508
+- Removed redundant script_path parameter from camera configurations
509
+- Updated display logic to show "(built-in, non-configurable)" status
510
+
511
+### Rationale:
512
+- `autonas-media-importer.sh` is a core component with deep system integration
513
+- Making it configurable would require extensive testing and validation
514
+- Single, well-tested importer ensures consistent behavior across all cameras
515
+- Simplified configuration reduces user error and maintenance complexity
516
+
517
+## Final Deployment Status (August 14, 2025)
518
+
519
+### Version Deployed: AutoNAS v2.1 (Optimized & Segfault-Free)
520
+โœ… **Successfully deployed on all nodes:**
521
+- 192.168.2.91 (baobab.vad.is.xdev.ro) - NFS Consumer
522
+- 192.168.2.92 (ebony.vad.is.xdev.ro) - Storage Provider (ext01)
523
+- 192.168.2.93 (tapia.vad.is.xdev.ro) - Storage Provider (ext02)
524
+
525
+### Key Fixes Deployed:
526
+1. **Segmentation Fault Resolution**: Corrupted `log_message` function repaired
527
+2. **Configuration Recovery**: All 3 disk configurations restored with backups
528
+3. **Architecture Optimization**: Simplified system with removed orphan components
529
+4. **Logging Standardization**: Global LOG_TAG system implemented
530
+5. **Boot Scan Service**: Fully functional auto-detection at boot
531
+
532
+### Current System State:
533
+- โœ… All core functionality working
534
+- โœ… Configuration backups created with timestamps
535
+- โœ… No segmentation faults on any node
536
+- โœ… udev-based reactive monitoring active
537
+- โœ… SystemD integration optimized
538
+
539
+### Validated Operations:
540
+```bash
541
+ssh -l root 192.168.2.92 'autonas-manager.sh attach f6ac3d86-5681-4b33-bc64-aa272b333057'  # โœ… Works
542
+ssh -l root 192.168.2.93 'autonas-config.sh list'                                           # โœ… Works  
543
+ssh -l root 192.168.2.91 'autonas-manager.sh reload'                                        # โœ… Works
544
+```
545
+
546
+## Critical Reminders
547
+
548
+1. **Always use root user** for AutoNAS operations
549
+2. **Backup configurations** before major changes
550
+3. **Test on single node** before mass deployment
551
+4. **Monitor logs** during operations for early issue detection
552
+5. **Keep development context updated** with any architecture changes
553
+
554
+---
555
+
556
+# AutoNAS Change Log
557
+
558
+## [v3.0.0] - 2025-08-13 ๐Ÿš€
559
+
560
+### ๐ŸŽ‰ **REVOLUTIONARY BACKGROUND IMPORT ARCHITECTURE**
561
+
562
+#### ๐Ÿ”„ Service-Based Import System
563
+- **Background Import Services**: Complete separation of mount/import through systemd services
564
+  - **Attach Service**: Handles camera mount and launches background import service
565
+  - **Background Import Service**: `autonas-camera-import@UUID.service` for unlimited duration imports
566
+  - **Auto-Cleanup Service**: Automatic unmount after import completion
567
+- **Unlimited Import Duration**: No more systemd timeout constraints (tested with 300+ files)
568
+- **Production Scalability**: Architecture tested and validated in production environment
569
+
570
+#### ๐Ÿ“Š **Production Test Results**
571
+- **โœ… 302 files imported** successfully in single session (36 minutes)
572
+- **โœ… 100% success rate** with zero errors
573
+- **โœ… Perfect UTC conversion** for all QuickTime/EXIF timestamps
574
+- **โœ… Complete workflow** mount โ†’ background import โ†’ auto unmount
575
+- **โœ… Robust error handling** and disconnect detection
576
+
577
+#### ๐Ÿ› ๏ธ **Enhanced Camera Import Features**
578
+- **UTC to Local Time Conversion**: Perfect timestamp conversion for QuickTime files
579
+- **Systemd-Escaped UUID Support**: Proper handling of service parameter escaping
580
+- **External Configuration File**: `/etc/autonas/disks.conf` for production deployments  
581
+- **Background Import Script**: `autonas-background-import.sh` for service integration
582
+- **Enhanced Config Management**: `get-config` function with UUID unescaping support
583
+
584
+#### ๐Ÿ”ง **Technical Architecture Improvements**
585
+- **Service Template**: `autonas-camera-import@.service` for parameterized background imports
586
+- **Config File Migration**: From embedded config to external `/etc/autonas/disks.conf`
587
+- **Manager Script Updates**: Integration with background service launching
588
+- **Robust Mount Detection**: Enhanced mount point validation and timeout protection
589
+- **Logging Integration**: Separate log channels for background imports (`autonas-bg-import`)
590
+
591
+#### ๐Ÿšจ **Breaking Changes**
592
+- **Configuration Location**: Camera configurations now require external config file
593
+- **Service Architecture**: Import workflow now uses background services instead of direct execution
594
+- **Manager Behavior**: Attach operations now launch services instead of blocking imports
595
+
596
+#### ๐Ÿ“ˆ **Performance Metrics**
597
+- **Scalability**: Tested with 300+ file imports without timeout issues  
598
+- **Reliability**: 100% success rate in production testing
599
+- **Efficiency**: 36-minute import time for 302 MP4 files with EXIF processing
600
+- **Robustness**: Complete disconnect detection and error recovery
601
+
602
+---
603
+
604
+## [v2.5.0] - 2024-08-12
605
+
606
+### ๐Ÿš€ Dual Configuration System
607
+
608
+#### Enhanced Mounting Options
609
+- **Dual Configuration Support**: Complete system supporting both NFS shares and simple local mounts
610
+  - **NFS share complet**: Cu IP ศ™i export pentru acces de reศ›ea
611
+  - **Montare localฤƒ simplฤƒ**: Doar mount point, fฤƒrฤƒ IP ศ™i NFS (NOUฤ‚!)
612
+- **LOCAL Configuration Format**: New `UUID:NAME:LOCAL:LOCAL:MOUNT_POINT:LOCAL` format
613
+- **Interactive Configuration Selection**: Enhanced `autonas-config.sh add` with mount type selection
614
+- **Mixed Environment Support**: Both NFS and LOCAL configurations can coexist seamlessly
615
+
616
+#### Core System Improvements
617
+- **Extended UUID Support**: Support for both standard UUIDs and FAT32 short UUIDs (e.g., `8765-4321`)
618
+- **Enhanced Manager Integration**: Complete autonas-manager.sh support for LOCAL configurations
619
+- **Clean Logging**: LOCAL configurations show "Skipping X for local mount configuration" instead of errors
620
+- **Synchronized Disk Display**: Fixed desynchronization between disk display and mapping logic
621
+
622
+#### Bug Fixes Resolved
623
+- **Disk Selection Mapping Bug**: Fixed issue where selecting disk 6 would map to wrong UUID
624
+- **LOG Spam Resolution**: Eliminated infinite "Waiting for interface LOCAL" loops
625
+- **UUID Regex Enhancement**: Updated regex pattern to handle FAT32 short UUIDs properly
626
+- **Manager Function Updates**: All network-related functions now properly detect and skip LOCAL configurations
627
+
628
+#### Technical Implementation
629
+```bash
630
+# NFS Configuration (existing)
631
+UUID:NAME:IP:INTERFACE:MOUNT_POINT:NFS_OPTIONS
632
+
633
+# LOCAL Configuration (new)
634
+UUID:NAME:LOCAL:LOCAL:MOUNT_POINT:LOCAL
635
+```
636
+
637
+#### Manager Function Enhancements
638
+- **`activate_ip()`**: Skips IP activation for LOCAL configurations
639
+- **`deactivate_ip()`**: Skips IP deactivation for LOCAL configurations  
640
+- **`add_nfs_export()`**: Skips NFS export for LOCAL configurations
641
+- **`remove_nfs_export()`**: Skips NFS export removal for LOCAL configurations
642
+
643
+#### Use Cases for LOCAL Configurations
644
+- **Simple local storage**: Diskuri pentru backup-uri locale fฤƒrฤƒ acces de reศ›ea
645
+- **Scratch space**: Space temporar pentru procesare localฤƒ de date  
646
+- **Development storage**: Storage local pentru cache-uri ศ™i fiศ™iere temporare
647
+- **Archive storage**: Archive locale care nu necesitฤƒ export NFS
648
+- **Mixed environments**: Combinaศ›ie de storage local ศ™i shares de reศ›ea
649
+
650
+#### Configuration Examples
651
+```properties
652
+# NFS Shares (network access)
653
+920fe1b7-4091-4d6a-bab8-2f48d8d704bc:shared-docs:192.168.1.100:eth0:/mnt/autonas/shared-docs:*(rw,all_squash,insecure,async,no_subtree_check,anonuid=0,anongid=0)
654
+
655
+# LOCAL Mounts (local only)  
656
+8765-4321:local-backup:LOCAL:LOCAL:/mnt/autonas/local-backup:LOCAL
657
+abcd-1234:scratch-space:LOCAL:LOCAL:/mnt/autonas/scratch-space:LOCAL
658
+```
659
+
660
+#### Backward Compatibility
661
+- **Full compatibility**: Existing NFS configurations continue to work unchanged
662
+- **No migration required**: Current setups work without any changes
663
+- **Enhanced functionality**: New LOCAL options available alongside existing NFS features
664
+
665
+## [v2.4.0] - 2025-08-11
666
+
667
+### ๐ŸŒ Interface Stability Management System
668
+
669
+#### Problema Rezolvatฤƒ
670
+- **USB/Thunderbolt interfaces instabile**: Interfeศ›ele USB ศ™i Thunderbolt dispar ศ™i revin periodic
671
+- **IP-uri pierdute**: IP-urile configurate pentru diskuri nu se readaugฤƒ automat cรขnd interfaศ›a revine
672
+- **NFS exports indisponibile**: Export-urile devin temporar inaccesibile din cauza IP-urilor lipsฤƒ
673
+
674
+#### Interface Management Tools
675
+- **autonas-interface-handler.sh**: Handler principal pentru evenimente udev de interfeศ›e
676
+- **Event-driven only**: Arhitecturฤƒ complet bazatฤƒ pe evenimente (fฤƒrฤƒ daemon/servicii permanente)
677
+- **Emergency diagnostics**: Tool-uri de diagnostic pentru depanare รฎn cazuri extreme
678
+
679
+#### Interface Handler System  
680
+- **autonas-interface-handler.sh**: Handler principal pentru evenimente udev de interfeศ›e
681
+- **Event-driven architecture**: Rฤƒspuns instant la schimbฤƒrile interfeศ›elor (nu polling)
682
+- **Multiple event types**: Detecteazฤƒ add/remove/change/carrier/operstate events
683
+- **Focus USB/Thunderbolt**: Tratament special pentru interfeศ›ele instabile
684
+- **Smart restoration**: Verificฤƒ starea interfeศ›elor รฎnainte de configurare IP
685
+- **Background processing**: Execuศ›ie asincronฤƒ pentru a evita timeout-urile udev
686
+- **Retry mechanism**: Logicฤƒ de retry pentru configurarea IP-urilor pe interfeศ›e instabile
687
+
688
+#### Advanced IP Management
689
+- **Interface existence checking**: Verificare inteligentฤƒ dacฤƒ interfaศ›a existฤƒ รฎnainte de configurare
690
+- **IP conflict resolution**: Detecteazฤƒ ศ™i evitฤƒ conflictele de IP-uri
691
+- **Retry mechanism**: Logic de retry pentru configurarea IP-urilor pe interfeศ›e instabile
692
+- **Shared IP management**: Gestionarea corectฤƒ a IP-urilor folosite de multiple diskuri
693
+- **Wait for interface**: Aศ™teaptฤƒ ca interfeศ›ele USB/Thunderbolt sฤƒ aparฤƒ (pรขnฤƒ la 30 secunde)
694
+
695
+#### Debug ศ™i Monitoring Integration
696
+- **Integrated monitoring**: Built-in status checking รฎn autonas.sh unified script
697
+- **Real-time logging**: Monitorizare รฎn timp real prin journalctl
698
+- **Configuration validation**: Built-in testing cu `autonas test <uuid>`
699
+- **Status analysis**: System status prin `autonas status`
700
+- **Network debugging**: Standard tools (ip, journalctl, udevadm) pentru troubleshooting
701
+
702
+#### Enhanced udev Rules
703
+- **98-autonas-interfaces.rules**: Reguli udev comprehensive pentru interfeศ›e de reศ›ea
704
+- **Event-driven primary mechanism**: Detectare principalฤƒ prin evenimente, nu polling
705
+- **Multiple trigger types**: add/remove/change/operstate/carrier events
706
+- **USB/Thunderbolt specific**: Tratament special pentru interfeศ›ele instabile
707
+- **State change monitoring**: Monitorizeazฤƒ schimbฤƒrile de stare operaศ›ionalฤƒ ศ™i carrier
708
+- **Instant response**: Rฤƒspuns รฎn 2-3 secunde la schimbฤƒrile interfeศ›elor
709
+
710
+#### Management Commands
711
+```bash
712
+# Debug interfeศ›e ศ™i IP-uri prin unified interface
713
+autonas status                    # System status complet
714
+autonas show                      # Device discovery ศ™i status
715
+
716
+# Monitorizare timp real
717
+journalctl -t autonas -f          # Live monitoring AutoNAS
718
+journalctl -t autonas-interface-handler -f  # Interface events
719
+
720
+# Network debugging standard
721
+ip addr show                      # Check interface status
722
+udevadm monitor --subsystem-match=net       # Monitor udev events
723
+```
724
+
725
+#### Installation & Service Integration
726
+- **Automatic installation**: Toate componentele sunt instalate automat de `deploy.sh`
727
+- **Service auto-start**: Serviciul de monitorizare porneศ™te automat la instalare
728
+- **Initial restore**: Restaurare automatฤƒ a IP-urilor la finalul instalฤƒrii
729
+- **Proper dependencies**: Dependenศ›e corecte cu serviciile de reศ›ea ศ™i NFS
730
+
731
+### ๐Ÿ”ง รŽmbunฤƒtฤƒศ›iri Core Manager
732
+
733
+#### Smart IP Configuration
734
+- **Interface existence validation**: Verificฤƒ dacฤƒ interfaศ›a existฤƒ รฎnainte de configurare
735
+- **Wait for interface**: Logicฤƒ de aศ™teptare pentru interfeศ›ele care apar cu รฎntรขrziere
736
+- **Retry mechanism**: Pรขnฤƒ la 3 รฎncercฤƒri pentru configurarea IP-urilor
737
+- **Conflict detection**: Evitฤƒ adฤƒugarea IP-urilor deja configurate
738
+
739
+#### Enhanced Error Handling
740
+- **Detailed error reporting**: Mesaje de eroare mai descriptive
741
+- **Recovery suggestions**: Sugestii pentru rezolvarea problemelor
742
+- **Graceful degradation**: Continuฤƒ operaศ›iunea chiar dacฤƒ unele componente eศ™ueazฤƒ
743
+
744
+### ๐Ÿ“š Documentaศ›ie Extinsฤƒ
745
+
746
+#### New Troubleshooting Section
747
+- **USB/Thunderbolt specific issues**: Secศ›iune dedicatฤƒ pentru problemele interfeศ›elor instabile
748
+- **Debug commands**: Liste complete de comenzi pentru diagnosticare
749
+- **Step-by-step solutions**: Soluศ›ii pas cu pas pentru probleme comune
750
+- **Power management tips**: Sugestii pentru managementul power al USB
751
+
752
+#### Updated Architecture Documentation
753
+- **Interface monitoring flow**: Documentare completฤƒ a fluxului de monitorizare
754
+- **Service interactions**: Interacศ›iunile รฎntre servicii ศ™i dependenศ›ele lor
755
+- **Debug methodology**: Metodologie pentru diagnosticarea problemelor
756
+
757
+### ๐ŸŽฏ Use Cases Noi
758
+
759
+#### Unstable Interface Environments
760
+- **USB docking stations**: Staศ›ii de andocare USB care se deconecteazฤƒ periodic
761
+- **Thunderbolt hubs**: Hub-uri Thunderbolt cu conectivitate intermitentฤƒ  
762
+- **USB-C multiport adapters**: Adaptoare multiport cu stabilitate variabilฤƒ
763
+- **Laptop docking scenarios**: Scenarii de laptop care se conecteazฤƒ/deconecteazฤƒ des
764
+
765
+#### Enterprise Environment
766
+- **Multiple identical setups**: Deploy pe multiple servere cu aceleaศ™i probleme interfeศ›e
767
+- **Centralized monitoring**: Monitorizare centralizatฤƒ a stabilitฤƒศ›ii interfeศ›elor
768
+- **Automated recovery**: Recuperare automatฤƒ fฤƒrฤƒ intervenศ›ie manualฤƒ
769
+
770
+## [v2.3.0] - 2025-07-22
771
+
772
+### ๐Ÿš€ Boot Recovery System
773
+
774
+#### Boot Scan Service
775
+- **Automatic boot detection**: New `autonas-boot-scan.service` detects and mounts configured disks at system boot
776
+- **Pre-connected disk support**: Handles disks that were already attached before system start
777
+- **Intelligent scanning**: Checks all configured UUIDs from `/etc/pve/autonas/disks.conf`
778
+- **Mount status detection**: Identifies disks already mounted elsewhere and handles appropriately
779
+
780
+#### Boot Scanner Script
781
+- **autonas-boot-scan.sh**: Comprehensive boot-time disk scanner
782
+- **UUID existence verification**: Checks if configured disk UUIDs are present as devices
783
+- **Mount state analysis**: Determines if disks are unmounted, mounted elsewhere, or correctly mounted
784
+- **Automatic attachment**: Uses `autonas-manager.sh` to properly mount and configure detected disks
785
+- **Detailed reporting**: Statistics on total, processed, already-mounted, and newly-attached disks
786
+
787
+#### System Integration
788
+- **Service dependencies**: Proper ordering after filesystem, udev-settle, network, and NFS services
789
+- **Installation automation**: Added to install/uninstall scripts with proper enable/disable
790
+- **Documentation updates**: Complete documentation of new boot recovery architecture
791
+- **RemainAfterExit=yes**: Service stays active to indicate successful boot scan completion
792
+
793
+#### Main Service Integration
794
+- **autonas.service**: New main AutoNAS service for centralized system management
795
+- **Enhanced reload functionality**: Comprehensive reload of udev rules, NFS exports, and systemd daemon
796
+- **Service orchestration**: Proper dependencies and integration with boot-scan service
797
+- **Centralized control**: Single point of management for the entire AutoNAS system
798
+
799
+#### Orphan File Prevention System
800
+- **Pre-installation cleanup**: Automatic cleanup of previous installations before reinstalling
801
+- **Uninstaller integration**: Install script now installs uninstaller for future clean upgrades
802
+- **Deploy script uninstall**: New `./deploy.sh uninstall` command for remote uninstallation
803
+- **Force mode uninstaller**: Silent cleanup mode with `--force` flag for automated use
804
+- **Evolution protection**: Prevents orphan files during project evolution and upgrades
805
+
806
+#### Problem Resolution
807
+- **Solves reboot issue**: Addresses problem where pre-connected disks weren't exported after system restart
808
+- **udev gap coverage**: Handles scenario where udev doesn't re-trigger events for existing devices
809
+- **NFS export recovery**: Ensures all configured disks are properly exported after boot
810
+- **Robust boot process**: System now handles both hot-plug and pre-connected disk scenarios
811
+
812
+## [v2.2.0] - 2025-07-22
813
+
814
+### ๐Ÿš€ Remote Deployment System
815
+
816
+#### Deploy Script Added
817
+- **Remote deployment support**: New `deploy.sh` script for automated installation on multiple targets
818
+- **Multi-target management**: Support for servers 192.168.2.91, 192.168.2.92, 192.168.2.93
819
+- **SSH-based automation**: Uses SSH keys for seamless remote operations
820
+- **Intelligent connectivity checks**: Host availability verification before operations
821
+
822
+#### Enhanced Reliability
823
+- **Host status verification**: Ping test before attempting SSH connections
824
+- **Graceful failure handling**: Skip unavailable hosts with clear warnings
825
+- **Connection testing**: SSH connectivity validation before deployment
826
+- **Error reporting**: Clear status messages for each operation step
827
+
828
+#### Deployment Features
829
+- **Complete installation**: Automated install, configure, and start services
830
+- **Service management**: Start, restart, stop remote AutoNAS services
831
+- **Status monitoring**: Remote status checking and health validation
832
+- **Cleanup operations**: Temporary file cleanup on target systems
833
+
834
+#### Command Operations
835
+- **install**: Complete AutoNAS installation and configuration
836
+- **start/restart/stop**: Service lifecycle management
837
+- **status**: Health check and configuration validation
838
+- **cleanup**: Temporary file removal
839
+- **help**: Comprehensive usage documentation
840
+
841
+#### Documentation Consolidation
842
+- **Merged TECHNICAL.md into README.md**: Complete technical documentation in single file
843
+- **Enhanced architecture section**: Detailed component descriptions and workflows
844
+- **Comprehensive troubleshooting**: Technical debugging and extensibility guides
845
+- **Unified documentation**: Single source of truth for all AutoNAS information
846
+
847
+## [v2.1.0] - 2024-12-02
848
+
849
+### ๐Ÿš€ udev Context Improvements
850
+
851
+#### Simplified Execution Strategy
852
+- **Direct systemd execution**: Removed unreliable direct execution in udev context
853
+- **Guaranteed privilege handling**: All mount operations now run through systemd service
854
+- **Improved reliability**: Eliminates "permission denied" issues in restricted udev context
855
+- **Consistent behavior**: Same execution path for all environments
856
+
857
+#### Enhanced Logging
858
+- **Streamlined logging**: Clear indication of systemd service usage
859
+- **Better debugging**: Simplified troubleshooting without fallback complexity
860
+
861
+## [v2.0.0] - 2024-12-02
862
+
863
+### ๐Ÿš€ Major Features Added
864
+
865
+#### Intelligent Device Detection
866
+- **Multiple device type support**: USB storage, SCSI removable, USB-to-SATA bridges
867
+- **UUID-based identification**: Precise device matching via filesystem UUID
868
+- **Smart udev rules**: Comprehensive detection for various hardware configurations
869
+
870
+#### Enhanced User Experience
871
+- **Interactive configuration helper**: `autonas-config.sh` with guided setup
872
+- **UUID parameter support**: Pre-populate UUIDs in `add` and `test` commands
873
+- **Automatic mounting post-configuration**: Immediate disk availability after setup
874
+- **Standardized NFS configuration**: Optimized settings applied automatically
875
+
876
+#### Advanced System Integration
877
+- **udev wrapper**: Prevents timeout issues with asynchronous execution
878
+- **Intelligent IP management**: Shared IP handling across multiple disks
879
+- **Comprehensive logging**: Structured logging with proper syslog tags
880
+- **Error handling and recovery**: Robust failure handling with detailed reporting
881
+
882
+### ๐Ÿ›ก๏ธ Data Protection & Safety
883
+
884
+#### Installation Safety
885
+- **Configuration preservation**: Existing `disks.conf` files are never overwritten
886
+- **User data detection**: Automatically detects and preserves user configurations
887
+- **Template system**: New installs get templates, upgrades preserve data
888
+
889
+#### Uninstallation Safety
890
+- **Data-preserving uninstall**: User configurations and mount points preserved
891
+- **Selective cleanup**: Only removes AutoNAS components, keeps user data
892
+- **Manual cleanup guidance**: Clear instructions for complete removal if desired
893
+
894
+### ๐Ÿ”ง Configuration Management
895
+
896
+#### Simplified Configuration Process
897
+```bash
898
+# Old method (manual editing)
899
+sudo nano /etc/pve/autonas/disks.conf
900
+
901
+# New method (guided interactive)
902
+sudo autonas-config.sh add <UUID>
903
+```
904
+
905
+#### Smart Validation
906
+- **UUID format validation**: Proper 8-4-4-4-12 hex format checking
907
+- **Disk name validation**: Character restrictions and reserved name checking
908
+- **Network interface validation**: Real-time interface existence checking
909
+- **IP address validation**: Format and availability checking
910
+
911
+#### Enhanced Commands
912
+- **`autonas-config.sh add [UUID]`**: Interactive configuration with optional UUID
913
+- **`autonas-config.sh test [UUID]`**: Configuration testing with optional UUID
914
+- **`autonas-config.sh list`**: Formatted display of all configurations
915
+- **`autonas-config.sh remove`**: Interactive configuration removal
916
+
917
+### ๐ŸŒ Network & NFS Improvements
918
+
919
+#### Standardized NFS Configuration
920
+```
921
+*(rw,all_squash,insecure,async,no_subtree_check,anonuid=0,anongid=0)
922
+```
923
+- **Optimized for performance**: Async writes with no_subtree_check
924
+- **Security balanced**: all_squash with root mapping for compatibility
925
+- **Wide compatibility**: insecure flag for broader client support
926
+
927
+#### Intelligent IP Management
928
+- **Shared IP support**: Multiple disks can use the same IP address
929
+- **Smart cleanup**: IPs only removed when no longer in use
930
+- **Automatic configuration**: IP setup integrated with disk mounting
931
+
932
+### ๐Ÿ” Monitoring & Debugging
933
+
934
+#### Enhanced Logging System
935
+- **Structured logging**: Separate tags for different components
936
+  - `autonas`: Main manager operations
937
+  - `autonas-wrapper`: udev wrapper operations
938
+  - `autonas-config`: Configuration helper operations
939
+- **Informative messages**: Clear indication of actions and results
940
+- **Debugging support**: Detailed error reporting with context
941
+
942
+#### Monitoring Commands
943
+```bash
944
+# Live monitoring all AutoNAS components
945
+journalctl -t autonas -t autonas-wrapper -t autonas-config -f
946
+
947
+# Component-specific monitoring
948
+journalctl -t autonas --since "10 minutes ago"
949
+
950
+# udev debugging
951
+udevadm monitor --subsystem-match=block
952
+```
953
+
954
+### ๐Ÿ“ Project Structure Improvements
955
+
956
+#### Organized Component Structure
957
+```
958
+autoNAS/
959
+โ”œโ”€โ”€ README.md                   # User documentation
960
+โ”œโ”€โ”€ DEVELOPMENT.md             # Technical documentation  
961
+โ”œโ”€โ”€ CHANGELOG.md               # This file
962
+โ”œโ”€โ”€ config/
963
+โ”‚   โ”œโ”€โ”€ disks.conf              # Configuration template
964
+โ”‚   โ”œโ”€โ”€ 99-autonas-disk.rules   # udev detection rules
965
+โ”‚   โ””โ”€โ”€ autonas-attach@.service # systemd fallback service
966
+โ””โ”€โ”€ scripts/
967
+    โ”œโ”€โ”€ autonas-manager.sh      # Main disk management
968
+    โ”œโ”€โ”€ autonas-udev-wrapper.sh # udev timeout prevention
969
+    โ”œโ”€โ”€ autonas-config.sh       # Interactive configuration
970
+    โ””โ”€โ”€ uninstall.sh            # Safe uninstallation
971
+```
972
+
973
+#### Documentation Overhaul
974
+- **Complete README**: Comprehensive user guide with examples
975
+- **Technical documentation**: Developer-focused implementation details
976
+- **Inline comments**: Extensive code documentation for maintainability
977
+
978
+### โšก Performance Optimizations
979
+
980
+#### udev Integration
981
+- **Timeout prevention**: Asynchronous wrapper prevents udev blocking
982
+- **Background processing**: Non-blocking device handling
983
+- **Immediate feedback**: Quick udev response with background operations
984
+
985
+#### File System Operations
986
+- **UUID-based mounting**: Consistent device identification
987
+- **Optimized mount points**: Organized `/mnt/autonas/` structure
988
+- **Efficient configuration parsing**: Fast config file processing
989
+
990
+### ๐Ÿ”’ Security Enhancements
991
+
992
+#### File Permissions
993
+- **Proper ownership**: All scripts owned by root:root
994
+- **Secure permissions**: 755 for scripts, 644 for configs
995
+- **Protected configuration**: Config files not world-writable
996
+
997
+#### NFS Security
998
+- **User mapping**: all_squash prevents privilege escalation
999
+- **Anonymous mapping**: anonuid=0,anongid=0 for consistent access
1000
+- **Performance vs security**: Balanced configuration for practical use
1001
+
1002
+### ๐Ÿงช Testing & Validation
1003
+
1004
+#### Configuration Testing
1005
+- **Real-time validation**: Test configurations against current system state
1006
+- **Device detection**: Check if UUIDs correspond to actual devices
1007
+- **Network validation**: Verify interface existence and IP availability
1008
+
1009
+#### Integration Testing
1010
+- **Manual testing support**: Commands for manual mount/unmount testing
1011
+- **Status verification**: Built-in checks for successful operations
1012
+- **Rollback capability**: Automatic cleanup on operation failures
1013
+
1014
+### ๐Ÿšจ Error Handling Improvements
1015
+
1016
+#### Graceful Failure Handling
1017
+- **Descriptive error messages**: Clear indication of what went wrong
1018
+- **Suggested remedies**: Specific commands to fix common issues
1019
+- **Logging preservation**: All errors logged for later analysis
1020
+
1021
+#### Recovery Mechanisms
1022
+- **Automatic rollback**: Failed operations clean up after themselves
1023
+- **State consistency**: System left in known good state after failures
1024
+- **Manual recovery**: Clear instructions for manual intervention when needed
1025
+
1026
+### ๐Ÿ“– Breaking Changes
1027
+
1028
+#### Configuration Format
1029
+- **No breaking changes**: Existing configurations continue to work
1030
+- **Enhanced format**: New configurations use optimized NFS settings
1031
+- **Backwards compatibility**: Old configurations preserved during upgrades
1032
+
1033
+#### Command Interface
1034
+- **Extended syntax**: Commands now accept optional parameters
1035
+- **Backwards compatibility**: Old syntax continues to work
1036
+- **Enhanced features**: New parameters provide additional functionality
1037
+
1038
+### ๐Ÿ”„ Migration Guide
1039
+
1040
+#### From Manual Configuration
1041
+If you've been manually editing configuration files:
1042
+1. **Backup existing configs**: `sudo cp /etc/pve/autonas/disks.conf ~/backup.conf`
1043
+2. **Deploy via cluster system**: `./deploy.sh install` (preserves existing configs)
1044
+3. **Use new tools**: `autonas list` to see current configurations
1045
+
1046
+#### From Previous AutoNAS Version
1047
+1. **Safe upgrade**: `./deploy.sh install` automatically preserves data
1048
+2. **New features**: Start using `autonas add <UUID>` for new disks
1049
+3. **Enhanced monitoring**: Use new logging commands for better visibility
1050
+
1051
+### ๐ŸŽฏ Future Roadmap
1052
+
1053
+#### Planned Features
1054
+- **Web interface**: GUI for configuration management
1055
+- **Notification system**: Email/webhook notifications for disk events
1056
+- **Health monitoring**: SMART data integration and disk health reporting
1057
+- **Cloud integration**: Automatic cloud backup triggers
1058
+
1059
+#### Performance Improvements
1060
+- **Parallel processing**: Concurrent handling of multiple disk operations
1061
+- **Caching**: Configuration caching for faster operations
1062
+- **Optimization**: Further NFS and mount option tuning
1063
+
1064
+#### Security Enhancements
1065
+- **TLS support**: Encrypted NFS where supported
1066
+- **Access control**: Per-disk user/group restrictions
1067
+- **Audit logging**: Enhanced security logging for compliance
1068
+
1069
+---
1070
+
1071
+### ๐Ÿ“ Notes
1072
+
1073
+- **Semantic versioning**: AutoNAS follows semver for version numbering
1074
+- **Stability focus**: All changes prioritize data safety and system stability
1075
+- **Community feedback**: Features developed based on user needs and feedback
+394 -0
README.md
@@ -0,0 +1,394 @@
1
+# AutoNAS v3.0 - Sistem de Montare Automatฤƒ cu Unified Interface
2
+
3
+AutoNAS este un sistem inteligent pentru montarea automatฤƒ a diskurilor externe cu configurarea IP-urilor, exporturilor NFS ศ™i **arhitectura revoluศ›ionarฤƒ Background Import** pentru import scalabil de camere digitale. Sistemul detecteazฤƒ automat conectarea diskurilor USB/SATA externe, le monteazฤƒ, configureazฤƒ IP-uri pe interfeศ›e de reศ›ea ศ™i exportฤƒ conศ›inutul prin NFS.
4
+
5
+## ๐ŸŽ‰ **Nouฤƒ รฎn v3.0: Clean User Interface**
6
+- **๐Ÿš€ Scriptul Unificat** - Un singur script `autonas` pentru toate operaศ›iunile
7
+- **โšก Interfaศ›ฤƒ Curatฤƒ** - Doar comanda `autonas` vizibilฤƒ รฎn autocomplete
8
+- **๐Ÿ”„ Background Import** - Import-uri รฎn background fฤƒrฤƒ timeout constraints  
9
+- **๐Ÿ“Š Cod Optimizat** - 47% reducere cod prin eliminarea duplicฤƒrilor
10
+- **๐Ÿ—‚๏ธ Scripturi Organizate** - Toate scripturile interne ascunse รฎn `/usr/local/lib/autonas/`
11
+
12
+## ๐ŸŒŸ **Interfaศ›a Curatฤƒ AutoNAS**
13
+
14
+### Comanda Principalฤƒ (Singura Vizibilฤƒ)
15
+```bash
16
+autonas <command> [options]
17
+```
18
+*Doar comanda `autonas` apare รฎn autocomplete - toate scripturile interne sunt ascunse*
19
+
20
+### Operaศ›iuni Disponibile
21
+```bash
22
+# Operaศ›iuni Diskuri
23
+autonas attach <uuid>         # Monteazฤƒ disk automat
24
+autonas detach <uuid>         # Demonteazฤƒ disk
25
+autonas list                  # Listeazฤƒ diskurile configurate
26
+
27
+# Management Configuraศ›ii  
28
+autonas add [uuid]            # Adaugฤƒ configuraศ›ie nouฤƒ
29
+autonas show                  # Afiศ™eazฤƒ toate device-urile detectate
30
+autonas status               # Status sistem complet
31
+
32
+# Utilitฤƒศ›i
33
+autonas mount <uuid>         # Montare manualฤƒ
34
+autonas umount <uuid>        # Demontare manualฤƒ
35
+autonas --help              # Ajutor complet
36
+```
37
+
38
+### Avantaje Interfaศ›ฤƒ Curatฤƒ
39
+- **Un singur command vizibil** - doar `autonas` รฎn autocomplete
40
+- **Interfaศ›ฤƒ consistentฤƒ** pentru toate operaศ›iunile
41
+- **Cod optimizat** cu 47% reducere prin eliminarea duplicฤƒrilor
42
+- **Scripturi organizate** - toate utilitarele interne รฎn `/usr/local/lib/autonas/`
43
+- **Logging unificat** cu tag-uri comune
44
+
45
+## ๐Ÿš€ Instalare รฎn Cluster
46
+
47
+AutoNAS este destinat exclusiv pentru instalare pe cluster de servere prin sistemul de deploy remote:
48
+
49
+```bash
50
+# Cloneazฤƒ repository-ul
51
+git clone <repository-url> autoNAS
52
+cd autoNAS
53
+```
54
+
55
+## ๐ŸŒ Deploy Remote
56
+
57
+AutoNAS foloseศ™te exclusiv deploy remote pentru instalarea ศ™i managementul pe nodurile cluster-ului:
58
+
59
+```bash
60
+# Instalare completฤƒ pe toate serverele (192.168.2.91-93)
61
+./deploy.sh install
62
+
63
+# Dezinstalare completฤƒ de pe toate serverele
64
+./deploy.sh uninstall
65
+
66
+# Instalare doar pe server specific
67
+./deploy.sh install 192.168.2.91
68
+
69
+# Management servicii
70
+./deploy.sh start      # Porneศ™te serviciile
71
+./deploy.sh restart    # Restarteazฤƒ serviciile
72
+./deploy.sh stop       # Opreศ™te serviciile
73
+./deploy.sh status     # Verificฤƒ statusul
74
+```
75
+
76
+### Caracteristici Deploy:
77
+- โœ… **Instalare exclusiv cluster** - destinat doar pentru noduri multiple
78
+- โœ… **Verificare host status** - testeazฤƒ disponibilitatea cu ping
79
+- โœ… **Conectivitate SSH** - valideazฤƒ accesul prin chei SSH
80
+- โœ… **Transfer eficient** - sincronizare cu rsync
81
+- โœ… **Error handling** - management robust al erorilor
82
+- โœ… **Logging colorat** - feedback clar pentru fiecare operaศ›ie
83
+
84
+### Pregฤƒtirea pentru Deploy:
85
+1. **Configureazฤƒ cheile SSH** pe serverele ศ›intฤƒ
86
+2. **Testeazฤƒ conectivitatea**: `./deploy.sh status`
87
+3. **Deploy complet**: `./deploy.sh install`
88
+
89
+## ๐Ÿ“‹ Funcศ›ionalitฤƒศ›i Principale
90
+
91
+### ๐Ÿ”Œ Detectare Automatฤƒ
92
+- **Detectare prin udev** pentru diskuri USB, SATA externe ศ™i USB-to-SATA bridges
93
+- **Suport pentru multiple tipuri** de device-uri (removable, ATA cu USB properties)
94
+- **Detectare inteligentฤƒ** bazatฤƒ pe UUID filesystem
95
+
96
+### ๐Ÿ—‚๏ธ Trei Tipuri de Configurare
97
+
98
+#### 1. **NFS Share Complet** (acces de reศ›ea)
99
+```bash
100
+autonas add <uuid>  # Selecteazฤƒ [1] - NFS share complet
101
+```
102
+- Montare automatฤƒ + configurare IP + export NFS
103
+- Acces complet de reศ›ea pentru alte maศ™ini
104
+- Perfect pentru backup servere ศ™i storage partajat
105
+
106
+#### 2. **Montare Localฤƒ Simplฤƒ** (doar local)  
107
+```bash
108
+autonas add <uuid>  # Selecteazฤƒ [2] - Montare localฤƒ
109
+```
110
+- Doar mount point local, fฤƒrฤƒ IP ศ™i NFS
111
+- Ideal pentru storage local rapid
112
+- Perfect pentru backup-uri ศ™i scratch space
113
+
114
+#### 3. **Import Camerฤƒ Automat** (procesare media)
115
+```bash
116
+autonas add <uuid>  # Selecteazฤƒ [3] - Import camerฤƒ
117
+```
118
+- Mount โ†’ import media files โ†’ unmount automat
119
+- Organizare automatฤƒ cu EXIF ศ™i UTC conversion
120
+- Background processing fฤƒrฤƒ timeout constraints
121
+
122
+### ๐ŸŒ Configuraศ›ie NFS Optimizatฤƒ
123
+```
124
+*(rw,all_squash,insecure,async,no_subtree_check,anonuid=0,anongid=0)
125
+```
126
+
127
+### ๐Ÿ”„ Management Inteligent
128
+- **Configurare prin UUID** pentru identificare precisฤƒ
129
+- **Protecศ›ia configuraศ›iilor** utilizatorului la reinstalare
130
+- **Logging detaliat** pentru debugging ศ™i monitorizare
131
+- **Error handling robust** cu mesaje informative
132
+
133
+## ๐Ÿ“Š Comenzi de Management Rapide
134
+
135
+### Flux de Lucru Tipic
136
+```bash
137
+# 1. Detecteazฤƒ UUID-ul diskului conectat
138
+autonas show
139
+
140
+# 2. Configureazฤƒ diskul (interactiv)
141
+autonas add <uuid>
142
+
143
+# 3. Verificฤƒ statusul
144
+autonas list
145
+autonas status
146
+
147
+# 4. Monitorizeazฤƒ log-urile
148
+journalctl -t autonas -f
149
+```
150
+
151
+### Configurare Rapidฤƒ Exemplu
152
+```bash
153
+# Conecteazฤƒ diskul ศ™i detecteazฤƒ UUID
154
+$ autonas show
155
+Available storage devices:
156
+[1] /dev/sdb1 โ†’ UUID: 920fe1b7-4091-4d6a-bab8-2f48d8d704bc (ext4, 1.8TB)
157
+
158
+# Configureazฤƒ pentru NFS
159
+$ sudo autonas add 920fe1b7-4091-4d6a-bab8-2f48d8d704bc
160
+Input name: backup-disk
161
+Configuration type: [1] NFS share complet
162
+Input IP: 192.168.10.25  
163
+Input interface: thunderbridge
164
+โœ“ Configuration added and disk mounted!
165
+
166
+# Verificฤƒ rezultatul
167
+$ autonas list
168
+Configured disks:
169
+[1] backup-disk (920fe1b7-4091-4d6a-bab8-2f48d8d704bc) โ†’ NFS: 192.168.10.25
170
+```
171
+
172
+## ๐Ÿ“ท Camera Import Automation
173
+
174
+AutoNAS v3.0 introduce arhitectura revoluศ›ionarฤƒ **Background Import** pentru import automat scalabil de camere digitale:
175
+
176
+### ๐Ÿ”„ Background Import Architecture
177
+- **Service-Based Import** - Separare completฤƒ mount/import prin systemd services
178
+- **Unlimited Duration** - Import-uri fฤƒrฤƒ timeout constraints (testat cu 300+ files)
179
+- **Auto-Unmount** - Workflow complet automat mount โ†’ import โ†’ unmount
180
+- **UTC Conversion** - Conversie perfectฤƒ UTC โ†’ Local Time pentru EXIF
181
+
182
+### Configurare Camera Import
183
+```bash
184
+# Configureazฤƒ camera pentru import automat
185
+autonas add <camera-uuid>
186
+# Selecteazฤƒ [3] - Import camerฤƒ automat
187
+# Seteazฤƒ destinaศ›ia: /mnt/storage/photos
188
+```
189
+
190
+### Workflow Automat Camera
191
+1. **Conectare camerฤƒ** โ†’ AutoNAS detecteazฤƒ UUID-ul configurat ca IMPORT
192
+2. **Montare temporarฤƒ** โ†’ Mount point temporar creat automat
193
+3. **Background Import** โ†’ Service separat proceseazฤƒ fiศ™iere fฤƒrฤƒ timeout
194
+4. **Organizare EXIF** โ†’ Sortare automatฤƒ pe date din metadate
195
+5. **Auto-Cleanup** โ†’ Demontare automatฤƒ dupฤƒ finalizare
196
+
197
+## ๐Ÿšจ Troubleshooting Rapid
198
+
199
+### Disk nu se detecteazฤƒ
200
+```bash
201
+journalctl -t autonas -f                    # Monitorizeazฤƒ log-urile
202
+autonas show                                # Verificฤƒ device-urile detectate
203
+udevadm monitor --subsystem-match=block     # Debug udev
204
+```
205
+
206
+### Probleme NFS
207
+```bash
208
+autonas status                 # Verificฤƒ configuraศ›ia
209
+showmount -e localhost         # Verificฤƒ export-urile
210
+systemctl status nfs-kernel-server
211
+```
212
+
213
+### Probleme de Montare
214
+```bash
215
+autonas list                   # Verificฤƒ configuraศ›iile
216
+autonas test <uuid>           # Testeazฤƒ configuraศ›ia specificฤƒ
217
+mount | grep autonas          # Verificฤƒ mount-urile active
218
+```
219
+
220
+## โš™๏ธ Arhitectura AutoNAS v3.0
221
+
222
+### ๐Ÿ“ Organizarea Scripturilor
223
+```
224
+/usr/local/bin/
225
+โ”œโ”€โ”€ autonas -> autonas.sh          # Singura comandฤƒ vizibilฤƒ utilizatorului
226
+โ”œโ”€โ”€ autonas.sh                     # Script principal CLI (1,208 linii)
227
+โ””โ”€โ”€ autonas-core.sh                # Biblioteca centralฤƒ (1,044 linii)
228
+
229
+/usr/local/lib/autonas/            # Scripturi interne (ascunse din autocomplete)
230
+โ”œโ”€โ”€ autonas-boot-scan.sh           # Scanner la bootare
231
+โ”œโ”€โ”€ autonas-disk-handler.sh        # Handler evenimente disk
232
+โ”œโ”€โ”€ autonas-media-importer.sh      # Importer automat media
233
+โ”œโ”€โ”€ autonas-network-handler.sh     # Handler eventi reศ›ea
234
+โ”œโ”€โ”€ autonas-udev-wrapper.sh        # Wrapper pentru udev
235
+โ””โ”€โ”€ autonas-uninstall.sh           # Uninstaller sistem
236
+```
237
+
238
+### ๐ŸŽฏ Single Source of Truth
239
+- **Zero duplicare cod** - toate funcศ›iile รฎn `autonas-core.sh`
240
+- **Interfaศ›ฤƒ unificatฤƒ** - toate operaศ›iunile prin comanda `autonas`
241
+- **Scripturi ascunse** - experienศ›ฤƒ utilizator curatฤƒ
242
+
243
+### ๐Ÿ“Š Realizฤƒri v3.0
244
+- **47% reducere cod** - ~2,300 linii eliminate prin refactorizare completฤƒ
245
+- **Comandฤƒ unicฤƒ vizibilฤƒ** - doar `autonas` รฎn autocomplete
246
+- **Organizare profesionalฤƒ** - toate utilitarele ascunse dar funcศ›ionale
247
+- **Integrare completฤƒ** - toate serviciile ศ™i regulile actualizate
248
+
249
+## โš™๏ธ Note Importante
250
+
251
+1. **Ruleazฤƒ ca root**: Toate comenzile AutoNAS necesitฤƒ `sudo`
252
+2. **Configuraศ›ii persistente**: Diskurile configurate se monteazฤƒ automat la conectare
253
+3. **Cleanup automat**: Demontarea curฤƒศ›ฤƒ automat mount points, IP-uri ศ™i export-uri NFS
254
+4. **Siguranศ›ฤƒ date**: Dezinstalarea pฤƒstreazฤƒ toate datele ศ™i configuraศ›iile
255
+5. **Script organizare**: Doar `autonas` vizibil - toate utilitarele รฎn `/usr/local/lib/autonas/`
256
+
257
+## ๐ŸŽฏ Use Cases Rapide
258
+
259
+- **๐ŸŒ NFS Backup Server**: Disk extern โ†’ detectare automatฤƒ โ†’ export NFS instant
260
+- **๐Ÿ“ Storage Local**: Backup-uri locale rapide fฤƒrฤƒ configurare reศ›ea
261
+- **๐Ÿ“ท Import Camere**: Conectare camerฤƒ โ†’ import automat โ†’ organizare EXIF
262
+- **๐Ÿ”ง Development**: Mixed storage (local + NFS) pentru workflow-uri complexe
263
+
264
+---
265
+
266
+**AutoNAS v3.0 - Clean Command Interface pentru Montare Automatฤƒ** ๐Ÿš€
267
+
268
+*Doar comanda `autonas` vizibilฤƒ - interfaศ›ฤƒ profesionalฤƒ ศ™i curatฤƒ*
269
+
270
+##  Camera Import Automation
271
+
272
+AutoNAS v3.0 introduce arhitectura revoluศ›ionarฤƒ **Background Import** pentru import automat scalabil de camere digitale cu workflow complet `mount โ†’ import โ†’ unmount`.
273
+
274
+### ๐Ÿš€ **NOUฤ‚ ARHITECTURฤ‚ BACKGROUND IMPORT**
275
+- **๐Ÿ”„ Service-Based Architecture** - Separare completฤƒ mount/import prin systemd services
276
+- **โšก Unlimited Duration** - Import-uri fฤƒrฤƒ timeout constraints (comprobat cu 300+ files)
277
+- **๐Ÿ› ๏ธ Auto-Unmount** - Demontare automatฤƒ dupฤƒ finalizarea import-ului
278
+- **๐Ÿ“Š Production Tested** - Validat cu camere reale Garmin (302 files, 100% success rate)
279
+
280
+### Caracteristici Camera Import
281
+- **๐ŸŽฏ Background Services** - Import ruleazฤƒ รฎn servicii systemd separate fฤƒrฤƒ timeout
282
+- **Detectare automatฤƒ** a structurilor de foldere pentru camere (DCIM, PRIVATE, MP_ROOT)
283
+- **Import cu EXIF** - organizare automatฤƒ pe baza metadatelor temporale cu UTC conversion
284
+- **Multiple formate suportate**: MP4, MOV, JPG, JPEG, PNG, ARW, DNG, MP4, AVI, MKV
285
+- **Organizare automatฤƒ pe date** din EXIF/QuickTime tags cu conversie UTC โ†’ Local Time
286
+- **Dry-run mode** pentru testare fฤƒrฤƒ modificarea fiศ™ierelor
287
+- **Progress tracking** cu statistici detaliate
288
+- **Cleanup GLV files** pentru camerele Garmin
289
+- **Scalabilitate Production** - Testat cu sute de fiศ™iere fฤƒrฤƒ probleme
290
+
291
+### Format Configuraศ›ie IMPORT
292
+```
293
+UUID:NAME:IMPORT:IMPORT:MOUNT_POINT:DESTINATION_PATH[:SCRIPT_PATH]
294
+```
295
+
296
+**Exemplu configuraศ›ie:**
297
+```
298
+1234-5678:camera-garmin:IMPORT:IMPORT:/mnt/autonas/camera-garmin:/mnt/storage/photos:/usr/local/bin/autonas-camera-import.sh
299
+```
300
+
301
+### Workflow Import Automat (Background Architecture)
302
+
303
+1. **Conectare camerฤƒ** โ†’ AutoNAS detecteazฤƒ UUID-ul configurat ca IMPORT
304
+2. **Montare temporarฤƒ** โ†’ Attach service monteazฤƒ รฎn mount point temporar
305
+3. **Background Import Launch** โ†’ Manager lanseazฤƒ direct `run_background_import()` process
306
+4. **Import nelimitat** โ†’ Background service proceseazฤƒ fiศ™iere fฤƒrฤƒ timeout constraints
307
+5. **Organizare EXIF** โ†’ Fiศ™ierele sunt sortate pe date din metadate (UTC โ†’ Local Time)
308
+6. **Auto-Cleanup** โ†’ Background service apeleazฤƒ detach dupฤƒ finalizare
309
+7. **Demontare automatฤƒ** โ†’ Camera este demontatฤƒ automat
310
+8. **Mount cleanup** โ†’ Mount point temporar este curฤƒศ›at
311
+
312
+**Avantaje Arhitecturฤƒ Background:**
313
+- โœ… **Scalabilitate infinitฤƒ** - Nu existฤƒ timeout-uri systemd pentru import
314
+- โœ… **Robusteศ›e** - Service separation previne crash-uri รฎn mount operations
315
+- โœ… **Monitorizare** - Log-uri separate pentru fiecare etapฤƒ
316
+- โœ… **Production Ready** - Testat cu 302 fiศ™iere, import complet รฎn 36 minute
317
+
318
+### Configurare Camera Import
319
+
320
+```bash
321
+# Adaugฤƒ configuraศ›ie pentru camerฤƒ
322
+autonas-config.sh add
323
+
324
+# Selecteazฤƒ UUID-ul camerei
325
+# Input UUID: 1234-5678
326
+
327
+# Selecteazฤƒ tipul de configurare
328
+# [3] - Import camerฤƒ automat
329
+
330
+# Seteazฤƒ numele camerei
331
+# Input name: camera-garmin
332
+
333
+# Seteazฤƒ destinaศ›ia pentru import
334
+# Input destination: /mnt/storage/photos
335
+
336
+# Script personalizat (opศ›ional, default: autonas-camera-import.sh)
337
+# Input script: [ENTER pentru default]
338
+```
339
+
340
+### Script Import Personalizat
341
+
342
+Poศ›i crea propriul script de import:
343
+
344
+```bash
345
+#!/bin/bash
346
+# /usr/local/bin/my-camera-import.sh
347
+
348
+MOUNT_POINT="$1"
349
+DESTINATION="$2"
350
+DISK_NAME="$3"
351
+
352
+# Exemplu: Import specific pentru Canon
353
+find "$MOUNT_POINT" -name "*.CR3" -exec cp {} "$DESTINATION/RAW/" \;
354
+find "$MOUNT_POINT" -name "*.JPG" -exec cp {} "$DESTINATION/JPEG/" \;
355
+
356
+echo "Import completed for $DISK_NAME"
357
+exit 0
358
+```
359
+
360
+### Testare Configuration
361
+
362
+```bash
363
+# Listeazฤƒ configuraศ›iile
364
+autonas-config.sh list
365
+
366
+# Testeazฤƒ configuraศ›ia IMPORT
367
+autonas-config.sh test camera-uuid
368
+
369
+# Monitorizeazฤƒ log-urile
370
+journalctl -t autonas -f
371
+```
372
+
373
+### Camera Import Script (autonas-camera-import.sh)
374
+
375
+Script-ul default oferฤƒ:
376
+- **Auto-detectare** structuri DCIM, PRIVATE, MP_ROOT
377
+- **EXIF processing** cu exiftool pentru date precise
378
+- **Organizare automatฤƒ** รฎn foldere YYYY-MM-DD
379
+- **Redenumire intelligentฤƒ** cu timestamp-uri
380
+- **Multiple opศ›iuni**: --dry-run, --verbose, --limit N
381
+- **Error handling** robust cu logging detaliat
382
+
383
+```bash
384
+# Manual import test
385
+autonas-camera-import.sh /mnt/camera /dest/path camera-name --dry-run --verbose
386
+```
387
+
388
+---
389
+
390
+**AutoNAS v3.0 - Clean Command Interface pentru Montare Automatฤƒ** ๐Ÿš€
391
+
392
+*Doar comanda `autonas` vizibilฤƒ - interfaศ›ฤƒ profesionalฤƒ ศ™i curatฤƒ*
393
+
394
+*Dezvoltat pentru ecosistemul Proxmox/Debian cu focus pe automatizare ศ™i siguranศ›a datelor*
BIN
autoSMART/.DS_Store
Binary file not shown.
+0 -0
autoSMART/examples/complete-deployment.sh
No changes.
+0 -0
autoSMART/scripts/deploy-production.sh
No changes.
+0 -0
autoSMART/scripts/deploy.sh
No changes.
+0 -0
autoSMART/scripts/install.sh
No changes.
+0 -0
autoSMART/scripts/monitor-cluster.sh
No changes.
+0 -0
autoSMART/scripts/smart-collector-daemon.pl
No changes.
+0 -0
autoSMART/scripts/uninstall.sh
No changes.
+19 -0
cluster.json
@@ -0,0 +1,19 @@
1
+{
2
+  "cluster": {
3
+    "name": "madagascar",
4
+    "nodes": [
5
+      {
6
+        "hostname": "ebony",
7
+        "ip": "192.168.2.92"
8
+      },
9
+      {
10
+        "hostname": "baobab", 
11
+        "ip": "192.168.2.91"
12
+      },
13
+      {
14
+        "hostname": "tapia",
15
+        "ip": "192.168.2.93"
16
+      }
17
+    ]
18
+  }
19
+}
+27 -0
config/98-autonas-interfaces.rules
@@ -0,0 +1,27 @@
1
+# AutoNAS Network Interface Rules - Detects when network interfaces come online
2
+# This is the primary mechanism for handling interface stability (not polling)
3
+
4
+
5
+# Trigger when network interfaces are added/removed
6
+ACTION=="add", SUBSYSTEM=="net", RUN+="/usr/local/bin/autonas-network-handler.sh interface_up %k"
7
+ACTION=="remove", SUBSYSTEM=="net", RUN+="/usr/local/bin/autonas-network-handler.sh interface_down %k"
8
+
9
+
10
+# Trigger on interface operational state changes (most important for USB/Thunderbolt)
11
+ACTION=="change", SUBSYSTEM=="net", ATTR{operstate}=="up", RUN+="/usr/local/bin/autonas-network-handler.sh interface_change %k up"
12
+ACTION=="change", SUBSYSTEM=="net", ATTR{operstate}=="down", RUN+="/usr/local/bin/autonas-network-handler.sh interface_change %k down"
13
+
14
+
15
+# Additional triggers for carrier state (link up/down)
16
+ACTION=="change", SUBSYSTEM=="net", ATTR{carrier}=="1", RUN+="/usr/local/bin/autonas-network-handler.sh interface_change %k carrier_up"
17
+ACTION=="change", SUBSYSTEM=="net", ATTR{carrier}=="0", RUN+="/usr/local/bin/autonas-network-handler.sh interface_change %k carrier_down"
18
+
19
+
20
+# Special handling for USB network interfaces (common with Thunderbolt/USB-C docks)
21
+ACTION=="add", SUBSYSTEM=="net", ENV{ID_BUS}=="usb", RUN+="/usr/local/bin/autonas-network-handler.sh usb_interface_up %k"
22
+ACTION=="remove", SUBSYSTEM=="net", ENV{ID_BUS}=="usb", RUN+="/usr/local/bin/autonas-network-handler.sh usb_interface_down %k"
23
+
24
+
25
+# Handle Thunderbolt interfaces specifically
26
+ACTION=="add", SUBSYSTEM=="net", DRIVERS=="thunderbolt", RUN+="/usr/local/bin/autonas-network-handler.sh usb_interface_up %k"
27
+ACTION=="remove", SUBSYSTEM=="net", DRIVERS=="thunderbolt", RUN+="/usr/local/bin/autonas-network-handler.sh usb_interface_down %k"
+38 -0
config/99-autonas-disk.rules
@@ -0,0 +1,38 @@
1
+# AutoNAS udev rules
2
+# Place this file in /etc/udev/rules.d/
3
+
4
+# Rule for USB storage devices - trigger on add/remove
5
+# Detect USB disks (whole disk)
6
+ACTION=="add", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", ENV{DEVTYPE}=="disk", ENV{ID_BUS}=="usb", RUN+="/bin/systemctl start autonas-attach@%E{ID_FS_UUID}.service"
7
+ACTION=="remove", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", ENV{DEVTYPE}=="disk", ENV{ID_BUS}=="usb", RUN+="/usr/local/bin/autonas-disk-handler.sh detach %E{ID_FS_UUID}"
8
+
9
+# Detect USB partitions (more common case)
10
+ACTION=="add", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", ENV{DEVTYPE}=="partition", ENV{ID_BUS}=="usb", RUN+="/bin/systemctl start autonas-attach@%E{ID_FS_UUID}.service"
11
+ACTION=="remove", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", ENV{DEVTYPE}=="partition", ENV{ID_BUS}=="usb", RUN+="/usr/local/bin/autonas-disk-handler.sh detach %E{ID_FS_UUID}"
12
+
13
+# Rule for ATA/SATA external storage devices (USB-to-SATA bridges)
14
+# Detect ATA disks (whole disk) - these appear as ATA but are actually USB external
15
+ACTION=="add", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", ENV{DEVTYPE}=="disk", ENV{ID_BUS}=="ata", ATTRS{removable}=="1", RUN+="/usr/local/bin/autonas-udev-wrapper.sh attach %E{ID_FS_UUID}"
16
+ACTION=="remove", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", ENV{DEVTYPE}=="disk", ENV{ID_BUS}=="ata", ATTRS{removable}=="1", RUN+="/usr/local/bin/autonas-disk-handler.sh detach %E{ID_FS_UUID}"
17
+
18
+# Detect ATA partitions (more common case)
19
+ACTION=="add", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", ENV{DEVTYPE}=="partition", ENV{ID_BUS}=="ata", ATTRS{removable}=="1", RUN+="/usr/local/bin/autonas-udev-wrapper.sh attach %E{ID_FS_UUID}"
20
+ACTION=="remove", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", ENV{DEVTYPE}=="partition", ENV{ID_BUS}=="ata", ATTRS{removable}=="1", RUN+="/usr/local/bin/autonas-disk-handler.sh detach %E{ID_FS_UUID}"
21
+
22
+# Special rule for USB-to-SATA bridges that appear as ATA but have USB properties
23
+# This safely identifies external USB drives that appear as ATA
24
+ACTION=="add", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", ENV{DEVTYPE}=="disk", ENV{ID_BUS}=="ata", ENV{ID_USB_TYPE}=="disk", RUN+="/usr/local/bin/autonas-udev-wrapper.sh attach %E{ID_FS_UUID}"
25
+ACTION=="remove", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", ENV{DEVTYPE}=="disk", ENV{ID_BUS}=="ata", ENV{ID_USB_TYPE}=="disk", RUN+="/usr/local/bin/autonas-disk-handler.sh detach %E{ID_FS_UUID}"
26
+
27
+# Detect USB-to-SATA bridge partitions
28
+ACTION=="add", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", ENV{DEVTYPE}=="partition", ENV{ID_BUS}=="ata", ENV{ID_USB_TYPE}=="disk", RUN+="/usr/local/bin/autonas-udev-wrapper.sh attach %E{ID_FS_UUID}"
29
+ACTION=="remove", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", ENV{DEVTYPE}=="partition", ENV{ID_BUS}=="ata", ENV{ID_USB_TYPE}=="disk", RUN+="/usr/local/bin/autonas-disk-handler.sh detach %E{ID_FS_UUID}"
30
+
31
+# Rule for SCSI external storage devices
32
+# Detect removable disks (whole disk) - exclude USB devices (handled above)
33
+ACTION=="add", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", ENV{DEVTYPE}=="disk", ATTRS{removable}=="1", ENV{ID_BUS}!="usb", RUN+="/bin/systemctl start autonas-attach@%E{ID_FS_UUID}.service"
34
+ACTION=="remove", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", ENV{DEVTYPE}=="disk", ATTRS{removable}=="1", ENV{ID_BUS}!="usb", RUN+="/usr/local/bin/autonas-disk-handler.sh detach %E{ID_FS_UUID}"
35
+
36
+# Detect removable partitions (more common case) - exclude USB devices (handled above)
37
+ACTION=="add", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", ENV{DEVTYPE}=="partition", ATTRS{removable}=="1", ENV{ID_BUS}!="usb", RUN+="/bin/systemctl start autonas-attach@%E{ID_FS_UUID}.service"
38
+ACTION=="remove", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", ENV{DEVTYPE}=="partition", ATTRS{removable}=="1", ENV{ID_BUS}!="usb", RUN+="/usr/local/bin/autonas-disk-handler.sh detach %E{ID_FS_UUID}"
+22 -0
config/autonas
@@ -0,0 +1,22 @@
1
+# AutoNAS Default Configuration
2
+# This file is sourced by AutoNAS scripts to set default behavior
3
+
4
+# Debug mode - set to "true" to enable verbose logging
5
+# When enabled, all AutoNAS operations will produce detailed debug output
6
+AUTONAS_DEBUG="false"
7
+
8
+# Log level for AutoNAS operations
9
+# Possible values: error, warn, info, debug
10
+AUTONAS_LOG_LEVEL="info"
11
+
12
+# Default timeout for disk operations (in seconds)
13
+AUTONAS_DISK_TIMEOUT="30"
14
+
15
+# Enable automatic cleanup of orphaned entries at boot
16
+AUTONAS_CLEANUP_ORPHANS="true"
17
+
18
+# NFS export defaults
19
+AUTONAS_NFS_DEFAULT_OPTIONS="*(rw,all_squash,insecure,async,no_subtree_check,anonuid=0,anongid=0)"
20
+
21
+# Udev rules timeout
22
+AUTONAS_UDEV_TIMEOUT="10"
+15 -0
config/autonas-attach@.service
@@ -0,0 +1,15 @@
1
+[Unit]
2
+Description=AutoNAS Attach Disk %i
3
+After=local-fs.target
4
+After=systemd-udev-settle.service
5
+
6
+[Service]
7
+Type=oneshot
8
+ExecStart=/usr/local/bin/autonas-disk-handler.sh attach-deferred %i
9
+RemainAfterExit=no
10
+TimeoutSec=120
11
+StandardOutput=journal
12
+StandardError=journal
13
+
14
+[Install]
15
+WantedBy=multi-user.target
+18 -0
config/autonas-boot-scan.service
@@ -0,0 +1,18 @@
1
+[Unit]
2
+Description=AutoNAS Boot Scanner - Detect and attach configured disks at boot
3
+After=local-fs.target
4
+After=systemd-udev-settle.service
5
+After=network.target
6
+After=nfs-kernel-server.service
7
+Wants=nfs-kernel-server.service
8
+
9
+[Service]
10
+Type=oneshot
11
+ExecStart=/usr/local/bin/autonas-boot-scan.sh
12
+RemainAfterExit=yes
13
+TimeoutSec=300
14
+StandardOutput=journal
15
+StandardError=journal
16
+
17
+[Install]
18
+WantedBy=multi-user.target
+20 -0
config/autonas.service
@@ -0,0 +1,20 @@
1
+[Unit]
2
+Description=AutoNAS Main Service - Automatic disk mounting and NFS export system
3
+Documentation=file:///usr/local/share/doc/autonas/README.md
4
+After=local-fs.target
5
+After=systemd-udev-settle.service
6
+After=network.target
7
+After=nfs-kernel-server.service
8
+Wants=nfs-kernel-server.service
9
+RequiredBy=autonas-boot-scan.service
10
+
11
+[Service]
12
+Type=oneshot
13
+RemainAfterExit=yes
14
+ExecStart=/bin/true
15
+ExecReload=/usr/local/bin/autonas-disk-handler.sh reload
16
+StandardOutput=journal
17
+StandardError=journal
18
+
19
+[Install]
20
+WantedBy=multi-user.target
+22 -0
config/autosmart
@@ -0,0 +1,22 @@
1
+# AutoSMART Default Configuration
2
+# This file is sourced by AutoSMART scripts to set default behavior
3
+
4
+# Debug mode - set to "true" to enable verbose logging
5
+# When enabled, all AutoSMART operations will produce detailed debug output
6
+AUTOSMART_DEBUG="false"
7
+
8
+# Log level for AutoSMART operations
9
+# Possible values: error, warn, info, debug
10
+AUTOSMART_LOG_LEVEL="info"
11
+
12
+# Default timeout for disk operations (in seconds)
13
+AUTOSMART_DISK_TIMEOUT="30"
14
+
15
+# Enable automatic cleanup of orphaned entries at boot
16
+AUTOSMART_CLEANUP_ORPHANS="true"
17
+
18
+# NFS export defaults
19
+AUTOSMART_NFS_DEFAULT_OPTIONS="*(rw,all_squash,insecure,async,no_subtree_check,anonuid=0,anongid=0)"
20
+
21
+# Udev rules timeout
22
+AUTOSMART_UDEV_TIMEOUT="10"
+30 -0
config/disks.conf
@@ -0,0 +1,30 @@
1
+# AutoNAS Disk Configuration File
2
+#
3
+# Configuration format for different device types:
4
+#
5
+# External Storage (NFS):
6
+# UUID:name:ip:interface:mount_point:nfs_options
7
+#
8
+# Camera Import (integrated media importer):  
9
+# UUID:name:IMPORT:IMPORT:temp_mount_point:destination_path
10
+# Note: Media importer script (/usr/local/bin/autonas-media-importer.sh) is built-in and non-configurable
11
+#
12
+# Examples:
13
+# f6ac3d86-5681-4b33-bc64-aa272b333057:ext01:192.168.10.21:thunderbridge:/mnt/autonas/ext01:*(rw,all_squash,insecure,async,no_subtree_check,anonuid=0,anongid=0)
14
+# 8765-4321:camera-real:IMPORT:IMPORT:/mnt/autonas/camera-real:/mnt/autonas/ext01/@Camera/import
15
+#
16
+# Default NFS Options (AutoNAS standard): *(rw,all_squash,insecure,async,no_subtree_check,anonuid=0,anongid=0)
17
+# - rw: Read/write access
18
+# - all_squash: Map all users to anonymous
19
+# - insecure: Allow connections from non-reserved ports
20
+# - async: Asynchronous writes (better performance)
21
+# - no_subtree_check: Better performance
22
+# - anonuid=0,anongid=0: Map anonymous to root (UID/GID 0)
23
+#
24
+# Rules for disk names:
25
+# - Max 50 characters
26
+# - Only letters, numbers, hyphens (-), underscores (_), and at symbol (@)
27
+# - Must start with letter or number
28
+# - Cannot use reserved names (root, home, tmp, etc.)
29
+#
30
+# Add your disk configurations below:
+409 -0
deploy.sh
@@ -0,0 +1,409 @@
1
+#!/bin/bash
2
+
3
+# AutoNAS Remote Deploy Script
4
+# Instaleazฤƒ ศ™i gestioneazฤƒ AutoNAS pe serverele remote 192.168.2.91-93
5
+
6
+set -e  # Exit on any error
7
+
8
+
9
+# Configuraศ›ii
10
+SSH_USER="root"
11
+REMOTE_DIR="/tmp/autonas-deploy"
12
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
13
+
14
+# Parse cluster.json for nodes
15
+parse_cluster_nodes() {
16
+    local json_file="$SCRIPT_DIR/cluster.json"
17
+    if ! [ -f "$json_file" ]; then
18
+        log_error "cluster.json not found in $SCRIPT_DIR"
19
+        exit 1
20
+    fi
21
+    jq -c '.cluster.nodes[]' "$json_file" 2>/dev/null
22
+}
23
+
24
+# Build arrays of IPs and hostnames
25
+get_targets() {
26
+    local nodes_json
27
+    nodes_json=$(parse_cluster_nodes)
28
+    local ips=()
29
+    local names=()
30
+    while IFS= read -r node; do
31
+        local ip name
32
+        ip=$(echo "$node" | jq -r '.ip')
33
+        name=$(echo "$node" | jq -r '.hostname')
34
+        ips+=("$ip")
35
+        names+=("$name")
36
+    done <<< "$nodes_json"
37
+    echo "${ips[@]}"
38
+}
39
+
40
+# Get node name by IP
41
+get_node_name() {
42
+    local search_ip="$1"
43
+    local nodes_json
44
+    nodes_json=$(parse_cluster_nodes)
45
+    while IFS= read -r node; do
46
+        local ip name
47
+        ip=$(echo "$node" | jq -r '.ip')
48
+        name=$(echo "$node" | jq -r '.hostname')
49
+        if [[ "$ip" == "$search_ip" ]]; then
50
+            echo "$name"
51
+            return
52
+        fi
53
+    done <<< "$nodes_json"
54
+    echo "$search_ip"
55
+}
56
+
57
+# Culori pentru output
58
+RED='\033[0;31m'
59
+GREEN='\033[0;32m'
60
+YELLOW='\033[1;33m'
61
+BLUE='\033[0;34m'
62
+NC='\033[0m' # No Color
63
+
64
+# Funcศ›ii helper
65
+log_info() {
66
+    echo -e "${BLUE}[INFO]${NC} $1"
67
+}
68
+
69
+log_success() {
70
+    echo -e "${GREEN}[SUCCESS]${NC} $1"
71
+}
72
+
73
+log_warning() {
74
+    echo -e "${YELLOW}[WARNING]${NC} $1"
75
+}
76
+
77
+log_error() {
78
+    echo -e "${RED}[ERROR]${NC} $1"
79
+}
80
+
81
+print_banner() {
82
+    echo "======================================"
83
+    echo "    AutoNAS Remote Deploy Script"
84
+    echo "======================================"
85
+    echo ""
86
+}
87
+
88
+# Funcศ›ie pentru verificarea dacฤƒ hostul este up
89
+check_host_up() {
90
+    local target="$1"
91
+    log_info "Verificare dacฤƒ hostul $target este accesibil..."
92
+
93
+    # Pentru simplitate, verificฤƒm direct SSH รฎn loc de ping pe macOS
94
+    if [[ "$OSTYPE" == "darwin"* ]]; then
95
+        # macOS: verificare directฤƒ SSH cu timeout rapid
96
+        if ssh -o ConnectTimeout=3 -o BatchMode=yes -o LogLevel=ERROR "$SSH_USER@$target" "echo 'OK'" >/dev/null 2>&1; then
97
+            log_success "Host $target este UP ศ™i SSH funcศ›ioneazฤƒ"
98
+            return 0
99
+        else
100
+            log_warning "Host $target nu este accesibil prin SSH"
101
+            return 1
102
+        fi
103
+    else
104
+        # Linux: folosim ping normal
105
+        if timeout 5 ping -c 2 -W 3 "$target" >/dev/null 2>&1; then
106
+            log_success "Host $target este UP"
107
+            return 0
108
+        else
109
+            log_warning "Host $target este DOWN sau nu rฤƒspunde la ping"
110
+            return 1
111
+        fi
112
+    fi
113
+}
114
+
115
+# Funcศ›ie pentru verificarea conectivitฤƒศ›ii SSH
116
+check_ssh_connectivity() {
117
+    local target="$1"
118
+
119
+    # Verificฤƒ mai รฎntรขi dacฤƒ hostul este up
120
+    if ! check_host_up "$target"; then
121
+        log_warning "Skipping SSH test pentru $target - hostul nu este up"
122
+        return 1
123
+    fi
124
+
125
+    log_info "Verificare conectivitate SSH pentru $target..."
126
+
127
+    if ssh -o ConnectTimeout=5 -o BatchMode=yes -o LogLevel=ERROR "$SSH_USER@$target" "echo 'SSH OK'" >/dev/null 2>&1; then
128
+        log_success "SSH conectare OK pentru $target"
129
+        return 0
130
+    else
131
+        log_error "SSH conectare FAILED pentru $target - verificฤƒ cheia SSH"
132
+        return 1
133
+    fi
134
+}
135
+
136
+# Funcศ›ie pentru copierea fiศ™ierelor pe ศ›inta remotฤƒ
137
+copy_files() {
138
+    local target="$1"
139
+    log_info "Copierea fiศ™ierelor pe $target..."
140
+
141
+    # Creare director temporar pe ศ›intฤƒ
142
+    ssh -o LogLevel=ERROR "$SSH_USER@$target" "mkdir -p $REMOTE_DIR"
143
+
144
+    # Copierea tuturor fiศ™ierelor proiectului
145
+    rsync -avz --delete --quiet \
146
+        --exclude='.git' \
147
+        --exclude='deploy.sh' \
148
+        --exclude='*.log' \
149
+        "$SCRIPT_DIR/" "$SSH_USER@$target:$REMOTE_DIR/"
150
+
151
+    log_success "Fiศ™iere copiate pe $target"
152
+}
153
+
154
+# Funcศ›ie genericฤƒ pentru executarea unei comenzi pe ศ›inta remotฤƒ
155
+run_on_target() {
156
+    local target="$1"
157
+    local action="$2"
158
+    local success_msg="$3"
159
+    local error_msg="$4"
160
+    local cmd_arg="${5:-$action}"
161
+    
162
+    log_info "$action pe $target..."
163
+    if ssh -o LogLevel=ERROR "$SSH_USER@$target" "bash $REMOTE_DIR/scripts/install.sh $cmd_arg"; then
164
+        log_success "$success_msg"
165
+    else
166
+        log_error "$error_msg"
167
+        return 1
168
+    fi
169
+}
170
+
171
+# Funcศ›ie pentru verificarea statusului (nu necesitฤƒ rsync)
172
+check_status() {
173
+    local target="$1"
174
+    log_info "Verificarea statusului AutoNAS pe $target..."
175
+    # รŽncearcฤƒ sฤƒ foloseascฤƒ uninstaller pentru status sau install.sh dacฤƒ existฤƒ
176
+    ssh -o LogLevel=ERROR "$SSH_USER@$target" "
177
+        if [ -f '$REMOTE_DIR/scripts/install.sh' ]; then
178
+            bash $REMOTE_DIR/scripts/install.sh status
179
+        elif [ -f '/usr/local/bin/autonas' ]; then
180
+            /usr/local/bin/autonas --version 2>/dev/null || echo 'AutoNAS instalat dar versiune necunoscutฤƒ'
181
+        else
182
+            echo 'AutoNAS nu este instalat'
183
+        fi
184
+    "
185
+}
186
+
187
+# Funcศ›ie pentru cleanup (ศ™tergerea fiศ™ierelor temporare)
188
+cleanup() {
189
+    local target="$1"
190
+    log_info "Cleanup fiศ™iere temporare pe $target..."
191
+
192
+    ssh -o LogLevel=ERROR "$SSH_USER@$target" "rm -rf $REMOTE_DIR" || true
193
+    log_success "Cleanup realizat pe $target"
194
+}
195
+
196
+# Funcศ›ie pentru cleanup complet (delegat cฤƒtre uninstaller)
197
+force_cleanup() {
198
+    local target="$1"
199
+    log_info "Cleanup forศ›at AutoNAS pe $target..."
200
+    
201
+    # รŽncearcฤƒ sฤƒ foloseascฤƒ uninstaller-ul existent
202
+    ssh -o LogLevel=ERROR "$SSH_USER@$target" "
203
+        if [ -f '/usr/local/bin/autonas-uninstall.sh' ]; then
204
+            bash /usr/local/bin/autonas-uninstall.sh --force
205
+        elif [ -f '/usr/local/lib/autonas/autonas-uninstall.sh' ]; then
206
+            bash /usr/local/lib/autonas/autonas-uninstall.sh --force
207
+        else
208
+            echo 'WARNING: Nu s-a gฤƒsit uninstaller-ul AutoNAS'
209
+        fi
210
+    " || true
211
+    
212
+    ssh -o LogLevel=ERROR "$SSH_USER@$target" "rm -rf $REMOTE_DIR" || true
213
+    log_success "Cleanup forศ›at completat pe $target"
214
+}
215
+
216
+# Funcศ›ie pentru uninstall AutoNAS (delegat cฤƒtre uninstaller)
217
+uninstall_autonas() {
218
+    local target="$1"
219
+    log_info "Dezinstalarea AutoNAS pe $target..."
220
+
221
+    if ssh -o LogLevel=ERROR "$SSH_USER@$target" "
222
+        if [ -f '/usr/local/bin/autonas-uninstall.sh' ]; then
223
+            bash /usr/local/bin/autonas-uninstall.sh
224
+            rm -f '/usr/local/bin/autonas-uninstall.sh'
225
+            echo 'AutoNAS dezinstalat cu succes!'
226
+        elif [ -f '/usr/local/lib/autonas/autonas-uninstall.sh' ]; then
227
+            bash /usr/local/lib/autonas/autonas-uninstall.sh
228
+            echo 'AutoNAS dezinstalat cu succes!'
229
+        else
230
+            echo 'ERROR: Scriptul de dezinstalare nu a fost gฤƒsit!'
231
+            exit 1
232
+        fi
233
+    "; then
234
+        log_success "AutoNAS dezinstalat cu succes de pe $target"
235
+    else
236
+        log_error "Dezinstalarea AutoNAS a eศ™uat pe $target"
237
+        return 1
238
+    fi
239
+}
240
+
241
+# Funcศ›ii de delegare pentru operaศ›iunile de servicii
242
+install_autonas() {
243
+    run_on_target "$1" "Instalarea AutoNAS" "AutoNAS instalat cu succes pe $1" "Instalarea AutoNAS a eศ™uat pe $1" "install"
244
+}
245
+
246
+start_services() {
247
+    run_on_target "$1" "Pornirea serviciilor AutoNAS" "Serviciile AutoNAS pornite cu succes pe $1" "Pornirea serviciilor AutoNAS a eศ™uat pe $1" "start"
248
+}
249
+
250
+restart_services() {
251
+    run_on_target "$1" "Restartarea serviciilor AutoNAS" "Serviciile AutoNAS restartate cu succes pe $1" "Restartarea serviciilor AutoNAS a eศ™uat pe $1" "restart"
252
+}
253
+
254
+stop_services() {
255
+    run_on_target "$1" "Oprirea serviciilor AutoNAS" "Serviciile AutoNAS oprite cu succes pe $1" "Oprirea serviciilor AutoNAS a eศ™uat pe $1" "stop"
256
+}
257
+
258
+check_dependencies() {
259
+    run_on_target "$1" "Verificarea dependinศ›elor" "Verificarea dependinศ›elor completatฤƒ pe $1" "Verificarea dependinศ›elor a eศ™uat pe $1" "check-deps"
260
+}
261
+
262
+install_dependencies() {
263
+    run_on_target "$1" "Instalarea dependinศ›elor" "Dependinศ›ele instalate cu succes pe $1" "Instalarea dependinศ›elor a eศ™uat pe $1" "install-deps"
264
+}
265
+
266
+# Funcศ›ie pentru afiศ™area ajutorului
267
+show_help() {
268
+    echo "Utilizare: $0 [COMANDฤ‚] [ศšINTE]"
269
+    echo ""
270
+    echo "COMENZI:"
271
+    echo "  install       - Instalare completฤƒ AutoNAS pe toate ศ›intele"
272
+    echo "  install-deps  - Instalare doar dependinศ›e (nfs-kernel-server, autofs, etc.)"
273
+    echo "  check-deps    - Verificare dependinศ›e fฤƒrฤƒ instalare"
274
+    echo "  uninstall     - Dezinstalare completฤƒ AutoNAS de pe toate ศ›intele"
275
+    echo "  start         - Porneศ™te serviciile AutoNAS"
276
+    echo "  restart       - Restarteazฤƒ serviciile AutoNAS"
277
+    echo "  stop          - Opreศ™te serviciile AutoNAS"
278
+    echo "  status        - Afiศ™eazฤƒ statusul serviciilor"
279
+    echo "  cleanup       - ศ˜terge fiศ™ierele temporare"
280
+    echo "  force-cleanup - Cleanup agresiv (inclusiv fiศ™iere orfane)"
281
+    echo "  help          - Afiศ™eazฤƒ acest ajutor"
282
+    echo ""
283
+    echo "ศšINTE (opศ›ional):"
284
+    echo "  192.168.2.91, 192.168.2.92, 192.168.2.93"
285
+    echo "  Dacฤƒ nu se specificฤƒ ศ›inte, se ruleazฤƒ pe toate"
286
+    echo ""
287
+    echo "Exemple:"
288
+    echo "  $0 check-deps                 # Verificฤƒ dependinศ›ele pe toate ศ›intele"
289
+    echo "  $0 install-deps               # Instaleazฤƒ dependinศ›ele pe toate ศ›intele"
290
+    echo "  $0 install                    # Instaleazฤƒ pe toate ศ›intele"
291
+    echo "  $0 install 192.168.2.91       # Instaleazฤƒ doar pe .91"
292
+    echo "  $0 restart 192.168.2.91 192.168.2.92  # Restart pe .91 ศ™i .92"
293
+    echo "  $0 status                     # Verificฤƒ statusul pe toate ศ›intele"
294
+    echo "  $0 force-cleanup              # Cleanup agresiv pe toate nodurile"
295
+}
296
+
297
+# Funcศ›ie pentru executarea unei comenzi pe ศ›inte specifice
298
+execute_command() {
299
+    local command="$1"
300
+    shift
301
+    local targets_to_use=("$@")
302
+
303
+
304
+    # Dacฤƒ nu sunt specificate ศ›inte, foloseศ™te toate din cluster.json
305
+    if [ ${#targets_to_use[@]} -eq 0 ]; then
306
+        targets_to_use=( $(get_targets) )
307
+    fi
308
+
309
+    log_info "Executare comandฤƒ '$command' pe noduri: ${targets_to_use[*]}"
310
+
311
+    for target in "${targets_to_use[@]}"; do
312
+        local node_name
313
+        node_name=$(get_node_name "$target")
314
+        echo ""
315
+        echo "======================================"
316
+        echo "  $command pe $node_name ($target)"
317
+        echo "======================================"
318
+
319
+        if ! check_ssh_connectivity "$target"; then
320
+            log_error "Nu se poate conecta la $target - skip"
321
+            continue
322
+        fi
323
+
324
+        case "$command" in
325
+            "install")
326
+                copy_files "$target"
327
+                install_autonas "$target"
328
+                start_services "$target"
329
+                cleanup "$target"
330
+                ;;
331
+            "install-deps")
332
+                copy_files "$target"
333
+                install_dependencies "$target"
334
+                cleanup "$target"
335
+                ;;
336
+            "check-deps")
337
+                copy_files "$target"
338
+                check_dependencies "$target"
339
+                cleanup "$target"
340
+                ;;
341
+            "uninstall")
342
+                uninstall_autonas "$target"
343
+                cleanup "$target"
344
+                ;;
345
+            "start")
346
+                start_services "$target"
347
+                ;;
348
+            "restart")
349
+                restart_services "$target"
350
+                ;;
351
+            "stop")
352
+                stop_services "$target"
353
+                ;;
354
+            "status")
355
+                check_status "$target"
356
+                ;;
357
+            "cleanup")
358
+                cleanup "$target"
359
+                ;;
360
+            "force-cleanup")
361
+                force_cleanup "$target"
362
+                ;;
363
+            *)
364
+                log_error "Comandฤƒ necunoscutฤƒ: $command"
365
+                return 1
366
+                ;;
367
+        esac
368
+
369
+        if [ $? -eq 0 ]; then
370
+            log_success "Comandฤƒ '$command' executatฤƒ cu succes pe $target"
371
+        else
372
+            log_error "Comandฤƒ '$command' a eศ™uat pe $target"
373
+        fi
374
+    done
375
+}
376
+
377
+# Main function
378
+main() {
379
+    print_banner
380
+
381
+    # Verificฤƒ dacฤƒ avem argumente
382
+    if [ $# -eq 0 ]; then
383
+        show_help
384
+        exit 1
385
+    fi
386
+
387
+    local command="$1"
388
+    shift
389
+
390
+    case "$command" in
391
+        "install"|"install-deps"|"check-deps"|"uninstall"|"start"|"restart"|"stop"|"status"|"cleanup"|"force-cleanup")
392
+            execute_command "$command" "$@"
393
+            ;;
394
+        "help"|"--help"|"-h")
395
+            show_help
396
+            ;;
397
+        *)
398
+            log_error "Comandฤƒ necunoscutฤƒ: $command"
399
+            echo ""
400
+            show_help
401
+            exit 1
402
+            ;;
403
+    esac
404
+}
405
+
406
+# Verificฤƒ dacฤƒ ruleazฤƒ ca script principal
407
+if [ "${BASH_SOURCE[0]}" = "${0}" ]; then
408
+    main "$@"
409
+fi
+218 -0
scripts/autonas-boot-scan.sh
@@ -0,0 +1,218 @@
1
+#!/bin/bash
2
+
3
+# AutoNAS Boot Scanner - Detects and attaches configured disks at boot time
4
+# This script runs at boot to handle disks that are already connected
5
+# Uses autonas-core.sh for all business logic
6
+
7
+# Load the AutoNAS core library
8
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
9
+source "${SCRIPT_DIR}/autonas-core.sh" || {
10
+    echo "Error: Cannot load AutoNAS core library" >&2
11
+    exit 1
12
+}
13
+
14
+# Set LOG_TAG for this component
15
+LOG_TAG="autonas-boot-scanner"
16
+
17
+# Main boot scan function
18
+boot_scan() {
19
+    log_message "AutoNAS boot scan started" "info"
20
+    
21
+    if [ ! -f "$CONFIG_FILE" ]; then
22
+        log_message "No configuration file found at $CONFIG_FILE - boot scan skipped" "info"
23
+        return 0
24
+    fi
25
+    
26
+    local total_disks=0
27
+    local processed_disks=0
28
+    local attached_disks=0
29
+    local already_mounted=0
30
+    
31
+    # Read configuration file and process each disk
32
+    while IFS=':' read -r uuid name ip interface mount_point nfs_options; do
33
+        # Skip empty lines and comments
34
+        [[ -z "$uuid" || "$uuid" =~ ^[[:space:]]*# ]] && continue
35
+        
36
+        total_disks=$((total_disks + 1))
37
+        
38
+        log_message "Checking configured disk: $name (UUID: $uuid)" "info"
39
+        
40
+        # Check if UUID exists as a device
41
+        if check_uuid_exists "$uuid"; then
42
+            processed_disks=$((processed_disks + 1))
43
+            
44
+            # Check mount status
45
+            case $(is_disk_mounted "$uuid" "$mount_point"; echo $?) in
46
+                0)
47
+                    log_message "Disk $name already mounted correctly at $mount_point" "info"
48
+                    already_mounted=$((already_mounted + 1))
49
+                    ;;
50
+                1)
51
+                    log_message "Disk $name mounted elsewhere, attempting AutoNAS attach" "info"
52
+                    if handle_attach "$uuid"; then
53
+                        attached_disks=$((attached_disks + 1))
54
+                        log_message "Successfully attached disk $name via AutoNAS" "info"
55
+                    else
56
+                        log_message "Failed to attach disk $name" "warning"
57
+                    fi
58
+                    ;;
59
+                2)
60
+                    log_message "Disk $name not mounted, attaching via AutoNAS" "info"
61
+                    if handle_attach "$uuid"; then
62
+                        attached_disks=$((attached_disks + 1))
63
+                        log_message "Successfully attached disk $name via AutoNAS" "info"
64
+                    else
65
+                        log_message "Failed to attach disk $name" "warning"
66
+                    fi
67
+                    ;;
68
+            esac
69
+        else
70
+            log_message "Disk $name (UUID: $uuid) not present - skipping" "debug"
71
+        fi
72
+        
73
+    done < "$CONFIG_FILE"
74
+    
75
+    # Summary report
76
+    log_message "AutoNAS boot scan completed:" "info"
77
+    log_message "  - Total configured disks: $total_disks" "info"
78
+    log_message "  - Present disks processed: $processed_disks" "info"
79
+    log_message "  - Already mounted correctly: $already_mounted" "info"
80
+    log_message "  - Newly attached: $attached_disks" "info"
81
+    
82
+    if [ $attached_disks -gt 0 ] || [ $already_mounted -gt 0 ]; then
83
+        log_message "AutoNAS boot scan successful - ${attached_disks} disks attached, ${already_mounted} already mounted" "info"
84
+    else
85
+        log_message "AutoNAS boot scan completed - no disks required processing" "info"
86
+    fi
87
+}
88
+
89
+# Function to clean up orphaned mounts and NFS exports at boot
90
+cleanup_boot_orphans() {
91
+    log_message "Starting boot-time cleanup of orphaned mounts and exports..." "info"
92
+    
93
+    local cleaned_mounts=0
94
+    local cleaned_exports=0
95
+    
96
+    # Get list of configured disks
97
+    if [ ! -f "$CONFIG_FILE" ]; then
98
+        log_message "No configuration file found - skipping orphan cleanup" "info"
99
+        return 0
100
+    fi
101
+    
102
+    local configured_uuids=$(grep -v "^#\|^$" "$CONFIG_FILE" | cut -d':' -f1 | sort)
103
+    
104
+    # Check mounted disks in /mnt/autonas/
105
+    if [ -d "/mnt/autonas" ]; then
106
+        for mount_dir in /mnt/autonas/*/; do
107
+            [ ! -d "$mount_dir" ] && continue
108
+            
109
+            local mount_name=$(basename "$mount_dir")
110
+            local is_configured=false
111
+            
112
+            # Check if this mount corresponds to a configured disk AND is physically present
113
+            local config_uuid=""
114
+            while IFS=':' read -r uuid name ip hostname mount_point nfs_options; do
115
+                [ -z "$uuid" ] && continue
116
+                if [ "$name" = "$mount_name" ]; then
117
+                    config_uuid="$uuid"
118
+                    # Check if the disk is physically present and mounted
119
+                    if [ -n "$(blkid | grep "$uuid")" ] && mountpoint -q "$mount_dir"; then
120
+                        is_configured=true
121
+                    fi
122
+                    break
123
+                fi
124
+            done < <(grep -v "^#\|^$" "$CONFIG_FILE")
125
+            
126
+            if [ "$is_configured" = false ]; then
127
+                log_message "Found orphaned mount point: $mount_dir" "info"
128
+                
129
+                # Unmount if mounted
130
+                if mountpoint -q "$mount_dir"; then
131
+                    log_message "Unmounting orphaned mount: $mount_dir" "info"
132
+                    umount "$mount_dir" 2>/dev/null || {
133
+                        log_message "Failed to unmount $mount_dir - forcing" "warn"
134
+                        umount -f "$mount_dir" 2>/dev/null || true
135
+                    }
136
+                fi
137
+                
138
+                # Remove empty directory
139
+                if [ -d "$mount_dir" ] && [ -z "$(ls -A "$mount_dir" 2>/dev/null)" ]; then
140
+                    rmdir "$mount_dir" 2>/dev/null && {
141
+                        log_message "Removed orphaned mount directory: $mount_dir" "info"
142
+                        ((cleaned_mounts++))
143
+                    }
144
+                fi
145
+            fi
146
+        done
147
+    fi
148
+    
149
+    # Clean up orphaned NFS exports
150
+    if [ -f "/etc/exports" ]; then
151
+        local temp_file=$(mktemp)
152
+        local skip_next=false
153
+        local current_uuid=""
154
+        
155
+        while IFS= read -r line; do
156
+            if [[ "$line" =~ ^#\ AutoNAS\ Export\ -\ UUID:([^[:space:]]+)\ NAME: ]]; then
157
+                current_uuid="${BASH_REMATCH[1]}"
158
+                local is_configured=false
159
+                
160
+                # Check if this UUID is configured AND physically present
161
+                while IFS= read -r configured_uuid; do
162
+                    [ -z "$configured_uuid" ] && continue
163
+                    if [ "$configured_uuid" = "$current_uuid" ]; then
164
+                        # Additional check: verify the disk is physically present
165
+                        if [ -n "$(blkid | grep "$current_uuid")" ]; then
166
+                            is_configured=true
167
+                        fi
168
+                        break
169
+                    fi
170
+                done <<< "$configured_uuids"
171
+                
172
+                if [ "$is_configured" = false ]; then
173
+                    log_message "Found orphaned NFS export for UUID: $current_uuid" "info"
174
+                    skip_next=true
175
+                    ((cleaned_exports++))
176
+                    continue
177
+                else
178
+                    echo "$line" >> "$temp_file"
179
+                    skip_next=false
180
+                fi
181
+            elif [ "$skip_next" = true ]; then
182
+                # Skip the export line for orphaned entry
183
+                skip_next=false
184
+                continue
185
+            else
186
+                echo "$line" >> "$temp_file"
187
+            fi
188
+        done < /etc/exports
189
+        
190
+        # Replace exports file if we made changes
191
+        if [ "$cleaned_exports" -gt 0 ]; then
192
+            mv "$temp_file" /etc/exports
193
+            # Reload NFS exports
194
+            exportfs -ra 2>/dev/null || true
195
+            log_message "Reloaded NFS exports after cleanup" "info"
196
+        else
197
+            rm -f "$temp_file"
198
+        fi
199
+    fi
200
+    
201
+    if [ "$cleaned_mounts" -gt 0 ] || [ "$cleaned_exports" -gt 0 ]; then
202
+        log_message "Boot cleanup completed: $cleaned_mounts mount points, $cleaned_exports NFS exports removed" "info"
203
+    else
204
+        log_message "Boot cleanup completed: no orphaned entries found" "info"
205
+    fi
206
+}
207
+
208
+# Wait for system to be ready
209
+log_message "Waiting for system to stabilize..." "info"
210
+sleep 5
211
+
212
+# Clean up any orphaned mounts and exports first
213
+cleanup_boot_orphans
214
+
215
+# Run the boot scan
216
+boot_scan
217
+
218
+exit 0
+0 -0
scripts/autonas-config.sh
No changes.
+1115 -0
scripts/autonas-core.sh
@@ -0,0 +1,1115 @@
1
+#!/bin/bash
2
+
3
+# AutoNAS Core Library
4
+# Shared business logic for all AutoNAS components
5
+# This library contains all core functions to eliminate duplication
6
+
7
+# Load default configuration
8
+if [ -f "/etc/default/autonas" ]; then
9
+    source "/etc/default/autonas"
10
+fi
11
+
12
+# Set defaults if not loaded from config
13
+AUTONAS_DEBUG="${AUTONAS_DEBUG:-false}"
14
+AUTONAS_LOG_LEVEL="${AUTONAS_LOG_LEVEL:-info}"
15
+
16
+# Global configuration
17
+CONFIG_FILE="/etc/pve/autonas/disks.conf"
18
+MOUNT_BASE="/mnt/autonas"
19
+
20
+# ============================================================================
21
+# LOGGING FUNCTIONS
22
+# ============================================================================
23
+
24
+# Function to log messages with debug support
25
+log_message() {
26
+    local message="$1"
27
+    local priority="${2:-info}"
28
+    local context="${3:-${LOG_TAG:-autonas}}"
29
+    
30
+    # Skip debug messages unless debug mode is enabled
31
+    if [ "$priority" = "debug" ] && [ "$AUTONAS_DEBUG" != "true" ]; then
32
+        return 0
33
+    fi
34
+    
35
+    # Log to syslog with facility local0 and specified priority
36
+    logger -p "local0.$priority" -t "$context" "$message"
37
+    
38
+    # Also log to stderr if debug mode is enabled
39
+    if [ "$AUTONAS_DEBUG" = "true" ]; then
40
+        echo "[$context] [$priority] $message" >&2
41
+    fi
42
+    
43
+    # Also echo to stdout/stderr for interactive use
44
+    if [ -t 1 ]; then
45
+        echo "$(date '+%Y-%m-%d %H:%M:%S') - $message"
46
+    fi
47
+}
48
+
49
+# Function for debug logging (convenience function)
50
+debug_log() {
51
+    log_message "$1" "debug" "${2:-${LOG_TAG:-autonas}}"
52
+}
53
+
54
+# ============================================================================
55
+# CONFIGURATION FUNCTIONS
56
+# ============================================================================
57
+
58
+# Function to get disk configuration by UUID
59
+get_disk_config() {
60
+    local uuid="$1"
61
+    grep "^${uuid}:" "$CONFIG_FILE" 2>/dev/null
62
+}
63
+
64
+# Function to parse configuration line
65
+parse_config() {
66
+    local config="$1"
67
+    IFS=':' read -r uuid name ip interface mount_point nfs_options <<< "$config"
68
+    echo "$uuid" "$name" "$ip" "$interface" "$mount_point" "$nfs_options"
69
+}
70
+
71
+# Function to get configuration for a specific UUID (handles systemd escaping)
72
+get_config() {
73
+    local uuid="$1"
74
+    
75
+    if [ -z "$uuid" ]; then
76
+        return 1
77
+    fi
78
+
79
+    # Un-escape systemd-escaped UUID (e.g., 8765\x2d4321 -> 8765-4321)
80
+    local unescaped_uuid
81
+    unescaped_uuid=$(echo "$uuid" | sed 's/\\x2d/-/g')
82
+
83
+    # Find configuration line for UUID (try both escaped and unescaped)
84
+    grep "^${unescaped_uuid}:" "$CONFIG_FILE" 2>/dev/null || grep "^${uuid}:" "$CONFIG_FILE" 2>/dev/null
85
+}
86
+
87
+# Function to get configuration for a specific name
88
+get_config_by_name() {
89
+    local name="$1"
90
+    
91
+    if [ -z "$name" ]; then
92
+        return 1
93
+    fi
94
+
95
+    # Find configuration line by name (second field)
96
+    grep ":${name}:" "$CONFIG_FILE" 2>/dev/null
97
+}
98
+
99
+# ============================================================================
100
+# VALIDATION FUNCTIONS
101
+# ============================================================================
102
+
103
+# Function to validate UUID format
104
+validate_uuid() {
105
+    local uuid="$1"
106
+    # UUID can be standard format (8-4-4-4-12) or shorter formats used by some filesystems
107
+    if [[ "$uuid" =~ ^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$ ]] || \
108
+       [[ "$uuid" =~ ^[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}$ ]] || \
109
+       [[ "$uuid" =~ ^[0-9A-Fa-f]{8}$ ]]; then
110
+        return 0
111
+    fi
112
+    return 1
113
+}
114
+
115
+# Function to validate disk name
116
+validate_disk_name() {
117
+    local name="$1"
118
+    
119
+    # Check length (max 50 characters)
120
+    if [[ ${#name} -gt 50 ]]; then
121
+        return 1
122
+    fi
123
+    
124
+    # Check if it starts with letter or number
125
+    if [[ ! "$name" =~ ^[a-zA-Z0-9] ]]; then
126
+        return 1
127
+    fi
128
+    
129
+    # Check allowed characters: letters, numbers, hyphens, underscores, at symbol
130
+    if [[ ! "$name" =~ ^[a-zA-Z0-9_@-]+$ ]]; then
131
+        return 1
132
+    fi
133
+    
134
+    # Check for reserved names
135
+    local reserved_names=("root" "home" "tmp" "var" "usr" "etc" "proc" "sys" "dev" "boot" "mnt" "media" "opt" "srv")
136
+    for reserved in "${reserved_names[@]}"; do
137
+        if [[ "$name" == "$reserved" ]]; then
138
+            return 1
139
+        fi
140
+    done
141
+    
142
+    return 0
143
+}
144
+
145
+# Function to check if UUID exists in configuration
146
+check_uuid_exists_in_config() {
147
+    local uuid="$1"
148
+    grep -q "^${uuid}:" "$CONFIG_FILE" 2>/dev/null
149
+}
150
+
151
+# Function to list existing disk names (helper for duplicate detection)
152
+list_existing_disk_names() {
153
+    if [[ -f "$CONFIG_FILE" ]]; then
154
+        echo "Existing disk names:"
155
+        while IFS=':' read -r uuid name rest; do
156
+            if [[ -n "$uuid" && -n "$name" ]]; then
157
+                echo "  โ€ข $name (UUID: ${uuid:0:8}...)"
158
+            fi
159
+        done < "$CONFIG_FILE"
160
+    fi
161
+}
162
+
163
+# Function to check if disk name already exists in configuration
164
+check_disk_name_exists() {
165
+    local name="$1"
166
+    if [[ -f "$CONFIG_FILE" ]]; then
167
+        # Check if name exists as second field in any configuration line
168
+        grep -q ":${name}:" "$CONFIG_FILE" 2>/dev/null
169
+    fi
170
+}
171
+
172
+# Function to validate disk name (includes duplicate check)
173
+validate_disk_name_complete() {
174
+    local name="$1"
175
+    local uuid="$2"  # Optional: exclude current UUID from duplicate check
176
+    
177
+    # Run basic validation first
178
+    if ! validate_disk_name "$name"; then
179
+        return 1
180
+    fi
181
+    
182
+    # Check for duplicate names
183
+    if check_disk_name_exists "$name"; then
184
+        # If UUID provided, check if this name belongs to the same UUID (allow updates)
185
+        if [[ -n "$uuid" ]] && [[ -f "$CONFIG_FILE" ]]; then
186
+            local existing_uuid=$(grep ":${name}:" "$CONFIG_FILE" | cut -d':' -f1)
187
+            if [[ "$existing_uuid" == "$uuid" ]]; then
188
+                # Same UUID, same name - this is an update, allow it
189
+                return 0
190
+            fi
191
+        fi
192
+        # Different UUID or no UUID provided - this is a duplicate
193
+        return 2  # Special return code for duplicate names
194
+    fi
195
+    
196
+    return 0
197
+}
198
+
199
+# Function to check if UUID exists in system
200
+check_uuid_exists() {
201
+    local uuid="$1"
202
+    blkid | grep -q "$uuid"
203
+}
204
+
205
+# Function to check if disk is already mounted at AutoNAS location
206
+is_disk_mounted() {
207
+    local uuid="$1"
208
+    local mount_point="$2"
209
+    
210
+    # Check if already mounted at the correct location
211
+    if mount | grep -q "UUID=$uuid.*$mount_point"; then
212
+        return 0  # Already mounted correctly
213
+    fi
214
+    
215
+    # Check if mounted elsewhere
216
+    if mount | grep -q "UUID=$uuid"; then
217
+        return 1  # Mounted elsewhere
218
+    fi
219
+    
220
+    return 2  # Not mounted
221
+}
222
+
223
+# ============================================================================
224
+# DEVICE FUNCTIONS
225
+# ============================================================================
226
+
227
+# Function to get device information
228
+get_device_info() {
229
+    local uuid="$1"
230
+    
231
+    # Find device by UUID using blkid
232
+    local device_line
233
+    device_line=$(blkid | grep "UUID=\"$uuid\"")
234
+    
235
+    if [[ -z "$device_line" ]]; then
236
+        return 1
237
+    fi
238
+    
239
+    local device=$(echo "$device_line" | cut -d: -f1)
240
+    local blkid_info=$(echo "$device_line" | cut -d: -f2-)
241
+    
242
+    echo "device:$device"
243
+    echo "$blkid_info"
244
+    return 0
245
+}
246
+
247
+# ============================================================================
248
+# NETWORK FUNCTIONS
249
+# ============================================================================
250
+
251
+# Function to check if network interface exists
252
+interface_exists() {
253
+    local interface="$1"
254
+    ip link show "$interface" >/dev/null 2>&1
255
+}
256
+
257
+# Function to check if interface is configured for AutoNAS
258
+interface_has_autonas_config() {
259
+    local interface="$1"
260
+    grep -q ":${interface}:" "$CONFIG_FILE" 2>/dev/null
261
+}
262
+
263
+# Function to check if IP is configured on interface
264
+is_ip_configured() {
265
+    local ip="$1"
266
+    local interface="$2"
267
+    ip addr show "$interface" | grep -q "inet $ip/"
268
+}
269
+
270
+# Function to count disks using specific IP
271
+count_disks_using_ip() {
272
+    local target_ip="$1"
273
+    local count=0
274
+    
275
+    while IFS=':' read -r uuid name ip interface mount_point nfs_options; do
276
+        # Skip empty lines and comments
277
+        [[ -z "$uuid" || "$uuid" =~ ^# ]] && continue
278
+        
279
+        if [[ "$ip" == "$target_ip" ]]; then
280
+            # Check if this disk is currently attached (mounted)
281
+            if mountpoint -q "$mount_point" 2>/dev/null; then
282
+                count=$((count + 1))
283
+            fi
284
+        fi
285
+    done < <(grep -v '^#' "$CONFIG_FILE" 2>/dev/null | grep -v '^$')
286
+    
287
+    echo $count
288
+}
289
+
290
+# Function to activate IP on interface with smart retry
291
+activate_ip() {
292
+    local ip="$1"
293
+    local interface="$2"
294
+    local max_retries=3
295
+    local retry_count=0
296
+    
297
+    # Skip activation for special cases
298
+    if [[ "$ip" == "IMPORT" || "$ip" == "LOCAL" ]]; then
299
+        log_message "Skipping IP activation for special configuration: $ip" "debug"
300
+        return 0
301
+    fi
302
+    
303
+    log_message "Activating IP $ip on interface $interface" "info"
304
+    
305
+    # Check if interface exists
306
+    if ! interface_exists "$interface"; then
307
+        log_message "Interface $interface does not exist - waiting for it to appear" "warning"
308
+        
309
+        # Wait for interface to appear (common with USB/Thunderbolt)
310
+        local wait_count=0
311
+        while [ $wait_count -lt 30 ] && ! interface_exists "$interface"; do
312
+            sleep 2
313
+            wait_count=$((wait_count + 1))
314
+            debug_log "Waiting for interface $interface... (${wait_count}/30)"
315
+        done
316
+        
317
+        if ! interface_exists "$interface"; then
318
+            log_message "Error: Interface $interface does not exist" "err"
319
+            return 1
320
+        fi
321
+        
322
+        log_message "Interface $interface is now available" "info"
323
+    fi
324
+    
325
+    # Check if IP is already configured
326
+    if is_ip_configured "$ip" "$interface"; then
327
+        log_message "IP $ip already configured on interface $interface"
328
+        return 0
329
+    fi
330
+    
331
+    # Check if interface is up
332
+    if ! ip link show "$interface" | grep -q "state UP"; then
333
+        log_message "Bringing up interface $interface"
334
+        if ! ip link set "$interface" up; then
335
+            log_message "Error: Failed to bring up interface $interface" "err"
336
+            return 1
337
+        fi
338
+        # Wait a moment for interface to come up
339
+        sleep 1
340
+    fi
341
+    
342
+    # Try to configure IP with retries
343
+    while [ $retry_count -lt $max_retries ]; do
344
+        if ip addr add "$ip/24" dev "$interface" 2>/dev/null; then
345
+            log_message "Successfully activated IP $ip on interface $interface"
346
+            return 0
347
+        else
348
+            retry_count=$((retry_count + 1))
349
+            if [ $retry_count -lt $max_retries ]; then
350
+                log_message "Failed to add IP $ip to interface $interface, retrying ($retry_count/$max_retries)" "warning"
351
+                sleep 2
352
+            fi
353
+        fi
354
+    done
355
+    
356
+    log_message "Error: Failed to activate IP $ip on interface $interface" "err"
357
+    return 1
358
+}
359
+
360
+# Function to restore IPs for interface with comprehensive checking
361
+restore_interface_ips() {
362
+    local interface="$1"
363
+    local restored=0
364
+    local total_configs=0
365
+    
366
+    log_message "Checking IP restoration needs for interface: $interface" "info"
367
+    
368
+    # Check if interface exists and is up
369
+    if ! interface_exists "$interface"; then
370
+        log_message "Interface $interface does not exist, skipping restoration" "warning"
371
+        return 1
372
+    fi
373
+    
374
+    # Check if interface is up
375
+    if ! ip link show "$interface" | grep -q "state UP"; then
376
+        log_message "Interface $interface is down, waiting for it to come up..." "info"
377
+        local wait_count=0
378
+        while [ $wait_count -lt 20 ] && ! ip link show "$interface" | grep -q "state UP"; do
379
+            sleep 1
380
+            wait_count=$((wait_count + 1))
381
+        done
382
+        
383
+        if ! ip link show "$interface" | grep -q "state UP"; then
384
+            log_message "Interface $interface did not come up within 20 seconds" "warning"
385
+            return 1
386
+        fi
387
+    fi
388
+    
389
+    log_message "Interface $interface is up, checking for required IP configurations" "info"
390
+    
391
+    while IFS= read -r line; do
392
+        # Skip comments and empty lines
393
+        [[ "$line" =~ ^[[:space:]]*# ]] && continue
394
+        [[ -z "$line" ]] && continue
395
+        
396
+        # Parse configuration
397
+        IFS=':' read -r uuid name ip config_interface mount_point nfs_options <<< "$line"
398
+        
399
+        # Check if this line is for our interface
400
+        if [ "$config_interface" = "$interface" ]; then
401
+            ((total_configs++))
402
+            debug_log "Found configuration: $name ($uuid) requires IP $ip on $interface"
403
+            
404
+            # Check if the disk is currently mounted
405
+            if mountpoint -q "$mount_point" 2>/dev/null; then
406
+                log_message "Disk $name is mounted, checking IP configuration" "info"
407
+                
408
+                # Check if IP is already configured
409
+                if ! is_ip_configured "$ip" "$interface"; then
410
+                    log_message "IP $ip missing on interface $interface for mounted disk: $name" "warning"
411
+                    
412
+                    # Use the core activate_ip function
413
+                    if activate_ip "$ip" "$interface"; then
414
+                        log_message "Successfully restored IP $ip on interface $interface for disk $name" "info"
415
+                        ((restored++))
416
+                    else
417
+                        log_message "Failed to restore IP $ip on interface $interface for disk $name" "error"
418
+                    fi
419
+                else
420
+                    debug_log "IP $ip already configured on interface $interface for disk $name"
421
+                fi
422
+            else
423
+                debug_log "Disk $name is not mounted, skipping IP configuration"
424
+            fi
425
+        fi
426
+    done < "$CONFIG_FILE"
427
+    
428
+    if [ $total_configs -eq 0 ]; then
429
+        debug_log "No AutoNAS configurations found for interface $interface"
430
+    elif [ $restored -gt 0 ]; then
431
+        log_message "Restored $restored/$total_configs IP addresses on interface $interface" "info"
432
+        
433
+        # Trigger NFS export refresh if we restored any IPs
434
+        log_message "Refreshing NFS exports after IP restoration" "info"
435
+        exportfs -ra 2>/dev/null
436
+        systemctl reload nfs-kernel-server 2>/dev/null
437
+    else
438
+        log_message "All required IPs already configured on interface $interface" "info"
439
+    fi
440
+    
441
+    return 0
442
+}
443
+
444
+# Function to deactivate IP on interface with smart checking
445
+deactivate_ip() {
446
+    local ip="$1"
447
+    local interface="$2"
448
+    
449
+    # Skip deactivation for special cases
450
+    if [[ "$ip" == "IMPORT" || "$ip" == "LOCAL" ]]; then
451
+        log_message "Skipping IP deactivation for special configuration: $ip" "debug"
452
+        return 0
453
+    fi
454
+    
455
+    # Check how many other disks are using this IP
456
+    local usage_count
457
+    usage_count=$(count_disks_using_ip "$ip")
458
+    
459
+    if [[ $usage_count -gt 1 ]]; then
460
+        log_message "IP $ip still used by $((usage_count - 1)) other disks, keeping it active"
461
+        return 0
462
+    fi
463
+    
464
+    log_message "Deactivating IP $ip on interface $interface"
465
+    
466
+    # Check if IP is configured
467
+    if ! is_ip_configured "$ip" "$interface"; then
468
+        log_message "IP $ip not configured on interface $interface"
469
+        return 0
470
+    fi
471
+    
472
+    # Remove IP from interface
473
+    if ip addr del "$ip/24" dev "$interface" 2>/dev/null; then
474
+        log_message "Successfully deactivated IP $ip on interface $interface"
475
+        return 0
476
+    else
477
+        log_message "Error: Failed to deactivate IP $ip on interface $interface" "err"
478
+        return 1
479
+    fi
480
+}
481
+
482
+# ============================================================================
483
+# NFS FUNCTIONS
484
+# ============================================================================
485
+
486
+# Function to add NFS export with AutoNAS identification
487
+add_nfs_export() {
488
+    local mount_point="$1"
489
+    local nfs_options="$2"
490
+    local uuid="${3:-}"
491
+    local name="${4:-}"
492
+    
493
+    # Skip NFS export for special cases
494
+    if [[ "$nfs_options" == "LOCAL" ]] || [[ "$mount_point" =~ ^.*@Camera.*$ ]]; then
495
+        log_message "Skipping NFS export for local/camera configuration" "debug"
496
+        return 0
497
+    fi
498
+    
499
+    log_message "Adding NFS export for $mount_point"
500
+    
501
+    # Create NFS export entry
502
+    local export_entry="$mount_point $nfs_options"
503
+    
504
+    # Check if export already exists
505
+    if grep -Fxq "$export_entry" /etc/exports 2>/dev/null; then
506
+        log_message "NFS export already exists: $export_entry"
507
+        return 0
508
+    fi
509
+    
510
+    # Add identifying comment if UUID/name provided
511
+    if [[ -n "$uuid" && -n "$name" ]]; then
512
+        echo "# AutoNAS Export - UUID:$uuid NAME:$name" >> /etc/exports
513
+    fi
514
+    
515
+    # Add export to /etc/exports
516
+    echo "$export_entry" >> /etc/exports
517
+    if [[ $? -eq 0 ]]; then
518
+        log_message "Successfully added NFS export: $export_entry"
519
+        
520
+        # Reload exports
521
+        if exportfs -ra; then
522
+            log_message "NFS exports reloaded successfully"
523
+            return 0
524
+        else
525
+            log_message "Warning: Failed to reload NFS exports" "warning"
526
+            return 1
527
+        fi
528
+    else
529
+        log_message "Error: Failed to add NFS export" "err"
530
+        return 1
531
+    fi
532
+}
533
+
534
+# Function to remove NFS export
535
+remove_nfs_export() {
536
+    local mount_point="$1"
537
+    local uuid="${2:-}"
538
+    local name="${3:-}"
539
+    local nfs_options="${4:-}"
540
+    
541
+    # Skip NFS export removal for special cases
542
+    if [[ "$mount_point" =~ ^.*@Camera.*$ ]] || [[ "$nfs_options" == "LOCAL" ]]; then
543
+        log_message "Skipping NFS export removal for camera/local configuration" "debug"
544
+        return 0
545
+    fi
546
+    
547
+    log_message "Removing NFS export for $mount_point"
548
+    
549
+    # Create temporary file without the export
550
+    local temp_exports=$(mktemp)
551
+    if [[ ! -f /etc/exports ]]; then
552
+        log_message "No /etc/exports file found"
553
+        rm -f "$temp_exports"
554
+        return 0
555
+    fi
556
+    
557
+    # If UUID provided, use AutoNAS marker method
558
+    if [[ -n "$uuid" ]]; then
559
+        local skip_next=false
560
+        local found_export=false
561
+        
562
+        # Process /etc/exports line by line
563
+        while IFS= read -r line; do
564
+            if [[ "$line" =~ ^#\ AutoNAS\ Export\ -\ UUID:${uuid}\ NAME: ]]; then
565
+                # Found our marker comment, skip this line and the next one
566
+                skip_next=true
567
+                found_export=true
568
+                debug_log "Found AutoNAS export marker for $name"
569
+                continue
570
+            elif [ "$skip_next" = true ]; then
571
+                # Skip the export line that follows our marker
572
+                skip_next=false
573
+                debug_log "Skipping export line for $name"
574
+                continue
575
+            else
576
+                # Keep all other lines
577
+                echo "$line" >> "$temp_exports"
578
+            fi
579
+        done < /etc/exports
580
+        
581
+        if [ "$found_export" = true ]; then
582
+            # Replace /etc/exports with cleaned version
583
+            mv "$temp_exports" /etc/exports
584
+            log_message "NFS export removed using AutoNAS marker for $name"
585
+        else
586
+            rm -f "$temp_exports"
587
+            # Fallback to generic method
588
+            grep -v "^${mount_point} " /etc/exports > "$temp_exports"
589
+            mv "$temp_exports" /etc/exports
590
+            log_message "NFS export removed using generic method for $mount_point"
591
+        fi
592
+    else
593
+        # Generic removal method
594
+        grep -v "^${mount_point} " /etc/exports > "$temp_exports"
595
+        mv "$temp_exports" /etc/exports
596
+        log_message "NFS export removed for $mount_point"
597
+    fi
598
+    
599
+    # Reload exports
600
+    if exportfs -ra; then
601
+        log_message "NFS exports reloaded successfully"
602
+        return 0
603
+    else
604
+        log_message "Warning: Failed to reload NFS exports" "warning"
605
+        return 1
606
+    fi
607
+}
608
+
609
+# ============================================================================
610
+# STORAGE FUNCTIONS
611
+# ============================================================================
612
+
613
+# Function to mount disk with comprehensive filesystem support
614
+mount_disk() {
615
+    local uuid="$1"
616
+    local mount_point="$2"
617
+    local filesystem_type="${3:-}"
618
+    
619
+    log_message "Mounting disk with UUID $uuid to $mount_point"
620
+    
621
+    # Wait for device to be ready (udev sometimes triggers too early)
622
+    local device_path="/dev/disk/by-uuid/$uuid"
623
+    local wait_count=0
624
+    while [ ! -e "$device_path" ] && [ $wait_count -lt 10 ]; do
625
+        debug_log "Waiting for device $device_path to appear..."
626
+        sleep 1
627
+        wait_count=$((wait_count + 1))
628
+    done
629
+    
630
+    if [ ! -e "$device_path" ]; then
631
+        # Try alternative method - find device by UUID using blkid
632
+        local device
633
+        device=$(blkid | grep "UUID=\"$uuid\"" | cut -d: -f1)
634
+        
635
+        if [[ -z "$device" ]]; then
636
+            log_message "Error: Device with UUID $uuid not found" "err"
637
+            return 1
638
+        fi
639
+        
640
+        device_path="$device"
641
+    fi
642
+    
643
+    # Get the actual device name
644
+    local actual_device=$(readlink -f "$device_path" 2>/dev/null || echo "$device_path")
645
+    log_message "Device UUID $uuid maps to $actual_device"
646
+    
647
+    # Check if device is already mounted
648
+    if mountpoint -q "$mount_point" 2>/dev/null; then
649
+        # Check if it's mounted to the correct device
650
+        local mounted_device
651
+        mounted_device=$(findmnt -n -o SOURCE "$mount_point")
652
+        if [[ "$mounted_device" == "$actual_device" ]]; then
653
+            log_message "Disk already mounted correctly at $mount_point"
654
+            return 0
655
+        else
656
+            log_message "Warning: Different device mounted at $mount_point, unmounting first" "warning"
657
+            umount "$mount_point" 2>/dev/null
658
+        fi
659
+    fi
660
+    
661
+    # Create mount point if it doesn't exist
662
+    if [[ ! -d "$mount_point" ]]; then
663
+        if mkdir -p "$mount_point"; then
664
+            log_message "Created mount point directory: $mount_point"
665
+        else
666
+            log_message "Error: Failed to create mount point directory: $mount_point" "err"
667
+            return 1
668
+        fi
669
+    fi
670
+    
671
+    # Detect filesystem if not provided
672
+    if [[ -z "$filesystem_type" ]]; then
673
+        filesystem_type=$(blkid -o value -s TYPE "$actual_device" 2>/dev/null)
674
+        debug_log "Detected filesystem type: $filesystem_type"
675
+    fi
676
+    
677
+    # Mount based on filesystem type
678
+    local mount_options
679
+    case "$filesystem_type" in
680
+        "ntfs")
681
+            mount_options="-t ntfs-3g -o rw,uid=0,gid=0,umask=000"
682
+            log_message "Mounting NTFS filesystem"
683
+            ;;
684
+        "exfat")
685
+            mount_options="-t exfat -o rw,uid=0,gid=0,umask=000"
686
+            log_message "Mounting exFAT filesystem"
687
+            ;;
688
+        "vfat"|"fat32")
689
+            mount_options="-t vfat -o rw,uid=0,gid=0,umask=000"
690
+            log_message "Mounting FAT32 filesystem"
691
+            ;;
692
+        "ext2"|"ext3"|"ext4")
693
+            mount_options="-t $filesystem_type"
694
+            log_message "Mounting Linux filesystem ($filesystem_type)"
695
+            ;;
696
+        "btrfs")
697
+            mount_options="-t btrfs -o defaults,compress=zstd"
698
+            log_message "Mounting BTRFS filesystem with compression"
699
+            ;;
700
+        "xfs")
701
+            mount_options="-t xfs"
702
+            log_message "Mounting XFS filesystem"
703
+            ;;
704
+        *)
705
+            mount_options=""
706
+            log_message "Unknown or no filesystem type, attempting default mount"
707
+            ;;
708
+    esac
709
+    
710
+    # Perform the mount
711
+    local mount_cmd="mount $mount_options \"$actual_device\" \"$mount_point\""
712
+    debug_log "Executing: $mount_cmd"
713
+    
714
+    if eval $mount_cmd; then
715
+        # Verify mount was successful
716
+        if mountpoint -q "$mount_point"; then
717
+            log_message "Disk mounted successfully at $mount_point"
718
+            
719
+            # Set appropriate permissions for the mount point
720
+            chmod 755 "$mount_point" 2>/dev/null
721
+            
722
+            return 0
723
+        else
724
+            log_message "Error: Mount command succeeded but mountpoint verification failed" "err"
725
+            return 1
726
+        fi
727
+    else
728
+        # Try fallback mount by UUID for better compatibility
729
+        log_message "Direct mount failed, attempting UUID fallback" "warning"
730
+        if mount UUID="$uuid" "$mount_point" 2>/dev/null; then
731
+            log_message "Disk mounted successfully using UUID fallback at $mount_point"
732
+            return 0
733
+        else
734
+            log_message "Error: Failed to mount $actual_device to $mount_point" "err"
735
+            return 1
736
+        fi
737
+    fi
738
+}
739
+
740
+# Function to unmount disk
741
+unmount_disk() {
742
+    local mount_point="$1"
743
+    
744
+    log_message "Unmounting disk from $mount_point"
745
+    
746
+    # Check if actually mounted
747
+    if ! mountpoint -q "$mount_point" 2>/dev/null; then
748
+        log_message "Path $mount_point is not a mount point"
749
+        return 0
750
+    fi
751
+    
752
+    # Attempt unmount with timeout
753
+    if timeout 30 umount "$mount_point"; then
754
+        log_message "Successfully unmounted $mount_point"
755
+        
756
+        # Remove mount point if empty
757
+        if rmdir "$mount_point" 2>/dev/null; then
758
+            debug_log "Removed empty mount point directory: $mount_point"
759
+        else
760
+            debug_log "Mount point directory not empty or removal failed: $mount_point"
761
+        fi
762
+        return 0
763
+    else
764
+        log_message "Error: Failed to unmount $mount_point" "err"
765
+        return 1
766
+    fi
767
+}
768
+
769
+# ============================================================================
770
+# CAMERA IMPORT FUNCTIONS
771
+# ============================================================================
772
+
773
+# Function to handle camera import
774
+handle_camera_import() {
775
+    local uuid="$1"
776
+    local mount_point="$2"
777
+    local import_config="$3"
778
+    
779
+    # Parse import configuration (format: destination_path only)
780
+    destination_path="$import_config"
781
+    
782
+    if [[ -z "$destination_path" ]]; then
783
+        log_message "Error: No destination path specified for camera import" "err"
784
+        return 1
785
+    fi
786
+    
787
+    # Always use the integrated media importer (non-configurable)
788
+    script_path="/usr/local/bin/autonas-media-importer.sh"
789
+    
790
+    # Check if import script exists
791
+    if [[ ! -x "$script_path" ]]; then
792
+        log_message "Error: Camera import script not found or not executable: $script_path" "err"
793
+        return 1
794
+    fi
795
+    
796
+    log_message "Starting camera import process for UUID: $uuid"
797
+    log_message "Import destination: $destination_path"
798
+    
799
+    # Clean up any previous transient unit before starting a new one
800
+    systemctl stop autonas-import-$uuid.service 2>/dev/null || true
801
+    systemctl reset-failed autonas-import-$uuid.service 2>/dev/null || true
802
+    systemctl disable autonas-import-$uuid.service 2>/dev/null || true
803
+    rm -f /run/systemd/transient/autonas-import-$uuid.service 2>/dev/null || true
804
+
805
+    # Run import in background using systemd-run for better process management
806
+    systemd-run --no-block --unit="autonas-import-$uuid" \
807
+                /usr/local/bin/autonas-disk-handler.sh import "$uuid" "$mount_point" "$destination_path" "$script_path" || {
808
+        log_message "Error: Failed to start background import process" "err"
809
+        return 1
810
+    }
811
+    
812
+    log_message "Camera import process started successfully"
813
+    return 0
814
+}
815
+
816
+# Function to run background import
817
+run_background_import() {
818
+    local uuid="$1"
819
+    local mount_point="$2"
820
+    local destination="$3"
821
+    local script_path="${4:-/usr/local/bin/autonas-media-importer.sh}"
822
+    
823
+    log_message "Running background import for UUID: $uuid" "info" "autonas-import"
824
+    log_message "Source: $mount_point, Destination: $destination" "info" "autonas-import"
825
+    
826
+    # Change to a safe directory
827
+    cd /tmp || cd /
828
+    
829
+    # Create destination directory if it doesn't exist
830
+    mkdir -p "$destination"
831
+    
832
+    # Ensure destination exists
833
+    if [[ ! -d "$destination" ]]; then
834
+        log_message "Error: Cannot access destination directory: $destination" "err" "autonas-import"
835
+        return 1
836
+    fi
837
+    
838
+    # Run the import script
839
+    log_message "Executing import script: $script_path" "info" "autonas-import"
840
+    if "$script_path" "$mount_point" "$destination" --verbose; then
841
+        log_message "Import completed successfully for UUID: $uuid" "info" "autonas-import"
842
+        
843
+        # Cleanup: unmount and remove mount point
844
+        cleanup_and_unmount "$uuid" "$mount_point"
845
+        return 0
846
+    else
847
+        log_message "Error: Import failed for UUID: $uuid" "err" "autonas-import"
848
+        cleanup_and_unmount "$uuid" "$mount_point"
849
+        return 1
850
+    fi
851
+}
852
+
853
+# Function to cleanup and unmount after camera import
854
+cleanup_and_unmount() {
855
+    local uuid="$1"
856
+    local mount_point="$2"
857
+    
858
+    log_message "Cleaning up after import for UUID: $uuid" "info" "autonas-import"
859
+    
860
+    # Unmount the device
861
+    if mountpoint -q "$mount_point" 2>/dev/null; then
862
+        if umount "$mount_point"; then
863
+            log_message "Successfully unmounted $mount_point" "info" "autonas-import"
864
+        else
865
+            log_message "Warning: Failed to unmount $mount_point" "warning" "autonas-import"
866
+        fi
867
+    fi
868
+    
869
+    # Remove mount point directory if empty
870
+    if [[ -d "$mount_point" ]] && rmdir "$mount_point" 2>/dev/null; then
871
+        log_message "Removed empty mount point directory: $mount_point" "info" "autonas-import"
872
+    fi
873
+    
874
+    log_message "Cleanup completed for UUID: $uuid" "info" "autonas-import"
875
+}
876
+
877
+# ============================================================================
878
+# MAIN WORKFLOW FUNCTIONS
879
+# ============================================================================
880
+
881
+# Function to handle disk attachment
882
+handle_attach() {
883
+    local uuid="$1"
884
+    
885
+    log_message "AutoNAS attach operation started for UUID: $uuid"
886
+    
887
+    # Get configuration for this UUID
888
+    local config
889
+    config=$(get_disk_config "$uuid")
890
+    
891
+    if [[ -z "$config" ]]; then
892
+        log_message "No configuration found for UUID: $uuid - disk will be ignored"
893
+        log_message "To configure this disk, run: autonas add"
894
+        return 1
895
+    fi
896
+    
897
+    log_message "Handling disk attachment for UUID: $uuid"
898
+    
899
+    # Parse configuration
900
+    local parsed
901
+    parsed=($(parse_config "$config"))
902
+    local cfg_uuid="${parsed[0]}"
903
+    local name="${parsed[1]}"
904
+    local ip="${parsed[2]}"
905
+    local interface="${parsed[3]}"
906
+    local mount_point="${parsed[4]}"
907
+    local nfs_options="${parsed[5]}"
908
+    
909
+    log_message "Processing disk: $name (IP: $ip, Mount: $mount_point)"
910
+    
911
+    # Handle different disk types
912
+    if [[ "$ip" == "IMPORT" && "$interface" == "IMPORT" ]]; then
913
+        # Camera import workflow: mount temporarily, import, then unmount
914
+        log_message "Detected camera import configuration for UUID: $uuid"
915
+        
916
+        # Mount disk for import
917
+        if mount_disk "$uuid" "$mount_point"; then
918
+            # Start import process
919
+            handle_camera_import "$uuid" "$mount_point" "$nfs_options"
920
+            return $?
921
+        else
922
+            log_message "Error: Failed to mount camera device" "err"
923
+            return 1
924
+        fi
925
+    elif [[ "$ip" == "LOCAL" ]]; then
926
+        # Local mount only (no network sharing)
927
+        if mount_disk "$uuid" "$mount_point"; then
928
+            log_message "Local disk mounted successfully at $mount_point"
929
+            return 0
930
+        else
931
+            return 1
932
+        fi
933
+    else
934
+        # Regular NFS workflow: activate IP, mount, export via NFS
935
+        if activate_ip "$ip" "$interface"; then
936
+            if mount_disk "$uuid" "$mount_point"; then
937
+                if add_nfs_export "$mount_point" "$nfs_options" "$uuid" "$name"; then
938
+                    log_message "Disk attached successfully: $name"
939
+                    return 0
940
+                else
941
+                    log_message "Warning: Disk mounted but NFS export failed" "warning"
942
+                    return 1
943
+                fi
944
+            else
945
+                deactivate_ip "$ip" "$interface"
946
+                return 1
947
+            fi
948
+        else
949
+            return 1
950
+        fi
951
+    fi
952
+}
953
+
954
+# Function to handle disk detachment
955
+handle_detach() {
956
+    local uuid="$1"
957
+    
958
+    log_message "AutoNAS detach operation started for UUID: $uuid"
959
+    
960
+    # Get configuration for this UUID
961
+    local config
962
+    config=$(get_disk_config "$uuid")
963
+    
964
+    if [[ -z "$config" ]]; then
965
+        log_message "No configuration found for UUID: $uuid"
966
+        return 1
967
+    fi
968
+    
969
+    log_message "Handling disk detachment for UUID: $uuid"
970
+    
971
+    # Parse configuration
972
+    local parsed
973
+    parsed=($(parse_config "$config"))
974
+    local cfg_uuid="${parsed[0]}"
975
+    local name="${parsed[1]}"
976
+    local ip="${parsed[2]}"
977
+    local interface="${parsed[3]}"
978
+    local mount_point="${parsed[4]}"
979
+    local nfs_options="${parsed[5]}"
980
+    
981
+    log_message "Processing disk: $name (Mount: $mount_point)"
982
+    
983
+    # Remove NFS export (if applicable)
984
+    if [[ "$ip" != "LOCAL" && "$ip" != "IMPORT" ]]; then
985
+        remove_nfs_export "$mount_point" "$uuid" "$name" "$nfs_options"
986
+    fi
987
+    
988
+    # Unmount disk
989
+    if unmount_disk "$mount_point"; then
990
+        # Deactivate IP (if applicable)
991
+        if [[ "$ip" != "LOCAL" && "$ip" != "IMPORT" ]]; then
992
+            deactivate_ip "$ip" "$interface"
993
+        fi
994
+        
995
+        log_message "Disk detached successfully: $name"
996
+        return 0
997
+    else
998
+        log_message "Error: Failed to detach disk: $name" "err"
999
+        return 1
1000
+    fi
1001
+}
1002
+
1003
+# Function to reload configuration
1004
+handle_reload() {
1005
+    log_message "Reloading AutoNAS configuration"
1006
+    
1007
+    log_message "Reloading udev rules"
1008
+    udevadm control --reload-rules
1009
+    udevadm trigger --subsystem-match=block
1010
+    
1011
+    log_message "Reloading NFS exports"
1012
+    exportfs -ra || log_message "Warning: Failed to reload NFS exports" "warning"
1013
+    
1014
+    log_message "Reloading systemd daemon"
1015
+    systemctl daemon-reload || log_message "Warning: Failed to reload systemd daemon" "warning"
1016
+    
1017
+    log_message "AutoNAS configuration reload completed"
1018
+    return 0
1019
+}
1020
+
1021
+# ============================================================================
1022
+# DISPLAY FUNCTIONS
1023
+# ============================================================================
1024
+
1025
+# Function to show available disks
1026
+show_available_disks() {
1027
+    echo "=== Available Storage Devices ==="
1028
+    echo
1029
+    
1030
+    local found_devices=0
1031
+    local blkid_output
1032
+    
1033
+    # Get blkid output and process it
1034
+    if ! blkid_output=$(blkid 2>/dev/null); then
1035
+        echo "Error: Unable to scan for block devices (are you running as root?)"
1036
+        return 1
1037
+    fi
1038
+    
1039
+    while IFS= read -r blkid_line; do
1040
+        [[ -z "$blkid_line" ]] && continue
1041
+        
1042
+        local device=$(echo "$blkid_line" | cut -d: -f1)
1043
+        
1044
+        # Skip if device doesn't exist (shouldn't happen with blkid, but just in case)
1045
+        [[ ! -b "$device" ]] && continue
1046
+        
1047
+        # Skip loop devices, ram disks, and other virtual devices
1048
+        case "$device" in
1049
+            /dev/loop*|/dev/ram*|/dev/dm-*) continue ;;
1050
+        esac
1051
+        
1052
+        # Extract device information
1053
+        local uuid=$(echo "$blkid_line" | grep -o 'UUID="[^"]*"' | cut -d'"' -f2)
1054
+        local label=$(echo "$blkid_line" | grep -o 'LABEL="[^"]*"' | cut -d'"' -f2)
1055
+        local fstype=$(echo "$blkid_line" | grep -o 'TYPE="[^"]*"' | cut -d'"' -f2)
1056
+        local partuuid=$(echo "$blkid_line" | grep -o 'PARTUUID="[^"]*"' | cut -d'"' -f2)
1057
+        
1058
+        # Skip if no UUID (we need UUID for AutoNAS)
1059
+        [[ -z "$uuid" ]] && continue
1060
+        
1061
+        found_devices=$((found_devices + 1))
1062
+        
1063
+        # Get device size
1064
+        local size=""
1065
+        if [[ -b "$device" ]]; then
1066
+            size=$(lsblk -b -d -o SIZE "$device" 2>/dev/null | tail -n1)
1067
+            if [[ -n "$size" ]] && [[ "$size" =~ ^[0-9]+$ ]]; then
1068
+                # Convert to human readable
1069
+                size=$(numfmt --to=iec --suffix=B "$size" 2>/dev/null || echo "${size}B")
1070
+            fi
1071
+        fi
1072
+        
1073
+        # Display device information
1074
+        echo "Device: $device"
1075
+        [[ -n "$size" ]] && echo "  Size: $size"
1076
+        echo "  UUID: $uuid"
1077
+        [[ -n "$label" ]] && echo "  Label: $label"
1078
+        [[ -n "$fstype" ]] && echo "  Filesystem: $fstype"
1079
+        
1080
+        # Check if already configured
1081
+        if grep -q "^${uuid}:" "$CONFIG_FILE" 2>/dev/null; then
1082
+            local config_line=$(grep "^${uuid}:" "$CONFIG_FILE" 2>/dev/null)
1083
+            local config_name=$(echo "$config_line" | cut -d: -f2)
1084
+            echo "  Status: โœ… Configured as '$config_name'"
1085
+        else
1086
+            echo "  Status: โš ๏ธ  Not configured"
1087
+        fi
1088
+        
1089
+        # Check if currently mounted
1090
+        local mount_info
1091
+        mount_info=$(findmnt -n -o TARGET "$device" 2>/dev/null)
1092
+        if [[ -n "$mount_info" ]]; then
1093
+            echo "  Mount: ๐ŸŸข $mount_info"
1094
+        else
1095
+            echo "  Mount: โšช Not mounted"
1096
+        fi
1097
+        
1098
+        echo
1099
+    done <<< "$blkid_output"
1100
+    
1101
+    if [[ $found_devices -eq 0 ]]; then
1102
+        echo "No storage devices with UUIDs found."
1103
+        echo "Make sure devices are connected and you're running as root."
1104
+    else
1105
+        echo "Found $found_devices storage device(s)"
1106
+        echo
1107
+        echo "To configure a device: autonas add <UUID>"
1108
+        echo "To list configured devices: autonas list"
1109
+    fi
1110
+    
1111
+    return 0
1112
+}
1113
+
1114
+# Mark that core library has been loaded
1115
+AUTONAS_CORE_LOADED=true
+82 -0
scripts/autonas-disk-handler.sh
@@ -0,0 +1,82 @@
1
+#!/bin/bash
2
+
3
+# AutoNAS Manager - System integration for udev/systemd events
4
+# This script is called by udev rules when disks are attached/detached
5
+# Uses autonas-core.sh for all business logic
6
+
7
+# Load the AutoNAS core library
8
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
9
+source "${SCRIPT_DIR}/autonas-core.sh" || {
10
+    echo "Error: Cannot load AutoNAS core library" >&2
11
+    exit 1
12
+}
13
+
14
+# Set LOG_TAG for this component
15
+LOG_TAG="autonas-disk-handler"
16
+
17
+# Main script logic
18
+case "$1" in
19
+    "attach")
20
+        if [ -z "$2" ]; then
21
+            log_message "Error: UUID required for attach operation" "err"
22
+            exit 1
23
+        fi
24
+        log_message "AutoNAS attach operation started for UUID: $2" "info"
25
+        handle_attach "$2"
26
+        ;;
27
+    "attach-deferred")
28
+        if [ -z "$2" ]; then
29
+            log_message "Error: UUID required for deferred attach operation" "err"
30
+            exit 1
31
+        fi
32
+        log_message "AutoNAS deferred attach operation started for UUID: $2" "info"
33
+        handle_attach "$2"
34
+        ;;
35
+    "detach")
36
+        if [ -z "$2" ]; then
37
+            log_message "Error: UUID or disk name required for detach operation" "err"
38
+            exit 1
39
+        fi
40
+        log_message "AutoNAS detach operation started for identifier: $2" "info"
41
+        
42
+        # Check if identifier is UUID (contains hyphens and matches UUID pattern) or name
43
+        if [[ "$2" =~ ^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$ ]] || [[ "$2" =~ ^[0-9a-fA-F]{4}-[0-9a-fA-F]{4}$ ]]; then
44
+            # It's a UUID - use directly
45
+            handle_detach "$2"
46
+        else
47
+            # It's a name - get UUID from config
48
+            local config_line
49
+            config_line=$(get_config_by_name "$2" 2>/dev/null)
50
+            if [ -n "$config_line" ]; then
51
+                local uuid=$(echo "$config_line" | cut -d: -f1)
52
+                handle_detach "$uuid"
53
+            else
54
+                log_message "No configuration found for name: $2 - detach skipped" "info"
55
+                log_message "This may be normal if the disk was not configured for AutoNAS" "info"
56
+                exit 0
57
+            fi
58
+        fi
59
+        ;;
60
+    "import")
61
+        if [ -z "$2" ] || [ -z "$3" ] || [ -z "$4" ]; then
62
+            log_message "Error: UUID, mount_point, and destination required for import operation" "err"
63
+            exit 1
64
+        fi
65
+        log_message "AutoNAS background import operation started for UUID: $2" "info"
66
+        run_background_import "$2" "$3" "$4" "$5"
67
+        ;;
68
+    "reload")
69
+        handle_reload
70
+        ;;
71
+    *)
72
+        echo "Usage: $0 {attach|attach-deferred|detach|import|reload} <UUID|name> [args...]"
73
+        echo "  attach <UUID>         - Attach disk by UUID (direct)"
74
+        echo "  attach-deferred <UUID> - Attach disk by UUID (via systemd)"
75
+        echo "  detach <UUID>         - Detach disk by UUID (via udev)"
76
+        echo "  detach <name>         - Detach disk by name (for manual/clean unmount)"
77
+        echo "  import <UUID> <mount> <dest> [script] - Run background camera import"
78
+        echo "This script is typically called by udev rules or systemd"
79
+        log_message "Invalid arguments provided: $*" "err"
80
+        exit 1
81
+        ;;
82
+esac
+0 -0
scripts/autonas-manager.sh
No changes.
+438 -0
scripts/autonas-media-importer.sh
@@ -0,0 +1,438 @@
1
+#!/bin/bash
2
+
3
+# AutoNAS Media Importer
4
+# Advanced media import engine that processes, organizes and imports media files from cameras
5
+# Usage: autonas-media-importer.sh <source_mount> <destination_path>
6
+
7
+# Global configuration
8
+LOG_TAG="autonas-import"
9
+
10
+# Function to log messages
11
+log_message() {
12
+    local message="$1"
13
+    local priority="${2:-info}"  # Default priority is info
14
+    
15
+    # Log to syslog with facility local0 and specified priority
16
+    logger -p "local0.$priority" -t "$LOG_TAG" "$message"
17
+    
18
+    # Also echo to stdout/stderr for interactive use
19
+    if [ -t 1 ]; then
20
+        echo "$(date '+%Y-%m-%d %H:%M:%S') - $message"
21
+    fi
22
+}
23
+
24
+# Usage function
25
+usage() {
26
+    echo "Usage: $0 <source_mount> <destination_path> [options]"
27
+    echo ""
28
+    echo "Arguments:"
29
+    echo "  source_mount     - Mount point of the camera (e.g., /mnt/autonas/camera)"
30
+    echo "  destination_path - Destination directory for imported files"
31
+    echo ""
32
+    echo "Options:"
33
+    echo "  --dry-run        - Show what would be done without actually doing it"
34
+    echo "  --keep-originals - Keep original files on camera after import"
35
+    echo "  --verbose        - Enable verbose output"
36
+    echo "  --limit N        - Process only N files (useful for testing)"
37
+    echo "  --help           - Show this help"
38
+    echo ""
39
+    echo "Examples:"
40
+    echo "  $0 /mnt/autonas/camera /mnt/autonas/photos/imported"
41
+    echo "  $0 /mnt/autonas/camera /mnt/autonas/photos/imported --dry-run --verbose"
42
+}
43
+
44
+# Parse command line arguments
45
+SOURCE_MOUNT=""
46
+DESTINATION=""
47
+DRY_RUN=0
48
+KEEP_ORIGINALS=0
49
+VERBOSE=0
50
+FILE_LIMIT=0
51
+
52
+while [[ $# -gt 0 ]]; do
53
+    case $1 in
54
+        --dry-run)
55
+            DRY_RUN=1
56
+            shift
57
+            ;;
58
+        --keep-originals)
59
+            KEEP_ORIGINALS=1
60
+            shift
61
+            ;;
62
+        --verbose)
63
+            VERBOSE=1
64
+            shift
65
+            ;;
66
+        --limit)
67
+            FILE_LIMIT="$2"
68
+            if ! [[ "$FILE_LIMIT" =~ ^[0-9]+$ ]]; then
69
+                echo "Error: --limit requires a number"
70
+                usage
71
+                exit 1
72
+            fi
73
+            shift 2
74
+            ;;
75
+        --help)
76
+            usage
77
+            exit 0
78
+            ;;
79
+        -*)
80
+            echo "Unknown option: $1"
81
+            usage
82
+            exit 1
83
+            ;;
84
+        *)
85
+            if [[ -z "$SOURCE_MOUNT" ]]; then
86
+                SOURCE_MOUNT="$1"
87
+            elif [[ -z "$DESTINATION" ]]; then
88
+                DESTINATION="$1"
89
+            else
90
+                echo "Too many arguments"
91
+                usage
92
+                exit 1
93
+            fi
94
+            shift
95
+            ;;
96
+    esac
97
+done
98
+
99
+# Validate arguments
100
+if [[ -z "$SOURCE_MOUNT" || -z "$DESTINATION" ]]; then
101
+    echo "Error: Both source_mount and destination_path are required"
102
+    usage
103
+    exit 1
104
+fi
105
+
106
+# Check if source exists and is mounted
107
+if [[ ! -d "$SOURCE_MOUNT" ]]; then
108
+    log_message "Error: Source mount point does not exist: $SOURCE_MOUNT" "err"
109
+    exit 1
110
+fi
111
+
112
+# Check if source is actually mounted
113
+if ! mountpoint -q "$SOURCE_MOUNT" 2>/dev/null; then
114
+    log_message "Warning: Source path is not a mount point: $SOURCE_MOUNT" "warning"
115
+fi
116
+
117
+# Create destination directory if it doesn't exist
118
+if [[ $DRY_RUN -eq 0 ]]; then
119
+    mkdir -p "$DESTINATION"
120
+    if [[ ! -d "$DESTINATION" ]]; then
121
+        log_message "Error: Cannot create destination directory: $DESTINATION" "err"
122
+        exit 1
123
+    fi
124
+fi
125
+
126
+# Check for required tools
127
+if ! command -v exiftool &> /dev/null; then
128
+    log_message "Error: exiftool is required but not installed" "err"
129
+    exit 1
130
+fi
131
+
132
+# Function to process a single file
133
+process_file() {
134
+    local file="$1"
135
+    local relative_path="${file#$SOURCE_MOUNT/}"
136
+    
137
+    # Check if source mount is still available
138
+    if ! mountpoint -q "$SOURCE_MOUNT" 2>/dev/null; then
139
+        log_message "Error: Source mount point is no longer available: $SOURCE_MOUNT" "err"
140
+        return 1
141
+    fi
142
+    
143
+    # Check if file still exists
144
+    if [[ ! -f "$file" ]]; then
145
+        log_message "Error: File no longer exists: $relative_path" "err"
146
+        log_message "Camera appears to be disconnected, stopping import" "warning"
147
+        exit 1
148
+    fi
149
+    
150
+    if [[ $VERBOSE -eq 1 ]]; then
151
+        log_message "Processing: $relative_path" "info"
152
+    fi
153
+    
154
+    # Check which group CreateDate comes from to determine correct handling
155
+    create_date_info=$(exiftool -G1 -s -CreateDate "$file" 2>/dev/null | grep CreateDate | head -1)
156
+    
157
+    # Check if exiftool failed (possible if device disconnected)
158
+    local exiftool_exit_code=$?
159
+    if [[ $exiftool_exit_code -ne 0 ]] && [[ $exiftool_exit_code -ne 1 ]]; then
160
+        log_message "Error: Cannot read file (device may be disconnected): $relative_path" "err"
161
+        log_message "Camera appears to be disconnected, stopping import" "warning"
162
+        exit 1
163
+    fi
164
+    
165
+    if [[ -z "$create_date_info" ]]; then
166
+        log_message "Warning: No CreateDate found in $relative_path, using file modification time" "warning"
167
+        # Fallback to file modification time
168
+        local file_date=$(date -r "$file" "+%Y-%m-%d %H:%M:%S" 2>/dev/null)
169
+        if [[ -n "$file_date" ]]; then
170
+            create_date_value="$file_date"
171
+            create_date_group="FileSystem"
172
+        else
173
+            log_message "Error: Cannot determine date for $relative_path" "err"
174
+            return 1
175
+        fi
176
+    else
177
+        create_date_group=$(echo "$create_date_info" | cut -d']' -f1 | cut -d'[' -f2)
178
+        create_date_value=$(echo "$create_date_info" | cut -d':' -f2- | xargs)
179
+        # Convert EXIF date format (YYYY:MM:DD HH:MM:SS) to standard format (YYYY-MM-DD HH:MM:SS)
180
+        create_date_value=$(echo "$create_date_value" | sed 's/^\([0-9]\{4\}\):\([0-9]\{2\}\):\([0-9]\{2\}\)/\1-\2-\3/')
181
+    fi
182
+    
183
+    if [[ $VERBOSE -eq 1 ]]; then
184
+        echo -n "  Date: [$create_date_value] from $create_date_group "
185
+    fi
186
+    
187
+    # Extract file extension
188
+    local filename=$(basename "$file")
189
+    local extension="${filename##*.}"
190
+    
191
+    # For QuickTime files, the CreateDate is in UTC and needs conversion to local time
192
+    if [[ "$create_date_group" == "QuickTime" ]]; then
193
+        # Convert UTC time to local time
194
+        local utc_timestamp=$(date -d "$create_date_value UTC" "+%s" 2>/dev/null)
195
+        if [[ -n "$utc_timestamp" ]]; then
196
+            create_date_value=$(date -d "@$utc_timestamp" "+%Y-%m-%d %H:%M:%S" 2>/dev/null)
197
+            if [[ $VERBOSE -eq 1 ]]; then
198
+                echo -n "(converted from UTC) "
199
+            fi
200
+        fi
201
+    fi
202
+    
203
+    # Create output directory structure
204
+    local date_dir=$(date -d "$create_date_value" "+%Y-%m-%d" 2>/dev/null)
205
+    if [[ -z "$date_dir" ]]; then
206
+        log_message "Error: Invalid date format for $relative_path: $create_date_value" "err"
207
+        return 1
208
+    fi
209
+    
210
+    local output_dir="$DESTINATION/$date_dir"
211
+    
212
+    if [[ $DRY_RUN -eq 0 ]]; then
213
+        mkdir -p "$output_dir"
214
+    fi
215
+    
216
+    # Generate output filename with timestamp
217
+    local timestamp=$(date -d "$create_date_value" "+%Y-%m-%d_%H-%M-%S" 2>/dev/null)
218
+    local output_filename="${timestamp}.${extension,,}"  # Convert extension to lowercase
219
+    local output_path="$output_dir/$output_filename"
220
+    
221
+    # Handle filename conflicts
222
+    local counter=1
223
+    local base_output_path="$output_path"
224
+    while [[ -f "$output_path" ]] && [[ $DRY_RUN -eq 0 ]]; do
225
+        local name_without_ext="${timestamp}_${counter}"
226
+        output_path="$output_dir/${name_without_ext}.${extension,,}"
227
+        counter=$((counter + 1))
228
+    done
229
+    
230
+    if [[ $DRY_RUN -eq 1 ]]; then
231
+        if [[ $KEEP_ORIGINALS -eq 1 ]]; then
232
+            echo "Would copy: $relative_path -> ${output_path#$DESTINATION/}"
233
+        else
234
+            echo "Would move: $relative_path -> ${output_path#$DESTINATION/}"
235
+        fi
236
+    else
237
+        # Perform the actual file operation
238
+        if [[ $KEEP_ORIGINALS -eq 1 ]]; then
239
+            if cp "$file" "$output_path"; then
240
+                if [[ $VERBOSE -eq 1 ]]; then
241
+                    echo "โœ“ Copied"
242
+                fi
243
+                log_message "Copied: $relative_path -> ${output_path#$DESTINATION/}" "info"
244
+                return 0
245
+            else
246
+                if [[ $VERBOSE -eq 1 ]]; then
247
+                    echo "โœ— Copy failed"
248
+                fi
249
+                log_message "Error: Failed to copy $relative_path" "err"
250
+                return 1
251
+            fi
252
+        else
253
+            if mv "$file" "$output_path"; then
254
+                if [[ $VERBOSE -eq 1 ]]; then
255
+                    echo "โœ“ Moved"
256
+                fi
257
+                log_message "Moved: $relative_path -> ${output_path#$DESTINATION/}" "info"
258
+                return 0
259
+            else
260
+                if [[ $VERBOSE -eq 1 ]]; then
261
+                    echo "โœ— Move failed"
262
+                fi
263
+                log_message "Error: Failed to move $relative_path" "err"
264
+                return 1
265
+            fi
266
+        fi
267
+    fi
268
+}
269
+
270
+# Function to find camera directories
271
+find_camera_directories() {
272
+    local search_patterns=("DCIM" "PRIVATE" "MP_ROOT" "AVCHD" "Photos" "Videos")
273
+    local found_dirs=()
274
+    
275
+    # Test if the mount point is accessible with a timeout
276
+    if ! timeout 3 ls "$SOURCE_MOUNT" >/dev/null 2>&1; then
277
+        log_message "Error: Mount point is not accessible (device likely disconnected): $SOURCE_MOUNT" "err"
278
+        exit 1
279
+    fi
280
+    
281
+    for pattern in "${search_patterns[@]}"; do
282
+        while IFS= read -r -d '' dir; do
283
+            found_dirs+=("$dir")
284
+        done < <(timeout 5 find "$SOURCE_MOUNT" -maxdepth 3 -type d -iname "$pattern" -print0 2>/dev/null)
285
+    done
286
+    
287
+    # If no camera directories found, search for common media file extensions
288
+    if [[ ${#found_dirs[@]} -eq 0 ]]; then
289
+        log_message "No camera directories found, searching for media files..." "info"
290
+        local media_extensions=("*.jpg" "*.jpeg" "*.png" "*.tiff" "*.cr2" "*.nef" "*.arw" "*.mp4" "*.mov" "*.avi" "*.mts" "*.m2ts")
291
+        
292
+        for ext in "${media_extensions[@]}"; do
293
+            while IFS= read -r -d '' file; do
294
+                local dir=$(dirname "$file")
295
+                if [[ ! " ${found_dirs[@]} " =~ " ${dir} " ]]; then
296
+                    found_dirs+=("$dir")
297
+                fi
298
+            done < <(timeout 5 find "$SOURCE_MOUNT" -maxdepth 3 -type f -iname "$ext" -print0 2>/dev/null)
299
+        done
300
+    fi
301
+    
302
+    printf '%s\n' "${found_dirs[@]}" | sort -u
303
+}
304
+
305
+# Main execution
306
+log_message "Starting camera import from $SOURCE_MOUNT to $DESTINATION" "info"
307
+
308
+if [[ $DRY_RUN -eq 1 ]]; then
309
+    log_message "DRY RUN MODE - No files will be actually moved/copied" "info"
310
+fi
311
+
312
+if [[ $KEEP_ORIGINALS -eq 1 ]]; then
313
+    log_message "KEEP ORIGINALS MODE - Files will be copied instead of moved" "info"
314
+fi
315
+
316
+# Find camera directories
317
+log_message "Scanning for camera directories..." "info"
318
+camera_dirs=$(find_camera_directories)
319
+
320
+if [[ -z "$camera_dirs" ]]; then
321
+    log_message "No camera directories or media files found in $SOURCE_MOUNT" "warning"
322
+    exit 0
323
+fi
324
+
325
+echo "Found camera directories:"
326
+echo "$camera_dirs" | while IFS= read -r dir; do
327
+    echo "  $dir"
328
+done
329
+
330
+# Process files
331
+total_files=0
332
+processed_files=0
333
+error_files=0
334
+
335
+# Delete GLV files (Garmin video preview files) - they're usually not needed
336
+log_message "Cleaning up GLV preview files..." "info"
337
+glv_count=0
338
+while IFS= read -r dir; do
339
+    if [[ $DRY_RUN -eq 1 ]]; then
340
+        glv_files=$(find "$dir" -type f -iname "*.glv" 2>/dev/null | wc -l)
341
+        if [[ $glv_files -gt 0 ]]; then
342
+            echo "Would delete $glv_files GLV files from $dir"
343
+            glv_count=$((glv_count + glv_files))
344
+        fi
345
+    else
346
+        while IFS= read -r -d '' glv_file; do
347
+            if rm "$glv_file" 2>/dev/null; then
348
+                glv_count=$((glv_count + 1))
349
+            fi
350
+        done < <(find "$dir" -type f -iname "*.glv" -print0 2>/dev/null)
351
+    fi
352
+done <<< "$camera_dirs"
353
+
354
+if [[ $glv_count -gt 0 ]]; then
355
+    if [[ $DRY_RUN -eq 1 ]]; then
356
+        log_message "Would delete $glv_count GLV preview files" "info"
357
+    else
358
+        log_message "Deleted $glv_count GLV preview files" "info"
359
+    fi
360
+fi
361
+
362
+# Process media files
363
+log_message "Processing media files..." "info"
364
+media_extensions=("*.jpg" "*.jpeg" "*.png" "*.tiff" "*.tif" "*.cr2" "*.nef" "*.arw" "*.dng" "*.mp4" "*.mov" "*.avi" "*.mts" "*.m2ts" "*.mkv" "*.wmv")
365
+
366
+# In dry-run mode, limit output to avoid overwhelming logs
367
+max_files_to_show=20
368
+files_shown=0
369
+files_processed_count=0
370
+
371
+while IFS= read -r dir; do
372
+    # Check if mount point is still available before processing each directory
373
+    if ! mountpoint -q "$SOURCE_MOUNT" 2>/dev/null; then
374
+        log_message "Camera disconnected, stopping import process" "warning"
375
+        break
376
+    fi
377
+    
378
+    for ext in "${media_extensions[@]}"; do
379
+        while IFS= read -r -d '' file; do
380
+            total_files=$((total_files + 1))
381
+            files_processed_count=$((files_processed_count + 1))
382
+            
383
+            # Check if camera is still connected before processing each file
384
+            if ! mountpoint -q "$SOURCE_MOUNT" 2>/dev/null; then
385
+                log_message "Camera disconnected during processing, stopping import" "warning"
386
+                exit 1
387
+            fi
388
+            
389
+            # Check file limit
390
+            if [[ $FILE_LIMIT -gt 0 && $files_processed_count -gt $FILE_LIMIT ]]; then
391
+                echo "Reached file limit of $FILE_LIMIT files, stopping processing..."
392
+                break 3
393
+            fi
394
+            
395
+            # In dry-run mode, limit verbose output
396
+            if [[ $DRY_RUN -eq 1 && $files_shown -ge $max_files_to_show ]]; then
397
+                if [[ $files_shown -eq $max_files_to_show ]]; then
398
+                    echo "... (limiting output in dry-run mode, processing continues)"
399
+                    files_shown=$((files_shown + 1))
400
+                fi
401
+                # Still process but don't show details
402
+                processed_files=$((processed_files + 1))
403
+            else
404
+                if [[ $DRY_RUN -eq 1 ]]; then
405
+                    files_shown=$((files_shown + 1))
406
+                fi
407
+                
408
+                if process_file "$file"; then
409
+                    processed_files=$((processed_files + 1))
410
+                else
411
+                    error_files=$((error_files + 1))
412
+                fi
413
+            fi
414
+        done < <(find "$dir" -type f -iname "$ext" -print0 2>/dev/null)
415
+    done
416
+done <<< "$camera_dirs"
417
+
418
+# Summary
419
+log_message "Import completed: $processed_files/$total_files files processed successfully" "info"
420
+if [[ $error_files -gt 0 ]]; then
421
+    log_message "Import had errors: $error_files files failed to process" "warning"
422
+fi
423
+
424
+echo ""
425
+echo "=== Import Summary ==="
426
+echo "Total files found: $total_files"
427
+echo "Successfully processed: $processed_files"
428
+echo "Errors: $error_files"
429
+if [[ $glv_count -gt 0 ]]; then
430
+    echo "GLV files cleaned up: $glv_count"
431
+fi
432
+
433
+# Exit with error code if there were errors
434
+if [[ $error_files -gt 0 ]]; then
435
+    exit 1
436
+else
437
+    exit 0
438
+fi
+101 -0
scripts/autonas-network-handler.sh
@@ -0,0 +1,101 @@
1
+#!/bin/bash
2
+
3
+# AutoNAS Network Handler - System integration for network interface events
4
+# This script is called by udev when network interfaces change state
5
+# Uses autonas-core.sh for all business logic
6
+
7
+# Load the AutoNAS core library
8
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
9
+source "${SCRIPT_DIR}/autonas-core.sh" || {
10
+    echo "Error: Cannot load AutoNAS core library" >&2
11
+    exit 1
12
+}
13
+
14
+# Set LOG_TAG for this component
15
+LOG_TAG="autonas-network-handler"
16
+
17
+# Function to handle interface coming up
18
+handle_interface_up() {
19
+    local interface="$1"
20
+    local event_type="$2"
21
+    
22
+    log_message "Interface up event: $interface ($event_type)" "info"
23
+    
24
+    # Check if this interface is used by AutoNAS
25
+    if interface_has_autonas_config "$interface"; then
26
+        log_message "Interface $interface is configured for AutoNAS, restoring IP configurations" "info"
27
+        
28
+        # Small delay to let interface stabilize completely
29
+        sleep 3
30
+        
31
+        # Restore IPs for this interface
32
+        if restore_interface_ips "$interface"; then
33
+            log_message "Successfully processed interface $interface restoration" "info"
34
+        else
35
+            log_message "Failed to fully process interface $interface restoration" "warning"
36
+        fi
37
+    else
38
+        log_message "Interface $interface is not configured for AutoNAS, ignoring" "debug"
39
+    fi
40
+}
41
+
42
+# Function to handle interface going down
43
+handle_interface_down() {
44
+    local interface="$1"
45
+    local event_type="$2"
46
+    
47
+    log_message "Interface down event: $interface ($event_type)" "info"
48
+    
49
+    if interface_has_autonas_config "$interface"; then
50
+        log_message "AutoNAS-configured interface $interface went down" "warning"
51
+    fi
52
+}
53
+
54
+# Main script logic
55
+ACTION="$1"
56
+INTERFACE="$2"
57
+EXTRA="$3"
58
+
59
+case "$ACTION" in
60
+    "interface_up"|"usb_interface_up")
61
+        if [ -n "$INTERFACE" ]; then
62
+            # Run in background to avoid udev timeout, but with shorter delay for faster response
63
+            (
64
+                sleep 2  # Reduced from 3 seconds for faster response
65
+                handle_interface_up "$INTERFACE" "$ACTION"
66
+            ) &
67
+            log_message "Started background handler for interface up: $INTERFACE (PID: $!)" "debug"
68
+        fi
69
+        ;;
70
+    "interface_down"|"usb_interface_down")
71
+        if [ -n "$INTERFACE" ]; then
72
+            handle_interface_down "$INTERFACE" "$ACTION"
73
+        fi
74
+        ;;
75
+    "interface_change")
76
+        if [ -n "$INTERFACE" ] && [ -n "$EXTRA" ]; then
77
+            case "$EXTRA" in
78
+                "up"|"carrier_up")
79
+                    (
80
+                        sleep 2
81
+                        handle_interface_up "$INTERFACE" "change_to_$EXTRA"
82
+                    ) &
83
+                    log_message "Started background handler for interface $EXTRA: $INTERFACE (PID: $!)" "debug"
84
+                    ;;
85
+                "down"|"carrier_down")
86
+                    handle_interface_down "$INTERFACE" "change_to_$EXTRA"
87
+                    ;;
88
+                *)
89
+                    log_message "Unknown interface change state: $EXTRA for interface $INTERFACE" "warning"
90
+                    ;;
91
+            esac
92
+        fi
93
+        ;;
94
+    *)
95
+        log_message "Unknown action: $ACTION with interface: $INTERFACE" "warning"
96
+        exit 1
97
+        ;;
98
+esac
99
+
100
+# Exit immediately so udev doesn't wait
101
+exit 0
+65 -0
scripts/autonas-udev-wrapper.sh
@@ -0,0 +1,65 @@
1
+#!/bin/bash
2
+
3
+# AutoNAS udev wrapper - runs the manager script in background to avoid udev timeout
4
+# Usage: autonas-udev-wrapper.sh attach <uuid>
5
+
6
+# Global configuration
7
+LOG_TAG="autonas-wrapper"
8
+
9
+# Set comprehensive environment for udev context
10
+export PATH="/usr/local/bin:/usr/bin:/bin:/sbin:/usr/sbin"
11
+export HOME="/root"
12
+export USER="root"
13
+export LOGNAME="root"
14
+export SHELL="/bin/bash"
15
+
16
+# Set proper umask for mount operations
17
+umask 022
18
+
19
+UUID="$2"
20
+ACTION="$1"
21
+
22
+# Validate arguments
23
+if [ -z "$ACTION" ] || [ -z "$UUID" ]; then
24
+    logger -p local0.err -t "$LOG_TAG" "Invalid arguments: ACTION='$ACTION', UUID='$UUID'"
25
+    exit 1
26
+fi
27
+
28
+# Log the call with device info
29
+logger -p local0.info -t "$LOG_TAG" "Called with action: $ACTION, UUID: $UUID"
30
+
31
+# Get device info for logging
32
+if [ -n "$UUID" ]; then
33
+    DEVICE_PATH="/dev/disk/by-uuid/$UUID"
34
+    if [ -e "$DEVICE_PATH" ]; then
35
+        ACTUAL_DEVICE=$(readlink -f "$DEVICE_PATH" 2>/dev/null)
36
+        logger -p local0.info -t "$LOG_TAG" "Device path: $ACTUAL_DEVICE"
37
+    fi
38
+fi
39
+
40
+# Run the actual script through systemd for reliable execution
41
+(
42
+    # Additional delay for device stabilization
43
+    sleep 3
44
+    
45
+    # Ensure we're running as root with full privileges
46
+    if [ "$(id -u)" != "0" ]; then
47
+        logger -p local0.err -t "$LOG_TAG" "Not running as root, UID: $(id -u)"
48
+        exit 1
49
+    fi
50
+    
51
+    # Use systemd service directly for reliable execution
52
+    if [ "$ACTION" = "attach" ]; then
53
+        systemctl start "autonas-attach@${UUID}.service"
54
+        logger -p local0.info -t "$LOG_TAG" "Started systemd service for UUID: $UUID"
55
+    else
56
+        logger -p local0.warning -t "$LOG_TAG" "Detach operations not supported through systemd wrapper"
57
+    fi
58
+    
59
+) &
60
+
61
+# Log background job started
62
+logger -p local0.info -t "$LOG_TAG" "Started background job for $ACTION $UUID (PID: $!)"
63
+
64
+# Exit immediately so udev doesn't wait
65
+exit 0
+225 -0
scripts/autonas-uninstall.sh
@@ -0,0 +1,225 @@
1
+#!/bin/bash
2
+
3
+# AutoNAS Uninstall Script
4
+# This script is installed on each cluster node for version-specific removal
5
+# Executed by deploy.sh or can be run directly on node: /usr/local/lib/autonas/autonas-uninstall.sh
6
+
7
+# Global configuration
8
+LOG_TAG="autonas-uninstall"
9
+
10
+set -e  # Exit on any error
11
+
12
+# Check for force flag for silent cleanup
13
+FORCE_MODE=false
14
+if [ "$1" = "--force" ]; then
15
+    FORCE_MODE=true
16
+fi
17
+
18
+# Helper function for conditional logging
19
+log_message() {
20
+    if [ "$FORCE_MODE" = false ]; then
21
+        echo "$1"
22
+    fi
23
+}
24
+
25
+CONFIG_DIR="/etc/pve/autonas"
26
+SCRIPT_NAME="autonas-disk-handler.sh"
27
+WRAPPER_NAME="autonas-udev-wrapper.sh"
28
+BOOT_SCAN_SCRIPT="autonas-boot-scan.sh"
29
+CAMERA_IMPORT_SCRIPT="autonas-media-importer.sh"
30
+INTERFACE_HANDLER_SCRIPT="autonas-network-handler.sh"
31
+UNIFIED_SCRIPT="autonas.sh"
32
+UDEV_RULES="99-autonas-disk.rules"
33
+SYSTEMD_SERVICE="autonas-attach@.service"
34
+MAIN_SERVICE="autonas.service"
35
+BOOT_SCAN_SERVICE="autonas-boot-scan.service"
36
+
37
+if [ "$FORCE_MODE" = false ]; then
38
+    echo "=== AutoNAS Uninstall Script ==="
39
+    echo ""
40
+fi
41
+
42
+# Check if running as root
43
+if [ "$EUID" -ne 0 ]; then
44
+    if [ "$FORCE_MODE" = false ]; then
45
+        echo "โŒ This script must be run as root (use sudo)"
46
+    fi
47
+    exit 1
48
+fi
49
+
50
+log_message "๐Ÿ—‘๏ธ  Uninstalling AutoNAS..."
51
+log_message ""
52
+
53
+# Remove scripts
54
+log_message "Removing AutoNAS scripts..."
55
+if [ -f "/usr/local/bin/$SCRIPT_NAME" ]; then
56
+    rm "/usr/local/bin/$SCRIPT_NAME"
57
+    log_message "โœ“ Manager script removed"
58
+fi
59
+
60
+if [ -f "/usr/local/bin/$WRAPPER_NAME" ]; then
61
+    rm "/usr/local/bin/$WRAPPER_NAME"
62
+    log_message "โœ“ Wrapper script removed"
63
+fi
64
+
65
+if [ -f "/usr/local/bin/$BOOT_SCAN_SCRIPT" ]; then
66
+    rm "/usr/local/bin/$BOOT_SCAN_SCRIPT"
67
+    log_message "โœ“ Boot scan script removed"
68
+fi
69
+
70
+if [ -f "/usr/local/bin/$CAMERA_IMPORT_SCRIPT" ]; then
71
+    rm "/usr/local/bin/$CAMERA_IMPORT_SCRIPT"
72
+    log_message "โœ“ Camera import script removed"
73
+fi
74
+
75
+if [ -f "/usr/local/bin/$INTERFACE_HANDLER_SCRIPT" ]; then
76
+    rm "/usr/local/bin/$INTERFACE_HANDLER_SCRIPT"
77
+    log_message "โœ“ Interface handler script removed"
78
+fi
79
+
80
+if [ -f "/usr/local/bin/$UNIFIED_SCRIPT" ]; then
81
+    rm "/usr/local/bin/$UNIFIED_SCRIPT"
82
+    log_message "โœ“ Unified AutoNAS script removed"
83
+fi
84
+
85
+# Remove symlink
86
+if [ -L "/usr/local/bin/autonas" ]; then
87
+    rm "/usr/local/bin/autonas"
88
+    log_message "โœ“ AutoNAS symlink removed"
89
+fi
90
+
91
+# Remove internal scripts directory
92
+if [ -d "/usr/local/lib/autonas" ]; then
93
+    rm -rf "/usr/local/lib/autonas"
94
+    log_message "โœ“ AutoNAS internal scripts directory removed"
95
+fi
96
+
97
+# Aggressive cleanup for orphaned files from previous versions
98
+log_message "Cleaning up orphaned files from previous versions..."
99
+for orphan_file in "autonas-interface-debug.sh" "autonas-test-interface-stability.sh"; do
100
+    if [ -f "/usr/local/bin/$orphan_file" ]; then
101
+        rm "/usr/local/bin/$orphan_file"
102
+        log_message "โœ“ Orphaned file removed: $orphan_file"
103
+    fi
104
+done
105
+
106
+# Remove udev rules
107
+log_message "Removing udev rules..."
108
+if [ -f "/etc/udev/rules.d/$UDEV_RULES" ]; then
109
+    rm "/etc/udev/rules.d/$UDEV_RULES"
110
+    udevadm control --reload-rules
111
+    log_message "โœ“ Udev rules removed"
112
+fi
113
+
114
+# Remove systemd service
115
+log_message "Removing systemd service..."
116
+if [ -f "/etc/systemd/system/$SYSTEMD_SERVICE" ]; then
117
+    systemctl stop autonas-attach@*.service 2>/dev/null || true
118
+    systemctl disable autonas-attach@*.service 2>/dev/null || true
119
+    rm "/etc/systemd/system/$SYSTEMD_SERVICE"
120
+    systemctl daemon-reload
121
+    log_message "โœ“ Systemd service removed"
122
+fi
123
+
124
+# Remove main service
125
+log_message "Removing main AutoNAS service..."
126
+if [ -f "/etc/systemd/system/$MAIN_SERVICE" ]; then
127
+    systemctl stop autonas.service 2>/dev/null || true
128
+    systemctl disable autonas.service 2>/dev/null || true
129
+    rm "/etc/systemd/system/$MAIN_SERVICE"
130
+    systemctl daemon-reload
131
+    log_message "โœ“ Main AutoNAS service removed"
132
+fi
133
+
134
+# Remove boot scan service
135
+log_message "Removing boot scan service..."
136
+if [ -f "/etc/systemd/system/$BOOT_SCAN_SERVICE" ]; then
137
+    systemctl stop autonas-boot-scan.service 2>/dev/null || true
138
+    systemctl disable autonas-boot-scan.service 2>/dev/null || true
139
+    rm "/etc/systemd/system/$BOOT_SCAN_SERVICE"
140
+    systemctl daemon-reload
141
+    log_message "โœ“ Boot scan service removed"
142
+fi
143
+
144
+# Handle configuration and data preservation
145
+log_message ""
146
+log_message "๐Ÿ“ Handling user data..."
147
+
148
+# Check if configuration exists and has user data
149
+if [ -f "$CONFIG_DIR/disks.conf" ]; then
150
+    if grep -v '^#' "$CONFIG_DIR/disks.conf" | grep -v '^$' | grep -q ':'; then
151
+        log_message "โš ๏ธ  User configurations detected in $CONFIG_DIR/disks.conf"
152
+        log_message "   Configuration file preserved for manual cleanup"
153
+        log_message "   Remove manually with: sudo rm -rf $CONFIG_DIR"
154
+    else
155
+        log_message "โ„น๏ธ  Configuration file contains only template - removing"
156
+        rm "$CONFIG_DIR/disks.conf"
157
+        rmdir "$CONFIG_DIR" 2>/dev/null || true
158
+    fi
159
+else
160
+    log_message "โ„น๏ธ  No configuration file found"
161
+    rmdir "$CONFIG_DIR" 2>/dev/null || true
162
+fi
163
+
164
+# Check for mounted AutoNAS disks
165
+log_message ""
166
+log_message "๐Ÿ’พ Checking for mounted AutoNAS disks..."
167
+mounted_autonas=$(mount | grep "/mnt/autonas/" | wc -l)
168
+if [ $mounted_autonas -gt 0 ]; then
169
+    log_message "โš ๏ธ  Found $mounted_autonas mounted AutoNAS disk(s):"
170
+    if [ "$FORCE_MODE" = false ]; then
171
+        mount | grep "/mnt/autonas/" | while read line; do
172
+            echo "   $line"
173
+        done
174
+    fi
175
+    log_message ""
176
+    log_message "   These disks are still mounted and in use."
177
+    log_message "   Mount points preserved: /mnt/autonas/"
178
+    log_message "   Unmount manually if needed: sudo umount /mnt/autonas/*"
179
+else
180
+    log_message "โ„น๏ธ  No AutoNAS disks currently mounted"
181
+    if [ -d "/mnt/autonas" ]; then
182
+        # Only remove if empty
183
+        if [ -z "$(ls -A /mnt/autonas)" ]; then
184
+            rmdir "/mnt/autonas"
185
+            log_message "โœ“ Empty AutoNAS mount directory removed"
186
+        else
187
+            log_message "โš ๏ธ  AutoNAS mount directory contains files - preserved"
188
+        fi
189
+    fi
190
+fi
191
+
192
+# Check NFS exports
193
+log_message ""
194
+log_message "๐ŸŒ Checking NFS exports..."
195
+if [ -f "/etc/exports" ] && grep -q "/mnt/autonas/" "/etc/exports" 2>/dev/null; then
196
+    log_message "โš ๏ธ  AutoNAS NFS exports found in /etc/exports"
197
+    log_message "   Please manually remove AutoNAS entries from /etc/exports"
198
+    log_message "   And reload NFS exports: sudo exportfs -ra"
199
+else
200
+    log_message "โ„น๏ธ  No AutoNAS NFS exports found"
201
+fi
202
+
203
+log_message ""
204
+log_message "๐ŸŽ‰ AutoNAS core components removed successfully!"
205
+
206
+if [ "$FORCE_MODE" = false ]; then
207
+    echo ""
208
+    echo "๐Ÿ“‹ Summary:"
209
+    echo "โœ“ Scripts removed from /usr/local/bin/"
210
+    echo "โœ“ Udev rules removed"
211
+    echo "โœ“ Systemd services removed"
212
+    echo ""
213
+    echo "โš ๏ธ  Preserved (manual cleanup required if desired):"
214
+    echo "โ€ข User configurations: $CONFIG_DIR/ (if contains user data)"
215
+    echo "โ€ข Mount points: /mnt/autonas/ (if contains data)"
216
+    echo "โ€ข NFS exports: /etc/exports (manual edit required)"
217
+    echo ""
218
+    echo "๐Ÿ“ To completely remove all AutoNAS data:"
219
+    echo "sudo rm -rf $CONFIG_DIR"
220
+    echo "sudo rm -rf /mnt/autonas"
221
+    echo "sudo nano /etc/exports  # Remove AutoNAS entries manually"
222
+    echo "sudo exportfs -ra"
223
+fi
224
+echo ""
225
+echo "๐Ÿ”„ To reinstall AutoNAS later, run: sudo bash scripts/install.sh"
+1211 -0
scripts/autonas.sh
@@ -0,0 +1,1211 @@
1
+#!/bin/bash
2
+
3
+# AutoNAS - Unified AutoNAS Management Tool
4
+# Combines manager, configuration, and all other functionality into one script
5
+# Usage: autonas <command> [options]
6
+
7
+# Load core AutoNAS library
8
+if [[ -f "/usr/local/bin/autonas-core.sh" ]]; then
9
+    source "/usr/local/bin/autonas-core.sh"
10
+else
11
+    echo "Error: AutoNAS core library not found at /usr/local/bin/autonas-core.sh" >&2
12
+    exit 1
13
+fi
14
+
15
+# Function to handle disk attachment
16
+handle_attach() {
17
+    local uuid="$1"
18
+    
19
+    log_message "AutoNAS attach operation started for UUID: $uuid"
20
+    
21
+    # Get configuration for this UUID
22
+    local config
23
+    config=$(get_disk_config "$uuid")
24
+    
25
+    if [[ -z "$config" ]]; then
26
+        log_message "No configuration found for UUID: $uuid - disk will be ignored"
27
+        log_message "To configure this disk, run: autonas-config.sh add"
28
+        return 1
29
+    fi
30
+    
31
+    log_message "Handling disk attachment for UUID: $uuid"
32
+    
33
+    # Parse configuration
34
+    local parsed
35
+    parsed=($(parse_config "$config"))
36
+    local cfg_uuid="${parsed[0]}"
37
+    local name="${parsed[1]}"
38
+    local ip="${parsed[2]}"
39
+    local interface="${parsed[3]}"
40
+    local mount_point="${parsed[4]}"
41
+    local nfs_options="${parsed[5]}"
42
+    
43
+    log_message "Processing disk: $name (IP: $ip, Mount: $mount_point)"
44
+    
45
+    # Handle different disk types
46
+    if [[ "$ip" == "IMPORT" && "$interface" == "IMPORT" ]]; then
47
+        # Camera import workflow: mount temporarily, import, then unmount
48
+        log_message "Detected camera import configuration for UUID: $uuid"
49
+        
50
+        # Mount disk for import
51
+        if mount_disk "$uuid" "$mount_point"; then
52
+            # Start import process
53
+            handle_camera_import "$uuid" "$mount_point" "$nfs_options"
54
+            return $?
55
+        else
56
+            log_message "Error: Failed to mount camera device" "err"
57
+            return 1
58
+        fi
59
+    elif [[ "$ip" == "LOCAL" ]]; then
60
+        # Local mount only (no network sharing)
61
+        if mount_disk "$uuid" "$mount_point"; then
62
+            log_message "Local disk mounted successfully at $mount_point"
63
+            return 0
64
+        else
65
+            return 1
66
+        fi
67
+    else
68
+        # Regular NFS workflow: activate IP, mount, export via NFS
69
+        if activate_ip "$ip" "$interface"; then
70
+            if mount_disk "$uuid" "$mount_point"; then
71
+                if add_nfs_export "$mount_point" "$nfs_options"; then
72
+                    log_message "Disk attached successfully: $name"
73
+                    return 0
74
+                else
75
+                    log_message "Warning: Disk mounted but NFS export failed" "warning"
76
+                    return 1
77
+                fi
78
+            else
79
+                deactivate_ip "$ip" "$interface"
80
+                return 1
81
+            fi
82
+        else
83
+            return 1
84
+        fi
85
+    fi
86
+}
87
+
88
+# Function to handle disk detachment
89
+handle_detach() {
90
+    local uuid="$1"
91
+    
92
+    log_message "AutoNAS detach operation started for UUID: $uuid"
93
+    
94
+    # Get configuration for this UUID
95
+    local config
96
+    config=$(get_disk_config "$uuid")
97
+    
98
+    if [[ -z "$config" ]]; then
99
+        log_message "No configuration found for UUID: $uuid"
100
+        return 1
101
+    fi
102
+    
103
+    log_message "Handling disk detachment for UUID: $uuid"
104
+    
105
+    # Parse configuration
106
+    local parsed
107
+    parsed=($(parse_config "$config"))
108
+    local cfg_uuid="${parsed[0]}"
109
+    local name="${parsed[1]}"
110
+    local ip="${parsed[2]}"
111
+    local interface="${parsed[3]}"
112
+    local mount_point="${parsed[4]}"
113
+    local nfs_options="${parsed[5]}"
114
+    
115
+    log_message "Processing disk: $name (Mount: $mount_point)"
116
+    
117
+    # Remove NFS export (if applicable)
118
+    if [[ "$ip" != "LOCAL" && "$ip" != "IMPORT" ]]; then
119
+        remove_nfs_export "$mount_point"
120
+    fi
121
+    
122
+    # Unmount disk
123
+    if unmount_disk "$mount_point"; then
124
+        # Deactivate IP (if applicable)
125
+        if [[ "$ip" != "LOCAL" && "$ip" != "IMPORT" ]]; then
126
+            deactivate_ip "$ip" "$interface"
127
+        fi
128
+        
129
+        log_message "Disk detached successfully: $name"
130
+        return 0
131
+    else
132
+        log_message "Error: Failed to detach disk: $name" "err"
133
+        return 1
134
+    fi
135
+}
136
+
137
+# Function to reload configuration
138
+handle_reload() {
139
+    log_message "Reloading AutoNAS configuration"
140
+    
141
+    log_message "Reloading udev rules"
142
+    udevadm control --reload-rules
143
+    udevadm trigger --subsystem-match=block
144
+    
145
+    log_message "Reloading NFS exports"
146
+    exportfs -ra || log_message "Warning: Failed to reload NFS exports" "warning"
147
+    
148
+    log_message "Reloading systemd daemon"
149
+    systemctl daemon-reload || log_message "Warning: Failed to reload systemd daemon" "warning"
150
+    
151
+    log_message "AutoNAS configuration reload completed"
152
+    return 0
153
+}
154
+
155
+# Function to manually mount a configured disk
156
+handle_manual_mount() {
157
+    local identifier="$1"  # UUID or name
158
+    
159
+    if [[ -z "$identifier" ]]; then
160
+        echo "Error: UUID or disk name required"
161
+        return 1
162
+    fi
163
+    
164
+    echo "Looking for disk configuration: $identifier"
165
+    
166
+    # Try to find configuration by UUID first, then by name
167
+    local config
168
+    config=$(get_disk_config "$identifier") || config=$(get_config_by_name "$identifier")
169
+    
170
+    if [[ -z "$config" ]]; then
171
+        echo "Error: No configuration found for '$identifier'"
172
+        echo "Use 'autonas list' to see configured disks"
173
+        return 1
174
+    fi
175
+    
176
+    # Parse configuration
177
+    local parsed
178
+    parsed=($(parse_config "$config"))
179
+    local uuid="${parsed[0]}"
180
+    local name="${parsed[1]}"
181
+    local ip="${parsed[2]}"
182
+    local interface="${parsed[3]}"
183
+    local mount_point="${parsed[4]}"
184
+    local nfs_options="${parsed[5]}"
185
+    
186
+    echo "Found configuration: $name (UUID: $uuid)"
187
+    
188
+    # Check if already mounted
189
+    if mountpoint -q "$mount_point" 2>/dev/null; then
190
+        echo "โœ… Disk already mounted at: $mount_point"
191
+        return 0
192
+    fi
193
+    
194
+    # Handle different disk types for mounting
195
+    if [[ "$ip" == "IMPORT" ]]; then
196
+        echo "โš ๏ธ  Camera import disks are not meant for manual mounting"
197
+        echo "   They are automatically imported when connected"
198
+        return 1
199
+    elif [[ "$ip" == "LOCAL" ]]; then
200
+        # Local mount only
201
+        echo "๐Ÿ”ต Mounting local disk..."
202
+        if mount_disk "$uuid" "$mount_point"; then
203
+            echo "โœ… Local disk mounted successfully at: $mount_point"
204
+            return 0
205
+        else
206
+            echo "โŒ Failed to mount local disk"
207
+            return 1
208
+        fi
209
+    else
210
+        # Network mount - need to activate IP first
211
+        echo "๐ŸŒ Mounting network disk..."
212
+        if activate_ip "$ip" "$interface"; then
213
+            if mount_disk "$uuid" "$mount_point"; then
214
+                if add_nfs_export "$mount_point" "$nfs_options" "$uuid" "$name"; then
215
+                    echo "โœ… Network disk mounted and exported successfully"
216
+                    echo "   Mount point: $mount_point"
217
+                    echo "   NFS export: $mount_point $nfs_options"
218
+                    return 0
219
+                else
220
+                    echo "โš ๏ธ  Disk mounted but NFS export failed"
221
+                    return 1
222
+                fi
223
+            else
224
+                deactivate_ip "$ip" "$interface"
225
+                echo "โŒ Failed to mount network disk"
226
+                return 1
227
+            fi
228
+        else
229
+            echo "โŒ Failed to activate network interface"
230
+            return 1
231
+        fi
232
+    fi
233
+}
234
+
235
+# Function to manually unmount a configured disk
236
+handle_manual_unmount() {
237
+    local identifier="$1"  # UUID or name
238
+    
239
+    if [[ -z "$identifier" ]]; then
240
+        echo "Error: UUID or disk name required"
241
+        return 1
242
+    fi
243
+    
244
+    echo "Looking for disk configuration: $identifier"
245
+    
246
+    # Try to find configuration by UUID first, then by name  
247
+    local config
248
+    config=$(get_disk_config "$identifier") || config=$(get_config_by_name "$identifier")
249
+    
250
+    if [[ -z "$config" ]]; then
251
+        echo "Error: No configuration found for '$identifier'"
252
+        echo "Use 'autonas list' to see configured disks"
253
+        return 1
254
+    fi
255
+    
256
+    # Parse configuration
257
+    local parsed
258
+    parsed=($(parse_config "$config"))
259
+    local uuid="${parsed[0]}"
260
+    local name="${parsed[1]}"
261
+    local ip="${parsed[2]}"
262
+    local interface="${parsed[3]}"
263
+    local mount_point="${parsed[4]}"
264
+    local nfs_options="${parsed[5]}"
265
+    
266
+    echo "Found configuration: $name (UUID: $uuid)"
267
+    
268
+    # Check if actually mounted
269
+    if ! mountpoint -q "$mount_point" 2>/dev/null; then
270
+        echo "โ„น๏ธ  Disk is not currently mounted: $mount_point"
271
+        return 0
272
+    fi
273
+    
274
+    echo "๐Ÿ”ฝ Unmounting disk..."
275
+    
276
+    # Remove NFS export first (if applicable)
277
+    if [[ "$ip" != "LOCAL" && "$ip" != "IMPORT" ]]; then
278
+        remove_nfs_export "$mount_point" "$uuid" "$name" "$nfs_options"
279
+    fi
280
+    
281
+    # Unmount disk
282
+    if unmount_disk "$mount_point"; then
283
+        # Deactivate IP if network disk
284
+        if [[ "$ip" != "LOCAL" && "$ip" != "IMPORT" ]]; then
285
+            deactivate_ip "$ip" "$interface"
286
+        fi
287
+        
288
+        echo "โœ… Disk unmounted successfully: $name"
289
+        return 0
290
+    else
291
+        echo "โŒ Failed to unmount disk: $name"
292
+        return 1
293
+    fi
294
+}
295
+
296
+# Show usage information
297
+show_usage() {
298
+    cat << EOF
299
+AutoNAS - Unified AutoNAS Management Tool
300
+
301
+Usage: $0 <command> [options]
302
+
303
+DISK OPERATIONS:
304
+  attach <uuid>              - Attach disk with specified UUID
305
+  detach <uuid>              - Detach disk with specified UUID
306
+  mount <uuid|name>          - Manually mount configured disk
307
+  unmount <uuid|name>        - Manually unmount configured disk
308
+  import <uuid> <source> <dest> [script] - Run background import (internal use)
309
+  reload                     - Reload AutoNAS configuration
310
+
311
+CONFIGURATION MANAGEMENT:
312
+  add [uuid]                 - Add new disk configuration
313
+  remove [uuid]              - Remove disk configuration
314
+  list                       - List all configured disks
315
+  test [uuid]                - Test disk configuration
316
+  show                       - Show available disks
317
+
318
+MAINTENANCE:
319
+  status                     - Show system status
320
+  debug enable               - Enable debug mode (verbose logging)
321
+  debug disable              - Disable debug mode
322
+  debug status               - Show current debug status
323
+  
324
+Examples:
325
+  $0 attach f6ac3d86-5681-4b33-bc64-aa272b333057
326
+  $0 add 8765-4321
327
+  $0 list
328
+  $0 show
329
+  $0 status
330
+
331
+EOF
332
+}
333
+
334
+# Function to show available disks
335
+show_available_disks() {
336
+    echo "=== Available Storage Devices ==="
337
+    echo
338
+    
339
+    local found_devices=0
340
+    local blkid_output
341
+    
342
+    # Get blkid output and process it
343
+    if ! blkid_output=$(blkid 2>/dev/null); then
344
+        echo "Error: Unable to scan for block devices (are you running as root?)"
345
+        return 1
346
+    fi
347
+    
348
+    while IFS= read -r blkid_line; do
349
+        [[ -z "$blkid_line" ]] && continue
350
+        
351
+        local device=$(echo "$blkid_line" | cut -d: -f1)
352
+        
353
+        # Skip if device doesn't exist (shouldn't happen with blkid, but just in case)
354
+        [[ ! -b "$device" ]] && continue
355
+        
356
+        # Skip loop devices, ram disks, and other virtual devices
357
+        case "$device" in
358
+            /dev/loop*|/dev/ram*|/dev/dm-*) continue ;;
359
+        esac
360
+        
361
+        # Extract device information
362
+        local uuid=$(echo "$blkid_line" | grep -o 'UUID="[^"]*"' | cut -d'"' -f2)
363
+        local label=$(echo "$blkid_line" | grep -o 'LABEL="[^"]*"' | cut -d'"' -f2)
364
+        local fstype=$(echo "$blkid_line" | grep -o 'TYPE="[^"]*"' | cut -d'"' -f2)
365
+        local partuuid=$(echo "$blkid_line" | grep -o 'PARTUUID="[^"]*"' | cut -d'"' -f2)
366
+        
367
+        # Skip if no UUID (we need UUID for AutoNAS)
368
+        [[ -z "$uuid" ]] && continue
369
+        
370
+        found_devices=$((found_devices + 1))
371
+        
372
+        # Get device size
373
+        local size=""
374
+        if [[ -b "$device" ]]; then
375
+            size=$(lsblk -b -d -o SIZE "$device" 2>/dev/null | tail -n1)
376
+            if [[ -n "$size" ]] && [[ "$size" =~ ^[0-9]+$ ]]; then
377
+                # Convert to human readable
378
+                size=$(numfmt --to=iec --suffix=B "$size" 2>/dev/null || echo "${size}B")
379
+            fi
380
+        fi
381
+        
382
+        # Display device information
383
+        echo "Device: $device"
384
+        [[ -n "$size" ]] && echo "  Size: $size"
385
+        echo "  UUID: $uuid"
386
+        [[ -n "$label" ]] && echo "  Label: $label"
387
+        [[ -n "$fstype" ]] && echo "  Filesystem: $fstype"
388
+        
389
+        # Check if already configured
390
+        if grep -q "^${uuid}:" "$CONFIG_FILE" 2>/dev/null; then
391
+            local config_line=$(grep "^${uuid}:" "$CONFIG_FILE" 2>/dev/null)
392
+            local config_name=$(echo "$config_line" | cut -d: -f2)
393
+            echo "  Status: โœ… Configured as '$config_name'"
394
+        else
395
+            echo "  Status: โš ๏ธ  Not configured"
396
+        fi
397
+        
398
+        # Check if currently mounted
399
+        local mount_info
400
+        mount_info=$(findmnt -n -o TARGET "$device" 2>/dev/null)
401
+        if [[ -n "$mount_info" ]]; then
402
+            echo "  Mount: ๐ŸŸข $mount_info"
403
+        else
404
+            echo "  Mount: โšช Not mounted"
405
+        fi
406
+        
407
+        echo
408
+    done <<< "$blkid_output"
409
+    
410
+    if [[ $found_devices -eq 0 ]]; then
411
+        echo "No storage devices with UUIDs found."
412
+        echo "Make sure devices are connected and you're running as root."
413
+    else
414
+        echo "Found $found_devices storage device(s)"
415
+        echo
416
+        echo "To configure a device: autonas add <UUID>"
417
+        echo "To list configured devices: autonas list"
418
+    fi
419
+    
420
+    return 0
421
+}
422
+
423
+# Show usage information
424
+
425
+# Function to check if UUID exists in configuration
426
+check_uuid_exists() {
427
+    local uuid="$1"
428
+    grep -q "^${uuid}:" "$CONFIG_FILE" 2>/dev/null
429
+}
430
+
431
+# Function to get device information
432
+get_device_info() {
433
+    local uuid="$1"
434
+    
435
+    # Find device by UUID using blkid
436
+    local device_line
437
+    device_line=$(blkid | grep "UUID=\"$uuid\"")
438
+    
439
+    if [[ -z "$device_line" ]]; then
440
+        return 1
441
+    fi
442
+    
443
+    local device=$(echo "$device_line" | cut -d: -f1)
444
+    local blkid_info=$(echo "$device_line" | cut -d: -f2-)
445
+    
446
+    echo "device:$device"
447
+    echo "$blkid_info"
448
+    return 0
449
+}
450
+
451
+# Function to list configured disks
452
+list_disks() {
453
+    echo "AutoNAS Disk Configurations:"
454
+    echo "============================"
455
+    echo ""
456
+
457
+    if [[ ! -f "$CONFIG_FILE" ]]; then
458
+        echo "No configuration file found at: $CONFIG_FILE"
459
+        echo "Use 'autonas add' to add your first disk configuration."
460
+        return 1
461
+    fi
462
+
463
+    local config_count=0
464
+    while IFS=':' read -r uuid name ip interface mount_point nfs_options; do
465
+        # Skip empty lines and comments
466
+        [[ -z "$uuid" || "$uuid" =~ ^# ]] && continue
467
+        
468
+        config_count=$((config_count + 1))
469
+        
470
+        echo "UUID: $uuid"
471
+        echo "Name: $name"
472
+        
473
+        # Check if it's a local mount configuration
474
+        if [[ "$ip" == "LOCAL" && "$interface" == "LOCAL" && "$nfs_options" == "LOCAL" ]]; then
475
+            echo "Type: ๐Ÿ“ Local Mount (no network sharing)"
476
+            echo "Mount Point: $mount_point"
477
+        elif [[ "$ip" == "IMPORT" && "$interface" == "IMPORT" ]]; then
478
+            echo "Type: ๐Ÿ“ท Camera Import (mount, import, unmount)"
479
+            echo "Import Destination: $nfs_options"
480
+            echo "Import Script: /usr/local/bin/autonas-media-importer.sh (built-in, non-configurable)"
481
+            echo "Temp Mount Point: $mount_point"
482
+        else
483
+            echo "Type: ๐ŸŒ NFS Network Share"
484
+            echo "IP: $ip"
485
+            echo "Interface: $interface"
486
+            echo "Mount Point: $mount_point"
487
+            echo "NFS Options: $nfs_options"
488
+        fi
489
+        
490
+        # Check device status
491
+        local device_info
492
+        if device_info=$(get_device_info "$uuid" 2>/dev/null); then
493
+            local device=$(echo "$device_info" | grep "^device:" | cut -d: -f2)
494
+            echo "Status: โœ… Connected"
495
+            
496
+            # Check if mounted
497
+            if mountpoint -q "$mount_point" 2>/dev/null; then
498
+                echo "Mount Status: ๐ŸŸข Mounted"
499
+                echo "Current Mount: $mount_point"
500
+            else
501
+                echo "Mount Status: ๐Ÿ”ด Not Mounted"
502
+            fi
503
+        else
504
+            echo "Status: ๐Ÿ”ด Not Connected"
505
+        fi
506
+        
507
+        echo "----"
508
+    done < <(grep -v '^#' "$CONFIG_FILE" 2>/dev/null | grep -v '^$')
509
+
510
+    if [[ $config_count -eq 0 ]]; then
511
+        echo "No disk configurations found."
512
+        echo "Use 'autonas add' to add your first disk configuration."
513
+        return 1
514
+    fi
515
+
516
+    echo ""
517
+    echo "Total configurations: $config_count"
518
+    return 0
519
+}
520
+
521
+# Function to add disk configuration
522
+add_disk() {
523
+    local preset_uuid="$1"  # Optional UUID parameter
524
+
525
+    echo "AutoNAS - Add New Disk Configuration"
526
+    echo "===================================="
527
+    echo ""
528
+
529
+    # Show available disks first
530
+    show_available_disks
531
+    if [ $? -ne 0 ]; then
532
+        echo "Cannot proceed without available disks."
533
+        return 1
534
+    fi
535
+
536
+    echo "Please enter the configuration for your disk:"
537
+    echo ""
538
+
539
+    # Get UUID with validation
540
+    local uuid="$preset_uuid"
541
+    if [ -n "$uuid" ]; then
542
+        echo "Using provided UUID: $uuid"
543
+
544
+        if ! validate_uuid "$uuid"; then
545
+            echo "Error: Invalid UUID format. Expected format: 12345678-1234-1234-1234-123456789abc"
546
+            echo "Please run without UUID parameter to enter manually."
547
+            return 1
548
+        fi
549
+
550
+        if check_uuid_exists "$uuid"; then
551
+            echo "Error: UUID $uuid is already configured."
552
+            echo "Use 'autonas remove $uuid' to remove existing configuration first."
553
+            return 1
554
+        fi
555
+    else
556
+        while true; do
557
+            read -p "Enter disk UUID: " uuid
558
+            if [ -z "$uuid" ]; then
559
+                echo "Error: UUID cannot be empty"
560
+                continue
561
+            fi
562
+
563
+            if ! validate_uuid "$uuid"; then
564
+                echo "Error: Invalid UUID format. Expected format: 12345678-1234-1234-1234-123456789abc"
565
+                continue
566
+            fi
567
+
568
+            if check_uuid_exists "$uuid"; then
569
+                echo "Error: UUID $uuid is already configured."
570
+                echo "Use 'autonas remove $uuid' to remove existing configuration first."
571
+                continue
572
+            fi
573
+
574
+            break
575
+        done
576
+    fi
577
+
578
+    # Get and validate disk name
579
+    local name
580
+    while true; do
581
+        read -p "Enter disk name (letters, numbers, hyphens, underscores, @ allowed): " name
582
+        if [ -z "$name" ]; then
583
+            echo "Error: Disk name cannot be empty"
584
+            continue
585
+        fi
586
+
587
+        if ! validate_disk_name_complete "$name"; then
588
+            local validation_result=$?
589
+            if [[ $validation_result -eq 2 ]]; then
590
+                echo "Error: Disk name '$name' already exists. Please choose another name."
591
+                echo ""
592
+                list_existing_disk_names
593
+                echo ""
594
+                continue
595
+            else
596
+                echo "Error: Invalid disk name. Requirements:"
597
+                echo "  - Max 50 characters"
598
+                echo "  - Must start with letter or number"
599
+                echo "  - Only letters, numbers, hyphens (-), underscores (_), and at symbol (@)"
600
+                echo "  - Cannot be reserved names (root, home, tmp, etc.)"
601
+                continue
602
+            fi
603
+        fi
604
+
605
+        break
606
+    done
607
+
608
+    # Choose configuration type
609
+    echo ""
610
+    echo "Select disk type:"
611
+    echo "1) NFS Network Share (default) - Share disk over network"
612
+    echo "2) Camera Import - Import photos/videos from camera and unmount"
613
+    echo "3) Local Mount - Mount locally without network sharing"
614
+    echo ""
615
+    
616
+    local config_type
617
+    read -p "Choose type [1-3] (default: 1): " config_type
618
+    config_type=${config_type:-1}
619
+
620
+    case "$config_type" in
621
+        1)
622
+            configure_nfs_disk "$uuid" "$name"
623
+            ;;
624
+        2)
625
+            configure_import_disk "$uuid" "$name"
626
+            ;;
627
+        3)
628
+            configure_local_disk "$uuid" "$name"
629
+            ;;
630
+        *)
631
+            echo "Invalid choice. Using NFS Network Share (default)."
632
+            configure_nfs_disk "$uuid" "$name"
633
+            ;;
634
+    esac
635
+}
636
+
637
+# Function to configure NFS disk
638
+configure_nfs_disk() {
639
+    local uuid="$1"
640
+    local name="$2"
641
+    
642
+    echo ""
643
+    echo "=== NFS Network Share Configuration ==="
644
+    
645
+    # Get IP address
646
+    local ip
647
+    while true; do
648
+        read -p "Enter IP address for NFS sharing (e.g., 192.168.1.100): " ip
649
+        if [ -z "$ip" ]; then
650
+            echo "Error: IP address cannot be empty"
651
+            continue
652
+        fi
653
+        
654
+        # Basic IP validation
655
+        if [[ ! "$ip" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
656
+            echo "Error: Invalid IP address format"
657
+            continue
658
+        fi
659
+        
660
+        # Check each octet
661
+        local valid_ip=true
662
+        IFS='.' read -ra OCTETS <<< "$ip"
663
+        for octet in "${OCTETS[@]}"; do
664
+            if [ "$octet" -lt 0 ] || [ "$octet" -gt 255 ]; then
665
+                valid_ip=false
666
+                break
667
+            fi
668
+        done
669
+        
670
+        if [ "$valid_ip" = false ]; then
671
+            echo "Error: IP address octets must be between 0-255"
672
+            continue
673
+        fi
674
+        
675
+        break
676
+    done
677
+    
678
+    # Get network interface
679
+    local interface
680
+    echo ""
681
+    echo "Available network interfaces:"
682
+    ip link show | grep "^[0-9]" | cut -d: -f2 | sed 's/^ *//' | grep -v "^lo$"
683
+    echo ""
684
+    
685
+    while true; do
686
+        read -p "Enter network interface (e.g., eth0, enp0s3): " interface
687
+        if [ -z "$interface" ]; then
688
+            echo "Error: Network interface cannot be empty"
689
+            continue
690
+        fi
691
+        
692
+        # Check if interface exists
693
+        if ! ip link show "$interface" >/dev/null 2>&1; then
694
+            echo "Error: Network interface '$interface' does not exist"
695
+            echo "Available interfaces:"
696
+            ip link show | grep "^[0-9]" | cut -d: -f2 | sed 's/^ *//' | grep -v "^lo$"
697
+            continue
698
+        fi
699
+        
700
+        break
701
+    done
702
+    
703
+    # Generate mount point
704
+    local mount_point="$MOUNT_BASE/$name"
705
+    echo ""
706
+    echo "Mount point will be: $mount_point"
707
+    
708
+    # Get NFS options
709
+    local nfs_options
710
+    echo ""
711
+    echo "NFS Options (press Enter for default):"
712
+    echo "Default: *(rw,all_squash,insecure,async,no_subtree_check,anonuid=0,anongid=0)"
713
+    read -p "Enter custom NFS options or press Enter for default: " nfs_options
714
+    
715
+    if [ -z "$nfs_options" ]; then
716
+        nfs_options="*(rw,all_squash,insecure,async,no_subtree_check,anonuid=0,anongid=0)"
717
+    fi
718
+    
719
+    # Create configuration entry
720
+    local config_entry="${uuid}:${name}:${ip}:${interface}:${mount_point}:${nfs_options}"
721
+    
722
+    # Show configuration summary
723
+    echo ""
724
+    echo "=== Configuration Summary ==="
725
+    echo "UUID: $uuid"
726
+    echo "Name: $name"
727
+    echo "Type: NFS Network Share"
728
+    echo "IP: $ip"
729
+    echo "Interface: $interface"
730
+    echo "Mount Point: $mount_point"
731
+    echo "NFS Options: $nfs_options"
732
+    echo ""
733
+    
734
+    # Confirm configuration
735
+    read -p "Save this configuration? (Y/n): " confirm
736
+    if [[ "$confirm" =~ ^[Nn]$ ]]; then
737
+        echo "Configuration cancelled."
738
+        return 1
739
+    fi
740
+    
741
+    # Save configuration
742
+    echo "$config_entry" >> "$CONFIG_FILE"
743
+    echo ""
744
+    echo "โœ… Configuration saved successfully!"
745
+    echo ""
746
+    echo "To test this configuration: autonas test $uuid"
747
+    echo "To attach this disk when connected: autonas attach $uuid"
748
+    
749
+    return 0
750
+}
751
+
752
+# Function to configure local disk
753
+configure_local_disk() {
754
+    local uuid="$1"
755
+    local name="$2"
756
+    
757
+    echo ""
758
+    echo "=== Local Mount Configuration ==="
759
+    echo "This disk will be mounted locally without network sharing."
760
+    echo ""
761
+    
762
+    # Generate mount point
763
+    local mount_point="$MOUNT_BASE/$name"
764
+    echo "Mount point will be: $mount_point"
765
+    echo ""
766
+    
767
+    # Create configuration entry
768
+    local config_entry="${uuid}:${name}:LOCAL:LOCAL:${mount_point}:LOCAL"
769
+    
770
+    # Show configuration summary
771
+    echo "=== Configuration Summary ==="
772
+    echo "UUID: $uuid"
773
+    echo "Name: $name"
774
+    echo "Type: Local Mount (no network sharing)"
775
+    echo "Mount Point: $mount_point"
776
+    echo ""
777
+    
778
+    # Confirm configuration
779
+    read -p "Save this configuration? (Y/n): " confirm
780
+    if [[ "$confirm" =~ ^[Nn]$ ]]; then
781
+        echo "Configuration cancelled."
782
+        return 1
783
+    fi
784
+    
785
+    # Save configuration
786
+    echo "$config_entry" >> "$CONFIG_FILE"
787
+    echo ""
788
+    echo "โœ… Configuration saved successfully!"
789
+    echo ""
790
+    echo "To test this configuration: autonas test $uuid"
791
+    echo "To attach this disk when connected: autonas attach $uuid"
792
+    
793
+    return 0
794
+}
795
+
796
+# Function to configure import disk (camera)
797
+configure_import_disk() {
798
+    local uuid="$1"
799
+    local name="$2"
800
+    
801
+    echo ""
802
+    echo "=== Camera Import Configuration ==="
803
+    echo "This device will be mounted temporarily, media imported, then unmounted."
804
+    echo ""
805
+    
806
+    # Get destination path for import
807
+    local destination_path
808
+    while true; do
809
+        read -p "Enter destination path for imported media: " destination_path
810
+        if [ -z "$destination_path" ]; then
811
+            echo "Error: Destination path cannot be empty"
812
+            continue
813
+        fi
814
+        
815
+        # Convert relative path to absolute
816
+        if [[ ! "$destination_path" =~ ^/ ]]; then
817
+            destination_path="$(pwd)/$destination_path"
818
+        fi
819
+        
820
+        # Validate parent directory exists
821
+        local parent_dir=$(dirname "$destination_path")
822
+        if [ ! -d "$parent_dir" ]; then
823
+            echo "Warning: Parent directory '$parent_dir' does not exist."
824
+            read -p "Create parent directories? (Y/n): " create_dirs
825
+            if [[ ! "$create_dirs" =~ ^[Nn]$ ]]; then
826
+                if mkdir -p "$parent_dir" 2>/dev/null; then
827
+                    echo "Created parent directories."
828
+                else
829
+                    echo "Error: Failed to create parent directories. Please check permissions."
830
+                    continue
831
+                fi
832
+            else
833
+                echo "Please enter a valid destination path."
834
+                continue
835
+            fi
836
+        fi
837
+        
838
+        break
839
+    done
840
+    
841
+    # Generate temporary mount point for import
842
+    local temp_mount_point="$MOUNT_BASE/$name"
843
+    
844
+    # Create configuration entry (simplified format - no script path)
845
+    local config_entry="${uuid}:${name}:IMPORT:IMPORT:${temp_mount_point}:${destination_path}"
846
+    
847
+    # Show configuration summary
848
+    echo ""
849
+    echo "=== Configuration Summary ==="
850
+    echo "UUID: $uuid"
851
+    echo "Name: $name"
852
+    echo "Type: Camera Import (mount, import, unmount)"
853
+    echo "Import destination: $destination_path"
854
+    echo "Import script: /usr/local/bin/autonas-media-importer.sh (built-in, non-configurable)"
855
+    echo "Temp mount point: $temp_mount_point"
856
+    echo ""
857
+    
858
+    # Confirm configuration
859
+    read -p "Save this configuration? (Y/n): " confirm
860
+    if [[ "$confirm" =~ ^[Nn]$ ]]; then
861
+        echo "Configuration cancelled."
862
+        return 1
863
+    fi
864
+    
865
+    # Save configuration
866
+    echo "$config_entry" >> "$CONFIG_FILE"
867
+    echo ""
868
+    echo "โœ… Configuration saved successfully!"
869
+    echo ""
870
+    echo "To test this configuration: autonas test $uuid"  
871
+    echo "When camera is connected, media will be imported automatically to: $destination_path"
872
+    
873
+    return 0
874
+}
875
+
876
+# Function to remove disk configuration
877
+remove_disk() {
878
+    local uuid="$1"
879
+    
880
+    if [[ -z "$uuid" ]]; then
881
+        echo "Usage: autonas remove <uuid>"
882
+        return 1
883
+    fi
884
+    
885
+    if [[ ! -f "$CONFIG_FILE" ]]; then
886
+        echo "No configuration file found."
887
+        return 1
888
+    fi
889
+    
890
+    # Check if UUID exists
891
+    if ! check_uuid_exists "$uuid"; then
892
+        echo "Error: UUID '$uuid' not found in configuration."
893
+        return 1
894
+    fi
895
+    
896
+    # Show current configuration
897
+    echo "Current configuration for UUID: $uuid"
898
+    echo "=================================="
899
+    local config=$(get_disk_config "$uuid")
900
+    local parsed=($(parse_config "$config"))
901
+    echo "Name: ${parsed[1]}"
902
+    echo "Type: ${parsed[2]}:${parsed[3]}"
903
+    echo "Mount: ${parsed[4]}"
904
+    echo ""
905
+    
906
+    # Confirm removal
907
+    read -p "Remove this configuration? (y/N): " confirm
908
+    if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
909
+        echo "Removal cancelled."
910
+        return 1
911
+    fi
912
+    
913
+    # Remove configuration
914
+    local temp_file=$(mktemp)
915
+    grep -v "^${uuid}:" "$CONFIG_FILE" > "$temp_file"
916
+    mv "$temp_file" "$CONFIG_FILE"
917
+    
918
+    echo "โœ… Configuration removed successfully!"
919
+    return 0
920
+}
921
+
922
+# Function to test disk configuration
923
+test_config() {
924
+    local uuid="$1"
925
+    
926
+    if [[ -z "$uuid" ]]; then
927
+        echo "Usage: autonas test <uuid>"
928
+        return 1
929
+    fi
930
+    
931
+    echo "AutoNAS Configuration Test"
932
+    echo "========================="
933
+    echo ""
934
+    
935
+    # Check if configuration exists
936
+    local config
937
+    config=$(get_disk_config "$uuid")
938
+    
939
+    if [[ -z "$config" ]]; then
940
+        echo "โŒ Configuration not found for UUID: $uuid"
941
+        echo ""
942
+        echo "Available configurations:"
943
+        list_disks
944
+        return 1
945
+    fi
946
+    
947
+    echo "โœ… Configuration found for UUID: $uuid"
948
+    
949
+    # Parse configuration
950
+    local parsed=($(parse_config "$config"))
951
+    local cfg_uuid="${parsed[0]}"
952
+    local name="${parsed[1]}"
953
+    local ip="${parsed[2]}"
954
+    local interface="${parsed[3]}"
955
+    local mount_point="${parsed[4]}"
956
+    local nfs_options="${parsed[5]}"
957
+    
958
+    echo "   Name: $name"
959
+    echo "   Type: $ip:$interface"
960
+    echo "   Mount Point: $mount_point"
961
+    echo ""
962
+    
963
+    # Test device detection
964
+    echo "๐Ÿ” Testing device detection..."
965
+    local device_info
966
+    if device_info=$(get_device_info "$uuid" 2>/dev/null); then
967
+        local device=$(echo "$device_info" | grep "^device:" | cut -d: -f2)
968
+        echo "โœ… Device found: $device"
969
+        
970
+        # Show device details
971
+        echo "$device_info" | grep -v "^device:" | while IFS= read -r line; do
972
+            echo "   $line"
973
+        done
974
+    else
975
+        echo "โŒ Device not found or not connected"
976
+        echo "   Make sure the device with UUID $uuid is connected"
977
+        return 1
978
+    fi
979
+    echo ""
980
+    
981
+    # Test network configuration (if applicable)
982
+    if [[ "$ip" != "LOCAL" && "$ip" != "IMPORT" ]]; then
983
+        echo "๐ŸŒ Testing network configuration..."
984
+        
985
+        # Test interface
986
+        if interface_exists "$interface"; then
987
+            echo "โœ… Network interface exists: $interface"
988
+        else
989
+            echo "โŒ Network interface not found: $interface"
990
+            echo "   Available interfaces:"
991
+            ip link show | grep "^[0-9]" | cut -d: -f2 | sed 's/^ *//' | grep -v "^lo$" | sed 's/^/     /'
992
+            return 1
993
+        fi
994
+        
995
+        # Test IP configuration
996
+        if is_ip_configured "$ip" "$interface"; then
997
+            echo "โœ… IP already configured: $ip on $interface"
998
+        else
999
+            echo "โ„น๏ธ  IP not currently configured: $ip on $interface"
1000
+            echo "   (This is normal - IP will be activated during attach)"
1001
+        fi
1002
+        echo ""
1003
+    fi
1004
+    
1005
+    # Test mount point
1006
+    echo "๐Ÿ“ Testing mount point..."
1007
+    if [[ -d "$mount_point" ]]; then
1008
+        if mountpoint -q "$mount_point" 2>/dev/null; then
1009
+            echo "โœ… Mount point exists and is mounted: $mount_point"
1010
+            local mounted_device=$(findmnt -n -o SOURCE "$mount_point")
1011
+            echo "   Mounted device: $mounted_device"
1012
+        else
1013
+            echo "โ„น๏ธ  Mount point directory exists but not mounted: $mount_point"
1014
+        fi
1015
+    else
1016
+        echo "โ„น๏ธ  Mount point directory will be created: $mount_point"
1017
+    fi
1018
+    echo ""
1019
+    
1020
+    # Test import configuration (if applicable)
1021
+    if [[ "$ip" == "IMPORT" && "$interface" == "IMPORT" ]]; then
1022
+        echo "๐Ÿ“ท Testing camera import configuration..."
1023
+        local destination="$nfs_options"
1024
+        
1025
+        if [[ -d "$destination" ]]; then
1026
+            echo "โœ… Import destination exists: $destination"
1027
+            if [[ -w "$destination" ]]; then
1028
+                echo "โœ… Import destination is writable"
1029
+            else
1030
+                echo "โš ๏ธ  Import destination is not writable"
1031
+                echo "   You may need to check permissions"
1032
+            fi
1033
+        else
1034
+            echo "โ„น๏ธ  Import destination will be created: $destination"
1035
+            local parent_dir=$(dirname "$destination")
1036
+            if [[ -d "$parent_dir" && -w "$parent_dir" ]]; then
1037
+                echo "โœ… Parent directory exists and is writable"
1038
+            else
1039
+                echo "โŒ Cannot create import destination"
1040
+                echo "   Parent directory: $parent_dir"
1041
+                return 1
1042
+            fi
1043
+        fi
1044
+        
1045
+        # Test import script
1046
+        if [[ -x "/usr/local/bin/autonas-media-importer.sh" ]]; then
1047
+            echo "โœ… Media import script is available and executable"
1048
+        else
1049
+            echo "โŒ Media import script not found or not executable"
1050
+            echo "   Expected: /usr/local/bin/autonas-media-importer.sh"
1051
+            return 1
1052
+        fi
1053
+        echo ""
1054
+    fi
1055
+    
1056
+    echo "๐ŸŽ‰ Configuration test completed successfully!"
1057
+    echo ""
1058
+    echo "You can now attach this disk with: autonas attach $uuid"
1059
+    return 0
1060
+}
1061
+
1062
+# Main configuration functions would go here...
1063
+
1064
+# Main command dispatcher
1065
+case "${1:-}" in
1066
+    "attach")
1067
+        if [[ -z "$2" ]]; then
1068
+            echo "Error: UUID required for attach command"
1069
+            show_usage
1070
+            exit 1
1071
+        fi
1072
+        handle_attach "$2"
1073
+        ;;
1074
+    "detach")
1075
+        if [[ -z "$2" ]]; then
1076
+            echo "Error: UUID required for detach command"
1077
+            show_usage
1078
+            exit 1
1079
+        fi
1080
+        handle_detach "$2"
1081
+        ;;
1082
+    "mount")
1083
+        if [[ -z "$2" ]]; then
1084
+            echo "Error: UUID or disk name required for mount command"
1085
+            show_usage
1086
+            exit 1
1087
+        fi
1088
+        handle_manual_mount "$2"
1089
+        ;;
1090
+    "unmount"|"umount")
1091
+        if [[ -z "$2" ]]; then
1092
+            echo "Error: UUID or disk name required for unmount command"
1093
+            show_usage
1094
+            exit 1
1095
+        fi
1096
+        handle_manual_unmount "$2"
1097
+        ;;
1098
+    "import")
1099
+        # Internal use only - background import process
1100
+        if [[ -z "$4" ]]; then
1101
+            echo "Error: Missing arguments for import command"
1102
+            exit 1
1103
+        fi
1104
+        run_background_import "$2" "$3" "$4" "$5"
1105
+        ;;
1106
+    "reload")
1107
+        handle_reload
1108
+        ;;
1109
+    "add")
1110
+        add_disk "$2"
1111
+        ;;
1112
+    "remove")
1113
+        if [[ -z "$2" ]]; then
1114
+            echo "Error: UUID required for remove command"
1115
+            show_usage
1116
+            exit 1
1117
+        fi
1118
+        remove_disk "$2"
1119
+        ;;
1120
+    "list")
1121
+        list_disks
1122
+        ;;
1123
+    "test")
1124
+        if [[ -z "$2" ]]; then
1125
+            echo "Error: UUID required for test command"
1126
+            show_usage
1127
+            exit 1
1128
+        fi
1129
+        test_config "$2"
1130
+        ;;
1131
+    "show")
1132
+        show_available_disks
1133
+        ;;
1134
+    "status")
1135
+        echo "=== AutoNAS System Status ==="
1136
+        echo "Configuration file: $CONFIG_FILE"
1137
+        if [[ -f "$CONFIG_FILE" ]]; then
1138
+            count=$(grep -c "^[^#].*:.*:.*:" "$CONFIG_FILE" 2>/dev/null || echo "0")
1139
+            echo "Configured disks: $count"
1140
+        else
1141
+            echo "Configured disks: 0 (no config file)"
1142
+        fi
1143
+        echo "NFS server: $(systemctl is-active nfs-kernel-server 2>/dev/null || echo "unknown")"
1144
+        echo "AutoNAS service: $(systemctl is-active autonas 2>/dev/null || echo "unknown")"
1145
+        echo "Boot scan service: $(systemctl is-active autonas-boot-scan 2>/dev/null || echo "unknown")"
1146
+        echo ""
1147
+        echo "Recent logs:"
1148
+        journalctl -t autonas -n 5 --no-pager 2>/dev/null || echo "No recent logs found"
1149
+        ;;
1150
+    "debug")
1151
+        case "${2:-}" in
1152
+            "enable")
1153
+                if [ -f "/etc/default/autonas" ]; then
1154
+                    sed -i 's/AUTONAS_DEBUG="false"/AUTONAS_DEBUG="true"/' /etc/default/autonas
1155
+                    echo "โœ“ Debug mode enabled - verbose logging is now active"
1156
+                    echo "  All AutoNAS operations will produce detailed debug output"
1157
+                else
1158
+                    echo "Error: Configuration file /etc/default/autonas not found"
1159
+                    exit 1
1160
+                fi
1161
+                ;;
1162
+            "disable")
1163
+                if [ -f "/etc/default/autonas" ]; then
1164
+                    sed -i 's/AUTONAS_DEBUG="true"/AUTONAS_DEBUG="false"/' /etc/default/autonas
1165
+                    echo "โœ“ Debug mode disabled - normal logging restored"
1166
+                else
1167
+                    echo "Error: Configuration file /etc/default/autonas not found"
1168
+                    exit 1
1169
+                fi
1170
+                ;;
1171
+            "status")
1172
+                if [ -f "/etc/default/autonas" ]; then
1173
+                    echo "=== AutoNAS Debug Configuration ==="
1174
+                    source /etc/default/autonas
1175
+                    echo "Debug mode: ${AUTONAS_DEBUG:-false}"
1176
+                    echo "Log level: ${AUTONAS_LOG_LEVEL:-info}"
1177
+                    if [ "$AUTONAS_DEBUG" = "true" ]; then
1178
+                        echo "Status: ๐ŸŸข Debug logging is ENABLED"
1179
+                        echo "  - Verbose messages will appear in logs and stderr"
1180
+                        echo "  - All operations will be traced in detail"
1181
+                    else
1182
+                        echo "Status: ๐Ÿ”ด Debug logging is DISABLED"
1183
+                        echo "  - Only normal info/warning/error messages will appear"
1184
+                    fi
1185
+                else
1186
+                    echo "Error: Configuration file /etc/default/autonas not found"
1187
+                    exit 1
1188
+                fi
1189
+                ;;
1190
+            "")
1191
+                echo "Error: Debug command requires an argument"
1192
+                echo "Usage: $0 debug {enable|disable|status}"
1193
+                exit 1
1194
+                ;;
1195
+            *)
1196
+                echo "Error: Unknown debug command '$2'"
1197
+                echo "Usage: $0 debug {enable|disable|status}"
1198
+                exit 1
1199
+                ;;
1200
+        esac
1201
+        ;;
1202
+    "help"|"-h"|"--help"|"")
1203
+        show_usage
1204
+        ;;
1205
+    *)
1206
+        echo "Error: Unknown command '$1'"
1207
+        echo
1208
+        show_usage
1209
+        exit 1
1210
+        ;;
1211
+esac
+0 -0
scripts/cleanup.sh
No changes.
+385 -0
scripts/install.sh
@@ -0,0 +1,385 @@
1
+#!/bin/bash
2
+
3
+# AutoNAS Installation & Node Admin Script
4
+# Executed on target nodes; deploy.sh invokes this with subcommands.
5
+# Usage: install.sh [install|start|restart|stop|status]
6
+
7
+set -e  # Exit on any error
8
+
9
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
10
+PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
11
+CONFIG_DIR="/etc/pve/autonas"
12
+
13
+# Script names
14
+UNIFIED_SCRIPT="autonas.sh"
15
+SCRIPT_NAME="autonas-disk-handler.sh"
16
+WRAPPER_NAME="autonas-udev-wrapper.sh"
17
+BOOT_SCAN_SCRIPT="autonas-boot-scan.sh"
18
+INTERFACE_HANDLER_SCRIPT="autonas-network-handler.sh"
19
+CAMERA_IMPORT_SCRIPT="autonas-media-importer.sh"
20
+UDEV_RULES="99-autonas-disk.rules"
21
+INTERFACE_RULES="98-autonas-interfaces.rules"
22
+SYSTEMD_SERVICE="autonas-attach@.service"
23
+MAIN_SERVICE="autonas.service"
24
+BOOT_SCAN_SERVICE="autonas-boot-scan.service"
25
+
26
+require_root() {
27
+    if [ "$EUID" -ne 0 ]; then
28
+        echo "โŒ This action must be run as root (use sudo)" >&2
29
+        exit 1
30
+    fi
31
+}
32
+
33
+# Verificฤƒ dacฤƒ un pachet este instalat
34
+is_package_installed() {
35
+    local package="$1"
36
+    dpkg -l "$package" 2>/dev/null | grep -q "^ii"
37
+}
38
+
39
+# Verificฤƒ dependinศ›ele necesare
40
+check_dependencies() {
41
+    local missing_packages=()
42
+    local required_packages=("nfs-kernel-server" "autofs" "udev" "libimage-exiftool-perl")
43
+    
44
+    echo "๐Ÿ” Verificare dependinศ›e AutoNAS..."
45
+    
46
+    for package in "${required_packages[@]}"; do
47
+        if is_package_installed "$package"; then
48
+            echo "โœ“ $package - instalat"
49
+        else
50
+            echo "โŒ $package - LIPSฤ‚"
51
+            missing_packages+=("$package")
52
+        fi
53
+    done
54
+    
55
+    if [ ${#missing_packages[@]} -gt 0 ]; then
56
+        echo ""
57
+        echo "โš ๏ธ  DEPENDINศšE LIPSฤ‚ DETECTATE:"
58
+        printf "   %s\n" "${missing_packages[@]}"
59
+        echo ""
60
+        echo "Pentru a instala dependinศ›ele lipsฤƒ, rulaศ›i:"
61
+        echo "   apt update && apt install -y ${missing_packages[*]}"
62
+        echo ""
63
+        echo "Sau utilizaศ›i comanda 'install-deps' pentru instalare automatฤƒ:"
64
+        echo "   $0 install-deps"
65
+        echo ""
66
+        return 1
67
+    else
68
+        echo "โœ… Toate dependinศ›ele sunt instalate"
69
+        return 0
70
+    fi
71
+}
72
+
73
+# Instaleazฤƒ doar dependinศ›ele lipsฤƒ
74
+install_dependencies() {
75
+    require_root
76
+    echo "๐Ÿ“ฆ Instalare dependinศ›e AutoNAS..."
77
+    
78
+    if ! command -v apt >/dev/null 2>&1; then
79
+        echo "โŒ Sistemul nu foloseศ™te apt - instalarea automatฤƒ nu este suportatฤƒ"
80
+        echo "Instalaศ›i manual pachetele: nfs-kernel-server autofs udev libimage-exiftool-perl"
81
+        exit 1
82
+    fi
83
+    
84
+    echo "Actualizare lista de pachete..."
85
+    if ! apt update; then
86
+        echo "โŒ Nu s-a putut actualiza lista de pachete - verificaศ›i conectivitatea la internet"
87
+        exit 1
88
+    fi
89
+    
90
+    echo "Instalare pachete necesare..."
91
+    if apt install -y nfs-kernel-server autofs udev libimage-exiftool-perl; then
92
+        echo "โœ… Dependinศ›ele au fost instalate cu succes"
93
+    else
94
+        echo "โŒ Eroare la instalarea dependinศ›elor"
95
+        exit 1
96
+    fi
97
+}
98
+
99
+do_start() {
100
+    require_root
101
+    echo "Starting AutoNAS services..."
102
+    systemctl enable nfs-kernel-server >/dev/null 2>&1 || true
103
+    systemctl start nfs-kernel-server || true
104
+    udevadm control --reload-rules || true
105
+    udevadm trigger --subsystem-match=block --action=add || true
106
+    echo "โœ“ Start complete"
107
+}
108
+
109
+do_restart() {
110
+    require_root
111
+    echo "Restarting AutoNAS services..."
112
+    systemctl restart nfs-kernel-server || true
113
+    udevadm control --reload-rules || true
114
+    udevadm trigger --subsystem-match=block --action=add || true
115
+    echo "โœ“ Restart complete"
116
+}
117
+
118
+do_stop() {
119
+    require_root
120
+    echo "Stopping AutoNAS services..."
121
+    systemctl stop nfs-kernel-server || true
122
+    echo "โœ“ Stop complete"
123
+}
124
+
125
+do_status() {
126
+    echo "=== Status Servicii ==="
127
+    systemctl status nfs-kernel-server --no-pager -l || true
128
+    echo ""
129
+    echo "=== Exports NFS ==="
130
+    cat /etc/exports 2>/dev/null || echo "Fiศ™ier /etc/exports nu existฤƒ"
131
+    echo ""
132
+    echo "=== Mount Points AutoNAS ==="
133
+    ls -la /mnt/autonas/ 2>/dev/null || echo "Director /mnt/autonas nu existฤƒ"
134
+    echo ""
135
+    echo "=== Configuraศ›ie Diskuri ==="
136
+    cat "$CONFIG_DIR/disks.conf" 2>/dev/null || echo "Fiศ™ier configuraศ›ie nu existฤƒ"
137
+    echo ""
138
+    echo "=== Procese AutoNAS ==="
139
+    ps aux | grep autonas | grep -v grep || true
140
+}
141
+
142
+do_install() {
143
+    require_root
144
+    echo "=== AutoNAS Installation Script ==="
145
+    echo ""
146
+    
147
+    # Verificฤƒ dependinศ›ele mai รฎntรขi
148
+    if ! check_dependencies; then
149
+        echo "โŒ Instalarea nu poate continua - dependinศ›e lipsฤƒ"
150
+        echo "Rulaศ›i mai รฎntรขi: $0 install-deps"
151
+        exit 1
152
+    fi
153
+    
154
+    echo ""
155
+    echo "Installing AutoNAS..."
156
+
157
+    echo "๐Ÿงน Cleanup previous installation to prevent orphan files..."
158
+    if [ -f "/usr/local/lib/autonas/autonas-uninstall.sh" ]; then
159
+        echo "Previous AutoNAS installation detected. Running uninstall first..."
160
+        bash /usr/local/lib/autonas/autonas-uninstall.sh --force >/dev/null 2>&1 || true
161
+        echo "Previous installation cleaned up."
162
+    fi
163
+
164
+    echo "๐Ÿ“ Creating directories..."
165
+    mkdir -p "$CONFIG_DIR"
166
+    mkdir -p "/mnt/autonas"
167
+    echo "โœ“ Directories created"
168
+
169
+    echo "Installing AutoNAS scripts..."
170
+    mkdir -p "/usr/local/lib/autonas"
171
+
172
+    if [ -f "$SCRIPT_DIR/$UNIFIED_SCRIPT" ]; then
173
+        cp "$SCRIPT_DIR/$UNIFIED_SCRIPT" "/usr/local/bin/"
174
+        chmod +x "/usr/local/bin/$UNIFIED_SCRIPT"
175
+        echo "โœ“ Unified AutoNAS script installed"
176
+        ln -sf "/usr/local/bin/$UNIFIED_SCRIPT" "/usr/local/bin/autonas"
177
+        echo "โœ“ Created 'autonas' command symlink"
178
+    fi
179
+
180
+    if [ -f "$SCRIPT_DIR/autonas-core.sh" ]; then
181
+        cp "$SCRIPT_DIR/autonas-core.sh" "/usr/local/bin/"
182
+        chmod +x "/usr/local/bin/autonas-core.sh"
183
+        echo "โœ“ Core library installed"
184
+    fi
185
+
186
+    cp "$SCRIPT_DIR/$SCRIPT_NAME" "/usr/local/bin/"
187
+    chmod +x "/usr/local/bin/$SCRIPT_NAME"
188
+    echo "โœ“ autonas-disk-handler.sh installed"
189
+
190
+    cp "$SCRIPT_DIR/$WRAPPER_NAME" "/usr/local/bin/"
191
+    chmod +x "/usr/local/bin/$WRAPPER_NAME"
192
+    echo "โœ“ autonas-udev-wrapper.sh installed"
193
+
194
+    if [ -f "$SCRIPT_DIR/$BOOT_SCAN_SCRIPT" ]; then
195
+        cp "$SCRIPT_DIR/$BOOT_SCAN_SCRIPT" "/usr/local/bin/"
196
+        chmod +x "/usr/local/bin/$BOOT_SCAN_SCRIPT"
197
+        echo "โœ“ Boot scan script installed"
198
+    fi
199
+
200
+    if [ -f "$SCRIPT_DIR/$INTERFACE_HANDLER_SCRIPT" ]; then
201
+        cp "$SCRIPT_DIR/$INTERFACE_HANDLER_SCRIPT" "/usr/local/bin/"
202
+        chmod +x "/usr/local/bin/$INTERFACE_HANDLER_SCRIPT"
203
+        echo "โœ“ Interface handler script installed"
204
+    fi
205
+
206
+    if [ -f "$SCRIPT_DIR/$CAMERA_IMPORT_SCRIPT" ]; then
207
+        cp "$SCRIPT_DIR/$CAMERA_IMPORT_SCRIPT" "/usr/local/bin/"
208
+        chmod +x "/usr/local/bin/$CAMERA_IMPORT_SCRIPT"
209
+        echo "โœ“ Camera import script installed"
210
+    fi
211
+
212
+    echo "Installing udev rules..."
213
+    cp "$PROJECT_DIR/config/$UDEV_RULES" "/etc/udev/rules.d/"
214
+    if [ -f "$PROJECT_DIR/config/$INTERFACE_RULES" ]; then
215
+        cp "$PROJECT_DIR/config/$INTERFACE_RULES" "/etc/udev/rules.d/"
216
+        echo "โœ“ Interface monitoring udev rules installed"
217
+    fi
218
+    udevadm control --reload-rules
219
+    echo "โœ“ Udev rules installed"
220
+
221
+    echo "Installing systemd services..."
222
+    cp "$PROJECT_DIR/config/$SYSTEMD_SERVICE" "/etc/systemd/system/"
223
+    systemctl daemon-reload
224
+    echo "โœ“ Systemd service installed"
225
+
226
+    echo "Installing main AutoNAS service..."
227
+    cp "$PROJECT_DIR/config/$MAIN_SERVICE" "/etc/systemd/system/"
228
+    systemctl daemon-reload
229
+    systemctl enable autonas.service
230
+    echo "โœ“ Main AutoNAS service installed and enabled"
231
+
232
+    echo "Installing boot scan service..."
233
+    cp "$PROJECT_DIR/config/$BOOT_SCAN_SERVICE" "/etc/systemd/system/"
234
+    systemctl daemon-reload
235
+    systemctl enable autonas-boot-scan.service
236
+    echo "โœ“ Boot scan service installed and enabled"
237
+
238
+    echo "Setting up configuration..."
239
+    if [ ! -f "$CONFIG_DIR/disks.conf" ]; then
240
+        cp "$PROJECT_DIR/config/disks.conf" "$CONFIG_DIR/"
241
+        echo "โœ“ Configuration template installed"
242
+    else
243
+        echo "โš ๏ธ  Configuration file already exists, preserving user settings"
244
+        echo "   Existing file: $CONFIG_DIR/disks.conf"
245
+        echo "   Template available at: $PROJECT_DIR/config/disks.conf"
246
+        if grep -v '^#' "$CONFIG_DIR/disks.conf" | grep -v '^$' | grep -q ':'; then
247
+            echo "โœ“ User configurations detected in existing file - preserving"
248
+        else
249
+            echo "โ„น๏ธ  Existing file appears to be template only"
250
+        fi
251
+    fi
252
+
253
+    echo "Starting services..."
254
+    systemctl enable nfs-kernel-server
255
+    systemctl start nfs-kernel-server
256
+    if [ ! -f /etc/exports ]; then
257
+        touch /etc/exports
258
+    fi
259
+
260
+    echo "๐Ÿ” Setting permissions..."
261
+    if [ -f "/usr/local/bin/$UNIFIED_SCRIPT" ]; then
262
+        chown root:root "/usr/local/bin/$UNIFIED_SCRIPT"
263
+        chmod 755 "/usr/local/bin/$UNIFIED_SCRIPT"
264
+    fi
265
+    chown root:root "/usr/local/bin/$SCRIPT_NAME"
266
+    chown root:root "/usr/local/bin/$WRAPPER_NAME"
267
+    if [ -f "/usr/local/bin/$CONFIG_SCRIPT" ]; then
268
+        chown root:root "/usr/local/bin/$CONFIG_SCRIPT"
269
+    fi
270
+    if [ -f "/usr/local/bin/$BOOT_SCAN_SCRIPT" ]; then
271
+        chown root:root "/usr/local/bin/$BOOT_SCAN_SCRIPT"
272
+    fi
273
+    if [ -f "/usr/local/bin/$INTERFACE_MONITOR_SCRIPT" ]; then
274
+        chown root:root "/usr/local/bin/$INTERFACE_MONITOR_SCRIPT"
275
+    fi
276
+    if [ -f "/usr/local/bin/$INTERFACE_HANDLER_SCRIPT" ]; then
277
+        chown root:root "/usr/local/bin/$INTERFACE_HANDLER_SCRIPT"
278
+    fi
279
+    chmod 755 "/usr/local/bin/$SCRIPT_NAME"
280
+    chmod 755 "/usr/local/bin/$WRAPPER_NAME"
281
+    if [ -f "/usr/local/bin/$UNIFIED_SCRIPT" ]; then
282
+        chmod 755 "/usr/local/bin/$UNIFIED_SCRIPT"
283
+    fi
284
+    if [ -f "/usr/local/bin/$CONFIG_SCRIPT" ]; then
285
+        chmod 755 "/usr/local/bin/$CONFIG_SCRIPT"
286
+    fi
287
+    if [ -f "/usr/local/bin/$BOOT_SCAN_SCRIPT" ]; then
288
+        chmod 755 "/usr/local/bin/$BOOT_SCAN_SCRIPT"
289
+    fi
290
+    if [ -f "/usr/local/bin/$INTERFACE_MONITOR_SCRIPT" ]; then
291
+        chmod 755 "/usr/local/bin/$INTERFACE_MONITOR_SCRIPT"
292
+    fi
293
+    if [ -f "/usr/local/bin/$INTERFACE_HANDLER_SCRIPT" ]; then
294
+        chmod 755 "/usr/local/bin/$INTERFACE_HANDLER_SCRIPT"
295
+    fi
296
+    echo "โœ“ Permissions set"
297
+
298
+    echo "๐Ÿ“ Verifying installation..."
299
+    [ -f "/usr/local/bin/$SCRIPT_NAME" ] && echo "โœ“ Manager script: /usr/local/bin/$SCRIPT_NAME"
300
+    [ -f "/usr/local/bin/$WRAPPER_NAME" ] && echo "โœ“ Wrapper script: /usr/local/bin/$WRAPPER_NAME"
301
+    [ -f "/usr/local/bin/$UNIFIED_SCRIPT" ] && echo "โœ“ Unified script: /usr/local/bin/$UNIFIED_SCRIPT"
302
+    [ -f "/usr/local/bin/$CONFIG_SCRIPT" ] && echo "โœ“ Configuration script: /usr/local/bin/$CONFIG_SCRIPT"
303
+    [ -f "/usr/local/bin/$BOOT_SCAN_SCRIPT" ] && echo "โœ“ Boot scan script: /usr/local/bin/$BOOT_SCAN_SCRIPT"
304
+    [ -f "/etc/udev/rules.d/$UDEV_RULES" ] && echo "โœ“ Udev rules: /etc/udev/rules.d/$UDEV_RULES"
305
+    [ -f "/etc/systemd/system/$SYSTEMD_SERVICE" ] && echo "โœ“ Systemd service: /etc/systemd/system/$SYSTEMD_SERVICE"
306
+    [ -f "/etc/systemd/system/$MAIN_SERVICE" ] && echo "โœ“ Main AutoNAS service: /etc/systemd/system/$MAIN_SERVICE"
307
+    [ -f "/etc/systemd/system/$BOOT_SCAN_SERVICE" ] && echo "โœ“ Boot scan service: /etc/systemd/system/$BOOT_SCAN_SERVICE"
308
+    [ -f "$CONFIG_DIR/disks.conf" ] && echo "โœ“ Configuration file: $CONFIG_DIR/disks.conf"
309
+
310
+    echo "Installing uninstall script for future upgrades..."
311
+    if [ -f "$SCRIPT_DIR/autonas-uninstall.sh" ]; then
312
+        cp "$SCRIPT_DIR/autonas-uninstall.sh" "/usr/local/lib/autonas/autonas-uninstall.sh"
313
+        chmod +x "/usr/local/lib/autonas/autonas-uninstall.sh"
314
+        chown root:root "/usr/local/lib/autonas/autonas-uninstall.sh"
315
+        echo "โœ“ Uninstall script: /usr/local/lib/autonas/autonas-uninstall.sh"
316
+    else
317
+        echo "โš ๏ธ  Uninstall script not found - manual cleanup may be required for future reinstalls"
318
+    fi
319
+
320
+    echo ""
321
+    echo "๐ŸŽ‰ AutoNAS installation completed successfully!"
322
+    echo ""
323
+    echo "๐Ÿ”„ Starting services..."
324
+    if [ -n "${INTERFACE_MONITOR_SCRIPT:-}" ] && [ -f "/usr/local/bin/$INTERFACE_MONITOR_SCRIPT" ]; then
325
+        echo "๐Ÿ”„ Running initial interface IP restore..."
326
+        "/usr/local/bin/$INTERFACE_MONITOR_SCRIPT" restore || true
327
+        echo "โœ“ Initial interface restore completed"
328
+    fi
329
+
330
+    echo ""
331
+    echo "๐Ÿ“ Next steps:"
332
+    echo "1. Connect your external disks to test auto-detection"
333
+    echo "2. Use 'autonas add <UUID>' to configure detected disks"
334
+    echo "3. Monitor with: journalctl -t autonas -t autonas-wrapper -f"
335
+    echo ""
336
+    echo "๐Ÿ”ง Configuration commands:"
337
+    echo "  autonas add [UUID]     - Add new disk configuration"
338
+    echo "  autonas list           - List configured disks"
339
+    echo "  autonas test [UUID]    - Test disk configuration"
340
+    echo "  autonas remove         - Remove disk configuration"
341
+    echo ""
342
+    echo "๐Ÿ“‹ Example disk configuration:"
343
+    echo "12345678-1234-1234-1234-123456789abc:storage1:192.168.1.100:eth0:/mnt/autonas/storage1:*(rw,all_squash,insecure,async,no_subtree_check,anonuid=0,anongid=0)"
344
+    echo ""
345
+    echo "โœ… AutoNAS is ready to use!"
346
+    echo "๐Ÿ” Interface monitoring is handled automatically by udev events"
347
+}
348
+
349
+cmd="${1:-install}"
350
+case "$cmd" in
351
+    install)
352
+        do_install
353
+        ;;
354
+    install-deps)
355
+        install_dependencies
356
+        ;;
357
+    check-deps)
358
+        check_dependencies
359
+        ;;
360
+    start)
361
+        do_start
362
+        ;;
363
+    restart)
364
+        do_restart
365
+        ;;
366
+    stop)
367
+        do_stop
368
+        ;;
369
+    status)
370
+        do_status
371
+        ;;
372
+    *)
373
+        echo "Usage: $0 [install|install-deps|check-deps|start|restart|stop|status]" >&2
374
+        echo ""
375
+        echo "Commands:"
376
+        echo "  install     - Install AutoNAS (requires dependencies)"
377
+        echo "  install-deps- Install only the required dependencies"
378
+        echo "  check-deps  - Check if dependencies are installed"
379
+        echo "  start       - Start AutoNAS services"
380
+        echo "  restart     - Restart AutoNAS services"
381
+        echo "  stop        - Stop AutoNAS services"
382
+        echo "  status      - Show AutoNAS status"
383
+        exit 2
384
+        ;;
385
+esac
+231 -0
scripts/uninstall.sh
@@ -0,0 +1,231 @@
1
+#!/bin/bash
2
+
3
+# AutoNAS Uninstall Script
4
+# This script is installed on each cluster node for version-specific removal
5
+# Executed by deploy.sh or can be run directly on node: /usr/local/lib/autonas/autonas-uninstall.sh
6
+
7
+# Global configuration
8
+LOG_TAG="autonas-uninstall"
9
+
10
+set -e  # Exit on any error
11
+
12
+# Check for force flag for silent cleanup
13
+FORCE_MODE=false
14
+if [ "$1" = "--force" ]; then
15
+    FORCE_MODE=true
16
+fi
17
+
18
+# Helper function for conditional logging
19
+log_message() {
20
+    if [ "$FORCE_MODE" = false ]; then
21
+        echo "$1"
22
+    fi
23
+}
24
+
25
+CONFIG_DIR="/etc/pve/autonas"
26
+SCRIPT_NAME="autonas-disk-handler.sh"
27
+WRAPPER_NAME="autonas-udev-wrapper.sh"
28
+CONFIG_SCRIPT="autonas-config.sh"
29
+BOOT_SCAN_SCRIPT="autonas-boot-scan.sh"
30
+CAMERA_IMPORT_SCRIPT="autonas-media-importer.sh"
31
+INTERFACE_HANDLER_SCRIPT="autonas-interface-handler.sh"
32
+UNIFIED_SCRIPT="autonas.sh"
33
+UDEV_RULES="99-autonas-disk.rules"
34
+SYSTEMD_SERVICE="autonas-attach@.service"
35
+MAIN_SERVICE="autonas.service"
36
+BOOT_SCAN_SERVICE="autonas-boot-scan.service"
37
+
38
+if [ "$FORCE_MODE" = false ]; then
39
+    echo "=== AutoNAS Uninstall Script ==="
40
+    echo ""
41
+fi
42
+
43
+# Check if running as root
44
+if [ "$EUID" -ne 0 ]; then
45
+    if [ "$FORCE_MODE" = false ]; then
46
+        echo "โŒ This script must be run as root (use sudo)"
47
+    fi
48
+    exit 1
49
+fi
50
+
51
+log_message "๐Ÿ—‘๏ธ  Uninstalling AutoNAS..."
52
+log_message ""
53
+
54
+# Remove scripts
55
+log_message "Removing AutoNAS scripts..."
56
+if [ -f "/usr/local/bin/$SCRIPT_NAME" ]; then
57
+    rm "/usr/local/bin/$SCRIPT_NAME"
58
+    log_message "โœ“ Manager script removed"
59
+fi
60
+
61
+if [ -f "/usr/local/bin/$WRAPPER_NAME" ]; then
62
+    rm "/usr/local/bin/$WRAPPER_NAME"
63
+    log_message "โœ“ Wrapper script removed"
64
+fi
65
+
66
+if [ -f "/usr/local/bin/$CONFIG_SCRIPT" ]; then
67
+    rm "/usr/local/bin/$CONFIG_SCRIPT"
68
+    log_message "โœ“ Configuration script removed"
69
+fi
70
+
71
+if [ -f "/usr/local/bin/$BOOT_SCAN_SCRIPT" ]; then
72
+    rm "/usr/local/bin/$BOOT_SCAN_SCRIPT"
73
+    log_message "โœ“ Boot scan script removed"
74
+fi
75
+
76
+if [ -f "/usr/local/bin/$CAMERA_IMPORT_SCRIPT" ]; then
77
+    rm "/usr/local/bin/$CAMERA_IMPORT_SCRIPT"
78
+    log_message "โœ“ Camera import script removed"
79
+fi
80
+
81
+if [ -f "/usr/local/bin/$INTERFACE_HANDLER_SCRIPT" ]; then
82
+    rm "/usr/local/bin/$INTERFACE_HANDLER_SCRIPT"
83
+    log_message "โœ“ Interface handler script removed"
84
+fi
85
+
86
+if [ -f "/usr/local/bin/$UNIFIED_SCRIPT" ]; then
87
+    rm "/usr/local/bin/$UNIFIED_SCRIPT"
88
+    log_message "โœ“ Unified AutoNAS script removed"
89
+fi
90
+
91
+# Remove symlink
92
+if [ -L "/usr/local/bin/autonas" ]; then
93
+    rm "/usr/local/bin/autonas"
94
+    log_message "โœ“ AutoNAS symlink removed"
95
+fi
96
+
97
+# Remove internal scripts directory
98
+if [ -d "/usr/local/lib/autonas" ]; then
99
+    rm -rf "/usr/local/lib/autonas"
100
+    log_message "โœ“ AutoNAS internal scripts directory removed"
101
+fi
102
+
103
+# Aggressive cleanup for orphaned files from previous versions
104
+log_message "Cleaning up orphaned files from previous versions..."
105
+for orphan_file in "autonas-interface-debug.sh" "autonas-test-interface-stability.sh"; do
106
+    if [ -f "/usr/local/bin/$orphan_file" ]; then
107
+        rm "/usr/local/bin/$orphan_file"
108
+        log_message "โœ“ Orphaned file removed: $orphan_file"
109
+    fi
110
+done
111
+
112
+# Remove udev rules
113
+log_message "Removing udev rules..."
114
+if [ -f "/etc/udev/rules.d/$UDEV_RULES" ]; then
115
+    rm "/etc/udev/rules.d/$UDEV_RULES"
116
+    udevadm control --reload-rules
117
+    log_message "โœ“ Udev rules removed"
118
+fi
119
+
120
+# Remove systemd service
121
+log_message "Removing systemd service..."
122
+if [ -f "/etc/systemd/system/$SYSTEMD_SERVICE" ]; then
123
+    systemctl stop autonas-attach@*.service 2>/dev/null || true
124
+    systemctl disable autonas-attach@*.service 2>/dev/null || true
125
+    rm "/etc/systemd/system/$SYSTEMD_SERVICE"
126
+    systemctl daemon-reload
127
+    log_message "โœ“ Systemd service removed"
128
+fi
129
+
130
+# Remove main service
131
+log_message "Removing main AutoNAS service..."
132
+if [ -f "/etc/systemd/system/$MAIN_SERVICE" ]; then
133
+    systemctl stop autonas.service 2>/dev/null || true
134
+    systemctl disable autonas.service 2>/dev/null || true
135
+    rm "/etc/systemd/system/$MAIN_SERVICE"
136
+    systemctl daemon-reload
137
+    log_message "โœ“ Main AutoNAS service removed"
138
+fi
139
+
140
+# Remove boot scan service
141
+log_message "Removing boot scan service..."
142
+if [ -f "/etc/systemd/system/$BOOT_SCAN_SERVICE" ]; then
143
+    systemctl stop autonas-boot-scan.service 2>/dev/null || true
144
+    systemctl disable autonas-boot-scan.service 2>/dev/null || true
145
+    rm "/etc/systemd/system/$BOOT_SCAN_SERVICE"
146
+    systemctl daemon-reload
147
+    log_message "โœ“ Boot scan service removed"
148
+fi
149
+
150
+# Handle configuration and data preservation
151
+log_message ""
152
+log_message "๐Ÿ“ Handling user data..."
153
+
154
+# Check if configuration exists and has user data
155
+if [ -f "$CONFIG_DIR/disks.conf" ]; then
156
+    if grep -v '^#' "$CONFIG_DIR/disks.conf" | grep -v '^$' | grep -q ':'; then
157
+        log_message "โš ๏ธ  User configurations detected in $CONFIG_DIR/disks.conf"
158
+        log_message "   Configuration file preserved for manual cleanup"
159
+        log_message "   Remove manually with: sudo rm -rf $CONFIG_DIR"
160
+    else
161
+        log_message "โ„น๏ธ  Configuration file contains only template - removing"
162
+        rm "$CONFIG_DIR/disks.conf"
163
+        rmdir "$CONFIG_DIR" 2>/dev/null || true
164
+    fi
165
+else
166
+    log_message "โ„น๏ธ  No configuration file found"
167
+    rmdir "$CONFIG_DIR" 2>/dev/null || true
168
+fi
169
+
170
+# Check for mounted AutoNAS disks
171
+log_message ""
172
+log_message "๐Ÿ’พ Checking for mounted AutoNAS disks..."
173
+mounted_autonas=$(mount | grep "/mnt/autonas/" | wc -l)
174
+if [ $mounted_autonas -gt 0 ]; then
175
+    log_message "โš ๏ธ  Found $mounted_autonas mounted AutoNAS disk(s):"
176
+    if [ "$FORCE_MODE" = false ]; then
177
+        mount | grep "/mnt/autonas/" | while read line; do
178
+            echo "   $line"
179
+        done
180
+    fi
181
+    log_message ""
182
+    log_message "   These disks are still mounted and in use."
183
+    log_message "   Mount points preserved: /mnt/autonas/"
184
+    log_message "   Unmount manually if needed: sudo umount /mnt/autonas/*"
185
+else
186
+    log_message "โ„น๏ธ  No AutoNAS disks currently mounted"
187
+    if [ -d "/mnt/autonas" ]; then
188
+        # Only remove if empty
189
+        if [ -z "$(ls -A /mnt/autonas)" ]; then
190
+            rmdir "/mnt/autonas"
191
+            log_message "โœ“ Empty AutoNAS mount directory removed"
192
+        else
193
+            log_message "โš ๏ธ  AutoNAS mount directory contains files - preserved"
194
+        fi
195
+    fi
196
+fi
197
+
198
+# Check NFS exports
199
+log_message ""
200
+log_message "๐ŸŒ Checking NFS exports..."
201
+if [ -f "/etc/exports" ] && grep -q "/mnt/autonas/" "/etc/exports" 2>/dev/null; then
202
+    log_message "โš ๏ธ  AutoNAS NFS exports found in /etc/exports"
203
+    log_message "   Please manually remove AutoNAS entries from /etc/exports"
204
+    log_message "   And reload NFS exports: sudo exportfs -ra"
205
+else
206
+    log_message "โ„น๏ธ  No AutoNAS NFS exports found"
207
+fi
208
+
209
+log_message ""
210
+log_message "๐ŸŽ‰ AutoNAS core components removed successfully!"
211
+
212
+if [ "$FORCE_MODE" = false ]; then
213
+    echo ""
214
+    echo "๐Ÿ“‹ Summary:"
215
+    echo "โœ“ Scripts removed from /usr/local/bin/"
216
+    echo "โœ“ Udev rules removed"
217
+    echo "โœ“ Systemd services removed"
218
+    echo ""
219
+    echo "โš ๏ธ  Preserved (manual cleanup required if desired):"
220
+    echo "โ€ข User configurations: $CONFIG_DIR/ (if contains user data)"
221
+    echo "โ€ข Mount points: /mnt/autonas/ (if contains data)"
222
+    echo "โ€ข NFS exports: /etc/exports (manual edit required)"
223
+    echo ""
224
+    echo "๐Ÿ“ To completely remove all AutoNAS data:"
225
+    echo "sudo rm -rf $CONFIG_DIR"
226
+    echo "sudo rm -rf /mnt/autonas"
227
+    echo "sudo nano /etc/exports  # Remove AutoNAS entries manually"
228
+    echo "sudo exportfs -ra"
229
+fi
230
+echo ""
231
+echo "๐Ÿ”„ To reinstall AutoNAS later, run: sudo bash scripts/install.sh"
+70 -0
scripts/verify-project.sh
@@ -0,0 +1,70 @@
1
+#!/usr/bin/env bash
2
+# Quick verifier to ensure this repository contains only AutoNAS artifacts
3
+# Scans for common autoSMART markers and suspicious files.
4
+
5
+set -euo pipefail
6
+
7
+ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
8
+cd "$ROOT_DIR"
9
+
10
+echo "[verify-project] Repository: $ROOT_DIR"
11
+
12
+patterns=(
13
+  'autoSMART'
14
+  'autosmart'
15
+  'smart-collector'
16
+  'SmartCollector'
17
+  'smartctl .*postgres'  # autosmart DB pipelines pattern
18
+)
19
+
20
+exclude_dirs=(
21
+  '.git'
22
+  '.venv'
23
+  'node_modules'
24
+  'dist'
25
+  'build'
26
+)
27
+
28
+found=0
29
+
30
+# Build a find command that prunes excluded directories
31
+find_cmd=(find .)
32
+for d in "${exclude_dirs[@]}"; do
33
+  find_cmd+=( -path "*/$d/*" -prune -o )
34
+done
35
+find_cmd+=( -type f ! -path "*/scripts/verify-project.sh" -print0 )
36
+
37
+for pat in "${patterns[@]}"; do
38
+  if "${find_cmd[@]}" | xargs -0 grep -EIn --color=never "$pat" > /tmp/_verify_hits 2>/dev/null; then
39
+    if [ -s /tmp/_verify_hits ]; then
40
+      echo "[verify-project] Suspicious matches for pattern: $pat"
41
+      cat /tmp/_verify_hits
42
+      echo ""
43
+      found=1
44
+    fi
45
+  fi
46
+done
47
+
48
+rm -f /tmp/_verify_hits || true
49
+
50
+# Also check for suspicious filenames accidentally copied over
51
+suspect_files=(
52
+  'smart-collector-daemon.pl'
53
+  'deploy-production.sh'
54
+  'monitor-cluster.sh'
55
+)
56
+
57
+for name in "${suspect_files[@]}"; do
58
+  if find . -type f -name "$name" | grep -q .; then
59
+    echo "[verify-project] Suspicious file present: $name"
60
+    found=1
61
+  fi
62
+done
63
+
64
+if [ "$found" -eq 0 ]; then
65
+  echo "[verify-project] OK: No autoSMART contamination detected."
66
+  exit 0
67
+else
68
+  echo "[verify-project] WARNING: Potential contamination detected. Review above matches."
69
+  exit 2
70
+fi
+650 -0
standalone-media-importer.sh
@@ -0,0 +1,650 @@
1
+#!/bin/bash
2
+
3
+# Standalone Media Importer
4
+# Version: 1.0
5
+# A comprehensive media file organizer that sorts photos and videos by date
6
+# with various organization patterns and timezone handling
7
+
8
+VERSION="1.0"
9
+SCRIPT_NAME="Standalone Media Importer"
10
+
11
+# Default values
12
+ORGANIZATION="y"  # year/month-day_hour-minute_second.ext
13
+SOURCE_PATTERNS=()
14
+DESTINATION=""
15
+KEEP_ORIGINALS=0
16
+DRY_RUN=0
17
+VERBOSE=0
18
+
19
+# Counters and statistics
20
+TOTAL_FILES=0
21
+PROCESSED_FILES=0
22
+SKIPPED_FILES=0
23
+ERROR_FILES=0
24
+TOTAL_SIZE=0
25
+PROCESSED_SIZE=0
26
+START_TIME=$(date +%s)
27
+
28
+# Colors for output
29
+RED='\033[0;31m'
30
+GREEN='\033[0;32m'
31
+YELLOW='\033[1;33m'
32
+BLUE='\033[0;34m'
33
+NC='\033[0m' # No Color
34
+
35
+# Function to print colored output
36
+print_color() {
37
+    local color="$1"
38
+    local message="$2"
39
+    echo -e "${color}${message}${NC}"
40
+}
41
+
42
+# Function to log messages with timestamp
43
+log_message() {
44
+    local message="$1"
45
+    local level="${2:-INFO}"
46
+    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
47
+    
48
+    case "$level" in
49
+        "ERROR")
50
+            print_color "$RED" "[$timestamp] ERROR: $message" >&2
51
+            ;;
52
+        "WARNING")
53
+            print_color "$YELLOW" "[$timestamp] WARNING: $message"
54
+            ;;
55
+        "SUCCESS")
56
+            print_color "$GREEN" "[$timestamp] SUCCESS: $message"
57
+            ;;
58
+        "INFO")
59
+            if [[ $VERBOSE -eq 1 ]]; then
60
+                print_color "$BLUE" "[$timestamp] INFO: $message"
61
+            fi
62
+            ;;
63
+        *)
64
+            echo "[$timestamp] $message"
65
+            ;;
66
+    esac
67
+}
68
+
69
+# Function to display help
70
+show_help() {
71
+    cat << EOF
72
+$SCRIPT_NAME v$VERSION
73
+
74
+USAGE:
75
+    $0 [OPTIONS]
76
+
77
+DESCRIPTION:
78
+    Organizes media files (photos and videos) by date with various naming patterns.
79
+    Handles timezone conversion for QuickTime files and preserves original timestamps.
80
+
81
+OPTIONS:
82
+    -o, --organization PATTERN
83
+        Organization pattern (default: y):
84
+        y -> target/yyyy/mm-dd_hh-mm-ss.orig_ext
85
+        m -> target/yyyy/mm/dd_hh-mm-ss.orig_ext  
86
+        d -> target/yyyy/mm/dd/mm-dd_hh-mm-ss.orig_ext
87
+        h -> target/yyyy/mm/dd/hh/mm-ss.orig_ext
88
+
89
+    -s, --source PATTERN
90
+        Source folder pattern(s) with simple regex support (*^$)
91
+        Can be specified multiple times
92
+        Examples:
93
+            -s "/DCIM/*Video$"
94
+            -s "/path/to/photos"
95
+            -s "*.jpg"
96
+        Default: all subfolders in current directory except destination
97
+
98
+    -d, --destination PATH
99
+        Destination folder (default: ./sorted)
100
+
101
+    -k, --keep-originals
102
+        Keep original files (copy instead of move)
103
+
104
+    --dry-run
105
+        Show what would be done without actually doing it
106
+
107
+    -v, --verbose
108
+        Enable verbose output
109
+
110
+    -h, --help
111
+        Show this help message
112
+
113
+    --version
114
+        Show version information
115
+
116
+EXAMPLES:
117
+    # Basic usage - organize all media in current directory
118
+    $0
119
+
120
+    # Organize with monthly folders, keep originals
121
+    $0 -o m -k
122
+
123
+    # Process specific folders with hourly organization
124
+    $0 -o h -s "/DCIM/Camera" -s "/DCIM/Video" -d "/media/sorted"
125
+
126
+    # Dry run with verbose output
127
+    $0 --dry-run -v -s "*.mov" -d "/tmp/test"
128
+
129
+DEPENDENCIES:
130
+    Required: exiftool
131
+    Optional: mediainfo, file (for enhanced metadata detection)
132
+
133
+EOF
134
+}
135
+
136
+# Function to show version
137
+show_version() {
138
+    echo "$SCRIPT_NAME v$VERSION"
139
+    echo "A comprehensive media file organizer with timezone support"
140
+}
141
+
142
+# Function to check dependencies
143
+check_dependencies() {
144
+    local missing_deps=()
145
+    
146
+    # Check for required dependencies
147
+    if ! command -v exiftool &> /dev/null; then
148
+        missing_deps+=("exiftool")
149
+    fi
150
+    
151
+    # Check for optional dependencies
152
+    local optional_missing=()
153
+    if ! command -v mediainfo &> /dev/null; then
154
+        optional_missing+=("mediainfo")
155
+    fi
156
+    
157
+    if ! command -v file &> /dev/null; then
158
+        optional_missing+=("file")
159
+    fi
160
+    
161
+    if [[ ${#missing_deps[@]} -gt 0 ]]; then
162
+        print_color "$RED" "ERROR: Missing required dependencies:"
163
+        for dep in "${missing_deps[@]}"; do
164
+            echo "  - $dep"
165
+        done
166
+        echo ""
167
+        echo "Installation instructions:"
168
+        echo "  macOS: brew install exiftool"
169
+        echo "  Ubuntu/Debian: sudo apt-get install libimage-exiftool-perl"
170
+        echo "  CentOS/RHEL: sudo yum install perl-Image-ExifTool"
171
+        echo "  Arch: sudo pacman -S perl-image-exiftool"
172
+        exit 1
173
+    fi
174
+    
175
+    if [[ ${#optional_missing[@]} -gt 0 && $VERBOSE -eq 1 ]]; then
176
+        log_message "Optional dependencies not found (functionality may be limited): ${optional_missing[*]}" "WARNING"
177
+    fi
178
+    
179
+    log_message "All required dependencies found" "SUCCESS"
180
+}
181
+
182
+# Function to get file size in bytes
183
+get_file_size() {
184
+    local file="$1"
185
+    if [[ -f "$file" ]]; then
186
+        if command -v stat &> /dev/null; then
187
+            # Try GNU stat first (Linux)
188
+            stat -c%s "$file" 2>/dev/null || stat -f%z "$file" 2>/dev/null
189
+        else
190
+            # Fallback to ls
191
+            ls -l "$file" | awk '{print $5}'
192
+        fi
193
+    else
194
+        echo "0"
195
+    fi
196
+}
197
+
198
+# Function to format file size
199
+format_size() {
200
+    local size=$1
201
+    if (( size < 1024 )); then
202
+        echo "${size}B"
203
+    elif (( size < 1048576 )); then
204
+        echo "$(( size / 1024 ))KB"
205
+    elif (( size < 1073741824 )); then
206
+        echo "$(( size / 1048576 ))MB"
207
+    else
208
+        echo "$(( size / 1073741824 ))GB"
209
+    fi
210
+}
211
+
212
+# Function to extract date from file
213
+extract_file_date() {
214
+    local file="$1"
215
+    local create_date=""
216
+    local date_source=""
217
+    
218
+    # Try to get creation date from EXIF data
219
+    local exif_output=$(exiftool -G1 -s -CreateDate -DateTimeOriginal -DateTime "$file" 2>/dev/null)
220
+    
221
+    if [[ -n "$exif_output" ]]; then
222
+        # Parse the exiftool output to find the best date
223
+        while IFS= read -r line; do
224
+            if [[ "$line" =~ ^\[([^\]]+)\][[:space:]]*([^:]+):[[:space:]]*(.+)$ ]]; then
225
+                local group="${BASH_REMATCH[1]}"
226
+                local tag="${BASH_REMATCH[2]}"
227
+                local value="${BASH_REMATCH[3]}"
228
+                
229
+                # Prefer DateTimeOriginal, then CreateDate, then DateTime
230
+                if [[ "$tag" == "DateTimeOriginal" && -z "$create_date" ]]; then
231
+                    create_date="$value"
232
+                    date_source="$group:$tag"
233
+                elif [[ "$tag" == "CreateDate" && "$date_source" != *"DateTimeOriginal"* ]]; then
234
+                    create_date="$value"
235
+                    date_source="$group:$tag"
236
+                elif [[ "$tag" == "DateTime" && -z "$create_date" ]]; then
237
+                    create_date="$value"
238
+                    date_source="$group:$tag"
239
+                fi
240
+            fi
241
+        done <<< "$exif_output"
242
+    fi
243
+    
244
+    # If no EXIF date found, try mediainfo for video files
245
+    if [[ -z "$create_date" ]] && command -v mediainfo &> /dev/null; then
246
+        local media_date=$(mediainfo --Inform="General;%Recorded_Date%" "$file" 2>/dev/null)
247
+        if [[ -n "$media_date" && "$media_date" != "0000-00-00 00:00:00" ]]; then
248
+            create_date="$media_date"
249
+            date_source="MediaInfo:Recorded_Date"
250
+        fi
251
+    fi
252
+    
253
+    # Fallback to file modification time
254
+    if [[ -z "$create_date" ]]; then
255
+        if [[ "$OSTYPE" == "darwin"* ]]; then
256
+            # macOS
257
+            create_date=$(stat -f "%Sm" -t "%Y:%m:%d %H:%M:%S" "$file" 2>/dev/null)
258
+        else
259
+            # Linux
260
+            create_date=$(date -r "$file" "+%Y:%m:%d %H:%M:%S" 2>/dev/null)
261
+        fi
262
+        date_source="FileSystem:ModificationTime"
263
+    fi
264
+    
265
+    if [[ -z "$create_date" ]]; then
266
+        return 1
267
+    fi
268
+    
269
+    # Convert EXIF format (YYYY:MM:DD HH:MM:SS) to standard format
270
+    create_date=$(echo "$create_date" | sed 's/^\([0-9]\{4\}\):\([0-9]\{2\}\):\([0-9]\{2\}\)/\1-\2-\3/')
271
+    
272
+    # Handle QuickTime UTC conversion
273
+    if [[ "$date_source" == *"QuickTime"* ]]; then
274
+        local utc_timestamp=$(date -d "$create_date UTC" "+%s" 2>/dev/null)
275
+        if [[ -n "$utc_timestamp" ]]; then
276
+            create_date=$(date -d "@$utc_timestamp" "+%Y-%m-%d %H:%M:%S" 2>/dev/null)
277
+            date_source="$date_source (converted from UTC)"
278
+        fi
279
+    fi
280
+    
281
+    echo "$create_date|$date_source"
282
+    return 0
283
+}
284
+
285
+# Function to generate destination path based on organization pattern
286
+generate_destination_path() {
287
+    local date_str="$1"
288
+    local original_filename="$2"
289
+    local base_destination="$3"
290
+    
291
+    # Extract date components
292
+    local year=$(date -d "$date_str" "+%Y" 2>/dev/null)
293
+    local month=$(date -d "$date_str" "+%m" 2>/dev/null)
294
+    local day=$(date -d "$date_str" "+%d" 2>/dev/null)
295
+    local hour=$(date -d "$date_str" "+%H" 2>/dev/null)
296
+    local minute=$(date -d "$date_str" "+%M" 2>/dev/null)
297
+    local second=$(date -d "$date_str" "+%S" 2>/dev/null)
298
+    
299
+    if [[ -z "$year" || -z "$month" || -z "$day" ]]; then
300
+        return 1
301
+    fi
302
+    
303
+    # Get file extension
304
+    local extension="${original_filename##*.}"
305
+    local lowercase_ext="${extension,,}"
306
+    
307
+    # Generate path and filename based on organization pattern
308
+    local dir_path=""
309
+    local filename=""
310
+    
311
+    case "$ORGANIZATION" in
312
+        "y")
313
+            # target/yyyy/mm-dd_hh-mm-ss.orig_ext
314
+            dir_path="$base_destination/$year"
315
+            filename="${month}-${day}_${hour}-${minute}-${second}.${lowercase_ext}"
316
+            ;;
317
+        "m")
318
+            # target/yyyy/mm/dd_hh-mm-ss.orig_ext
319
+            dir_path="$base_destination/$year/$month"
320
+            filename="${day}_${hour}-${minute}-${second}.${lowercase_ext}"
321
+            ;;
322
+        "d")
323
+            # target/yyyy/mm/dd/mm-dd_hh-mm-ss.orig_ext
324
+            dir_path="$base_destination/$year/$month/$day"
325
+            filename="${month}-${day}_${hour}-${minute}-${second}.${lowercase_ext}"
326
+            ;;
327
+        "h")
328
+            # target/yyyy/mm/dd/hh/mm-ss.orig_ext
329
+            dir_path="$base_destination/$year/$month/$day/$hour"
330
+            filename="${minute}-${second}.${lowercase_ext}"
331
+            ;;
332
+        *)
333
+            log_message "Invalid organization pattern: $ORGANIZATION" "ERROR"
334
+            return 1
335
+            ;;
336
+    esac
337
+    
338
+    echo "$dir_path/$filename"
339
+    return 0
340
+}
341
+
342
+# Function to find files matching patterns
343
+find_source_files() {
344
+    local files=()
345
+    
346
+    if [[ ${#SOURCE_PATTERNS[@]} -eq 0 ]]; then
347
+        # Default: find all media files in current directory and subdirectories
348
+        # Exclude destination directory if it's a subdirectory of current directory
349
+        local find_cmd="find . -type f"
350
+        
351
+        # Add exclusion for destination if it's relative to current directory
352
+        if [[ "$DESTINATION" =~ ^\./.*$ ]] || [[ "$DESTINATION" =~ ^[^/].*$ ]]; then
353
+            local abs_dest=$(cd "$DESTINATION" 2>/dev/null && pwd)
354
+            local abs_current=$(pwd)
355
+            if [[ "$abs_dest" == "$abs_current"* ]]; then
356
+                find_cmd="$find_cmd ! -path \"$DESTINATION/*\""
357
+            fi
358
+        fi
359
+        
360
+        # Add media file extensions
361
+        local extensions=("*.jpg" "*.jpeg" "*.png" "*.tiff" "*.tif" "*.cr2" "*.nef" "*.arw" "*.dng" "*.raw" "*.mp4" "*.mov" "*.avi" "*.mts" "*.m2ts" "*.mkv" "*.wmv" "*.3gp" "*.m4v")
362
+        local ext_pattern=""
363
+        for ext in "${extensions[@]}"; do
364
+            if [[ -n "$ext_pattern" ]]; then
365
+                ext_pattern="$ext_pattern -o"
366
+            fi
367
+            ext_pattern="$ext_pattern -iname $ext"
368
+        done
369
+        
370
+        eval "$find_cmd \\( $ext_pattern \\)" | while IFS= read -r file; do
371
+            echo "$file"
372
+        done
373
+    else
374
+        # Use specified patterns
375
+        for pattern in "${SOURCE_PATTERNS[@]}"; do
376
+            # Handle different pattern types
377
+            if [[ -d "$pattern" ]]; then
378
+                # Directory pattern
379
+                find "$pattern" -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.tiff" -o -iname "*.tif" -o -iname "*.cr2" -o -iname "*.nef" -o -iname "*.arw" -o -iname "*.dng" -o -iname "*.raw" -o -iname "*.mp4" -o -iname "*.mov" -o -iname "*.avi" -o -iname "*.mts" -o -iname "*.m2ts" -o -iname "*.mkv" -o -iname "*.wmv" -o -iname "*.3gp" -o -iname "*.m4v" \) 2>/dev/null
380
+            elif [[ "$pattern" == *"*"* ]] || [[ "$pattern" == *"?"* ]]; then
381
+                # Glob pattern
382
+                for file in $pattern; do
383
+                    if [[ -f "$file" ]]; then
384
+                        echo "$file"
385
+                    fi
386
+                done
387
+            else
388
+                # Exact file or directory
389
+                if [[ -f "$pattern" ]]; then
390
+                    echo "$pattern"
391
+                elif [[ -d "$pattern" ]]; then
392
+                    find "$pattern" -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.tiff" -o -iname "*.tif" -o -iname "*.cr2" -o -iname "*.nef" -o -iname "*.arw" -o -iname "*.dng" -o -iname "*.raw" -o -iname "*.mp4" -o -iname "*.mov" -o -iname "*.avi" -o -iname "*.mts" -o -iname "*.m2ts" -o -iname "*.mkv" -o -iname "*.wmv" -o -iname "*.3gp" -o -iname "*.m4v" \) 2>/dev/null
393
+                fi
394
+            fi
395
+        done
396
+    fi
397
+}
398
+
399
+# Function to process a single file
400
+process_file() {
401
+    local file="$1"
402
+    local file_size=$(get_file_size "$file")
403
+    TOTAL_SIZE=$((TOTAL_SIZE + file_size))
404
+    
405
+    log_message "Processing: $file" "INFO"
406
+    
407
+    # Extract date information
408
+    local date_info=$(extract_file_date "$file")
409
+    if [[ $? -ne 0 ]] || [[ -z "$date_info" ]]; then
410
+        log_message "Could not extract date from $file - skipping" "WARNING"
411
+        SKIPPED_FILES=$((SKIPPED_FILES + 1))
412
+        return 1
413
+    fi
414
+    
415
+    local date_str="${date_info%|*}"
416
+    local date_source="${date_info#*|}"
417
+    
418
+    log_message "Date: $date_str (from $date_source)" "INFO"
419
+    
420
+    # Generate destination path
421
+    local dest_path=$(generate_destination_path "$date_str" "$(basename "$file")" "$DESTINATION")
422
+    if [[ $? -ne 0 ]] || [[ -z "$dest_path" ]]; then
423
+        log_message "Could not generate destination path for $file" "ERROR"
424
+        ERROR_FILES=$((ERROR_FILES + 1))
425
+        return 1
426
+    fi
427
+    
428
+    # Handle filename conflicts
429
+    local counter=1
430
+    local original_dest_path="$dest_path"
431
+    while [[ -f "$dest_path" ]]; do
432
+        local dir_path=$(dirname "$original_dest_path")
433
+        local filename=$(basename "$original_dest_path")
434
+        local name_without_ext="${filename%.*}"
435
+        local ext="${filename##*.}"
436
+        dest_path="$dir_path/${name_without_ext}_${counter}.${ext}"
437
+        counter=$((counter + 1))
438
+    done
439
+    
440
+    local dest_dir=$(dirname "$dest_path")
441
+    
442
+    if [[ $DRY_RUN -eq 1 ]]; then
443
+        if [[ $KEEP_ORIGINALS -eq 1 ]]; then
444
+            print_color "$BLUE" "Would copy: $file -> $dest_path"
445
+        else
446
+            print_color "$BLUE" "Would move: $file -> $dest_path"
447
+        fi
448
+        PROCESSED_FILES=$((PROCESSED_FILES + 1))
449
+        PROCESSED_SIZE=$((PROCESSED_SIZE + file_size))
450
+        return 0
451
+    fi
452
+    
453
+    # Create destination directory
454
+    if ! mkdir -p "$dest_dir"; then
455
+        log_message "Could not create directory: $dest_dir" "ERROR"
456
+        ERROR_FILES=$((ERROR_FILES + 1))
457
+        return 1
458
+    fi
459
+    
460
+    # Copy or move file
461
+    if [[ $KEEP_ORIGINALS -eq 1 ]]; then
462
+        if cp "$file" "$dest_path"; then
463
+            log_message "Copied: $file -> $dest_path" "SUCCESS"
464
+            PROCESSED_FILES=$((PROCESSED_FILES + 1))
465
+            PROCESSED_SIZE=$((PROCESSED_SIZE + file_size))
466
+            return 0
467
+        else
468
+            log_message "Failed to copy: $file" "ERROR"
469
+            ERROR_FILES=$((ERROR_FILES + 1))
470
+            return 1
471
+        fi
472
+    else
473
+        if mv "$file" "$dest_path"; then
474
+            log_message "Moved: $file -> $dest_path" "SUCCESS"
475
+            PROCESSED_FILES=$((PROCESSED_FILES + 1))
476
+            PROCESSED_SIZE=$((PROCESSED_SIZE + file_size))
477
+            return 0
478
+        else
479
+            log_message "Failed to move: $file" "ERROR"
480
+            ERROR_FILES=$((ERROR_FILES + 1))
481
+            return 1
482
+        fi
483
+    fi
484
+}
485
+
486
+# Function to display final report
487
+show_report() {
488
+    local end_time=$(date +%s)
489
+    local elapsed_time=$((end_time - START_TIME))
490
+    local hours=$((elapsed_time / 3600))
491
+    local minutes=$(((elapsed_time % 3600) / 60))
492
+    local seconds=$((elapsed_time % 60))
493
+    
494
+    echo ""
495
+    print_color "$GREEN" "=========================================="
496
+    print_color "$GREEN" "           PROCESSING REPORT"
497
+    print_color "$GREEN" "=========================================="
498
+    echo ""
499
+    
500
+    echo "Files Summary:"
501
+    echo "  Total files found:     $TOTAL_FILES"
502
+    echo "  Successfully processed: $PROCESSED_FILES"
503
+    echo "  Skipped (no date):     $SKIPPED_FILES"
504
+    echo "  Errors:                $ERROR_FILES"
505
+    echo ""
506
+    
507
+    echo "Size Summary:"
508
+    echo "  Total size found:      $(format_size $TOTAL_SIZE)"
509
+    echo "  Successfully processed: $(format_size $PROCESSED_SIZE)"
510
+    echo ""
511
+    
512
+    echo "Time Summary:"
513
+    printf "  Time elapsed:          %02d:%02d:%02d\n" $hours $minutes $seconds
514
+    
515
+    if [[ $elapsed_time -gt 0 && $PROCESSED_FILES -gt 0 ]]; then
516
+        local files_per_second=$((PROCESSED_FILES / elapsed_time))
517
+        local mb_per_second=$((PROCESSED_SIZE / elapsed_time / 1048576))
518
+        echo "  Speed:                 $files_per_second files/sec, ${mb_per_second}MB/sec"
519
+    fi
520
+    
521
+    echo ""
522
+    
523
+    if [[ $DRY_RUN -eq 1 ]]; then
524
+        print_color "$YELLOW" "DRY RUN MODE - No files were actually moved/copied"
525
+    elif [[ $KEEP_ORIGINALS -eq 1 ]]; then
526
+        print_color "$BLUE" "COPY MODE - Original files were preserved"
527
+    else
528
+        print_color "$GREEN" "MOVE MODE - Files were moved to destination"
529
+    fi
530
+    
531
+    echo ""
532
+    print_color "$GREEN" "=========================================="
533
+}
534
+
535
+# Parse command line arguments
536
+while [[ $# -gt 0 ]]; do
537
+    case $1 in
538
+        -o|--organization)
539
+            ORGANIZATION="$2"
540
+            if [[ ! "$ORGANIZATION" =~ ^[ymdh]$ ]]; then
541
+                print_color "$RED" "Error: Invalid organization pattern. Must be one of: y, m, d, h"
542
+                exit 1
543
+            fi
544
+            shift 2
545
+            ;;
546
+        -s|--source)
547
+            SOURCE_PATTERNS+=("$2")
548
+            shift 2
549
+            ;;
550
+        -d|--destination)
551
+            DESTINATION="$2"
552
+            shift 2
553
+            ;;
554
+        -k|--keep-originals)
555
+            KEEP_ORIGINALS=1
556
+            shift
557
+            ;;
558
+        --dry-run)
559
+            DRY_RUN=1
560
+            shift
561
+            ;;
562
+        -v|--verbose)
563
+            VERBOSE=1
564
+            shift
565
+            ;;
566
+        -h|--help)
567
+            show_help
568
+            exit 0
569
+            ;;
570
+        --version)
571
+            show_version
572
+            exit 0
573
+            ;;
574
+        *)
575
+            print_color "$RED" "Error: Unknown option: $1"
576
+            echo "Use -h or --help for usage information."
577
+            exit 1
578
+            ;;
579
+    esac
580
+done
581
+
582
+# Set default destination if not specified
583
+if [[ -z "$DESTINATION" ]]; then
584
+    DESTINATION="./sorted"
585
+fi
586
+
587
+# Convert destination to absolute path
588
+DESTINATION=$(cd "$(dirname "$DESTINATION")" 2>/dev/null && pwd)/$(basename "$DESTINATION") || DESTINATION=$(realpath "$DESTINATION" 2>/dev/null) || DESTINATION="$DESTINATION"
589
+
590
+# Display configuration
591
+print_color "$GREEN" "$SCRIPT_NAME v$VERSION"
592
+echo ""
593
+echo "Configuration:"
594
+echo "  Organization pattern: $ORGANIZATION"
595
+echo "  Destination:         $DESTINATION"
596
+echo "  Keep originals:      $([ $KEEP_ORIGINALS -eq 1 ] && echo "Yes" || echo "No")"
597
+echo "  Dry run:             $([ $DRY_RUN -eq 1 ] && echo "Yes" || echo "No")"
598
+echo "  Verbose:             $([ $VERBOSE -eq 1 ] && echo "Yes" || echo "No")"
599
+
600
+if [[ ${#SOURCE_PATTERNS[@]} -gt 0 ]]; then
601
+    echo "  Source patterns:"
602
+    for pattern in "${SOURCE_PATTERNS[@]}"; do
603
+        echo "    - $pattern"
604
+    done
605
+else
606
+    echo "  Source patterns:     All media files in current directory"
607
+fi
608
+
609
+echo ""
610
+
611
+# Check dependencies
612
+check_dependencies
613
+
614
+# Create destination directory if it doesn't exist (unless dry run)
615
+if [[ $DRY_RUN -eq 0 ]]; then
616
+    if ! mkdir -p "$DESTINATION"; then
617
+        print_color "$RED" "Error: Cannot create destination directory: $DESTINATION"
618
+        exit 1
619
+    fi
620
+fi
621
+
622
+# Find all source files
623
+print_color "$BLUE" "Scanning for media files..."
624
+mapfile -t files < <(find_source_files)
625
+TOTAL_FILES=${#files[@]}
626
+
627
+if [[ $TOTAL_FILES -eq 0 ]]; then
628
+    print_color "$YELLOW" "No media files found matching the specified patterns."
629
+    exit 0
630
+fi
631
+
632
+print_color "$BLUE" "Found $TOTAL_FILES media files to process"
633
+echo ""
634
+
635
+# Process each file
636
+for file in "${files[@]}"; do
637
+    if [[ -f "$file" ]]; then
638
+        process_file "$file"
639
+    fi
640
+done
641
+
642
+# Show final report
643
+show_report
644
+
645
+# Exit with appropriate code
646
+if [[ $ERROR_FILES -gt 0 ]]; then
647
+    exit 1
648
+else
649
+    exit 0
650
+fi