Merge pull request #7080 from evinrude/feature_mknod

Feature mknod
This commit is contained in:
Thomas S Hatch 2013-09-05 18:02:55 -07:00
commit 4bfc18e17c
2 changed files with 390 additions and 0 deletions

View File

@ -2051,6 +2051,265 @@ def makedirs_perms(name,
group,
int('{0}'.format(mode)) if mode else None)
def get_devmm(name):
'''
Get major/minor info from a device
CLI Example:
.. code-block:: bash
salt '*' file.get_devmm /dev/ttyUSB0
'''
if is_chrdev(name) or is_blkdev(name):
stat_structure = os.stat(name)
return (os.major(stat_structure.st_rdev),os.minor(stat_structure.st_rdev))
else:
return (0,0)
def is_chrdev(name):
'''
Check if a file exists and is a character device.
CLI Example:
.. code-block:: bash
salt '*' file.is_chrdev /dev/ttyUSB0
'''
stat_structure = None
try:
stat_structure = os.stat(name)
except OSError as exc:
if exc.errno == errno.ENOENT:
#If the character device does not exist in the first place
return False
else:
raise
return stat.S_ISCHR(stat_structure.st_mode)
def mknod_chrdev(name,
major,
minor,
user=None,
group=None,
mode='0660'):
'''
Create a character device.
CLI Example:
.. code-block:: bash
salt '*' file.mknod_chrdev /dev/tty0 4 0
'''
ret = {'name': name,
'changes': {},
'comment': '',
'result': False}
log.debug("Creating character device name:{0} major:{1} minor:{2} mode:{3}".format(name,
major,
minor,
mode))
try:
if __opts__['test']:
ret['changes'] = {'new' : 'Character device {0} created.'.format(name)}
ret['result'] = None
else:
if os.mknod(name,
int(str(mode).lstrip('0'),8)|stat.S_IFCHR,
os.makedev(major,minor)) is None:
ret['changes'] = {'new' : 'Character device {0} created.'.format(name)}
ret['result'] = True
except OSError as exc:
#be happy it is already there....however, if you are trying to change the major/minor, you will need to unlink it first as os.mknod will not overwrite
if exc.errno != errno.EEXIST:
raise
else:
ret['comment'] = 'File {0} exists and cannot be overwritten'.format(name)
#quick pass at verifying the permissions of the newly created character device
check_perms(name,
None,
user,
group,
int('{0}'.format(mode)) if mode else None)
return ret
def is_blkdev(name):
'''
Check if a file exists and is a block device.
CLI Example:
.. code-block:: bash
salt '*' file.is_blkdev /dev/sda1
'''
stat_structure = None
try:
stat_structure = os.stat(name)
except OSError as exc:
if exc.errno == errno.ENOENT:
#If the block device does not exist in the first place
return False
else:
raise
return stat.S_ISBLK(stat_structure.st_mode)
def mknod_blkdev(name,
major,
minor,
user=None,
group=None,
mode='0660'):
'''
Create a block device.
CLI Example:
.. code-block:: bash
salt '*' file.mknod_blkdev /dev/loop8 7 8
'''
ret = {'name': name,
'changes': {},
'comment': '',
'result': False}
log.debug("Creating block device name:{0} major:{1} minor:{2} mode:{3}".format(name,
major,
minor,
mode))
try:
if __opts__['test']:
ret['changes'] = {'new' : 'Block device {0} created.'.format(name)}
ret['result'] = None
else:
if os.mknod(name,
int(str(mode).lstrip('0'),8)|stat.S_IFBLK,
os.makedev(major,minor)) is None:
ret['changes'] = {'new' : 'Block device {0} created.'.format(name)}
ret['result'] = True
except OSError as exc:
#be happy it is already there....however, if you are trying to change the major/minor, you will need to unlink it first as os.mknod will not overwrite
if exc.errno != errno.EEXIST:
raise
else:
ret['comment'] = 'File {0} exists and cannot be overwritten'.format(name)
#quick pass at verifying the permissions of the newly created block device
check_perms(name,
None,
user,
group,
int('{0}'.format(mode)) if mode else None)
return ret
def is_fifo(name):
'''
Check if a file exists and is a FIFO.
CLI Example:
.. code-block:: bash
salt '*' file.is_fifo /dev/mypipe
'''
stat_structure = None
try:
stat_structure = os.stat(name)
except OSError as exc:
if exc.errno == errno.ENOENT:
#If the fifo does not exist in the first place
return False
else:
raise
return stat.S_ISFIFO(stat_structure.st_mode)
def mknod_fifo(name,
user=None,
group=None,
mode='0660'):
'''
Create a FIFO pipe.
CLI Example:
.. code-block:: bash
salt '*' file.mknod_fifo /dev/fifopipe
'''
ret = {'name': name,
'changes': {},
'comment': '',
'result': False}
log.debug("Creating FIFO name:{0}".format(name))
try:
if __opts__['test']:
ret['changes'] = {'new' : 'Fifo pipe {0} created.'.format(name)}
ret['result'] = None
else:
if os.mkfifo(name,int(str(mode).lstrip('0'),8)) is None:
ret['changes'] = {'new' : 'Fifo pipe {0} created.'.format(name)}
ret['result'] = True
except OSError as exc:
#be happy it is already there
if exc.errno != errno.EEXIST:
raise
else:
ret['comment'] = 'File {0} exists and cannot be overwritten'.format(name)
#quick pass at verifying the permissions of the newly created fifo
check_perms(name,
None,
user,
group,
int('{0}'.format(mode)) if mode else None)
return ret
def mknod(name,
ntype,
major=0,
minor=0,
user=None,
group=None,
mode='0600'):
'''
Create a block device, character device, or fifi pipe.
Identical to the gnu mknod.
CLI Example:
.. code-block:: bash
salt '*' file.mknod /dev/gadget c 134 8
salt '*' file.mknod /dev/sza1 b 8 900
salt '*' file.nknod /dev/pipe p
'''
ret = False
makedirs(name,
user,
group)
if ntype == 'c':
ret = mknod_chrdev(name,
major,
minor,
user,
group,
mode)
elif ntype == 'b':
ret = mknod_blkdev(name,
major,
minor,
user,
group,
mode)
elif ntype == 'p':
ret = mknod_fifo(name,
user,
group,
mode)
else:
raise Exception("Node type unavailable: '{0}'. Available node types are character ('c'), block ('b'), and pipe ('p').".format(ntype))
return ret
def list_backups(path, limit=None):
'''

View File

@ -2409,3 +2409,134 @@ def serialize(name,
template=None,
show_diff=show_diff,
contents=contents)
def mknod(name, ntype, major=0, minor=0, user=None, group=None, mode='0600'):
'''
Create a special file similar to the 'nix mknod command. The supported device types are
p (fifo pipe), c (character device), and b (block device). Provide the major and minor
numbers when specifying a character device or block device. A fifo pipe does not require
this information. The command will create the necessary dirs if needed. If a file of the
same name not of the same type/major/minor exists, it will not be overwritten or unlinked
(deleted). This is logically in place as a safety measure because you can really shoot
yourself in the foot here and it is the behavior of 'nix mknod. It is also important to
note that not just anyone can create special devices. Usually this is only done as root.
If the state is executed as none other than root on a minion, you may recieve a permision
error.
name
name of the file
ntype
node type 'p' (fifo pipe), 'c' (character device), or 'b' (block device)
major
major number of the device
does not apply to a fifo pipe
minor
minor number of the device
does not apply to a fifo pipe
user
owning user of the device/pipe
group
owning group of the device/pipe
mode
permissions on the device/pipe
Usage::
/dev/chr:
file.mknod:
- ntype: c
- major: 180
- minor: 31
- user: root
- group: root
- mode: 660
/dev/blk:
file.mknod:
- ntype: b
- major: 8
- minor: 999
- user: root
- group: root
- mode: 660
/dev/fifo:
file.mknod:
- ntype: p
- user: root
- group: root
- mode: 660
.. versionadded:: 0.17.0
'''
ret = {'name': name,
'changes': {},
'comment': '',
'result': False}
if ntype == 'c':
#check for file existence
if __salt__['file.file_exists'](name):
ret['comment'] = "File exists and is not a character device {0}. Cowardly refusing to continue".format(name)
#if it is a character device
elif not __salt__['file.is_chrdev'](name):
ret = __salt__['file.mknod'](name, ntype, major, minor, user, group, mode)
#check the major/minor
else:
devmaj, devmin = __salt__['file.get_devmm'](name)
if (major, minor) != (devmaj, devmin):
ret['comment'] = "Character device {0} exists and has a different major/minor {1}/{2}. Cowardly refusing to continue".format(name, devmaj, devmin)
#check the perms
else:
ret, perms = __salt__['file.check_perms'](name, None, user, group, mode)
if not ret['changes']:
ret['comment'] = "Character device {0} is in the correct state".format(name)
elif ntype == 'b':
#check for file existence
if __salt__['file.file_exists'](name):
ret['comment'] = "File exists and is not a block device {0}. Cowardly refusing to continue".format(name)
#if it is a block device
elif not __salt__['file.is_blkdev'](name):
ret = __salt__['file.mknod'](name, ntype, major, minor, user, group, mode)
#check the major/minor
else:
devmaj, devmin = __salt__['file.get_devmm'](name)
if (major, minor) != (devmaj, devmin):
ret['comment'] = "Block device {0} exists and has a different major/minor {1}/{2}. Cowardly refusing to continue".format(name, devmaj, devmin)
#check the perms
else:
ret, perms = __salt__['file.check_perms'](name, None, user, group, mode)
if not ret['changes']:
ret['comment'] = "Block device {0} is in the correct state".format(name)
elif ntype == 'p':
#check for file existence, if it is a fifo, user, group, and mode
if __salt__['file.file_exists'](name):
ret['comment'] = "File exists and is not a fifo pipe {0}. Cowardly refusing to continue".format(name)
#if it is a fifo
elif not __salt__['file.is_fifo'](name):
ret = __salt__['file.mknod'](name, ntype, major, minor, user, group, mode)
#check the perms
else:
ret, perms = __salt__['file.check_perms'](name, None, user, group, mode)
if not ret['changes']:
ret['comment'] = "Fifo pipe {0} is in the correct state".format(name)
else:
ret['comment'] = "Node type unavailable: '{0}. Available node types are character ('c'), block ('b'), and pipe ('p')".format(ntype)
return ret