eg.wakeonlan 1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- eg_wakeonlan-1.1/LICENSE.txt +27 -0
- eg_wakeonlan-1.1/PKG-INFO +105 -0
- eg_wakeonlan-1.1/README.md +74 -0
- eg_wakeonlan-1.1/pyproject.toml +67 -0
- eg_wakeonlan-1.1/setup.cfg +4 -0
- eg_wakeonlan-1.1/src/eg.wakeonlan.egg-info/PKG-INFO +105 -0
- eg_wakeonlan-1.1/src/eg.wakeonlan.egg-info/SOURCES.txt +13 -0
- eg_wakeonlan-1.1/src/eg.wakeonlan.egg-info/dependency_links.txt +1 -0
- eg_wakeonlan-1.1/src/eg.wakeonlan.egg-info/entry_points.txt +2 -0
- eg_wakeonlan-1.1/src/eg.wakeonlan.egg-info/top_level.txt +1 -0
- eg_wakeonlan-1.1/src/wakeonlan/__init__.py +8 -0
- eg_wakeonlan-1.1/src/wakeonlan/__main__.py +9 -0
- eg_wakeonlan-1.1/src/wakeonlan/py.typed +0 -0
- eg_wakeonlan-1.1/src/wakeonlan/wakeonlan.py +275 -0
- eg_wakeonlan-1.1/tests/test_wakeonlan.py +17 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
Copyright (c) 2018, Eugene Gershnik
|
|
2
|
+
All rights reserved.
|
|
3
|
+
|
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
|
6
|
+
|
|
7
|
+
* Redistributions of source code must retain the above copyright notice, this
|
|
8
|
+
list of conditions and the following disclaimer.
|
|
9
|
+
|
|
10
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
|
11
|
+
this list of conditions and the following disclaimer in the documentation
|
|
12
|
+
and/or other materials provided with the distribution.
|
|
13
|
+
|
|
14
|
+
* Neither the name of the copyright holder nor the names of its
|
|
15
|
+
contributors may be used to endorse or promote products derived from
|
|
16
|
+
this software without specific prior written permission.
|
|
17
|
+
|
|
18
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
19
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
20
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
21
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
22
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
23
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
24
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
25
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
26
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
27
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: eg.wakeonlan
|
|
3
|
+
Version: 1.1
|
|
4
|
+
Summary: Yet another wake-on-lan library
|
|
5
|
+
Author-email: Eugene Gershnik <gershnik@hotmail.com>
|
|
6
|
+
License: BSD-3-Clause
|
|
7
|
+
Project-URL: Homepage, https://github.com/gershnik/wakeonlan
|
|
8
|
+
Keywords: wakeonlan
|
|
9
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
10
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
11
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
12
|
+
Classifier: Operating System :: Microsoft
|
|
13
|
+
Classifier: Operating System :: POSIX
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
16
|
+
Classifier: Intended Audience :: System Administrators
|
|
17
|
+
Classifier: Topic :: System
|
|
18
|
+
Classifier: Topic :: System :: Networking
|
|
19
|
+
Classifier: Programming Language :: Python
|
|
20
|
+
Classifier: Programming Language :: Python :: 3
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
26
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
27
|
+
Classifier: Typing :: Typed
|
|
28
|
+
Requires-Python: >=3.7
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
License-File: LICENSE.txt
|
|
31
|
+
|
|
32
|
+
# wakeonlan #
|
|
33
|
+
|
|
34
|
+
Yet another wake-on-lan command line script.
|
|
35
|
+
|
|
36
|
+
## Why another one?
|
|
37
|
+
|
|
38
|
+
I couldn't find one that worked and did what I need. Specifically I need:
|
|
39
|
+
* A command line utility that works on Mac, Windows and Linux
|
|
40
|
+
* Can use saved configurations rather than force me to remember the MAC addresses of the machines I need to wake.
|
|
41
|
+
* Ideally, let me manipulate (create, delete, update, list) saved configurations using the same utility.
|
|
42
|
+
* Ideally, be open source so I can see what it is doing and know it doesn't do anything nefarious
|
|
43
|
+
|
|
44
|
+
None of the existing tools I found satisfied these criteria (even without the last two) so I wrote my own.
|
|
45
|
+
|
|
46
|
+
### Pre-requisites
|
|
47
|
+
|
|
48
|
+
Python 3.7 or above. No additional packages required.
|
|
49
|
+
|
|
50
|
+
### Installation
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip3 install eg.wakeonlan
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Usage
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
#### Wake up a machine given its MAC address XX:XX:XX:XX:XX:XX
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
wakeonlan XX:XX:XX:XX:XX:XX [-a BroadcastAddress] [-p Port]
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
If not specified BroadcastAddress is 255.255.255.255 and Port is 9
|
|
66
|
+
|
|
67
|
+
#### Save wake up configuration to be used later
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
wakeonlan --save Name XX:XX:XX:XX:XX:XX [-a BroadcastAddress] [-p Port]
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Name can be anything. The configuration is saved into `$HOME/.wakeonlan` file in JSON format
|
|
74
|
+
--save can be abbreviated as -s
|
|
75
|
+
|
|
76
|
+
#### Wake up a machine given saved configuration name
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
wakeonlan Name
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
#### List existing configuration names
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
wakeonlan --list
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
`--list` can be abbreviated as `-l`
|
|
89
|
+
|
|
90
|
+
#### Delete a configuration
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
wakeonlan --delete Name
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`--delete` can be abbreviated as `-d`
|
|
97
|
+
|
|
98
|
+
### Transferring configurations to another machine
|
|
99
|
+
|
|
100
|
+
Saved configurations are stored in `$HOME/.wakeonlan` file (`%USERPROFILE%\.wakeonlan` for Windows users).
|
|
101
|
+
Copy this file to another machine into equivalent location to transfer all the configurations.
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# wakeonlan #
|
|
2
|
+
|
|
3
|
+
Yet another wake-on-lan command line script.
|
|
4
|
+
|
|
5
|
+
## Why another one?
|
|
6
|
+
|
|
7
|
+
I couldn't find one that worked and did what I need. Specifically I need:
|
|
8
|
+
* A command line utility that works on Mac, Windows and Linux
|
|
9
|
+
* Can use saved configurations rather than force me to remember the MAC addresses of the machines I need to wake.
|
|
10
|
+
* Ideally, let me manipulate (create, delete, update, list) saved configurations using the same utility.
|
|
11
|
+
* Ideally, be open source so I can see what it is doing and know it doesn't do anything nefarious
|
|
12
|
+
|
|
13
|
+
None of the existing tools I found satisfied these criteria (even without the last two) so I wrote my own.
|
|
14
|
+
|
|
15
|
+
### Pre-requisites
|
|
16
|
+
|
|
17
|
+
Python 3.7 or above. No additional packages required.
|
|
18
|
+
|
|
19
|
+
### Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip3 install eg.wakeonlan
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Usage
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
#### Wake up a machine given its MAC address XX:XX:XX:XX:XX:XX
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
wakeonlan XX:XX:XX:XX:XX:XX [-a BroadcastAddress] [-p Port]
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
If not specified BroadcastAddress is 255.255.255.255 and Port is 9
|
|
35
|
+
|
|
36
|
+
#### Save wake up configuration to be used later
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
wakeonlan --save Name XX:XX:XX:XX:XX:XX [-a BroadcastAddress] [-p Port]
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Name can be anything. The configuration is saved into `$HOME/.wakeonlan` file in JSON format
|
|
43
|
+
--save can be abbreviated as -s
|
|
44
|
+
|
|
45
|
+
#### Wake up a machine given saved configuration name
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
wakeonlan Name
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
#### List existing configuration names
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
wakeonlan --list
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`--list` can be abbreviated as `-l`
|
|
58
|
+
|
|
59
|
+
#### Delete a configuration
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
wakeonlan --delete Name
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`--delete` can be abbreviated as `-d`
|
|
66
|
+
|
|
67
|
+
### Transferring configurations to another machine
|
|
68
|
+
|
|
69
|
+
Saved configurations are stored in `$HOME/.wakeonlan` file (`%USERPROFILE%\.wakeonlan` for Windows users).
|
|
70
|
+
Copy this file to another machine into equivalent location to transfer all the configurations.
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Copyright (c) 2018, Eugene Gershnik
|
|
2
|
+
# Use of this source code is governed by a BSD-style
|
|
3
|
+
# license that can be found in the LICENSE.txt file or at
|
|
4
|
+
# https://opensource.org/licenses/BSD-3-Clause
|
|
5
|
+
|
|
6
|
+
[build-system]
|
|
7
|
+
requires = [
|
|
8
|
+
"setuptools>=61"
|
|
9
|
+
]
|
|
10
|
+
build-backend = "setuptools.build_meta"
|
|
11
|
+
|
|
12
|
+
[tool.setuptools]
|
|
13
|
+
include-package-data = false
|
|
14
|
+
|
|
15
|
+
[tool.setuptools.dynamic]
|
|
16
|
+
version = {attr = "wakeonlan.__version__"}
|
|
17
|
+
|
|
18
|
+
[tool.setuptools.packages.find]
|
|
19
|
+
where = ["src"]
|
|
20
|
+
|
|
21
|
+
[project]
|
|
22
|
+
name = "eg.wakeonlan"
|
|
23
|
+
dynamic = ["version"]
|
|
24
|
+
description="Yet another wake-on-lan library"
|
|
25
|
+
readme="README.md"
|
|
26
|
+
authors= [
|
|
27
|
+
{ name = 'Eugene Gershnik', email='gershnik@hotmail.com'}
|
|
28
|
+
]
|
|
29
|
+
requires-python = ">=3.7"
|
|
30
|
+
keywords = ["wakeonlan"]
|
|
31
|
+
license = {text = "BSD-3-Clause"}
|
|
32
|
+
classifiers = [
|
|
33
|
+
"Development Status :: 5 - Production/Stable",
|
|
34
|
+
|
|
35
|
+
"License :: OSI Approved :: BSD License",
|
|
36
|
+
|
|
37
|
+
"Operating System :: MacOS :: MacOS X",
|
|
38
|
+
"Operating System :: Microsoft",
|
|
39
|
+
"Operating System :: POSIX",
|
|
40
|
+
|
|
41
|
+
"Environment :: Console",
|
|
42
|
+
|
|
43
|
+
"Intended Audience :: End Users/Desktop",
|
|
44
|
+
"Intended Audience :: System Administrators",
|
|
45
|
+
|
|
46
|
+
"Topic :: System",
|
|
47
|
+
"Topic :: System :: Networking",
|
|
48
|
+
|
|
49
|
+
"Programming Language :: Python",
|
|
50
|
+
"Programming Language :: Python :: 3",
|
|
51
|
+
"Programming Language :: Python :: 3.7",
|
|
52
|
+
"Programming Language :: Python :: 3.8",
|
|
53
|
+
"Programming Language :: Python :: 3.9",
|
|
54
|
+
"Programming Language :: Python :: 3.10",
|
|
55
|
+
"Programming Language :: Python :: 3.11",
|
|
56
|
+
"Programming Language :: Python :: 3.12",
|
|
57
|
+
|
|
58
|
+
"Typing :: Typed"
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
[project.urls]
|
|
62
|
+
Homepage = 'https://github.com/gershnik/wakeonlan'
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
[project.scripts]
|
|
66
|
+
wakeonlan = "wakeonlan.wakeonlan:main"
|
|
67
|
+
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: eg.wakeonlan
|
|
3
|
+
Version: 1.1
|
|
4
|
+
Summary: Yet another wake-on-lan library
|
|
5
|
+
Author-email: Eugene Gershnik <gershnik@hotmail.com>
|
|
6
|
+
License: BSD-3-Clause
|
|
7
|
+
Project-URL: Homepage, https://github.com/gershnik/wakeonlan
|
|
8
|
+
Keywords: wakeonlan
|
|
9
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
10
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
11
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
12
|
+
Classifier: Operating System :: Microsoft
|
|
13
|
+
Classifier: Operating System :: POSIX
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
16
|
+
Classifier: Intended Audience :: System Administrators
|
|
17
|
+
Classifier: Topic :: System
|
|
18
|
+
Classifier: Topic :: System :: Networking
|
|
19
|
+
Classifier: Programming Language :: Python
|
|
20
|
+
Classifier: Programming Language :: Python :: 3
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
26
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
27
|
+
Classifier: Typing :: Typed
|
|
28
|
+
Requires-Python: >=3.7
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
License-File: LICENSE.txt
|
|
31
|
+
|
|
32
|
+
# wakeonlan #
|
|
33
|
+
|
|
34
|
+
Yet another wake-on-lan command line script.
|
|
35
|
+
|
|
36
|
+
## Why another one?
|
|
37
|
+
|
|
38
|
+
I couldn't find one that worked and did what I need. Specifically I need:
|
|
39
|
+
* A command line utility that works on Mac, Windows and Linux
|
|
40
|
+
* Can use saved configurations rather than force me to remember the MAC addresses of the machines I need to wake.
|
|
41
|
+
* Ideally, let me manipulate (create, delete, update, list) saved configurations using the same utility.
|
|
42
|
+
* Ideally, be open source so I can see what it is doing and know it doesn't do anything nefarious
|
|
43
|
+
|
|
44
|
+
None of the existing tools I found satisfied these criteria (even without the last two) so I wrote my own.
|
|
45
|
+
|
|
46
|
+
### Pre-requisites
|
|
47
|
+
|
|
48
|
+
Python 3.7 or above. No additional packages required.
|
|
49
|
+
|
|
50
|
+
### Installation
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip3 install eg.wakeonlan
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Usage
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
#### Wake up a machine given its MAC address XX:XX:XX:XX:XX:XX
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
wakeonlan XX:XX:XX:XX:XX:XX [-a BroadcastAddress] [-p Port]
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
If not specified BroadcastAddress is 255.255.255.255 and Port is 9
|
|
66
|
+
|
|
67
|
+
#### Save wake up configuration to be used later
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
wakeonlan --save Name XX:XX:XX:XX:XX:XX [-a BroadcastAddress] [-p Port]
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Name can be anything. The configuration is saved into `$HOME/.wakeonlan` file in JSON format
|
|
74
|
+
--save can be abbreviated as -s
|
|
75
|
+
|
|
76
|
+
#### Wake up a machine given saved configuration name
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
wakeonlan Name
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
#### List existing configuration names
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
wakeonlan --list
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
`--list` can be abbreviated as `-l`
|
|
89
|
+
|
|
90
|
+
#### Delete a configuration
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
wakeonlan --delete Name
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`--delete` can be abbreviated as `-d`
|
|
97
|
+
|
|
98
|
+
### Transferring configurations to another machine
|
|
99
|
+
|
|
100
|
+
Saved configurations are stored in `$HOME/.wakeonlan` file (`%USERPROFILE%\.wakeonlan` for Windows users).
|
|
101
|
+
Copy this file to another machine into equivalent location to transfer all the configurations.
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
LICENSE.txt
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/eg.wakeonlan.egg-info/PKG-INFO
|
|
5
|
+
src/eg.wakeonlan.egg-info/SOURCES.txt
|
|
6
|
+
src/eg.wakeonlan.egg-info/dependency_links.txt
|
|
7
|
+
src/eg.wakeonlan.egg-info/entry_points.txt
|
|
8
|
+
src/eg.wakeonlan.egg-info/top_level.txt
|
|
9
|
+
src/wakeonlan/__init__.py
|
|
10
|
+
src/wakeonlan/__main__.py
|
|
11
|
+
src/wakeonlan/py.typed
|
|
12
|
+
src/wakeonlan/wakeonlan.py
|
|
13
|
+
tests/test_wakeonlan.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
wakeonlan
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Copyright (c) 2018, Eugene Gershnik
|
|
2
|
+
# Use of this source code is governed by a BSD-style
|
|
3
|
+
# license that can be found in the LICENSE.txt file or at
|
|
4
|
+
# https://opensource.org/licenses/BSD-3-Clause
|
|
5
|
+
|
|
6
|
+
"""wakeonlan package"""
|
|
7
|
+
|
|
8
|
+
from .wakeonlan import VERSION as __version__, wake, saveName, getNameRecord, getNames, deleteName
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Copyright (c) 2018, Eugene Gershnik
|
|
2
|
+
# Use of this source code is governed by a BSD-style
|
|
3
|
+
# license that can be found in the LICENSE.txt file or at
|
|
4
|
+
# https://opensource.org/licenses/BSD-3-Clause
|
|
5
|
+
|
|
6
|
+
import sys
|
|
7
|
+
from .wakeonlan import main
|
|
8
|
+
|
|
9
|
+
sys.exit(main())
|
|
File without changes
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
# Copyright (c) 2018, Eugene Gershnik
|
|
2
|
+
# Use of this source code is governed by a BSD-style
|
|
3
|
+
# license that can be found in the LICENSE.txt file or at
|
|
4
|
+
# https://opensource.org/licenses/BSD-3-Clause
|
|
5
|
+
|
|
6
|
+
import sys
|
|
7
|
+
import os
|
|
8
|
+
import socket
|
|
9
|
+
import argparse
|
|
10
|
+
import re
|
|
11
|
+
import json
|
|
12
|
+
import shutil
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Any, Dict, Sequence, Tuple, Union
|
|
15
|
+
|
|
16
|
+
VERSION = '1.1'
|
|
17
|
+
|
|
18
|
+
PROG = 'wakeonlan'
|
|
19
|
+
|
|
20
|
+
DESCRIPTION = 'Send Wake-On-Lan packet to a given machine'
|
|
21
|
+
|
|
22
|
+
USAGE = r'''
|
|
23
|
+
%(prog)s MAC [-a IPADDR] [-p PORT]
|
|
24
|
+
%(prog)s NAME
|
|
25
|
+
%(prog)s --save NAME MAC [-a IPADDR] [-p PORT]
|
|
26
|
+
%(prog)s --delete NAME
|
|
27
|
+
%(prog)s --list
|
|
28
|
+
%(prog)s --version
|
|
29
|
+
%(prog)s --help
|
|
30
|
+
'''
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
DEFAULT_IP = '255.255.255.255'
|
|
34
|
+
DEFAULT_PORT = 9
|
|
35
|
+
CONFIG_HOME = Path(os.environ.get('WAKEONLAN_HOME', Path.home()))
|
|
36
|
+
CONFIG_PATH = CONFIG_HOME / '.wakeonlan'
|
|
37
|
+
CONFIG_TMP_PATH = CONFIG_HOME /'.wakeonlan.tmp'
|
|
38
|
+
MAC_PATTERN = re.compile(r'[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}')
|
|
39
|
+
IP_PATTERN = re.compile(r'(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)')
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
WAKE_CMD = 1
|
|
43
|
+
WAKE_BY_NAME_CMD = 2
|
|
44
|
+
SAVE_CMD = 3
|
|
45
|
+
DELETE_CMD = 4
|
|
46
|
+
LIST_CMD = 5
|
|
47
|
+
|
|
48
|
+
MacAddress = Sequence[int]
|
|
49
|
+
IPAddress = str
|
|
50
|
+
Port = int
|
|
51
|
+
SocketAddress = Union[Tuple[Any, ...], str, Any] #see socket._Address
|
|
52
|
+
HostRecord = Tuple[MacAddress, Tuple[IPAddress, Port]]
|
|
53
|
+
|
|
54
|
+
class WakeOnLanError(Exception):
|
|
55
|
+
def __init__(self, message):
|
|
56
|
+
super().__init__(message)
|
|
57
|
+
|
|
58
|
+
def splitMac(mac):
|
|
59
|
+
return [int(x, 16) for x in mac.split(':')]
|
|
60
|
+
|
|
61
|
+
def joinMac(macItems):
|
|
62
|
+
return ':'.join([f'{x:02X}' for x in macItems])
|
|
63
|
+
|
|
64
|
+
def parseArgs():
|
|
65
|
+
|
|
66
|
+
def mac_address_or_name(string):
|
|
67
|
+
if MAC_PATTERN.match(string):
|
|
68
|
+
return splitMac(string)
|
|
69
|
+
return string
|
|
70
|
+
|
|
71
|
+
def ip_address(string):
|
|
72
|
+
if not IP_PATTERN.match(string):
|
|
73
|
+
raise argparse.ArgumentTypeError('invalid IPv4 address ' + string)
|
|
74
|
+
return string
|
|
75
|
+
|
|
76
|
+
def port(string):
|
|
77
|
+
try:
|
|
78
|
+
val = int(string)
|
|
79
|
+
if val < 0 or val >= 65535:
|
|
80
|
+
raise argparse.ArgumentTypeError('invalid port ' + string)
|
|
81
|
+
return val
|
|
82
|
+
except ValueError:
|
|
83
|
+
raise argparse.ArgumentTypeError('invalid port ' + string)
|
|
84
|
+
|
|
85
|
+
def exitWithMessage(parser, message):
|
|
86
|
+
print(message, file=sys.stderr)
|
|
87
|
+
parser.print_usage()
|
|
88
|
+
sys.exit(1)
|
|
89
|
+
|
|
90
|
+
parser = argparse.ArgumentParser(description=DESCRIPTION, usage=USAGE, add_help=False,
|
|
91
|
+
prog=PROG)
|
|
92
|
+
argsGroup = parser.add_argument_group('arguments')
|
|
93
|
+
argsGroup.add_argument('macOrName', type=mac_address_or_name, nargs='?', metavar='MAC or NAME',
|
|
94
|
+
help='''MAC address or saved name of the machine to wake.
|
|
95
|
+
MAC address must be in XX:XX:XX:XX:XX:XX format''')
|
|
96
|
+
flagsGroup = parser.add_argument_group('switches')
|
|
97
|
+
flagsGroup.add_argument('-a', dest='ipaddr', type=ip_address,
|
|
98
|
+
help='Broadcast IPv4 address. This is NOT the IP address of the machine')
|
|
99
|
+
flagsGroup.add_argument('-p', dest='port', type=port,
|
|
100
|
+
help='Wake-On-Lan port')
|
|
101
|
+
manageGroud = flagsGroup.add_mutually_exclusive_group()
|
|
102
|
+
manageGroud.add_argument('--save', '-s', type=str, dest='saveName', metavar='NAME',
|
|
103
|
+
help='Save wake arguments as NAME')
|
|
104
|
+
manageGroud.add_argument('--delete', '-d', type=str, dest='deleteName', metavar='NAME',
|
|
105
|
+
help='Delete saved NAME')
|
|
106
|
+
manageGroud.add_argument('--list', '-l', action='store_true', dest='listNames',
|
|
107
|
+
help='List saved names')
|
|
108
|
+
flagsGroup.add_argument('--version', action='version', version=f'%(prog)s {VERSION}')
|
|
109
|
+
flagsGroup.add_argument('--help', '-h', action='help',
|
|
110
|
+
help='show this help message and exit')
|
|
111
|
+
parser.set_defaults(cmd=0)
|
|
112
|
+
|
|
113
|
+
args = parser.parse_args()
|
|
114
|
+
|
|
115
|
+
if not args.saveName is None:
|
|
116
|
+
if not type(args.macOrName) is list:
|
|
117
|
+
exitWithMessage(parser, 'Must specify MAC address to save')
|
|
118
|
+
args.cmd = SAVE_CMD
|
|
119
|
+
elif not args.deleteName is None:
|
|
120
|
+
if not args.macOrName is None:
|
|
121
|
+
exitWithMessage(parser, 'parameter MAC_OR_NAME: not allowed with --delete/-d')
|
|
122
|
+
if not args.ipaddr is None:
|
|
123
|
+
exitWithMessage(parser, 'argument -a: not allowed with argument with --delete/-d')
|
|
124
|
+
if not args.port is None:
|
|
125
|
+
exitWithMessage(parser, 'argument -p: not allowed with argument with --delete/-d')
|
|
126
|
+
args.cmd = DELETE_CMD
|
|
127
|
+
elif args.listNames:
|
|
128
|
+
if not args.macOrName is None:
|
|
129
|
+
exitWithMessage(parser, 'parameter MAC_OR_NAME: not allowed with --list/-l')
|
|
130
|
+
if not args.ipaddr is None:
|
|
131
|
+
exitWithMessage(parser, 'argument -a: not allowed with argument with --list/-l')
|
|
132
|
+
if not args.port is None:
|
|
133
|
+
exitWithMessage(parser, 'argument -p: not allowed with argument with --list/-l')
|
|
134
|
+
args.cmd = LIST_CMD
|
|
135
|
+
|
|
136
|
+
if args.cmd == 0:
|
|
137
|
+
if args.macOrName is None:
|
|
138
|
+
exitWithMessage(parser, 'MAC or name is required')
|
|
139
|
+
if type(args.macOrName) is list:
|
|
140
|
+
args.cmd = WAKE_CMD
|
|
141
|
+
else:
|
|
142
|
+
if not args.ipaddr is None:
|
|
143
|
+
exitWithMessage(parser, 'Cannot specify broadcast address with name')
|
|
144
|
+
if not args.port is None:
|
|
145
|
+
exitWithMessage(parser, 'Cannot specify port with name')
|
|
146
|
+
args.cmd = WAKE_BY_NAME_CMD
|
|
147
|
+
|
|
148
|
+
if args.cmd == SAVE_CMD or args.cmd == WAKE_CMD:
|
|
149
|
+
args.ipaddr = DEFAULT_IP if args.ipaddr is None else args.ipaddr
|
|
150
|
+
args.port = DEFAULT_PORT if args.port is None else args.port
|
|
151
|
+
|
|
152
|
+
return args
|
|
153
|
+
|
|
154
|
+
def wake(mac: MacAddress, addr: SocketAddress) -> None :
|
|
155
|
+
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
|
|
156
|
+
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
|
157
|
+
|
|
158
|
+
payload = bytearray(17 * 6)
|
|
159
|
+
for i in range(6):
|
|
160
|
+
payload[i] = 0xFF
|
|
161
|
+
for i in range(6, len(payload), 6):
|
|
162
|
+
payload[i:] = mac
|
|
163
|
+
|
|
164
|
+
sock.sendto(payload, addr)
|
|
165
|
+
|
|
166
|
+
def loadConfig():
|
|
167
|
+
try:
|
|
168
|
+
with open(CONFIG_PATH, 'rt') as config:
|
|
169
|
+
config = json.load(config)
|
|
170
|
+
if type(config) != dict:
|
|
171
|
+
raise WakeOnLanError(f'{CONFIG_PATH} is malformed')
|
|
172
|
+
return config
|
|
173
|
+
except json.JSONDecodeError:
|
|
174
|
+
raise WakeOnLanError(f'{CONFIG_PATH} is malformed')
|
|
175
|
+
except OSError:
|
|
176
|
+
pass
|
|
177
|
+
return {'names':{}}
|
|
178
|
+
|
|
179
|
+
def saveConfig(config):
|
|
180
|
+
try:
|
|
181
|
+
with open(CONFIG_TMP_PATH, 'wt') as tempfile:
|
|
182
|
+
json.dump(config, tempfile, indent=2)
|
|
183
|
+
shutil.move(CONFIG_TMP_PATH, CONFIG_PATH)
|
|
184
|
+
except OSError as err:
|
|
185
|
+
raise WakeOnLanError(f'Unable to save: {err.strerror}')
|
|
186
|
+
|
|
187
|
+
def getNamesDict(config):
|
|
188
|
+
names = config.get('names')
|
|
189
|
+
if type(names) != dict:
|
|
190
|
+
raise WakeOnLanError(f'`names` not found in {CONFIG_PATH}')
|
|
191
|
+
return names
|
|
192
|
+
|
|
193
|
+
def parseNameRecord(name, nameRecord):
|
|
194
|
+
if type(nameRecord) != dict:
|
|
195
|
+
raise WakeOnLanError(f'`{name}` entry in {CONFIG_PATH} is malformed')
|
|
196
|
+
mac = nameRecord.get('mac')
|
|
197
|
+
if type(mac) != str or not MAC_PATTERN.match(mac):
|
|
198
|
+
raise WakeOnLanError(f'mac address in `{name}` entry in {CONFIG_PATH} is missing or malformed')
|
|
199
|
+
mac = splitMac(mac)
|
|
200
|
+
ip = nameRecord.get('ip', DEFAULT_IP)
|
|
201
|
+
if type(ip) != str or not IP_PATTERN.match(ip):
|
|
202
|
+
raise WakeOnLanError(f'ip address in `{name}` entry in {CONFIG_PATH} is malformed')
|
|
203
|
+
port = nameRecord.get('port', DEFAULT_PORT)
|
|
204
|
+
if type(port) != int or port < 0 or port > 65535:
|
|
205
|
+
raise WakeOnLanError(f'port address in `{name}` entry in {CONFIG_PATH} is malformed')
|
|
206
|
+
|
|
207
|
+
return (mac, (ip, port))
|
|
208
|
+
|
|
209
|
+
def getNameRecord(name: str) -> Union[HostRecord, None]:
|
|
210
|
+
config = loadConfig()
|
|
211
|
+
names = getNamesDict(config)
|
|
212
|
+
nameRecord = names.get(name)
|
|
213
|
+
if nameRecord is None:
|
|
214
|
+
return None
|
|
215
|
+
return parseNameRecord(name, nameRecord)
|
|
216
|
+
|
|
217
|
+
def getNames() -> Dict[str, HostRecord] :
|
|
218
|
+
config = loadConfig()
|
|
219
|
+
names = getNamesDict(config)
|
|
220
|
+
ret = {}
|
|
221
|
+
for name, nameRecord in names.items():
|
|
222
|
+
ret[name] = parseNameRecord(name, nameRecord)
|
|
223
|
+
return ret
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def saveName(name: str, mac: MacAddress, ipaddr: IPAddress, port: Port) -> None :
|
|
227
|
+
config = loadConfig()
|
|
228
|
+
names = getNamesDict(config)
|
|
229
|
+
record: Dict[str, Any] = {
|
|
230
|
+
'mac': joinMac(mac)
|
|
231
|
+
}
|
|
232
|
+
if ipaddr != DEFAULT_IP:
|
|
233
|
+
record['ip'] = ipaddr
|
|
234
|
+
if port != DEFAULT_PORT:
|
|
235
|
+
record['port'] = port
|
|
236
|
+
names[name] = record
|
|
237
|
+
saveConfig(config)
|
|
238
|
+
|
|
239
|
+
def deleteName(name: str) -> None :
|
|
240
|
+
config = loadConfig()
|
|
241
|
+
names = getNamesDict(config)
|
|
242
|
+
names.pop(name, None)
|
|
243
|
+
saveConfig(config)
|
|
244
|
+
|
|
245
|
+
def main():
|
|
246
|
+
args = parseArgs()
|
|
247
|
+
|
|
248
|
+
try:
|
|
249
|
+
|
|
250
|
+
if args.cmd == WAKE_CMD:
|
|
251
|
+
print(f'wake: {args.macOrName}, {args.ipaddr}, {args.port}')
|
|
252
|
+
wake(args.macOrName, (args.ipaddr, args.port))
|
|
253
|
+
elif args.cmd == WAKE_BY_NAME_CMD:
|
|
254
|
+
nameRecord = getNameRecord(args.macOrName)
|
|
255
|
+
if nameRecord is None:
|
|
256
|
+
raise WakeOnLanError(f'Name {args.macOrName} not found')
|
|
257
|
+
mac, addr = nameRecord
|
|
258
|
+
print(f'wake: {joinMac(mac)}, {addr[0]}, {addr[1]}')
|
|
259
|
+
wake(mac, addr)
|
|
260
|
+
elif args.cmd == SAVE_CMD:
|
|
261
|
+
saveName(args.saveName, args.macOrName, args.ipaddr, args.port)
|
|
262
|
+
print(f'Name {args.saveName} saved')
|
|
263
|
+
elif args.cmd == DELETE_CMD:
|
|
264
|
+
deleteName(args.deleteName)
|
|
265
|
+
print(f'Name {args.deleteName} deleted')
|
|
266
|
+
elif args.cmd == LIST_CMD:
|
|
267
|
+
names = getNames()
|
|
268
|
+
for name, nameRecord in names.items():
|
|
269
|
+
mac, addr = nameRecord
|
|
270
|
+
mac = joinMac(mac)
|
|
271
|
+
print(f'{name} - {mac}, {addr[0]}, {addr[1]}')
|
|
272
|
+
return 0
|
|
273
|
+
except WakeOnLanError as ex:
|
|
274
|
+
print(ex, file=sys.stderr)
|
|
275
|
+
return 1
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from wakeonlan import *
|
|
2
|
+
|
|
3
|
+
def test_save():
|
|
4
|
+
assert getNames() == {}
|
|
5
|
+
saveName("test", (1,1,1,1,1,1), "127.0.0.1", 9)
|
|
6
|
+
rec = getNameRecord("test")
|
|
7
|
+
assert not rec is None
|
|
8
|
+
assert len(rec) == 2
|
|
9
|
+
assert rec[0] == [1,1,1,1,1,1]
|
|
10
|
+
assert rec[1] == ("127.0.0.1", 9)
|
|
11
|
+
assert getNames() == {
|
|
12
|
+
"test": ([1,1,1,1,1,1], ("127.0.0.1", 9))
|
|
13
|
+
}
|
|
14
|
+
deleteName("test")
|
|
15
|
+
assert getNames() == {}
|
|
16
|
+
assert getNameRecord("test") == None
|
|
17
|
+
|