<commit_before>--[[
LuCI - Lua Configuration Interface

Copyright 2008 <NAME> <<EMAIL>>
Copyright 2008 <NAME> <<EMAIL>>

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

$Id$
]]--

local io = require "io"
local os = require "os"
local fs = require "luci.fs"
local util = require "luci.util"
local ltn12 = require "luci.ltn12"
local posix = require "posix"

local type, assert, error = type, assert, error

module "luci.sys.mtdow"

WRITE_IMAGE = 0
WRITE_COMBINED = 1
WRITE_EMULATED = 2

ERROR_INTERNAL = 1
ERROR_NOTFOUND = 2
ERROR_RESOURCE = 3
ERROR_NODETECT = 4
ERROR_NOTAVAIL = 5
ERROR_NOSTREAM = 6
ERROR_INVMAGIC = 7

Writer = util.class()

-- x86
EmulatedWriter = util.class(Writer)
EmulatedWriter.blocks = {
	image = {
		magic = "eb48",
		device = "/dev/hda",
		write = WRITE_SEPARATELY
	}
}

function EmulatedWriter.write_block(self, name, imagestream, appendpattern)
	if appendpattern then
		os.execute("grep rootfs /proc/mtd >/dev/null || "
			.. "{ echo /dev/hda2,65536,rootfs > "
			.. "/sys/module/block2mtd/parameters/block2mtd }")
	end
	return Writer.write_block(self, name, imagestream, appendpattern)
end

-- Broadcom
CFEWriter = util.class(Writer)
CFEWriter.blocks = {
	image = {
		magic = {"4844", "5735"},
		device = "linux",
		write = WRITE_COMBINED
	}
}

-- Magicbox
CommonWriter = util.class(Writer)
CommonWriter.blocks = {
	image = {
		device = "linux",
		write = WRITE_COMBINED
	}
}

-- Atheros
RedWriter = util.class(Writer)
RedWriter.blocks = {
	kernel = {
		device = "vmlinux.bin.l7",
		write = WRITE_IMAGE
	},
	rootfs = {
		device = "rootfs",
		write = WRITE_COMBINED
	} 
}

-- Auto Detect
function native_writer()
	local w = Writer()
	
	-- Detect amd64 / x86
	local x86 = {"x86_64", "i386", "i486", "i586", "i686"}
	if util.contains(x86, posix.uname("%m")) then
		return EmulatedWriter()
	end
	
	-- Detect CFE
	if w:_find_mtdblock("cfe") and w:_find_mtdblock("linux") then
		return CFEWriter()
	end
	
	-- Detect Redboot
	if w:_find_mtdblock("RedBoot") and w:_find_mtdblock("vmlinux.bin.l7") then
		return RedWriter()
	end
	
	-- Detect MagicBox
	if fs.readfile("/proc/cpuinfo"):find("MagicBox") then
	 	return CommonWriter() 
	end
end



Writer.MTD = "/sbin/mtd"
Writer.SAFEMTD = "/tmp/mtd"
Writer.IMAGEFIFO = "/tmp/mtdimage.fifo"

function Writer.write_block(self, name, imagestream, appendfile)
	assert(self.blocks[name], ERROR_NOTFOUND)
	local block = self.blocks[name]
	local device = block.device
	device = fs.stat(device) and device or self:_find_mtdblock(device)
	assert(device, ERROR_NODETECT)
	if block.magic then
		imagestream = self:_check_magic(imagestream, block.magic)
	end
	assert(imagestream, ERROR_INVMAGIC)
	
	if appendfile then
		if block.write == WRITE_COMBINED then
			return (self:_write_combined(device, imagestream, appendfile) == 0)
		elseif block.write == WRITE_EMULATED then
			return (self:_write_emulated(device, imagestream, appendfile) == 0)
		else
			error(ERROR_NOTAVAIL)
		end
	else
		return (self:_write_memory(device, imagestream) == 0)
	end
end

function Writer._check_magic(self, imagestream, magic)
	magic = type(magic) == "table" and magic or {magic}
	
	local block = imagestream()
	assert(block, ERROR_NOSTREAM)
	local cm = "%x%x" % {block:byte(1), block:byte(2)}
	
	if util.contains(magic, cm) then
		return ltn12.source.cat(ltn12.source.string(block), imagestream)
	end
end

function Writer._find_mtdblock(self, mtdname)
	local k
	local prefix = "/dev/mtd"
	prefix = prefix .. (fs.stat(prefix) and "/" or "")
	
	for l in io.lines("/proc/mtd") do
		local k = l:match('mtd([%%w-_]+):.*"%s"' % mtdname)
		if k then return prefix..k end
	end
end

function Writer._write_emulated(self, devicename, imagestream, appendfile)
	local stat = (self:_write_memory(device, imagestream) == 0)
	stat = stat and (self:_refresh_block("rootfs") == 0)
	local squash = self:_find_mtdblock("rootfs_data")
	if squash then
		stat = stat and (self:_append("rootfs_data", imagestream, true) == 0)
	else
		stat = stat and (self:_append("rootfs", imagestream) == 0)
	end
	return stat
end

function Writer._write_memory(self, devicename, imagestream)
	local devicestream = ltn12.sink.file(io.open(devicename, "w"))
	local stat, err = ltn12.pump.all(imagestream, devicestream)
	if stat then
		return os.execute("sync")
	end
end

function Writer._write_combined(self, devicename, imagestream, appendfile)
	local imageproc = posix.fork()
	assert(imageproc ~= -1, ERROR_RESOURCE)
	if imageproc == 0 then
		fs.unlink(self.IMAGEFIFO)
		assert(posix.mkfifo(self.IMAGEFIFO), ERROR_RESOURCE)
		local imagefifo = io.open(self.IMAGEFIFO, "w")
		assert(imagefifo, ERROR_RESOURCE)
		ltn12.pump.all(imagestream, ltn12.sink.file(imagefifo))
		os.exit(0)
	end
	
	return os.execute( 
		"%s -j '%s' write '%s' '%s'" % {
			self.MTD, appendfile, self.IMAGEFIFO, devicename
		}
	)
end

function Writer._refresh_block(self, devicename)
	return os.execute("%s refresh '%s'" % {self.MTD, devicename})
end

function Writer._append(self, devicename, appendfile, erase)
	erase = erase and ("-e '%s' " % devicename) or ''
	
	return os.execute( 
		"%s %s jffs2write '%s' '%s'" % {
			self.MTD, erase, appendfile, devicename
		}
	)
end<commit_msg>More mtdow fixes<commit_after>--[[
LuCI - Lua Configuration Interface

Copyright 2008 <NAME> <<EMAIL>>
Copyright 2008 <NAME> <<EMAIL>>

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

$Id$
]]--

local io = require "io"
local os = require "os"
local fs = require "luci.fs"
local util = require "luci.util"
local ltn12 = require "luci.ltn12"
local posix = require "posix"

local type, assert, error = type, assert, error

module "luci.sys.mtdow"

WRITE_IMAGE = 0
WRITE_COMBINED = 1
WRITE_EMULATED = 2

ERROR_INTERNAL = 1
ERROR_NOTFOUND = 2
ERROR_RESOURCE = 3
ERROR_NODETECT = 4
ERROR_NOTAVAIL = 5
ERROR_NOSTREAM = 6
ERROR_INVMAGIC = 7

Writer = util.class()

-- x86
EmulatedWriter = util.class(Writer)
EmulatedWriter.blocks = {
	image = {
		magic = "eb48",
		device = "/dev/hda",
		write = WRITE_SEPARATELY
	}
}

function EmulatedWriter.write_block(self, name, imagestream, appendpattern)
	if appendpattern then
		os.execute("grep rootfs /proc/mtd >/dev/null || "
			.. "{ echo /dev/hda2,65536,rootfs > "
			.. "/sys/module/block2mtd/parameters/block2mtd }")
	end
	return Writer.write_block(self, name, imagestream, appendpattern)
end

-- Broadcom
CFEWriter = util.class(Writer)
CFEWriter.blocks = {
	image = {
		magic = {"4844", "5735"},
		device = "linux",
		write = WRITE_IMAGE
	}
}

-- Magicbox
CommonWriter = util.class(Writer)
CommonWriter.blocks = {
	image = {
		device = "linux",
		write = WRITE_COMBINED
	}
}

-- Atheros
RedWriter = util.class(Writer)
RedWriter.blocks = {
	kernel = {
		device = "vmlinux.bin.l7",
		write = WRITE_IMAGE
	},
	rootfs = {
		device = "rootfs",
		write = WRITE_COMBINED
	} 
}

-- Auto Detect
function native_writer()
	local w = Writer()
	
	-- Detect amd64 / x86
	local x86 = {"x86_64", "i386", "i486", "i586", "i686"}
	if util.contains(x86, posix.uname("%m")) then
		return EmulatedWriter()
	end
	
	-- Detect CFE
	if w:_find_mtdblock("cfe") and w:_find_mtdblock("linux") then
		return CFEWriter()
	end
	
	-- Detect Redboot
	if w:_find_mtdblock("RedBoot") and w:_find_mtdblock("vmlinux.bin.l7") then
		return RedWriter()
	end
	
	-- Detect MagicBox
	if fs.readfile("/proc/cpuinfo"):find("MagicBox") then
	 	return CommonWriter() 
	end
end



Writer.MTD = "/sbin/mtd"
Writer.SAFEMTD = "/tmp/mtd"
Writer.IMAGEFIFO = "/tmp/mtdimage.fifo"

function Writer.write_block(self, name, imagestream, appendfile)
	assert(self.blocks[name], ERROR_NOTFOUND)
	local block = self.blocks[name]
	local device = block.device
	device = fs.stat(device) and device or self:_find_mtdblock(device)
	assert(device, ERROR_NODETECT)
	if block.magic then
		imagestream = self:_check_magic(imagestream, block.magic)
	end
	assert(imagestream, ERROR_INVMAGIC)
	
	if appendfile then
		if block.write == WRITE_COMBINED then
			return (self:_write_combined(device, imagestream, appendfile) == 0)
		elseif block.write == WRITE_EMULATED then
			return (self:_write_emulated(device, imagestream, appendfile) == 0)
		else
			error(ERROR_NOTAVAIL)
		end
	else
		return (self:_write_memory(device, imagestream) == 0)
	end
end

function Writer._check_magic(self, imagestream, magic)
	magic = type(magic) == "table" and magic or {magic}
	
	local block = imagestream()
	assert(block, ERROR_NOSTREAM)
	local cm = "%x%x" % {block:byte(1), block:byte(2)}
	
	if util.contains(magic, cm) then
		return ltn12.source.cat(ltn12.source.string(block), imagestream)
	end
end

function Writer._find_mtdblock(self, mtdname)
	local k
	local prefix = "/dev/mtd"
	prefix = prefix .. (fs.stat(prefix) and "/" or "")
	
	for l in io.lines("/proc/mtd") do
		local k = l:match('mtd([%%w-_]+):.*"%s"' % mtdname)
		if k then return prefix..k end
	end
end

function Writer._write_emulated(self, devicename, imagestream, appendfile)
	local stat = (self:_write_memory(device, imagestream) == 0)
	stat = stat and (self:_refresh_block("rootfs") == 0)
	local squash = self:_find_mtdblock("rootfs_data")
	if squash then
		stat = stat and (self:_append("rootfs_data", imagestream, true) == 0)
	else
		stat = stat and (self:_append("rootfs", imagestream) == 0)
	end
	return stat
end

function Writer._write_memory(self, devicename, imagestream)
	local imageproc = posix.fork()
	assert(imageproc ~= -1, ERROR_RESOURCE)
	if imageproc == 0 then
		fs.unlink(self.IMAGEFIFO)
		assert(posix.mkfifo(self.IMAGEFIFO), ERROR_RESOURCE)
		local imagefifo = io.open(self.IMAGEFIFO, "w")
		assert(imagefifo, ERROR_RESOURCE)
		ltn12.pump.all(imagestream, ltn12.sink.file(imagefifo))
		os.exit(0)
	end
	
	return os.execute( 
		"%s write '%s' '%s'" % {
		self.MTD, self.IMAGEFIFO, devicename
		}
	)	
end

function Writer._write_combined(self, devicename, imagestream, appendfile)
	local imageproc = posix.fork()
	assert(imageproc ~= -1, ERROR_RESOURCE)
	if imageproc == 0 then
		fs.unlink(self.IMAGEFIFO)
		assert(posix.mkfifo(self.IMAGEFIFO), ERROR_RESOURCE)
		local imagefifo = io.open(self.IMAGEFIFO, "w")
		assert(imagefifo, ERROR_RESOURCE)
		ltn12.pump.all(imagestream, ltn12.sink.file(imagefifo))
		os.exit(0)
	end
	
	return os.execute( 
		"%s -j '%s' write '%s' '%s'" % {
			self.MTD, appendfile, self.IMAGEFIFO, devicename
		}
	)
end

function Writer._refresh_block(self, devicename)
	return os.execute("%s refresh '%s'" % {self.MTD, devicename})
end

function Writer._append(self, devicename, appendfile, erase)
	erase = erase and ("-e '%s' " % devicename) or ''
	
	return os.execute( 
		"%s %s jffs2write '%s' '%s'" % {
			self.MTD, erase, appendfile, devicename
		}
	)
end
{'fraction_non_alphanumeric': 0.13560564412680962, 'fraction_numerical': 0.018050210738501007, 'mean_word_length': 4.376847290640394, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6692939', 'n_tokens_mistral': 4412, 'n_tokens_neox': 4086, 'n_words': 982}