|
|
#-*- coding: utf-8 -*-
|
|
|
|
|
|
# Copyright 2008-2010 Mir Calculate Ltd. http://www.calculate-linux.org
|
|
|
#
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
# You may obtain a copy of the License at
|
|
|
#
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
#
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
# See the License for the specific language governing permissions and
|
|
|
# limitations under the License.
|
|
|
|
|
|
import os
|
|
|
import sys
|
|
|
import re
|
|
|
import stat
|
|
|
# Вывод в строку ввода
|
|
|
import readline
|
|
|
# Файловый объект из строки
|
|
|
import cStringIO
|
|
|
import termios
|
|
|
# Для ввода символа
|
|
|
import tty
|
|
|
# Работа со временем
|
|
|
import time
|
|
|
from cl_utils import scan, getModeFile, getpathenv, runOsCommand
|
|
|
|
|
|
"""общие функции серверных программ"""
|
|
|
|
|
|
def unicList(listEl):
|
|
|
"""Уникальный список с сохранением порядка"""
|
|
|
retList = []
|
|
|
[not x in retList and retList.append(x) for x in listEl]
|
|
|
return retList
|
|
|
|
|
|
|
|
|
def dialogYn(message):
|
|
|
"""Вывод сообщения, ожидание нажатия Y или n
|
|
|
|
|
|
если Y - True если n - False"""
|
|
|
def getChar():
|
|
|
fd = sys.stdin.fileno()
|
|
|
oldSet = termios.tcgetattr(fd)
|
|
|
tty.setraw(fd)
|
|
|
char = sys.stdin.read(1)
|
|
|
termios.tcsetattr(fd, termios.TCSADRAIN, oldSet)
|
|
|
return char
|
|
|
def term(char):
|
|
|
if ord(char) == 3:
|
|
|
return None
|
|
|
if char == "Y":
|
|
|
return True
|
|
|
elif char == "n":
|
|
|
return False
|
|
|
else:
|
|
|
char = getChar()
|
|
|
return term(char)
|
|
|
sys.stdout.write(message + ":")
|
|
|
char = getChar()
|
|
|
res = term(char)
|
|
|
sys.stdout.write("\n")
|
|
|
return res
|
|
|
|
|
|
|
|
|
def dialogYesNo(message):
|
|
|
"""Вывод сообщения, ожидание набора Yes или No (в любом регистре)
|
|
|
|
|
|
если Yes - True, если No - False"""
|
|
|
sys.stdout.write(message + ": ")
|
|
|
strIn=sys.stdin.readline().lower().strip()
|
|
|
sys.stdout.write("\n")
|
|
|
if "yes" == strIn:
|
|
|
return True
|
|
|
elif "no" == strIn:
|
|
|
return False
|
|
|
else:
|
|
|
return self.dialogYesNo(message)
|
|
|
|
|
|
|
|
|
def chownR(directory, uid, gid):
|
|
|
"""изменяет владельца и группу
|
|
|
|
|
|
для всех файлов и директорий внутри directory
|
|
|
"""
|
|
|
fileObj = scan()
|
|
|
scanObjs = fileObj.scanDirs([directory])
|
|
|
# меняем владельца домашней директории
|
|
|
os.chown(directory, uid,gid)
|
|
|
# Меняем владельца директорий
|
|
|
for dirCh in scanObjs[0].dirs:
|
|
|
os.chown(dirCh, uid,gid)
|
|
|
# Меняем владельца файлов
|
|
|
for fileCh in scanObjs[0].files:
|
|
|
os.chown(fileCh, uid,gid)
|
|
|
# Меняем владельца ссылок
|
|
|
for linkCh in scanObjs[0].links:
|
|
|
os.lchown(linkCh[1], uid, gid)
|
|
|
return True
|
|
|
|
|
|
def copyDir(destDir, srcDir):
|
|
|
"""Копируем директорию srcDir в destDir
|
|
|
|
|
|
При копировании сохраняются владелец, группа, права
|
|
|
"""
|
|
|
if os.path.exists(destDir) and not os.listdir(destDir):
|
|
|
os.rmdir(destDir)
|
|
|
if not os.path.exists(destDir):
|
|
|
# Создаем директорию
|
|
|
os.makedirs(destDir)
|
|
|
# Файловый объект
|
|
|
fileObj = scan()
|
|
|
# Сканируем директорию
|
|
|
scanObjs = fileObj.scanDirs([srcDir])
|
|
|
if not scanObjs:
|
|
|
return True
|
|
|
for dirSrc in scanObjs[0].dirs:
|
|
|
#создаем в домашней директории директории из srcDir
|
|
|
dirName = destDir + dirSrc.split(srcDir)[1]
|
|
|
os.mkdir(dirName)
|
|
|
mode,uid,gid = getModeFile(dirSrc)
|
|
|
os.chown(dirName, uid,gid)
|
|
|
os.chmod(destDir, mode)
|
|
|
# размер файлового буфера в байтах (5Mb)
|
|
|
sizeBuffer = 5242880
|
|
|
for fileCopy in scanObjs[0].files:
|
|
|
oldFile = destDir + fileCopy.split(srcDir)[1]
|
|
|
#копируем файлы
|
|
|
# Открываем файл - источник
|
|
|
fd = os.open(fileCopy, os.O_RDONLY)
|
|
|
fst = os.fstat(fd)
|
|
|
uid = fst.st_uid
|
|
|
gid = fst.st_gid
|
|
|
mode = stat.S_IMODE(fst.st_mode)
|
|
|
size = fst.st_size
|
|
|
# Открываем файл приемник
|
|
|
fdCr = os.open(oldFile, os.O_CREAT|os.O_WRONLY, mode)
|
|
|
if size:
|
|
|
# Количество циклов копирования
|
|
|
numbCycles = size/sizeBuffer
|
|
|
# Размер остатка файла после выполения циклов копирования
|
|
|
sizeTailFile = size - numbCycles * sizeBuffer
|
|
|
for i in xrange(numbCycles):
|
|
|
# Читаем порцию данных
|
|
|
buff = os.read(fd, sizeBuffer)
|
|
|
# Записываем порцию данных
|
|
|
os.write(fdCr, buff)
|
|
|
# Если есть остаток файла записываем его
|
|
|
if sizeTailFile:
|
|
|
# Читаем остаток файла
|
|
|
buff = os.read(fd, sizeTailFile)
|
|
|
# Записываем остаток файла
|
|
|
os.write(fdCr, buff)
|
|
|
# Закрываем файлы
|
|
|
os.close(fd)
|
|
|
os.close(fdCr)
|
|
|
# Меняем владельца
|
|
|
os.chown(oldFile, uid, gid)
|
|
|
#os.chmod(oldFile, mode)
|
|
|
for linkCreate in scanObjs[0].links:
|
|
|
#копируем ссылки
|
|
|
dst = destDir + linkCreate[1].split(srcDir)[1]
|
|
|
srcDestList = linkCreate[0].split(srcDir)
|
|
|
if len(srcDestList)>1:
|
|
|
src = destDir + srcDestList[1]
|
|
|
else:
|
|
|
src = linkCreate[0]
|
|
|
os.symlink(src,dst)
|
|
|
if os.path.exists(dst):
|
|
|
mode,uid,gid = getModeFile(dst)
|
|
|
#Изменение прав на ссылки
|
|
|
os.lchown(dst, uid, gid)
|
|
|
# Удаляем сокеты
|
|
|
for rmSocket in scanObjs[0].sockets:
|
|
|
os.remove(rmSocket)
|
|
|
mode,uid,gid = getModeFile(srcDir)
|
|
|
os.chmod(destDir, mode)
|
|
|
os.chown(destDir, uid,gid)
|
|
|
return True
|
|
|
|
|
|
def rawInput(promptText="", inputText=""):
|
|
|
"""Создает поле ввода
|
|
|
|
|
|
promptText - текст перед полем ввода
|
|
|
inputText - текст в поле ввода
|
|
|
"""
|
|
|
if inputText:
|
|
|
# Записываем текст для последующего вывода в строке ввода
|
|
|
readline.set_pre_input_hook(lambda:\
|
|
|
readline.insert_text(inputText) or\
|
|
|
readline.redisplay())
|
|
|
strInput = ""
|
|
|
if promptText:
|
|
|
# Получаем текст введенный пользователем
|
|
|
strInput = raw_input(promptText)
|
|
|
else:
|
|
|
strInput = raw_input()
|
|
|
if inputText:
|
|
|
# Сбрасываем строку ввода
|
|
|
readline.set_pre_input_hook(None)
|
|
|
return strInput
|
|
|
|
|
|
def execProg(cmdStrProg, inStr=False, retFull=True, envProg={}):
|
|
|
"""Выполняет внешнюю программу
|
|
|
|
|
|
Параметры:
|
|
|
cmdStrProg внешняя программа
|
|
|
inStr данные передаваемые программе на страндартный вход.
|
|
|
Возвращаемые параметры:
|
|
|
строка которую выведет внешняя программа или False в случае ошибки
|
|
|
"""
|
|
|
env_path = {"PATH":getpathenv()}
|
|
|
env = {}
|
|
|
env.update(os.environ.items() + env_path.items() + envProg.items())
|
|
|
retCode,programOut = runOsCommand(cmdStrProg,inStr,retFull,env)
|
|
|
if not retCode:
|
|
|
return programOut
|
|
|
return False
|
|
|
|
|
|
def genSleep(timeSleep=(0.2, 0.4, 0.8)):
|
|
|
"""Генератор задержек"""
|
|
|
for t in timeSleep:
|
|
|
time.sleep(t)
|
|
|
yield(t)
|
|
|
|
|
|
def stringIsJpeg(string):
|
|
|
"""Определяет является ли строка - jpeg изображением"""
|
|
|
if len(string)<8:
|
|
|
return False
|
|
|
FD = cStringIO.StringIO(string)
|
|
|
isJpeg = False
|
|
|
FD.seek(0, 0)
|
|
|
(firstByte, secondByte) = FD.read(2)
|
|
|
if (ord(firstByte) == 0xff and ord(secondByte) == 0xd8):
|
|
|
(firstByte, secondByte) = FD.read(2)
|
|
|
if (ord(firstByte) == 0xff and ord(secondByte) == 0xe0):
|
|
|
isJpeg = True
|
|
|
return isJpeg
|
|
|
|
|
|
def isCorrectStringNet(strNetworks, checkNet=True):
|
|
|
"""Проверяет на корректность строку доверительных сетей
|
|
|
|
|
|
Выводит cписок сетей
|
|
|
"""
|
|
|
splNet = strNetworks.replace(","," ").split(" ")
|
|
|
if checkNet:
|
|
|
checkIP = False
|
|
|
res=re.compile("^\d\d?\d?\.\d\d?\d?\.\d\d?\d?\.\d\d?\d?\/\d\d?$")
|
|
|
else:
|
|
|
checkIP = True
|
|
|
res=re.compile("^\d\d?\d?\.\d\d?\d?\.\d\d?\d?\.\d\d?\d?$")
|
|
|
flagError = False
|
|
|
networks = []
|
|
|
for i in splNet:
|
|
|
r = i.strip()
|
|
|
if not r:
|
|
|
continue
|
|
|
find =res.search(r)
|
|
|
if not find:
|
|
|
flagError = True
|
|
|
break
|
|
|
else:
|
|
|
splIP = map(lambda x: 255>=int(x.split("/")[0]) and\
|
|
|
x.split("/")[0], find.group().split("."))
|
|
|
if not splIP[0] or splIP[0] and int(splIP[0]) == 0:
|
|
|
flagError = True
|
|
|
break
|
|
|
if not splIP[3] or splIP[3] and int(splIP[3]) == 255:
|
|
|
flagError = True
|
|
|
break
|
|
|
if checkNet:
|
|
|
netList = r.split("/")
|
|
|
if len(netList)==2:
|
|
|
try:
|
|
|
netMaskInt = int(netList[1])
|
|
|
except:
|
|
|
flagError = True
|
|
|
break
|
|
|
if netMaskInt>31 or netMaskInt<4:
|
|
|
flagError = True
|
|
|
break
|
|
|
else:
|
|
|
flagError = True
|
|
|
break
|
|
|
if checkIP and splIP[3] and int(splIP[3]) == 0:
|
|
|
flagError = True
|
|
|
break
|
|
|
for t in splIP:
|
|
|
if t == False:
|
|
|
flagError = True
|
|
|
break
|
|
|
if flagError:
|
|
|
break
|
|
|
networks.append(r)
|
|
|
if flagError:
|
|
|
return False
|
|
|
else:
|
|
|
return list(set(networks))
|
|
|
|
|
|
def searchLineInFile(name, fileName, numEl=0):
|
|
|
"""Ищет строку в которой есть название разделенное ':'
|
|
|
|
|
|
в файле похожем на /etc/passwd"""
|
|
|
if os.path.exists(fileName):
|
|
|
FD = open(fileName)
|
|
|
lines = FD.readlines()
|
|
|
FD.close()
|
|
|
lineFound = ""
|
|
|
for line in lines:
|
|
|
if name == line.split(":")[numEl]:
|
|
|
lineFound = line
|
|
|
break
|
|
|
if lineFound:
|
|
|
return lineFound
|
|
|
else:
|
|
|
return False
|
|
|
|
|
|
def getMaxInFile(fileName, numMin, numMax, numEl=2):
|
|
|
"""Получаем максимальный номер из файла похожего на /etc/group"""
|
|
|
lst = []
|
|
|
lst.append(0)
|
|
|
if os.path.exists(fileName):
|
|
|
FD = open(fileName)
|
|
|
lines = FD.readlines()
|
|
|
FD.close()
|
|
|
for line in lines:
|
|
|
if not ':' in line:
|
|
|
continue
|
|
|
num = int(line.split(":")[numEl])
|
|
|
if num<=numMax and num>=numMin:
|
|
|
lst.append(num)
|
|
|
return max(lst)
|
|
|
return False
|
|
|
|
|
|
def chortToFullName(listNames, domain):
|
|
|
"""Из списка коротких имен получаем cписок полных имен
|
|
|
|
|
|
К коротким именам добавляем домен, длинные выдаем как есть
|
|
|
"""
|
|
|
listFillNames = []
|
|
|
for name in listNames:
|
|
|
if "." in name:
|
|
|
listFillNames.append(name)
|
|
|
else:
|
|
|
listFillNames.append("%s.%s" %(name,domain))
|
|
|
return listFillNames
|
|
|
|
|
|
def addInfoUser(name, uid, gid, comment):
|
|
|
"""Добавляем информацию о пользователе"""
|
|
|
class user():
|
|
|
"""Информация о пользователе"""
|
|
|
name = ""
|
|
|
uid = ""
|
|
|
gid = ""
|
|
|
comment = ""
|
|
|
us = user()
|
|
|
us.name = name
|
|
|
us.uid = uid
|
|
|
us.gid = gid
|
|
|
us.comment = comment
|
|
|
return us
|
|
|
|
|
|
def addInfoGroup(name, gid, comment, rid="", type="", sid=""):
|
|
|
"""Добавляем информацию о группе"""
|
|
|
class group():
|
|
|
"""Информация о группе"""
|
|
|
name = ""
|
|
|
gid = ""
|
|
|
comment = ""
|
|
|
rid = ""
|
|
|
type = ""
|
|
|
sid = ""
|
|
|
gr = group()
|
|
|
gr.name = name
|
|
|
gr.gid = gid
|
|
|
gr.comment = comment
|
|
|
gr.rid = rid
|
|
|
gr.type = type
|
|
|
gr.sid = sid
|
|
|
return gr |