2008-03-05 09:52:00 -05:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// Microsoft Research Singularity
|
|
|
|
//
|
|
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
//
|
|
|
|
// File: DistroBuilder.cs
|
|
|
|
//
|
|
|
|
// Note: Main entry point for DistroBuilder tool, used to collect
|
|
|
|
// application metadata into a manifest.
|
|
|
|
//
|
|
|
|
using System;
|
|
|
|
using System.IO;
|
|
|
|
using System.Xml;
|
2008-11-17 18:29:00 -05:00
|
|
|
using System.Diagnostics;
|
|
|
|
using System.Collections.Generic;
|
2008-03-05 09:52:00 -05:00
|
|
|
using System.Security.Cryptography;
|
|
|
|
|
|
|
|
public class DistroBuilder
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// Fields in the distro build class
|
|
|
|
//
|
|
|
|
|
|
|
|
XmlNode systemPolicy; // the external xml policy
|
|
|
|
|
|
|
|
// manifest and well-defined nodes
|
|
|
|
XmlDocument systemManifest;
|
|
|
|
XmlNode manifestRoot;
|
|
|
|
XmlNode drivers;
|
|
|
|
|
|
|
|
// internal node that we build and add to the manifest
|
|
|
|
XmlNode fileList;
|
|
|
|
|
|
|
|
// all files in the distro (full names, plus the separate directory prefix)
|
|
|
|
string distroDirectoryName;
|
2008-11-17 18:29:00 -05:00
|
|
|
readonly Set<String> applicationFiles = new Set<String>();
|
|
|
|
readonly Set<String> manifestFiles = new Set<String>();
|
|
|
|
readonly Set<String> otherFiles = new Set<String>();
|
2008-03-05 09:52:00 -05:00
|
|
|
|
|
|
|
// key filenames
|
2008-11-17 18:29:00 -05:00
|
|
|
string kernelPath; // kernel path+name
|
|
|
|
string systemPath; // system manifest path+name
|
|
|
|
string systemName; // just the name of the manifest
|
|
|
|
string iniFilePath; // ini file
|
2008-03-05 09:52:00 -05:00
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
// whether this is a subordinate kernel or not
|
|
|
|
bool subordinateKernel;
|
|
|
|
|
|
|
|
static string[] nativeSuffixes = { ".x86", ".x64", ".arm" };
|
|
|
|
|
|
|
|
private static bool IsNativeBinaryName(string path)
|
|
|
|
{
|
|
|
|
foreach (string suffix in nativeSuffixes) {
|
|
|
|
if (path.EndsWith(suffix)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static bool IsManifestName(string path)
|
|
|
|
{
|
|
|
|
return (path.EndsWith(".manifest"));
|
|
|
|
}
|
|
|
|
|
|
|
|
private static string NativeBinaryToPrefix(string path)
|
|
|
|
{
|
|
|
|
foreach (string suffix in nativeSuffixes) {
|
|
|
|
if (path.EndsWith(suffix)) {
|
|
|
|
return path.Substring(0, path.Length - suffix.Length);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static string NativeBinaryToManifest(string path)
|
|
|
|
{
|
|
|
|
string prefix = NativeBinaryToPrefix(path);
|
|
|
|
if (prefix != null) {
|
|
|
|
return prefix + ".manifest";
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static string StripPathFromFile(string path)
|
|
|
|
{
|
|
|
|
int index = path.LastIndexOf('/');
|
|
|
|
if (index < 0) {
|
|
|
|
index = path.LastIndexOf('\\');
|
|
|
|
}
|
|
|
|
if (index >= 0) {
|
|
|
|
return path.Substring(index + 1);
|
|
|
|
}
|
|
|
|
return path;
|
|
|
|
}
|
2008-03-05 09:52:00 -05:00
|
|
|
|
|
|
|
// set up an object that can build the distribution
|
2008-11-17 18:29:00 -05:00
|
|
|
internal DistroBuilder(string kernelFile,
|
|
|
|
string policyFile,
|
|
|
|
string outputFile,
|
|
|
|
string iniFile,
|
|
|
|
string distroDirectoryName,
|
|
|
|
string distroDescriptionFileName,
|
|
|
|
bool subKernel)
|
2008-03-05 09:52:00 -05:00
|
|
|
{
|
2008-11-17 18:29:00 -05:00
|
|
|
subordinateKernel = subKernel;
|
|
|
|
|
|
|
|
kernelPath = kernelFile;
|
|
|
|
|
2008-03-05 09:52:00 -05:00
|
|
|
// copy output file names.
|
2008-11-17 18:29:00 -05:00
|
|
|
systemPath = outputFile;
|
|
|
|
iniFilePath = iniFile;
|
2008-03-05 09:52:00 -05:00
|
|
|
|
|
|
|
// load the system policy.
|
|
|
|
XmlDocument policyDoc = new XmlDocument();
|
|
|
|
policyDoc.Load(policyFile);
|
|
|
|
systemPolicy = GetChild(policyDoc, "distribution");
|
|
|
|
|
|
|
|
// set up Xml pieces.
|
|
|
|
systemManifest = new XmlDocument();
|
2008-11-17 18:29:00 -05:00
|
|
|
manifestRoot = systemManifest.CreateElement("system");
|
|
|
|
systemManifest.AppendChild(manifestRoot);
|
2008-03-05 09:52:00 -05:00
|
|
|
|
|
|
|
fileList = AddElement(null, "files");
|
|
|
|
drivers = AddElement(null, "drivers");
|
|
|
|
|
|
|
|
FileInfo allFiles = new FileInfo(distroDescriptionFileName);
|
|
|
|
StreamReader stream = allFiles.OpenText();
|
2008-11-17 18:29:00 -05:00
|
|
|
|
|
|
|
for (string s = null; (s = stream.ReadLine()) != null;) {
|
|
|
|
if (IsNativeBinaryName(s)) {
|
|
|
|
if (s.Equals(kernelPath, StringComparison.OrdinalIgnoreCase)) {
|
|
|
|
// The kernel doesn't go in the default binary list.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
applicationFiles.Add(s);
|
2008-03-05 09:52:00 -05:00
|
|
|
}
|
2008-11-17 18:29:00 -05:00
|
|
|
else if (IsManifestName(s)) {
|
|
|
|
manifestFiles.Add(s);
|
2008-03-05 09:52:00 -05:00
|
|
|
}
|
|
|
|
else {
|
2008-11-17 18:29:00 -05:00
|
|
|
otherFiles.Add(s);
|
2008-03-05 09:52:00 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
stream.Close();
|
|
|
|
|
|
|
|
// add the output file to the list
|
2008-11-17 18:29:00 -05:00
|
|
|
systemName = StripPathFromFile(systemPath);
|
2008-03-05 09:52:00 -05:00
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
FileInfo outFile = new FileInfo(systemPath);
|
|
|
|
systemPath = outFile.FullName;
|
|
|
|
if (!otherFiles.ContainsKey(systemPath)) {
|
|
|
|
otherFiles.Add(systemPath);
|
2008-03-05 09:52:00 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// now get the fully path for the distro directory name
|
|
|
|
FileInfo directoryInfo = new FileInfo(distroDirectoryName);
|
|
|
|
this.distroDirectoryName = directoryInfo.FullName;
|
|
|
|
}
|
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
const string ServiceConfigElementName = "serviceConfig";
|
|
|
|
const string ServiceElementName = "service";
|
|
|
|
const string ServiceNameAttributeName = "name";
|
|
|
|
const string ManifestNameAttributeName = "binary";
|
|
|
|
const string ServiceActivationModeAttributeName = "activationMode";
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// This method modifies the system manifest XML document by inserting service elements for
|
|
|
|
/// services specified on the command line. If any existing service elements are found that
|
|
|
|
/// have the same service name, then the service specification provided on the command line
|
|
|
|
/// overrides the existing service specification.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="document">The policy document to modify.</param>
|
|
|
|
/// <param name="services">The set of service specifications to add to the document.</param>
|
|
|
|
internal void AddServicesToSystemManifest(XmlElement serviceConfigElement, IEnumerable<ServiceInfo> services)
|
|
|
|
{
|
|
|
|
XmlDocument document = serviceConfigElement.OwnerDocument;
|
|
|
|
Dictionary<String, XmlElement> existingServices = new Dictionary<String, XmlElement>();
|
|
|
|
|
|
|
|
// First, build an index of all of the existing <service> elements,
|
|
|
|
// using the value of the 'name' attribute as the key.
|
|
|
|
foreach (XmlNode node in serviceConfigElement.ChildNodes) {
|
|
|
|
if (node.NodeType != XmlNodeType.Element) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
XmlElement element = (XmlElement)node;
|
|
|
|
if (element.Name != ServiceElementName) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
string serviceName = element.GetAttribute(ServiceNameAttributeName);
|
|
|
|
if (String.IsNullOrEmpty(serviceName)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
existingServices[serviceName] = element;
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach (ServiceInfo service in services) {
|
|
|
|
string serviceName = service.ServiceName;
|
|
|
|
XmlElement serviceElement;
|
|
|
|
if (existingServices.TryGetValue(serviceName, out serviceElement)) {
|
|
|
|
WriteWarningLine("Found existing service '{0}' in source policy document. Overriding with values specified on command line.", serviceName);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
serviceElement = document.CreateElement(ServiceElementName);
|
|
|
|
serviceConfigElement.AppendChild(serviceElement);
|
|
|
|
serviceElement.SetAttribute(ServiceNameAttributeName, serviceName);
|
|
|
|
existingServices.Add(serviceName, serviceElement);
|
|
|
|
}
|
|
|
|
|
|
|
|
serviceElement.SetAttribute(ServiceActivationModeAttributeName, service.ActivationMode);
|
|
|
|
serviceElement.SetAttribute(ManifestNameAttributeName, service.ManifestName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-05 09:52:00 -05:00
|
|
|
//////////////////////////////////////////////// Methods to help with XML.
|
|
|
|
//
|
2008-11-17 18:29:00 -05:00
|
|
|
private XmlElement AddElement(XmlElement parent, string name)
|
2008-03-05 09:52:00 -05:00
|
|
|
{
|
2008-11-17 18:29:00 -05:00
|
|
|
XmlElement element = systemManifest.CreateElement(name);
|
2008-03-05 09:52:00 -05:00
|
|
|
if (parent != null) {
|
|
|
|
parent.AppendChild(element);
|
|
|
|
}
|
|
|
|
return element;
|
|
|
|
}
|
|
|
|
|
|
|
|
private XmlNode AddImported(XmlNode parent, XmlNode root, bool deep)
|
|
|
|
{
|
|
|
|
XmlNode element = systemManifest.ImportNode(root, true);
|
|
|
|
if (parent != null) {
|
|
|
|
parent.AppendChild(element);
|
|
|
|
}
|
|
|
|
return element;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return an array with every child of the parent whose name matches
|
|
|
|
// <name>
|
|
|
|
private static XmlNode[] GetChildren(XmlNode parent, string name)
|
|
|
|
{
|
2008-11-17 18:29:00 -05:00
|
|
|
List<XmlNode> result = new List<XmlNode>();
|
2008-03-05 09:52:00 -05:00
|
|
|
|
|
|
|
foreach (XmlNode child in parent.ChildNodes) {
|
|
|
|
if (child.Name == name) {
|
|
|
|
result.Add(child);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result.Count == 0) {
|
|
|
|
return new XmlNode[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
XmlNode[] children = new XmlNode [result.Count];
|
|
|
|
for (int i = 0; i < result.Count; i++) {
|
|
|
|
children[i] = (XmlNode)result[i];
|
|
|
|
}
|
|
|
|
return children;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the first child named `name'
|
|
|
|
private static XmlNode GetChild(XmlNode parent, string name)
|
|
|
|
{
|
|
|
|
return parent[name];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get end node along a path of first matches
|
|
|
|
private static XmlNode GetDescendant(XmlNode root, string [] path)
|
|
|
|
{
|
|
|
|
XmlNode parent = root;
|
|
|
|
|
|
|
|
foreach (string pathelement in path) {
|
|
|
|
parent = GetChild(parent, pathelement);
|
|
|
|
if (parent == null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the named attribute if it exists.
|
|
|
|
private static string GetAttribute(XmlNode node, string attrib)
|
|
|
|
{
|
|
|
|
XmlAttribute xa = node.Attributes[attrib];
|
|
|
|
return xa != null ? xa.Value : null;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static string GetAttribute(XmlNode node, string attrib, string value)
|
|
|
|
{
|
|
|
|
XmlAttribute xa = node.Attributes[attrib];
|
|
|
|
return xa != null ? xa.Value : value;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static int GetAttribute(XmlNode node, string attrib, int value)
|
|
|
|
{
|
|
|
|
XmlAttribute xa = node.Attributes[attrib];
|
|
|
|
return xa != null ? Int32.Parse(xa.Value) : value;
|
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// return true if the node's name is in names.
|
|
|
|
private bool TestNodeIs(XmlNode node, string [] names)
|
|
|
|
{
|
|
|
|
foreach (string name in names) {
|
|
|
|
if (node.Name == name) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
const string DriverElementName = "driver";
|
2008-03-05 09:52:00 -05:00
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
// TODO: this attribute create code should be in a function!
|
2008-03-05 09:52:00 -05:00
|
|
|
// add a DriverCategory node into the <drivers>
|
|
|
|
private void AddDriverNode(string name, string path,
|
|
|
|
string signature, string iclass,
|
2008-11-17 18:29:00 -05:00
|
|
|
IEnumerable<XmlNode> values)
|
2008-03-05 09:52:00 -05:00
|
|
|
{
|
|
|
|
// create the new node
|
2008-11-17 18:29:00 -05:00
|
|
|
XmlElement driver = systemManifest.CreateElement(DriverElementName);
|
2008-03-05 09:52:00 -05:00
|
|
|
|
|
|
|
// set its name, signature, and path
|
2008-11-17 18:29:00 -05:00
|
|
|
driver.SetAttribute("name", name);
|
|
|
|
driver.SetAttribute("signature", signature);
|
|
|
|
driver.SetAttribute("path", path);
|
2008-03-05 09:52:00 -05:00
|
|
|
if (iclass != "") {
|
2008-11-17 18:29:00 -05:00
|
|
|
driver.SetAttribute("class", iclass);
|
2008-03-05 09:52:00 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// add any enumerates via copy.
|
|
|
|
foreach (XmlNode node in values) {
|
|
|
|
driver.AppendChild(node.CloneNode(true));
|
|
|
|
}
|
|
|
|
|
|
|
|
// and insert this node into the registry:
|
|
|
|
drivers.AppendChild(driver);
|
|
|
|
}
|
|
|
|
|
|
|
|
// given a driverCategory that potentially has many device signatures, split
|
|
|
|
// it by device and create an entry in the drivers for each device
|
|
|
|
private void CreateRegistryEntriesFromCategory(XmlNode category,
|
|
|
|
string name,
|
|
|
|
string path)
|
|
|
|
{
|
2008-11-17 18:29:00 -05:00
|
|
|
List<XmlNode> values = new List<XmlNode>();
|
2008-03-05 09:52:00 -05:00
|
|
|
|
|
|
|
// first parse the entries in the driver category to fill out the
|
|
|
|
// Endpoint, FixedHardware, and DynamicHardware sets
|
|
|
|
string iclass = GetAttribute(category, "class", "");
|
|
|
|
|
|
|
|
// now populate these with children based on a few basic matching rules
|
|
|
|
foreach (XmlNode node in category.ChildNodes) {
|
|
|
|
if (node.Name == "enumerates" ||
|
|
|
|
node.Name == "endpoints" ||
|
|
|
|
node.Name == "fixedHardware" ||
|
|
|
|
node.Name == "dynamicHardware" ||
|
|
|
|
node.Name == "configs") {
|
|
|
|
values.Add(AddImported(null, node, true));
|
|
|
|
}
|
|
|
|
else if (node.Name != "device") {
|
|
|
|
//
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// get every device signature in this driver category
|
|
|
|
XmlNode[] signatureTags = GetChildren(category, "device");
|
|
|
|
|
|
|
|
// there's a chance (for example, with the Hal) that there are no
|
|
|
|
// signatures. In this case, we process the category once, with a null
|
|
|
|
// signature
|
|
|
|
if (signatureTags.Length == 0) {
|
|
|
|
AddDriverNode(name, path, "", iclass, values);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
foreach (XmlNode signature in signatureTags) {
|
|
|
|
string value = GetAttribute(signature, "signature", "");
|
|
|
|
AddDriverNode(name, path, value, iclass, values);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is the main method for creating a driver registry.
|
|
|
|
public void CreateDriverRegistry()
|
|
|
|
{
|
2008-11-17 18:29:00 -05:00
|
|
|
foreach (string filename in manifestFiles) {
|
|
|
|
// get the manifest as an Xml document
|
|
|
|
XmlDocument manifestDoc = new XmlDocument();
|
|
|
|
manifestDoc.Load(filename);
|
2008-03-05 09:52:00 -05:00
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
XmlNode application = GetChild(manifestDoc, "application");
|
2008-03-05 09:52:00 -05:00
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
// Read the name and path from the manifest
|
|
|
|
string name = GetAttribute(application, "name");
|
2008-03-05 09:52:00 -05:00
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
// Console.WriteLine("{0}:", filename);
|
|
|
|
foreach (XmlNode process in GetChildren(application, "process")) {
|
|
|
|
string path = GetAttribute(process, "path", "");
|
2008-03-05 09:52:00 -05:00
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
foreach (XmlNode categories in GetChildren(process, "categories")) {
|
|
|
|
foreach (XmlNode category in GetChildren(categories, "category")) {
|
|
|
|
if (GetAttribute(category, "name") != "driver") {
|
|
|
|
continue;
|
|
|
|
}
|
2008-03-05 09:52:00 -05:00
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
string iclass = GetAttribute(category, "class", "");
|
2008-03-05 09:52:00 -05:00
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
// now process all DriverCategories
|
|
|
|
CreateRegistryEntriesFromCategory(category, name, path);
|
2008-03-05 09:52:00 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private bool NamesMatch(string target, string prefix, bool isPrefix)
|
|
|
|
{
|
|
|
|
int len = isPrefix ? prefix.Length :
|
|
|
|
(target.Length > prefix.Length ? target.Length : prefix.Length);
|
|
|
|
|
|
|
|
return (String.Compare(target, 0, prefix, 0, len, true) == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Remove unwanted drivers from the rot using the policy.
|
|
|
|
private void RemoveNodes(XmlNode root, XmlNode policy)
|
|
|
|
{
|
|
|
|
foreach (XmlNode rule in policy.ChildNodes) {
|
|
|
|
string attrName = "";
|
|
|
|
string attrVal = "";
|
|
|
|
bool isPrefix = false;
|
|
|
|
|
|
|
|
if (rule.Name == "driver") {
|
|
|
|
attrName = "name";
|
|
|
|
}
|
|
|
|
else if (rule.Name == "device") {
|
|
|
|
attrName = "signature";
|
|
|
|
isPrefix = true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
continue;
|
|
|
|
}
|
2008-11-17 18:29:00 -05:00
|
|
|
List<XmlNode> removals = new List<XmlNode>();
|
2008-03-05 09:52:00 -05:00
|
|
|
attrVal = GetAttribute(rule, attrName);
|
|
|
|
foreach (XmlNode candidate in root.ChildNodes) {
|
|
|
|
string target = GetAttribute(candidate, attrName);
|
|
|
|
|
|
|
|
if (NamesMatch(target, attrVal, isPrefix)) {
|
|
|
|
removals.Add(candidate);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
foreach (XmlNode oldnode in removals) {
|
|
|
|
root.RemoveChild(oldnode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// in addition, we use the imperative mechanism to create the "follows"
|
|
|
|
// ordering, which lets us specify a more total order on the initialization
|
|
|
|
// of drivers
|
|
|
|
private void ApplyOrdering(XmlNode root, XmlNode policy)
|
|
|
|
{
|
|
|
|
foreach (XmlNode rule in policy.ChildNodes) {
|
|
|
|
string signature = GetAttribute(rule, "signature");
|
|
|
|
string name = GetAttribute(rule, "name");
|
|
|
|
foreach (XmlNode candidate in root.ChildNodes) {
|
2008-11-17 18:29:00 -05:00
|
|
|
if (candidate.NodeType != XmlNodeType.Element)
|
|
|
|
continue;
|
|
|
|
|
2008-03-05 09:52:00 -05:00
|
|
|
string candidatesignature = GetAttribute(candidate, "signature");
|
|
|
|
if (candidatesignature.StartsWith(signature)) {
|
2008-11-17 18:29:00 -05:00
|
|
|
XmlElement tag = AddElement((XmlElement)candidate, rule.Name);
|
|
|
|
tag.SetAttribute("name", name);
|
2008-03-05 09:52:00 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// and this is the master method for applying the imperative policy
|
|
|
|
private void ApplyPolicyToRegistry()
|
|
|
|
{
|
|
|
|
// get its driversConfig:
|
|
|
|
XmlNode policy = GetChild(systemPolicy, "driverRegistryConfig");
|
|
|
|
|
|
|
|
// go through each imperative command
|
|
|
|
foreach (XmlNode child in policy.ChildNodes) {
|
|
|
|
if (child.Name == "remove") {
|
|
|
|
RemoveNodes(drivers, child);
|
|
|
|
}
|
|
|
|
else if (child.Name == "ordering") {
|
|
|
|
ApplyOrdering(drivers, child);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This prints the distribution manifest when all is done
|
|
|
|
public void PrintManifestFile()
|
|
|
|
{
|
2008-11-17 18:29:00 -05:00
|
|
|
XmlTextWriter w = new XmlTextWriter(systemPath,
|
2008-03-05 09:52:00 -05:00
|
|
|
System.Text.Encoding.UTF8);
|
|
|
|
w.Formatting = Formatting.Indented;
|
|
|
|
systemManifest.Save(w);
|
|
|
|
w.Close();
|
|
|
|
}
|
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
// TODO: there ought to be some policy that decides what should
|
|
|
|
// to in the distribution, but for now we just take as
|
|
|
|
// input a list of files that have been built, and assume
|
|
|
|
// it is the output of this alluded-to step
|
2008-03-05 09:52:00 -05:00
|
|
|
|
|
|
|
// Every file in the distro must be added to a list, both so that the file
|
|
|
|
// can be added to SingBoot.ini, and so that it can have a filename
|
|
|
|
// associated with it in the namespace
|
|
|
|
private void AddFileNode(string pathName, int index, bool visible,
|
|
|
|
int manifestIndex)
|
|
|
|
{
|
2008-11-17 18:29:00 -05:00
|
|
|
XmlElement file = AddElement(null, "file");
|
2008-03-05 09:52:00 -05:00
|
|
|
|
|
|
|
// get values for all the attributes of this file:
|
2008-11-17 18:29:00 -05:00
|
|
|
bool isExecutable = (IsNativeBinaryName(pathName) &&
|
|
|
|
!pathName.Equals(kernelPath, StringComparison.OrdinalIgnoreCase));
|
|
|
|
bool isManifest = IsManifestName(pathName);
|
|
|
|
string shortName = StripPathFromFile(pathName).ToLower();
|
2008-03-05 09:52:00 -05:00
|
|
|
|
|
|
|
string [] nameSet = pathName.Split('\\');
|
2008-11-17 18:29:00 -05:00
|
|
|
int fileIndex = 0;
|
|
|
|
for (int i = 0; i < nameSet.Length; i++) {
|
|
|
|
if (nameSet[i] == "Files") {
|
|
|
|
fileIndex = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// if this is the "/Distro/Files" directory
|
|
|
|
// allow subdirectories in the short name
|
|
|
|
if (fileIndex > 0 && (((nameSet.Length - 1) - fileIndex > 1))) {
|
|
|
|
isExecutable = false;
|
|
|
|
isManifest = false;
|
|
|
|
shortName = null;
|
|
|
|
for (int i = fileIndex + 1; i < nameSet.Length; i++) {
|
|
|
|
shortName = shortName + "/" + nameSet[i].ToLower();
|
|
|
|
}
|
|
|
|
}
|
2008-03-05 09:52:00 -05:00
|
|
|
string distroName = pathName.Remove(0, distroDirectoryName.Length);
|
|
|
|
distroName = distroName.Replace('\\', '/');
|
|
|
|
|
|
|
|
// add the attributes:
|
2008-11-17 18:29:00 -05:00
|
|
|
file.SetAttribute("distroName", distroName);
|
|
|
|
file.SetAttribute("name", shortName);
|
|
|
|
file.SetAttribute("id", index.ToString());
|
2008-03-05 09:52:00 -05:00
|
|
|
|
|
|
|
if (isExecutable) {
|
2008-11-17 18:29:00 -05:00
|
|
|
file.SetAttribute("executable", "true");
|
2008-03-05 09:52:00 -05:00
|
|
|
}
|
|
|
|
else if (isManifest) {
|
2008-11-17 18:29:00 -05:00
|
|
|
file.SetAttribute("manifest", "true");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (manifestIndex > 0) {
|
|
|
|
file.SetAttribute("manifestId", manifestIndex.ToString());
|
2008-03-05 09:52:00 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// add the file to the master file list
|
2008-11-17 18:29:00 -05:00
|
|
|
fileList.AppendChild(file);
|
2008-03-05 09:52:00 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// This calls the above method to populate the fileList with all files that
|
|
|
|
// are to be included in the distribution
|
|
|
|
private void BuildFileList()
|
|
|
|
{
|
2008-11-17 18:29:00 -05:00
|
|
|
int position = 3;
|
2008-03-05 09:52:00 -05:00
|
|
|
|
|
|
|
// first of all, let's set the kernel.dmp and output manifest file
|
|
|
|
// entries
|
2008-11-17 18:29:00 -05:00
|
|
|
AddFileNode(kernelPath, 0, false, 2);
|
|
|
|
AddFileNode(systemPath, 1, false, -1);
|
|
|
|
AddFileNode(NativeBinaryToManifest(kernelPath), 2, false, -1);
|
|
|
|
|
|
|
|
if (!subordinateKernel) {
|
|
|
|
|
|
|
|
// now let's build the file list:
|
|
|
|
// get the policy on what goes in the bootscript
|
|
|
|
XmlNode policy = GetDescendant(systemPolicy, new string[] {"bootScript",
|
|
|
|
"folders"});
|
|
|
|
foreach (XmlNode rule in policy.ChildNodes) {
|
|
|
|
if (rule.Name != "folder") {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
string folder = GetAttribute(rule, "name");
|
|
|
|
foreach (string applicationName in applicationFiles) {
|
|
|
|
string manifestName = applicationName + ".manifest";
|
|
|
|
string shortAppName = applicationName.Replace(distroDirectoryName, "");
|
|
|
|
if (shortAppName.StartsWith("\\" + folder)) {
|
|
|
|
if (manifestFiles.ContainsKey(manifestName)) {
|
|
|
|
AddFileNode(applicationName, position, true,
|
|
|
|
++position);
|
|
|
|
AddFileNode(manifestName, position, true, -1);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
AddFileNode(applicationName, position, true, -1);
|
|
|
|
}
|
|
|
|
position++;
|
2008-03-05 09:52:00 -05:00
|
|
|
}
|
|
|
|
}
|
2008-11-17 18:29:00 -05:00
|
|
|
foreach (string fileName in otherFiles) {
|
|
|
|
string shortFileName = fileName.Replace(distroDirectoryName, "");
|
|
|
|
if (shortFileName.StartsWith("\\" + folder)) {
|
|
|
|
AddFileNode(fileName, position++, true, -1);
|
|
|
|
}
|
2008-03-05 09:52:00 -05:00
|
|
|
}
|
2008-11-17 18:29:00 -05:00
|
|
|
// NB - we don't copy a manifest unless we've associated it with an
|
|
|
|
// app
|
2008-03-05 09:52:00 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Given only a list of drivers, a list of files, and some policy, we need
|
|
|
|
// to create a system manifest. This is how we do it for now.
|
2008-11-17 18:29:00 -05:00
|
|
|
internal void InstallPolicies(IEnumerable<ServiceInfo> services)
|
2008-03-05 09:52:00 -05:00
|
|
|
{
|
|
|
|
// build the file list that goes into the manifest
|
|
|
|
BuildFileList();
|
|
|
|
|
|
|
|
// set up the initConfig tag and append the file list to it
|
|
|
|
XmlNode initConfig = GetChild(systemPolicy, "initConfig");
|
|
|
|
XmlNode newInitConfig = systemManifest.ImportNode(initConfig, true);
|
|
|
|
newInitConfig.AppendChild(fileList);
|
|
|
|
|
|
|
|
// get the namingConventions
|
|
|
|
XmlNode namingConventions = GetChild(systemPolicy, "namingConventions");
|
|
|
|
XmlNode newNaming = systemManifest.ImportNode(namingConventions, true);
|
|
|
|
|
|
|
|
// get process grouping data
|
|
|
|
XmlNode processConfig = GetChild(systemPolicy, "processConfig");
|
|
|
|
XmlNode newProcessConfig = null;
|
|
|
|
if (processConfig != null) {
|
|
|
|
newProcessConfig = systemManifest.ImportNode(processConfig, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
// get service configurations
|
2008-11-17 18:29:00 -05:00
|
|
|
XmlNode serviceConfig = GetChild(systemPolicy, ServiceConfigElementName);
|
|
|
|
XmlElement newServiceConfig = serviceConfig != null ? (XmlElement)systemManifest.ImportNode(serviceConfig, true)
|
|
|
|
: systemManifest.CreateElement(ServiceConfigElementName);
|
|
|
|
AddServicesToSystemManifest(newServiceConfig, services);
|
|
|
|
|
2008-03-05 09:52:00 -05:00
|
|
|
|
|
|
|
// apply the imperative policy to the Driver Registry (this prunes it)
|
|
|
|
ApplyPolicyToRegistry();
|
|
|
|
|
|
|
|
// add everything to the manifest
|
|
|
|
manifestRoot.AppendChild(drivers);
|
|
|
|
manifestRoot.AppendChild(newNaming);
|
|
|
|
manifestRoot.AppendChild(newServiceConfig);
|
|
|
|
if (newProcessConfig != null) {
|
|
|
|
manifestRoot.AppendChild(newProcessConfig);
|
|
|
|
}
|
|
|
|
manifestRoot.AppendChild(newInitConfig);
|
|
|
|
}
|
|
|
|
|
|
|
|
// When everything is set, we still need the Singboot.ini
|
|
|
|
// file. This is how we make it:
|
|
|
|
public void MakeIniFile(string distrodir)
|
|
|
|
{
|
2008-11-17 18:29:00 -05:00
|
|
|
using (StreamWriter stream = new StreamWriter(iniFilePath, false)) {
|
|
|
|
string ruler = new String('#', 79);
|
|
|
|
stream.WriteLine(ruler);
|
|
|
|
stream.WriteLine("# SingBoot.ini");
|
|
|
|
stream.WriteLine("# Build Date: {0}", System.DateTime.Now.ToString());
|
|
|
|
stream.WriteLine(ruler);
|
|
|
|
|
|
|
|
using (MD5 md5 = MD5.Create()) {
|
|
|
|
foreach (XmlNode file in fileList) {
|
|
|
|
string installedFileName = GetAttribute(file, "distroName");
|
|
|
|
string originalFileName =
|
|
|
|
distrodir + installedFileName.Replace("/", "\\");
|
|
|
|
|
|
|
|
FileInfo fileInfo = new FileInfo(originalFileName);
|
|
|
|
using (FileStream fs = fileInfo.OpenRead()) {
|
|
|
|
byte[] hash = md5.ComputeHash(fs);
|
|
|
|
stream.Write("Hash-MD5=");
|
|
|
|
foreach (byte b in hash) {
|
|
|
|
stream.Write("{0:x2}", b);
|
|
|
|
}
|
|
|
|
}
|
2008-03-05 09:52:00 -05:00
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
stream.WriteLine(" Size={0} Path={1}",
|
|
|
|
fileInfo.Length, installedFileName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// NB Trailing ruler helps identify the end of file
|
|
|
|
stream.WriteLine(ruler);
|
|
|
|
}
|
|
|
|
}
|
2008-03-05 09:52:00 -05:00
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
/// <summary>
|
|
|
|
/// Writes an error line that matches the Visual Studio format for errors.
|
|
|
|
/// This allows VS to find the errors in its output window.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="line">The error message to write.</param>
|
|
|
|
static void WriteErrorLine(string message)
|
|
|
|
{
|
|
|
|
Console.WriteLine("error : " + message);
|
|
|
|
}
|
2008-03-05 09:52:00 -05:00
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
static void WriteErrorLine(string format, params object[] args)
|
|
|
|
{
|
|
|
|
WriteErrorLine(String.Format(format, args));
|
|
|
|
}
|
2008-03-05 09:52:00 -05:00
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
static void WriteWarningLine(string message)
|
|
|
|
{
|
|
|
|
Console.WriteLine("warning : " + message);
|
|
|
|
}
|
2008-03-05 09:52:00 -05:00
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
static void WriteWarningLine(string format, params object[] args)
|
|
|
|
{
|
|
|
|
WriteErrorLine(String.Format(format, args));
|
2008-03-05 09:52:00 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Print the correct command line args for the program
|
|
|
|
static void PrintUsage()
|
|
|
|
{
|
|
|
|
Console.WriteLine(
|
|
|
|
"Usage:\n" +
|
|
|
|
" distrobuilder [options]\n" +
|
|
|
|
"Options:\n" +
|
2008-11-17 18:29:00 -05:00
|
|
|
" /desc:<desc> - Distribution description.\n" +
|
2008-03-05 09:52:00 -05:00
|
|
|
" /dir:<path> - Set distribution root directory\n" +
|
2008-11-17 18:29:00 -05:00
|
|
|
" /ini:<ini> - Set output boot.ini file.\n" +
|
|
|
|
" /kernel:<kernel> - Set input kernel file.\n" +
|
2008-03-05 09:52:00 -05:00
|
|
|
" /out:<file> - Set name of output system manifest.\n" +
|
|
|
|
" /policy:<file> - Set input system policy file.\n" +
|
|
|
|
"Summary:\n" +
|
|
|
|
" Builds a system manifest for a collection of application manifests and\n" +
|
2008-11-17 18:29:00 -05:00
|
|
|
" a file list.\n" +
|
2008-03-05 09:52:00 -05:00
|
|
|
"");
|
|
|
|
}
|
|
|
|
|
|
|
|
// main entry point:
|
2008-11-17 18:29:00 -05:00
|
|
|
static int Main(string[] args)
|
2008-03-05 09:52:00 -05:00
|
|
|
{
|
|
|
|
string outfile = null;
|
|
|
|
string policyfile = null;
|
|
|
|
string distrodir = null;
|
|
|
|
string distrodesc = null;
|
|
|
|
string inifile = null;
|
2008-11-17 18:29:00 -05:00
|
|
|
string kernelfile = null;
|
|
|
|
|
|
|
|
bool errors = false;
|
|
|
|
|
|
|
|
bool subKernel = false;
|
|
|
|
|
|
|
|
List<ServiceInfo> services = new List<ServiceInfo>();
|
2008-03-05 09:52:00 -05:00
|
|
|
|
|
|
|
// parse the cmdline
|
|
|
|
foreach (string arg in args) {
|
2008-11-17 18:29:00 -05:00
|
|
|
if (arg.StartsWith("/") || arg.StartsWith("-")) {
|
|
|
|
int separator = arg.IndexOf(':', 1);
|
|
|
|
if (separator == -1) {
|
|
|
|
separator = arg.IndexOf('=', 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
string name;
|
|
|
|
string value;
|
|
|
|
|
|
|
|
if (separator != -1) {
|
|
|
|
name = arg.Substring(1, separator - 1);
|
|
|
|
value = arg.Substring(separator + 1);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
name = arg.Substring(1);
|
|
|
|
value = "";
|
|
|
|
}
|
|
|
|
|
|
|
|
name = name.ToLower();
|
|
|
|
|
|
|
|
switch (name) {
|
|
|
|
case "desc":
|
|
|
|
if (value == "") {
|
|
|
|
WriteErrorLine("The '/desc' argument requires a value.");
|
|
|
|
errors = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
distrodesc = value;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "dir":
|
|
|
|
if (value == "") {
|
|
|
|
WriteErrorLine("The '/dir' argument requires a value.");
|
|
|
|
errors = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
distrodir = value;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "ini":
|
|
|
|
if (value == "") {
|
|
|
|
WriteErrorLine("The '/ini' argument requires a value.");
|
|
|
|
errors = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
inifile = value;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "kernel":
|
|
|
|
if (value == "") {
|
|
|
|
WriteErrorLine("The '/kernel' argument requires a value.");
|
|
|
|
errors = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
kernelfile = value;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "out":
|
|
|
|
if (value == "") {
|
|
|
|
WriteErrorLine("The '/out' argument requires a value.");
|
|
|
|
errors = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
outfile = value;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "policy":
|
|
|
|
if (value == "") {
|
|
|
|
WriteErrorLine("The '/policy' argument requires a value.");
|
|
|
|
errors = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
policyfile = value;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "service": {
|
|
|
|
if (value == "") {
|
|
|
|
WriteErrorLine("The '/service' argument requires a value.");
|
|
|
|
errors = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ServiceInfo service;
|
|
|
|
try {
|
|
|
|
service = ParseServiceSpecification(value);
|
|
|
|
}
|
|
|
|
catch (ParseException ex) {
|
|
|
|
WriteErrorLine("The service description provided to the '/service' switch is invalid.");
|
|
|
|
WriteErrorLine("The value is: " + value);
|
|
|
|
WriteErrorLine(ex.Message);
|
|
|
|
errors = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
Debug.Assert(service != null);
|
|
|
|
|
|
|
|
bool foundExisting = false;
|
|
|
|
foreach (ServiceInfo existingService in services) {
|
|
|
|
if (existingService.ServiceName == service.ServiceName) {
|
|
|
|
foundExisting = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (foundExisting) {
|
|
|
|
WriteErrorLine("The service '{0}' is specified more than once on the command line.");
|
|
|
|
errors = true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
services.Add(service);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
case "subordinate":
|
|
|
|
subKernel = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "help":
|
|
|
|
case "?":
|
|
|
|
PrintUsage();
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
default:
|
|
|
|
WriteErrorLine("The '/{0}' argument is not recognized.", arg);
|
|
|
|
errors = true;
|
|
|
|
break;
|
|
|
|
}
|
2008-03-05 09:52:00 -05:00
|
|
|
}
|
2008-11-17 18:29:00 -05:00
|
|
|
else {
|
|
|
|
WriteErrorLine("Unrecognized argument: " + arg);
|
|
|
|
errors = true;
|
2008-03-05 09:52:00 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
if (String.IsNullOrEmpty(kernelfile)) {
|
|
|
|
WriteErrorLine("The '/kernel' argument is required, but is not provided.");
|
|
|
|
errors = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (String.IsNullOrEmpty(policyfile)) {
|
|
|
|
WriteErrorLine("The '/policy' argument is required, but is not provided.");
|
|
|
|
errors = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (String.IsNullOrEmpty(outfile)) {
|
|
|
|
WriteErrorLine("The '/out' argument is required, but is not provided.");
|
|
|
|
errors = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (String.IsNullOrEmpty(distrodesc)) {
|
|
|
|
WriteErrorLine("The '/desc' argument is required, but is not provided.");
|
|
|
|
errors = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (String.IsNullOrEmpty(distrodir)) {
|
|
|
|
WriteErrorLine("The '/dir' argument is required, but is not provided.");
|
|
|
|
errors = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (String.IsNullOrEmpty(inifile)) {
|
|
|
|
WriteErrorLine("The '/ini' argument is required, but is not provided.");
|
|
|
|
errors = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (errors) {
|
|
|
|
return 1;
|
2008-03-05 09:52:00 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// check all input files
|
2008-11-17 18:29:00 -05:00
|
|
|
if (!File.Exists(kernelfile)) {
|
|
|
|
WriteErrorLine("Error: kernel file '{0}' not found", kernelfile);
|
|
|
|
errors = true;
|
|
|
|
}
|
2008-03-05 09:52:00 -05:00
|
|
|
if (!File.Exists(policyfile)) {
|
2008-11-17 18:29:00 -05:00
|
|
|
WriteErrorLine("Error: policy file '{0}' not found", policyfile);
|
|
|
|
errors = true;
|
2008-03-05 09:52:00 -05:00
|
|
|
}
|
|
|
|
if (!File.Exists(distrodesc)) {
|
2008-11-17 18:29:00 -05:00
|
|
|
WriteErrorLine("Error: distro desc file '{0}' not found", distrodesc);
|
|
|
|
errors = true;
|
2008-03-05 09:52:00 -05:00
|
|
|
}
|
|
|
|
if (!Directory.Exists(distrodir)) {
|
2008-11-17 18:29:00 -05:00
|
|
|
WriteErrorLine("Error: directory '{0}' not found", distrodir);
|
|
|
|
errors = true;
|
2008-03-05 09:52:00 -05:00
|
|
|
}
|
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
if (errors) {
|
|
|
|
return 1;
|
|
|
|
}
|
2008-03-05 09:52:00 -05:00
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
#if false
|
|
|
|
try {
|
|
|
|
#endif
|
|
|
|
DistroBuilder p = new DistroBuilder(
|
|
|
|
kernelfile, policyfile, outfile, inifile, distrodir, distrodesc, subKernel);
|
|
|
|
|
|
|
|
// first aggregate all drivers into a <DriverRegistry>
|
|
|
|
p.CreateDriverRegistry();
|
|
|
|
// now apply policy to the system config
|
|
|
|
p.InstallPolicies(services);
|
|
|
|
// then output the manifest
|
|
|
|
p.PrintManifestFile();
|
|
|
|
// lastly make the ini file
|
|
|
|
p.MakeIniFile(distrodir);
|
|
|
|
return 0;
|
|
|
|
#if false
|
|
|
|
}
|
|
|
|
catch (Exception ex) {
|
|
|
|
for (Exception current = ex; current != null; current = current.InnerException) {
|
|
|
|
WriteErrorLine(current.Message);
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// This method parses the service specifications passed on the command line
|
|
|
|
/// with the '/service:' switch.
|
|
|
|
/// </summary>
|
|
|
|
/// <remarks>
|
|
|
|
/// The specification has the format:
|
|
|
|
///
|
|
|
|
/// name(,arg=value)*
|
|
|
|
///
|
|
|
|
/// where the valid arguments are:
|
|
|
|
/// * manifest: Specifies the manifest name (binary name) for this service.
|
|
|
|
/// The default is the same as the service name.
|
|
|
|
/// * type: Specifies the service type, one of "managed" or "unmanaged".
|
|
|
|
/// The default is "managed".
|
|
|
|
/// </remarks>
|
|
|
|
/// <param name="arg">The specification.</param>
|
|
|
|
/// <returns></returns>
|
|
|
|
/// <exception cref="ParseException">Thrown if the specification is not valid.</exception>
|
|
|
|
static ServiceInfo ParseServiceSpecification(string spec)
|
|
|
|
{
|
|
|
|
char[] word_splitters = { ',', ';' };
|
|
|
|
string[] words = spec.Split(word_splitters);
|
|
|
|
Debug.Assert(words != null);
|
|
|
|
|
|
|
|
if (words.Length == 0) {
|
|
|
|
throw new ParseException("No values provided in service specification.");
|
|
|
|
}
|
|
|
|
|
|
|
|
string serviceName = words[0];
|
|
|
|
|
|
|
|
if (String.IsNullOrEmpty(serviceName)) {
|
|
|
|
throw new ParseException("The service name is invalid.");
|
|
|
|
}
|
|
|
|
|
|
|
|
string manifestName = null;
|
|
|
|
string activationMode = null;
|
|
|
|
|
|
|
|
for (int i = 1; i < words.Length; i++) {
|
|
|
|
string word = words[i];
|
|
|
|
int equals_index = word.IndexOf('=');
|
|
|
|
if (equals_index == -1) {
|
|
|
|
equals_index = word.IndexOf(':');
|
|
|
|
}
|
|
|
|
if (equals_index == -1) {
|
|
|
|
throw new ParseException(String.Format("The value '{0}' does not have a value separator ('=' or ':').", word));
|
|
|
|
}
|
|
|
|
|
|
|
|
string name = word.Substring(0, equals_index);
|
|
|
|
string value = word.Substring(equals_index + 1);
|
|
|
|
|
|
|
|
name = name.ToLower();
|
|
|
|
|
|
|
|
switch (name) {
|
|
|
|
case "manifest":
|
|
|
|
// Ignore entries with empty value.
|
|
|
|
if (String.IsNullOrEmpty(value)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Duplicate 'manifest' values are illegal.
|
|
|
|
if (!String.IsNullOrEmpty(manifestName)) {
|
|
|
|
throw new ParseException("Duplicate 'manifest' values are illegal.");
|
|
|
|
}
|
|
|
|
manifestName = value;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "mode":
|
|
|
|
if (String.IsNullOrEmpty(value)) {
|
|
|
|
throw new ParseException("The 'mode' value for the /service switch requires a value, but none was provided.");
|
|
|
|
}
|
|
|
|
|
|
|
|
value = value.ToLower();
|
|
|
|
if (!IsValidServiceActivationMode(value)) {
|
|
|
|
throw new ParseException(String.Format("The value '{0}' is not a valid service activation mode.", value));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!String.IsNullOrEmpty(activationMode)) {
|
|
|
|
throw new ParseException("The service activation mode has already been specified.");
|
|
|
|
}
|
|
|
|
|
|
|
|
activationMode = value;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
throw new ParseException(String.Format("The service parameter '{0}' is not recognized.", name));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (String.IsNullOrEmpty(manifestName)) {
|
|
|
|
manifestName = serviceName;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (String.IsNullOrEmpty(activationMode)) {
|
|
|
|
activationMode = "demand";
|
|
|
|
}
|
|
|
|
|
|
|
|
ServiceInfo service = new ServiceInfo();
|
|
|
|
service.ServiceName = serviceName;
|
|
|
|
service.ActivationMode = activationMode;
|
|
|
|
service.ManifestName = manifestName;
|
|
|
|
|
|
|
|
return service;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool IsValidServiceActivationMode(string mode)
|
|
|
|
{
|
|
|
|
return mode == "demand" || mode == "alwaysactive" || mode == "manual";
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
internal class ServiceInfo
|
|
|
|
{
|
|
|
|
public string ServiceName;
|
|
|
|
public string ManifestName;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// One of "Demand", "AlwaysActive", or "Manual".
|
|
|
|
/// </summary>
|
|
|
|
public string ActivationMode;
|
|
|
|
}
|
|
|
|
|
|
|
|
class ParseException : Exception
|
|
|
|
{
|
|
|
|
public ParseException(string msg)
|
|
|
|
: base(msg)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class Set<T> : IEnumerable<T>
|
|
|
|
{
|
|
|
|
SortedList<T,bool> _list = new SortedList<T,bool>();
|
|
|
|
|
|
|
|
public IEnumerator<T> GetEnumerator()
|
|
|
|
{
|
|
|
|
return _list.Keys.GetEnumerator();
|
|
|
|
}
|
|
|
|
|
|
|
|
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
|
|
|
{
|
|
|
|
return _list.Keys.GetEnumerator();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void Add(T value)
|
|
|
|
{
|
|
|
|
_list.Add(value, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
public bool ContainsKey(T value)
|
|
|
|
{
|
|
|
|
return _list.ContainsKey(value);
|
2008-03-05 09:52:00 -05:00
|
|
|
}
|
|
|
|
}
|
2008-11-17 18:29:00 -05:00
|
|
|
|