aboutsummaryrefslogtreecommitdiffstats
path: root/config
diff options
context:
space:
mode:
authorjim-p <jimp@pfsense.org>2012-05-04 16:52:03 -0400
committerjim-p <jimp@pfsense.org>2012-05-04 16:53:09 -0400
commit966c44e63d204906efaefebc66c9611f910486cb (patch)
treef3f15dd4c6c9722cf6a2a5cb4532241703e6b14a /config
parentbb3c2ac31d526e96ac473ce1bccf227a48c8f85e (diff)
downloadpfsense-packages-966c44e63d204906efaefebc66c9611f910486cb.tar.gz
pfsense-packages-966c44e63d204906efaefebc66c9611f910486cb.tar.bz2
pfsense-packages-966c44e63d204906efaefebc66c9611f910486cb.zip
Add a System Patches package to apply and maintain patches on a box. Should make it easier to test and deliver fixes.
Diffstat (limited to 'config')
-rw-r--r--config/systempatches/patches.inc140
-rw-r--r--config/systempatches/system_patches.php272
-rw-r--r--config/systempatches/system_patches_edit.php211
-rw-r--r--config/systempatches/systempatches.xml66
4 files changed, 689 insertions, 0 deletions
diff --git a/config/systempatches/patches.inc b/config/systempatches/patches.inc
new file mode 100644
index 00000000..78cc35f2
--- /dev/null
+++ b/config/systempatches/patches.inc
@@ -0,0 +1,140 @@
+<?php
+/*
+ patches.inc
+ Copyright (C) 2012 Jim Pingle
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+require_once("globals.inc");
+require_once("util.inc");
+
+$git_root_url = "http://github.com/bsdperimeter/pfsense/commit/";
+$patch_suffix = ".patch";
+$patch_dir = "/var/patches";
+$patch_cmd = "/usr/bin/patch --directory=/ ";
+
+function patch_commit($patch, $action, $test=false) {
+ global $patch_dir, $patch_cmd, $patch_suffix;
+ $filename = '-i ' . $patch_dir . '/' . $patch['uniqid'] . $patch_suffix;
+ $check = ($test) ? "--check" : "";
+ $force = ($action == "revert") ? "-f" : "-t";
+ $direction = ($action == "revert") ? "--reverse" : "--forward";
+ $whitespace = $patch['ignorewhitespace'] ? "--ignore-whitespace" : "";
+ $patchlevel = '-p' . $patch['patchlevel'];
+ patch_write($patch);
+ $status = mwexec("{$patch_cmd} {$force} {$patchlevel} {$filename} {$check} {$direction} {$whitespace}", false);
+ //patch_erase($patch);
+ if ($status == 0)
+ return true;
+ else
+ return false;
+}
+
+/* Attempt to apply a patch */
+function patch_apply($patch) {
+ return patch_commit($patch, "apply", false);
+}
+
+/* Attempt to revert a patch */
+function patch_revert($patch) {
+ return patch_commit($patch, "revert", false);
+}
+
+/* Test if a patch would apply cleanly */
+function patch_test_apply($patch) {
+ return patch_commit($patch, "apply", true);
+}
+
+/* Test if a patch would revert cleanly */
+function patch_test_revert($patch) {
+ return patch_commit($patch, "revert", true);
+}
+
+/* Fetch a patch from a URL or github */
+function patch_fetch(& $patch) {
+ $url = patch_fixup_url($patch['location']);
+ $text = @file_get_contents($url);
+ if (empty($text)) {
+ return false;
+ } else {
+ $patch['patch'] = base64_encode($text);
+ write_config("Fetched patch {$patch['descr']}");
+ return true;
+ }
+}
+
+/* Write a patch file out to $patch_dir */
+function patch_write($patch) {
+ global $patch_dir, $patch_suffix;
+ if (!file_exists($patch_dir)) {
+ safe_mkdir($patch_dir);
+ }
+ if (empty($patch['patch'])) {
+ return false;
+ } else {
+ $text = base64_decode($patch['patch']);
+ $filename = $patch_dir . '/' . $patch['uniqid'] . $patch_suffix;
+ return (file_put_contents($filename, $text) > 0);
+ }
+}
+
+function patch_erase($patch) {
+ global $patch_dir, $patch_suffix;
+ if (!file_exists($patch_dir)) {
+ return true;
+ }
+ $filename = $patch_dir . '/' . $patch['uniqid'] . $patch_suffix;
+ return @unlink($filename);
+}
+
+/* Detect a github URL or commit ID and fix it up */
+function patch_fixup_url($url) {
+ global $git_root_url, $patch_suffix;
+ // If it's a commit id then prepend git url, and add .patch
+ if (is_commit_id($url)) {
+ $url = $git_root_url . $url . $patch_suffix;
+ } elseif (is_URL($url)) {
+ $urlbits = explode("/", $url);
+ if (substr($urlbits[2], -10) == "github.com") {
+ // If it's a github url and does not already end in .patch, add it
+ if (substr($url, -strlen($patch_suffix)) != $patch_suffix) {
+ // Make sure it's really a URL to a commit id before adding .patch
+ if (is_commit_id(array_pop($urlbits))) {
+ $url .= $patch_suffix;
+ }
+ }
+ }
+ }
+ return $url;
+}
+
+function is_commit_id($str) {
+ return preg_match("/^[0-9a-f]{5,40}$/", $str);
+}
+
+function is_github_url($url) {
+ $urlbits = explode("/", $url);
+ return (substr($urlbits[2], -10) == "github.com");
+}
+?> \ No newline at end of file
diff --git a/config/systempatches/system_patches.php b/config/systempatches/system_patches.php
new file mode 100644
index 00000000..181db150
--- /dev/null
+++ b/config/systempatches/system_patches.php
@@ -0,0 +1,272 @@
+<?php
+/*
+ system_patches.php
+ Copyright (C) 2012 Jim Pingle
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+/*
+ pfSense_MODULE: system
+*/
+
+##|+PRIV
+##|*IDENT=page-system-patches
+##|*NAME=System: Patches
+##|*DESCR=Allow access to the 'System: Patches' page.
+##|*MATCH=system_patches.php*
+##|-PRIV
+
+require("guiconfig.inc");
+require_once("functions.inc");
+require_once("itemid.inc");
+require_once("patches.inc");
+
+if (!is_array($config['installedpackages']['patches']['item']))
+ $config['installedpackages']['patches']['item'] = array();
+
+$a_patches = &$config['installedpackages']['patches']['item'];
+
+/* if a custom message has been passed along, lets process it */
+if ($_GET['savemsg'])
+ $savemsg = $_GET['savemsg'];
+
+if ($_POST) {
+ $pconfig = $_POST;
+ if ($_POST['apply']) {
+ write_config();
+ }
+}
+
+if ($_GET['act'] == "del") {
+ if ($a_patches[$_GET['id']]) {
+ unset($a_patches[$_GET['id']]);
+ write_config();
+ header("Location: system_patches.php");
+ exit;
+ }
+}
+
+if (($_GET['act'] == "fetch") && ($a_patches[$_GET['id']])) {
+ $savemsg = patch_fetch(& $a_patches[$_GET['id']]) ? gettext("Patch Fetched Successfully") : gettext("Patch Fetch Failed");
+}
+if (($_GET['act'] == "test") && ($a_patches[$_GET['id']])) {
+ $savemsg = patch_test_apply($a_patches[$_GET['id']]) ? gettext("Patch can be applied cleanly") : gettext("Patch can NOT be applied cleanly");
+ $savemsg .= empty($savemsg) ? "" : "<br/>";
+ $savemsg .= patch_test_revert($a_patches[$_GET['id']]) ? gettext("Patch can be reverted cleanly") : gettext("Patch can NOT be reverted cleanly");
+}
+if (($_GET['act'] == "apply") && ($a_patches[$_GET['id']])) {
+ $savemsg = patch_apply($a_patches[$_GET['id']]) ? gettext("Patch applied successfully") : gettext("Patch could NOT be applied!");
+}
+if (($_GET['act'] == "revert") && ($a_patches[$_GET['id']])) {
+ $savemsg = patch_revert($a_patches[$_GET['id']]) ? gettext("Patch reverted successfully") : gettext("Patch could NOT be reverted!");
+}
+
+
+if (isset($_POST['del_x'])) {
+ /* delete selected patches */
+ if (is_array($_POST['patch']) && count($_POST['patch'])) {
+ foreach ($_POST['patch'] as $patchi) {
+ unset($a_patches[$patchi]);
+ }
+ write_config();
+ header("Location: system_patches.php");
+ exit;
+ }
+} else {
+ /* yuck - IE won't send value attributes for image buttons, while Mozilla does - so we use .x/.y to find move button clicks instead... */
+ unset($movebtn);
+ foreach ($_POST as $pn => $pd) {
+ if (preg_match("/move_(\d+)_x/", $pn, $matches)) {
+ $movebtn = $matches[1];
+ break;
+ }
+ }
+ /* move selected patches before this patch */
+ if (isset($movebtn) && is_array($_POST['patch']) && count($_POST['patch'])) {
+ $a_patches_new = array();
+
+ /* copy all patches < $movebtn and not selected */
+ for ($i = 0; $i < $movebtn; $i++) {
+ if (!in_array($i, $_POST['patch']))
+ $a_patches_new[] = $a_patches[$i];
+ }
+
+ /* copy all selected patches */
+ for ($i = 0; $i < count($a_patches); $i++) {
+ if ($i == $movebtn)
+ continue;
+ if (in_array($i, $_POST['patch']))
+ $a_patches_new[] = $a_patches[$i];
+ }
+
+ /* copy $movebtn patch */
+ if ($movebtn < count($a_patches))
+ $a_patches_new[] = $a_patches[$movebtn];
+
+ /* copy all patches > $movebtn and not selected */
+ for ($i = $movebtn+1; $i < count($a_patches); $i++) {
+ if (!in_array($i, $_POST['patch']))
+ $a_patches_new[] = $a_patches[$i];
+ }
+ $a_patches = $a_patches_new;
+ write_config();
+ header("Location: system_patches.php");
+ return;
+ }
+}
+
+$pgtitle = array(gettext("System"),gettext("Patches"));
+include("head.inc");
+
+echo "<script type=\"text/javascript\" language=\"javascript\" src=\"/javascript/domTT/domLib.js\"></script>";
+echo "<script type=\"text/javascript\" language=\"javascript\" src=\"/javascript/domTT/domTT.js\"></script>";
+echo "<script type=\"text/javascript\" language=\"javascript\" src=\"/javascript/domTT/behaviour.js\"></script>";
+echo "<script type=\"text/javascript\" language=\"javascript\" src=\"/javascript/domTT/fadomatic.js\"></script>";
+
+?>
+<link rel="stylesheet" href="/javascript/chosen/chosen.css" />
+<body link="#000000" vlink="#000000" alink="#000000">
+<?php include("fbegin.inc"); ?>
+<form action="system_patches.php" method="post" name="iform">
+<script type="text/javascript" language="javascript" src="/javascript/row_toggle.js"></script>
+<?php if ($savemsg) print_info_box($savemsg); ?>
+<table width="100%" border="0" cellpadding="0" cellspacing="0">
+<tr><td><div id="mainarea">
+<table class="tabcont" width="100%" border="0" cellpadding="0" cellspacing="0">
+<tr><td colspan="8" align="center">
+<?php echo gettext("This page allows you to add patches, either from the official code repository or ones pasted in from e-mail or other sources."); ?>
+<br/><br/>
+<strong><?php echo gettext("Use with caution!"); ?></strong>
+<br/><br/>
+</td></tr>
+<tr id="frheader">
+<td width="5%" class="list">&nbsp;</td>
+<td width="5%" class="listhdrr"><?=gettext("Description");?></td>
+<td width="65%" class="listhdrr"><?=gettext("URL/ID");?></td>
+<td width="5%" class="listhdrr"><?=gettext("Fetch");?></td>
+<td width="5%" class="listhdrr"><?=gettext("Test");?></td>
+<td width="5%" class="listhdrr"><?=gettext("Apply");?></td>
+<td width="5%" class="listhdr"><?=gettext("Revert");?></td>
+<td width="5%" class="list">
+<table border="0" cellspacing="0" cellpadding="1">
+ <tr><td width="17">
+ <?php if (count($a_patches) == 0): ?>
+ <img src="./themes/<?= $g['theme']; ?>/images/icons/icon_x_d.gif" width="17" height="17" title="<?=gettext("delete selected patches");?>" border="0">
+ <?php else: ?>
+ <input name="del" type="image" src="./themes/<?= $g['theme']; ?>/images/icons/icon_x.gif" width="17" height="17" title="<?=gettext("delete selected patches"); ?>" onclick="return confirm('<?=gettext("Do you really want to delete the selected patches?");?>')">
+ <?php endif; ?>
+ </td>
+ <td><a href="system_patches_edit.php"><img src="/themes/<?= $g['theme']; ?>/images/icons/icon_plus.gif" width="17" height="17" border="0" title="<?=gettext("add new patch"); ?>"></a></td>
+ </tr>
+</table>
+</td>
+</tr>
+
+<?php
+$npatches = $i = 0;
+foreach ($a_patches as $thispatch):
+ $can_apply = patch_test_apply($thispatch);
+ $can_revert = patch_test_revert($thispatch);
+
+?>
+ <tr valign="top" id="fr<?=$npatches;?>">
+ <td class="listt"><input type="checkbox" id="frc<?=$npatches;?>" name="patch[]" value="<?=$i;?>" onClick="fr_bgcolor('<?=$npatches;?>')" style="margin: 0; padding: 0; width: 15px; height: 15px;"></td>
+ <td class="listlr" onClick="fr_toggle(<?=$npatches;?>)" id="frd<?=$npatches;?>" ondblclick="document.location='system_patches_edit.php?id=<?=$npatches;?>';">
+ <?=$thispatch['descr'];?>
+ </td>
+ <td class="listr" onClick="fr_toggle(<?=$npatches;?>)" id="frd<?=$npatches;?>" ondblclick="document.location='system_patches_edit.php?id=<?=$npatches;?>';">
+
+ <?php
+ if (!empty($thispatch['location']))
+ echo $thispatch['location'];
+ elseif (!empty($thispatch['patch']))
+ echo gettext("Saved Patch");
+ ?>
+ </td>
+ <td class="listr" onClick="fr_toggle(<?=$npatches;?>)" id="frd<?=$npatches;?>" ondblclick="document.location='system_patches_edit.php?id=<?=$npatches;?>';">
+ <?php if (empty($thispatch['patch'])): ?>
+ <a href="system_patches.php?id=<?=$i;?>&act=fetch"><?php echo gettext("Fetch"); ?></a>
+ <?php else: ?>
+ <a href="system_patches.php?id=<?=$i;?>&act=fetch"><?php echo gettext("Re-Fetch"); ?></a>
+ <?php endif; ?>
+ </td>
+ <td class="listr" onClick="fr_toggle(<?=$npatches;?>)" id="frd<?=$npatches;?>" ondblclick="document.location='system_patches_edit.php?id=<?=$npatches;?>';">
+ <?php if (!empty($thispatch['patch'])): ?>
+ <a href="system_patches.php?id=<?=$i;?>&act=test"><?php echo gettext("Test"); ?></a>
+ <?php endif; ?>
+ </td>
+ <td class="listr" onClick="fr_toggle(<?=$npatches;?>)" id="frd<?=$npatches;?>" ondblclick="document.location='system_patches_edit.php?id=<?=$npatches;?>';">
+ <?php if ($can_apply): ?>
+ <a href="system_patches.php?id=<?=$i;?>&act=apply"><?php echo gettext("Apply"); ?></a>
+ <?php endif; ?>
+ </td>
+ <td class="listr" onClick="fr_toggle(<?=$npatches;?>)" id="frd<?=$npatches;?>" ondblclick="document.location='system_patches_edit.php?id=<?=$npatches;?>';">
+ <?php if ($can_revert): ?>
+ <a href="system_patches.php?id=<?=$i;?>&act=revert"><?php echo gettext("Revert"); ?></a>
+ <?php endif; ?>
+ </td>
+ <td valign="middle" class="list" nowrap>
+ <table border="0" cellspacing="0" cellpadding="1">
+ <tr>
+ <td><input onmouseover="fr_insline(<?=$npatches;?>, true)" onmouseout="fr_insline(<?=$npatches;?>, false)" name="move_<?=$i;?>" src="/themes/<?= $g['theme']; ?>/images/icons/icon_left.gif" title="<?=gettext("move selected patches before this patch");?>" height="17" type="image" width="17" border="0"></td>
+ <td><a href="system_patches_edit.php?id=<?=$i;?>"><img src="/themes/<?= $g['theme']; ?>/images/icons/icon_e.gif" width="17" height="17" border="0" title="<?=gettext("edit patch"); ?>"></a></td>
+ </tr>
+ <tr>
+ <td align="center" valign="middle"><a href="system_patches.php?act=del&id=<?=$i;?>" onclick="return confirm('<?=gettext("Do you really want to delete this patch?");?>')"><img src="./themes/<?= $g['theme']; ?>/images/icons/icon_x.gif" width="17" height="17" border="0" title="<?=gettext("delete patch");?>"></a></td>
+ <td></td>
+ </tr>
+ </table>
+ </td></tr>
+<?php $i++; $npatches++; endforeach; ?>
+ <tr>
+ <td class="list" colspan="7"></td>
+ <td class="list" valign="middle" nowrap>
+ <table border="0" cellspacing="0" cellpadding="1">
+ <tr>
+ <td><?php if ($npatches == 0): ?><img src="/themes/<?= $g['theme']; ?>/images/icons/icon_left_d.gif" width="17" height="17" title="<?=gettext("move selected patches to end"); ?>" border="0"><?php else: ?><input name="move_<?=$i;?>" type="image" src="/themes/<?= $g['theme']; ?>/images/icons/icon_left.gif" width="17" height="17" title="<?=gettext("move selected patches to end");?>" border="0"><?php endif; ?></td>
+ </tr>
+ <tr>
+ <td width="17">
+ <?php if (count($a_patches) == 0): ?>
+ <img src="./themes/<?= $g['theme']; ?>/images/icons/icon_x_d.gif" width="17" height="17" title="<?=gettext("delete selected patches");?>" border="0">
+ <?php else: ?>
+ <input name="del" type="image" src="./themes/<?= $g['theme']; ?>/images/icons/icon_x.gif" width="17" height="17" title="<?=gettext("delete selected patches"); ?>" onclick="return confirm('<?=gettext("Do you really want to delete the selected patches?");?>')">
+ <?php endif; ?>
+ </td>
+ <td><a href="system_patches_edit.php"><img src="/themes/<?= $g['theme']; ?>/images/icons/icon_plus.gif" width="17" height="17" border="0" title="<?=gettext("add new patch"); ?>"></a></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr><td></td><td colspan="6">
+ <?php echo gettext("NOTE: Each patch is tested, and the appropriate action is shown. If neither 'Apply' or 'Revert' shows up, the patch cannot be used (check the patchlevel and whitespace options)."); ?>
+ <br/><br/>
+ <?php echo gettext("Use the 'Test' link to see if a patch can be applied or reverted. You can reorder patches so that higher patches apply later than lower patches."); ?>
+ </td><td></td></tr>
+ </table>
+</div></td></tr>
+</table>
+</form>
+<?php include("fend.inc"); ?>
+</body>
+</html>
diff --git a/config/systempatches/system_patches_edit.php b/config/systempatches/system_patches_edit.php
new file mode 100644
index 00000000..7983a081
--- /dev/null
+++ b/config/systempatches/system_patches_edit.php
@@ -0,0 +1,211 @@
+<?php
+/*
+ system_patches_edit.php
+ Copyright (C) 2012 Jim Pingle
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+/*
+ pfSense_MODULE: system
+*/
+
+##|+PRIV
+##|*IDENT=page-system-patches-edit
+##|*NAME=System: Edit Patches
+##|*DESCR=Allow access to the 'System: Edit Patches' page.
+##|*MATCH=system_patches_edit.php*
+##|-PRIV
+
+require("guiconfig.inc");
+require_once("itemid.inc");
+require_once("patches.inc");
+
+if (!is_array($config['installedpackages']['patches']['item'])) {
+ $config['installedpackages']['patches']['item'] = array();
+}
+$a_patches = &$config['installedpackages']['patches']['item'];
+
+$id = $_GET['id'];
+if (isset($_POST['id']))
+ $id = $_POST['id'];
+
+if (isset($_GET['dup'])) {
+ $id = $_GET['dup'];
+ $after = $_GET['dup'];
+}
+
+if (isset($id) && $a_patches[$id]) {
+ $pconfig['descr'] = $a_patches[$id]['descr'];
+ $pconfig['location'] = $a_patches[$id]['location'];
+ $pconfig['patch'] = $a_patches[$id]['patch'];
+ $pconfig['patchlevel'] = $a_patches[$id]['patchlevel'];
+ $pconfig['ignorewhitespace'] = isset($a_patches[$id]['ignorewhitespace']);
+ $pconfig['autoapply'] = isset($a_patches[$id]['autoapply']);
+ $pconfig['uniqid'] = $a_patches[$id]['uniqid'];
+}
+
+if (isset($_GET['dup']))
+ unset($id);
+
+unset($input_errors);
+
+if ($_POST) {
+ $pconfig = $_POST;
+
+ /* input validation */
+ if(empty($_POST['location'])) {
+ $reqdfields = explode(" ", " patch");
+ $reqdfieldsn = array(gettext("Description"),gettext("Patch Contents"));
+ } else {
+ $reqdfields = explode(" ", "descr location");
+ $reqdfieldsn = array(gettext("Description"),gettext("URL/Commit ID"));
+ }
+
+ do_input_validation($_POST, $reqdfields, $reqdfieldsn, &$input_errors);
+
+ if (!empty($_POST['location']) && !is_commit_id($_POST['location']) && !is_URL($_POST['location'])) {
+ $input_errors[] = gettext("The supplied commit ID/URL appears to be invalid.");
+ }
+ if (!is_numeric($_POST['patchlevel'])) {
+ $input_errors[] = gettext("Patch level must be numeric!");
+ }
+
+ if (!$input_errors) {
+ $thispatch = array();
+
+ $thispatch['descr'] = $_POST['descr'];
+ $thispatch['location'] = patch_fixup_url($_POST['location']);
+ if (!empty($_POST['patch'])) {
+ $thispatch['patch'] = base64_encode($_POST['patch']);
+ }
+ if (is_github_url($thispatch['location']) && ($_POST['patchlevel'] == 0))
+ $thispatch['patchlevel'] = 1;
+ else
+ $thispatch['patchlevel'] = $_POST['patchlevel'];
+ $thispatch['ignorewhitespace'] = isset($_POST['ignorewhitespace']);
+ $thispatch['autoapply'] = isset($_POST['autoapply']);
+ if (empty($_POST['uniqid'])) {
+ $thispatch['uniqid'] = uniqid();
+ } else {
+ $thispatch['uniqid'] = $_POST['uniqid'];
+ }
+
+ // Update the patch entry now
+ if (isset($id) && $a_patches[$id])
+ $a_patches[$id] = $thispatch;
+ else {
+ if (is_numeric($after))
+ array_splice($a_patches, $after+1, 0, array($thispatch));
+ else
+ $a_patches[] = $thispatch;
+ }
+
+ write_config();
+ header("Location: system_patches.php");
+ return;
+ }
+}
+
+$pgtitle = array(gettext("System"),gettext("Patches"), gettext("Edit"));
+include("head.inc");
+
+?>
+<link rel="stylesheet" href="/pfCenter/javascript/chosen/chosen.css" />
+</head>
+
+<body link="#0000CC" vlink="#0000CC" alink="#0000CC">
+<script src="/pfCenter/javascript/chosen/chosen.proto.js" type="text/javascript"></script>
+
+<?php
+include("fbegin.inc"); ?>
+<?php if ($input_errors) print_input_errors($input_errors); ?>
+<form action="system_patches_edit.php" method="post" name="iform" id="iform">
+<table width="100%" border="0" cellpadding="6" cellspacing="0">
+<tr>
+ <td colspan="2" valign="top" class="listtopic"><?=gettext("Edit Patch Entry"); ?></td>
+</tr>
+<tr>
+ <td width="22%" valign="top" class="vncellreq"><strong><?=gettext("Description"); ?></strong></td>
+ <td width="78%" class="vtable">
+ <input name="descr" type="text" class="formfld unknown" id="descr" size="40" value="<?=htmlspecialchars($pconfig['descr']);?>">
+ <br> <span class="vexpl"><?=gettext("Enter a description here for your reference."); ?></span></td>
+</tr>
+<tr>
+ <td width="22%" valign="top" class="vncell"><?=gettext("URL/Commit ID"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="location" type="text" class="formfld unknown" id="location" size="40" value="<?=htmlspecialchars($pconfig['location']);?>">
+ <br> <span class="vexpl"><?=gettext("Enter a URL to a patch, or a commit ID from the main github repository (NOT the tools or packages repos!)."); ?></span></td>
+</tr>
+<tr>
+ <td width="22%" valign="top" class="vncell"><?=gettext("Patch Contents"); ?></td>
+ <td width="78%" class="vtable">
+ <textarea name="patch" class="" id="patch" ROWS="15" COLS="70" wrap="off"><?=base64_decode($pconfig['patch']);?></textarea>
+ <br> <span class="vexpl"><?=gettext("The contents of the patch. You can paste a patch here, or enter a URL/commit ID above, it can then be fetched into here automatically."); ?></span></td>
+</tr>
+<tr>
+ <td width="22%" valign="top" class="vncell"><?=gettext("Patch Level:"); ?></td>
+ <td width="78%" class="vtable">
+ <select name="patchlevel" class="formselect" id="patchlevel">
+<?php for ($i = 0; $i < 20; $i++): ?>
+ <option value="<?=$i;?>" <?php if ($i == $pconfig['patchlevel']) echo "selected"; ?>><?=$i;?></option>
+<?php endfor; ?>
+ </select>
+ </td>
+</tr>
+<tr>
+ <td width="22%" valign="top" class="vncell"><?=gettext("Ignore Whitespace"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="ignorewhitespace" type="checkbox" id="ignorewhitespace" value="yes" <?php if ($pconfig['ignorewhitespace']) echo "checked"; ?>>
+ <strong><?=gettext("Ignore Whitespace"); ?></strong><br />
+ <span class="vexpl"><?=gettext("Set this option to ignore whitespace in the patch."); ?></span>
+ </td>
+</tr>
+<!-- This isn't ready yet
+<tr>
+ <td width="22%" valign="top" class="vncell"><?=gettext("Auto Apply"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="autoapply" type="checkbox" id="autoapply" value="yes" <?php if ($pconfig['autoapply']) echo "checked"; ?>>
+ <strong><?=gettext("Auto-Apply Patch"); ?></strong><br />
+ <span class="vexpl"><?=gettext("Set this option to apply the patch automatically when possible, useful for patches to survive after firmware updates."); ?></span>
+ </td>
+</tr>
+-->
+<tr>
+ <td width="22%" valign="top">&nbsp;</td>
+ <td width="78%">Patch id: <?php echo $pconfig['uniqid']; ?></td>
+</tr>
+<tr>
+ <td width="22%" valign="top">&nbsp;</td>
+ <td width="78%">
+ <input name="Submit" type="submit" class="formbtn" value="<?=gettext("Save"); ?>"> <input type="button" class="formbtn" value="<?=gettext("Cancel"); ?>" onclick="history.back()">
+ <?php if (isset($id) && $a_patches[$id]): ?>
+ <input name="id" type="hidden" value="<?=htmlspecialchars($id);?>">
+ <input name="uniqid" type="hidden" value="<?=htmlspecialchars($pconfig['uniqid']);?>">
+ <?php endif; ?>
+ </td>
+</tr>
+</table>
+</form>
+<?php include("fend.inc"); ?>
+</body>
+</html>
diff --git a/config/systempatches/systempatches.xml b/config/systempatches/systempatches.xml
new file mode 100644
index 00000000..3730c84f
--- /dev/null
+++ b/config/systempatches/systempatches.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE packagegui SYSTEM "../schema/packages.dtd">
+<?xml-stylesheet type="text/xsl" href="../xsl/package.xsl"?>
+<packagegui>
+ <copyright>
+ <![CDATA[
+/* ========================================================================== */
+/*
+ systempatches.xml
+ part of pfSense (http://www.pfSense.com)
+ Copyright (C) 2012 Jim Pingle
+ All rights reserved.
+/* ========================================================================== */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+ */
+/* ========================================================================== */
+ ]]>
+ </copyright>
+ <description>System Patches</description>
+ <requirements>None</requirements>
+ <faq>Applies patches supplied by the user to the firewall.</faq>
+ <name>System Patches</name>
+ <version>0.5</version>
+ <title>System: Patches</title>
+ <menu>
+ <name>Patches</name>
+ <tooltiptext></tooltiptext>
+ <section>System</section>
+ <url>/system_patches.php</url>
+ </menu>
+ <additional_files_needed>
+ <prefix>/usr/local/www/</prefix>
+ <chmod>644</chmod>
+ <item>http://www.pfsense.com/packages/config/systempatches/system_patches.php</item>
+ </additional_files_needed>
+ <additional_files_needed>
+ <prefix>/usr/local/www/</prefix>
+ <chmod>644</chmod>
+ <item>http://www.pfsense.com/packages/config/systempatches/system_patches_edit.php</item>
+ </additional_files_needed>
+ <additional_files_needed>
+ <prefix>/usr/local/pkg/</prefix>
+ <chmod>644</chmod>
+ <item>http://www.pfsense.com/packages/config/systempatches/patches.inc</item>
+ </additional_files_needed>
+</packagegui> \ No newline at end of file