, I thought it would be a good idea to familiarize myself with the inner workings and customizations.
One feature that is useful for power users is the command line interface that is accessible through ssh.
, but I'm not going to be covering it in this post.
I wrote this for my system specifically. I did write it as generally as possible, taking user input, so it should work on almost all systems.
I was also unaware of the python argparse module, so it's not as elegant as it could be. I may update it in my repository, but I likely won't update this post.
#! /usr/bin/env python2
import subprocess as sp
from datetime import datetime as dt
from os import path, geteuid, getcwd
from sys import argv, exit
def run(test):
"""
Run the functions that comprise the disk checking routine.
"""
rootCheck()
continueCheck()
print 'Volume Checking For /volume1'
mountPoint, optMount, fileSystem = getFileSystem()
logfile = setLogFile(test, fileSystem)
initLog(logfile)
logFileSystem(logfile, mountPoint, optMount, fileSystem)
stopRunningProcesses(test, logfile)
umountVolumes(test, logfile, optMount)
flags = getFlags(test, logfile)
runCheck(test, logfile, fileSystem, mountPoint, flags)
rebootSystem(test, logfile)
def getTime():
"""
Get the current time
"""
now = dt.now().strftime
time = now('%H:%M:%S')
return time
def getDate():
"""
Get the current date
"""
now = dt.now().strftime
date = now('%d/%m/%y')
return date
def writeLog(logfile, data):
"""
Open the specified log file, get the current time,
print it to the screen and append it to the log.
Close the log file.
"""
with open(logfile, 'a') as outFile:
time = getTime()
print '%s -> %s' % (time, data)
outFile.write('%s -> %s\n' % (time, data))
outFile.close()
def initLog(logfile):
"""
Open the specified log file, get the current time/date,
print it to the screen and append it to the log file with a
--- START LOG --- opening tag. Close the file.
"""
with open(logfile, 'a') as outFile:
time = getTime()
date = getDate()
dateTime = '%s %s' %(date, time)
print dateTime
print 'Starting Log: %s' % logfile
startLog = '\n\n%s\n--- START LOG ---\n\n' %dateTime
outFile.write(startLog)
outFile.close()
def closeLog(logfile):
"""
Open the specified log file, get the current time
print it to the screen and append it to the log with a
--- END OF LOG --- tag. Close the file.
"""
with open(logfile, 'a') as outFile:
time = getTime()
print 'End Log: %s' % logfile
endLog = '\n\n%s\n--- END OF LOG ---\n' %time
outFile.write(endLog)
outFile.close()
def exitError(logfile, err):
"""
Write to the specified log file the given error (err) message.
Close the file, and exit the script.
"""
writeLog(logfile, err)
closeLog(logfile)
exit(err)
def rootCheck():
"""
If the current user id is not root, exit.
If the current working directory is not /, exit.
"""
if geteuid() != 0:
err = 'This script must be run as the root user!\nExiting Now.'
exit(err)
if getcwd() != '/':
err = 'This script must be run from \'/\'!\nExiting Now.'
exit(err)
def continueCheck():
"""
Prompt the user with a warning, ask for confirmation before continuing.
If 'n', exit the script. If 'y', continue.
"""
proceed = 'x'
warning = "\n\
WARNING: THIS PROGRAM STOPS FILESYSTEM PROCESSES AND UNMOUNTS VOLUMES!\n\
PLEASE MAKE SURE YOU'VE STOPPED ALL RUNNING PROCESSES\n\
AND DISCONNECTED FROM NETWORK SHARES BEFORE YOU CONTINUE.\n\
THE SYSTEM WILL REBOOT TO COMPLETE THE PROCESS.\n\
(it's also recommended that you disable your system beep temporarily)\n\
"
print warning
while proceed not in ['Y','y','N','n']:
proceed = raw_input('Are you sure you want to continue? (y/n): ')
if proceed == 'n' or 'N':
exit('Maybe next time. Take it easy.')
if proceed == 'y' or 'Y':
print 'Continuing...\n\n'
def getFileSystem():
"""
Get the mounted volume information from the system.
Check for /volume1 and /opt. If they don't exist, exit.
Return the mountPoint, optMount, fileSystem of /volume1.
"""
system = sp.check_output('mount').split('\n')
optMount = 0
for mount in system:
try:
if '/volume1' in mount:
if not '/opt' in mount:
volumeInfoList = mount.split(' ')
mountPoint = volumeInfoList[0]
fileSystem = volumeInfoList[4]
if '/opt' in mount:
optMount = 1
except:
err = 'Can\'t find volume1!!'
exit(err)
return (mountPoint, optMount, fileSystem)
def setLogFile(test, fileSystem):
"""
With the specified fileSystem and test value, check for/create the
/log directory and a log file of either fsck.ext4.log, e2fsck.log,
or test.log.
Print the results to the screen and return logfile.
"""
logdir = '/log'
if not path.exists(logdir):
print 'Log directory %s does not exist. Creating it now.' % logdir
try:
sp.check_output(['mkdir', logdir])
print 'Directory successfully created.'
except:
exit('Something went wrong.')
if test:
logfile = '%s/test.log' % logdir
else:
if fileSystem == 'ext4':
logfile = '%s/fsck.ext4.log' % logdir
if fileSystem == 'ext2':
logfile = '%s/fsck.ext2.log' % logdir
if not path.exists(logfile):
print 'Log file does not exist. Creating it now.'
try:
sp.check_output(['touch', logfile])
except:
exit('Something went wrong.')
print 'Log directory: %s' % logdir
print 'Log file: %s' % logfile
return logfile
def logFileSystem(logfile, mountPoint, optMount, fileSystem):
"""
Write the system information to the given log file.
"""
if not optMount:
writeLog(logfile, '/opt Mount: No')
writeLog(logfile, '/opt Mount: Yes')
writeLog(logfile, 'Mount Point: %s' % mountPoint)
writeLog(logfile, 'File System: %s' % fileSystem)
def stopRunningProcesses(test, logfile):
"""
Stop the file services specified in the list.
Log the service as it's stopped.
If it's a test, log the command but do not execute.
"""
fileServiceList = ['S25download.sh', 'S20pgsql.sh', 'S80samba.sh', 'S83nfsd.sh', 'S81atalk.sh']
serviceDir = '/usr/syno/etc/rc.d/'
cmd = 'stop'
writeLog(logfile, 'Running Commands:')
for fileService in fileServiceList:
if path.exists('%s%s' %(serviceDir,fileService)):
service = '%s%s' %(serviceDir, fileService)
stopService = '%s %s' %(service, cmd)
if test:
writeLog(logfile, stopService)
else:
try:
writeLog(logfile, stopService)
sp.check_output([service,cmd])
except:
err = 'Error Stopping Processes!\nSomething went wrong...'
exitError(logfile, err)
def umountVolumes(test, logfile, optMount):
"""
Unmount the volumes /volume1 and /opt (if available).
Append to the log. If it's a test, log the command but do not execute.
"""
writeLog (logfile, 'Unmounting volumes...')
if test:
writeLog (logfile, 'umount /volume1')
if optMount:
writeLog (logfile, 'umount /opt')
else:
writeLog (logfile, 'umount /volume1')
sp.check_output(['umount','/volume1'])
if optMount:
writeLog (logfile, 'umount /opt')
sp.check_output(['umount','/opt'])
def getFlags(test, logfile):
"""
Set the fsck flags to p (auto-fix), v (verbose), f (force).
If it's a test, change p to n (no action).
If not the default flags, enter the desired sequence.
Log and print the flags.
"""
if not test:
useDefault = 'x'
while useDefault not in ['y','Y','n','N']:
useDefault = raw_input('Use the default -pvf flags for the disk check? (y/n): ')
if useDefault in ['y','Y']:
flags = '-pvf'
else:
sp.check_output(['fsck.ext4'],['--help'])
flags = raw_input('Please specify the flags you would like to use.\n\
(example: -nvf): ')
else:
flags = '-nvf'
writeLog(logfile, 'Using flags: %s' % flags)
return flags
def runCheck(test, logfile, fileSystem, mountPoint, flags):
"""
Choose the correct checking system given the file system provided.
ext2 and ext4 are supported. Other systems will exit the script.
Log the running command, run the command and
write the output to the logfile.
"""
if fileSystem == 'ext4':
checkCommand = 'fsck.ext4'
elif fileSystem == 'ext2':
checkCommand = 'e2fsck'
else:
err = 'Unrecognized file system!\nSomething went wrong!'
exitError(logfile, err)
running = 'Running Command: %s %s %s' % (checkCommand, flags, mountPoint)
writeLog(logfile, running)
if test:
writeLog(logfile, 'sp.check_output([checkCommand,flags,mountPoint])')
else:
writeLog(logfile, sp.check_output([checkCommand,flags,mountPoint]))
def rebootSystem(test, logfile):
"""
Log the reboot step and close the logfile.
If it's not a test, reboot the system.
"""
writeLog(logfile, '* Rebooting System *')
if test:
closeLog(logfile)
else:
closeLog(logfile)
sp.check_output('reboot')
if __name__=="__main__":
test = 0
help = "\n\
SYNOCHK HELP!\n\
Usage: [python] synochk [-h, -t]\n\
\n\
You will be prompted later for flags relating to the disk checking process.\n\
\n\
Synochk must be run as the root administrator from the root directory '/'.\n\
\n\
[Invalid Flags] Bring up this help dialog\n\
-t, -test Run synochk in 'test' mode. Your file system will not be modified.\n\
Test mode will create a test.log file and log the results of the test.\n\
-d Display the disclaimer\n\n\
"
disclaimer = 'DISCLAIMER:\n\
The author of this script is not responsible for any damage\n\
caused during it\'s execution. There are many safeguards in place\n\
to prevent harm, and let\'s be honest, if you\'re using this script\n\
in an ssh shell, you probably know what you\'re doing.\n\
Synology does not support any tampering in the terminal.\n\
Neither does the author.\n\
Play safe.\n\n\
Peace in the middle east,\n\t\t\t- The Author\n\n'
testMode = '\n\nTEST MODE ENABLED!\nYOUR SYSTEM WILL NOT BE MODIFIED.\n'
if len(argv)>2:
exit(help)
if argv[1] not in ['-t','-T','-test','-TEST']:
exit(help)
if argv[1] in ['-d','-D']:
exit(disclaimer)
if argv[1] in ['-t','-test']:
print testMode
print disclaimer
test = 1
test = 1
run(test)