11#!/usr/bin/env python3
22"""
3- Apply LXC patches using sed to kernel source files.
3+ Apply LXC patches to kernel source files using pure Python .
44"""
55
6- import subprocess
76import sys
87from pathlib import Path
98
109
1110def find_cgroup_file () -> str :
1211 """Determine the cgroup file path based on kernel version."""
13- if Path ("kernel/cgroup.c" ). exists ():
14- # Check if it contains the function signature
15- content = Path ( "kernel/cgroup.c" ) .read_text (encoding = 'utf-8' )
12+ cgroup_path = Path ("kernel/cgroup.c" )
13+ if cgroup_path . exists ():
14+ content = cgroup_path .read_text (encoding = 'utf-8' )
1615 if "int cgroup_add_file" in content :
1716 return "kernel/cgroup.c"
1817 return "kernel/cgroup/cgroup.c"
1918
2019
2120def check_already_patched (file_path : str , patch_type : str ) -> bool :
2221 """Check if the file already contains LXC patches."""
23- content = Path (file_path ).read_text (encoding = 'utf-8' )
22+ path = Path (file_path )
23+ if not path .exists ():
24+ return False
25+
26+ content = path .read_text (encoding = 'utf-8' )
2427
2528 if patch_type == "cgroup" :
2629 return 'snprintf(name, CGROUP_FILE_NAME_MAX' in content
@@ -30,54 +33,113 @@ def check_already_patched(file_path: str, patch_type: str) -> bool:
3033
3134
3235def apply_cgroup_patch (cgroup_file : str ) -> None :
33- """Apply the cgroup patch using sed."""
34- sed_script = r'''/int cgroup_add_file/,/return 0;/{
35- /return 0;/i\
36- \tif (cft->ss && (cgrp->root->flags & CGRP_ROOT_NOPREFIX) && !(cft->flags & CFTYPE_NO_PREFIX)) {\
37- \tsnprintf(name, CGROUP_FILE_NAME_MAX, "%s.%s", cft->ss->name, cft->name);\
38- \tkernfs_create_link(cgrp->kn, name, kn);\
39- \t}
40- }'''
41-
42- try :
43- subprocess .run (
44- ["sed" , "-i" , sed_script , cgroup_file ],
45- check = True ,
46- capture_output = True ,
47- text = True
48- )
49- print (f"Patch applied successfully to { cgroup_file } " )
50- except subprocess .CalledProcessError as e :
51- print (f"Error applying cgroup patch: { e } " , file = sys .stderr )
52- sys .exit (1 )
36+ """Apply the cgroup patch using pure Python."""
37+ path = Path (cgroup_file )
38+ content = path .read_text (encoding = 'utf-8' )
39+ lines = content .split ('\n ' )
40+
41+ # Find the cgroup_add_file function and insert the patch before return 0;
42+ new_lines = []
43+ in_function = False
44+ brace_count = 0
45+ inserted = False
46+
47+ for line in lines :
48+ stripped = line .strip ()
49+
50+ # Check if we're entering the cgroup_add_file function
51+ if "int cgroup_add_file" in stripped :
52+ in_function = True
53+
54+ if in_function and not inserted :
55+ # Count braces to track function scope
56+ brace_count += stripped .count ('{' )
57+ brace_count -= stripped .count ('}' )
58+
59+ # Look for "return 0;" within the function
60+ if stripped == "return 0;" and brace_count > 0 :
61+ # Insert the patch before return 0;
62+ indent = len (line ) - len (line .lstrip ())
63+ base_indent = ' ' * indent
64+
65+ patch_code = [
66+ f"{ base_indent } if (cft->ss && (cgrp->root->flags & CGRP_ROOT_NOPREFIX) && !(cft->flags & CFTYPE_NO_PREFIX)) {{" ,
67+ f"{ base_indent } snprintf(name, CGROUP_FILE_NAME_MAX, \" %s.%s\" , cft->ss->name, cft->name);" ,
68+ f"{ base_indent } kernfs_create_link(cgrp->kn, name, kn);" ,
69+ f"{ base_indent } }}" ,
70+ ]
71+ new_lines .extend (patch_code )
72+ inserted = True
73+
74+ new_lines .append (line )
75+
76+ if not inserted :
77+ print (f"Warning: Could not find insertion point in { cgroup_file } " , file = sys .stderr )
78+ return
79+
80+ path .write_text ('\n ' .join (new_lines ), encoding = 'utf-8' )
81+ print (f"Patch applied successfully to { cgroup_file } " )
5382
5483
5584def apply_netfilter_patch () -> None :
56- """Apply the xt_qtaguid patch using sed."""
57- netfilter_file = "net/netfilter/xt_qtaguid.c"
58-
59- # This is a complex sed script that:
60- # 1. Changes 'struct rtnl_link_stats64 dev_stats, *stats' to 'struct rtnl_link_stats64 *stats'
61- # 2. Adds 'stats = &no_dev_stats;' before the active check
62- # 3. Deletes the if block and its next 5 lines
63- sed_script = r'''/int iface_stat_fmt_proc_show/,/^}/ {
64- s/struct rtnl_link_stats64 dev_stats, \*stats/struct rtnl_link_stats64 *stats/
65- /if (iface_entry->active)/i\
66- \tstats = \&no_dev_stats;
67- /if (iface_entry->active)/,+5d
68- }'''
69-
70- try :
71- subprocess .run (
72- ["sed" , "-i" , sed_script , netfilter_file ],
73- check = True ,
74- capture_output = True ,
75- text = True
76- )
77- print (f"Patch applied successfully to { netfilter_file } " )
78- except subprocess .CalledProcessError as e :
79- print (f"Error applying netfilter patch: { e } " , file = sys .stderr )
80- sys .exit (1 )
85+ """Apply the xt_qtaguid patch using pure Python."""
86+ netfilter_file = Path ("net/netfilter/xt_qtaguid.c" )
87+
88+ if not netfilter_file .exists ():
89+ print (f"Error: { netfilter_file } not found" , file = sys .stderr )
90+ return
91+
92+ content = netfilter_file .read_text (encoding = 'utf-8' )
93+ lines = content .split ('\n ' )
94+
95+ new_lines = []
96+ in_function = False
97+ brace_count = 0
98+ modified = False
99+ skip_lines = 0
100+
101+ for line in lines :
102+ if skip_lines > 0 :
103+ skip_lines -= 1
104+ continue
105+
106+ stripped = line .strip ()
107+
108+ # Check if we're entering iface_stat_fmt_proc_show function
109+ if "int iface_stat_fmt_proc_show" in stripped :
110+ in_function = True
111+
112+ if in_function and not modified :
113+ # Track braces within the function
114+ brace_count += stripped .count ('{' )
115+ brace_count -= stripped .count ('}' )
116+
117+ # Replace variable declaration
118+ if "struct rtnl_link_stats64 dev_stats, *stats" in line :
119+ line = line .replace (
120+ "struct rtnl_link_stats64 dev_stats, *stats" ,
121+ "struct rtnl_link_stats64 *stats"
122+ )
123+
124+ # Insert stats assignment before the active check
125+ if "if (iface_entry->active)" in line :
126+ indent = len (line ) - len (line .lstrip ())
127+ base_indent = ' ' * indent
128+ new_lines .append (f"{ base_indent } stats = &no_dev_stats;" )
129+
130+ # Skip the if block and next 5 lines
131+ skip_lines = 5
132+ modified = True
133+ continue
134+
135+ new_lines .append (line )
136+
137+ if not modified :
138+ print (f"Warning: Could not apply netfilter patch" , file = sys .stderr )
139+ return
140+
141+ netfilter_file .write_text ('\n ' .join (new_lines ), encoding = 'utf-8' )
142+ print (f"Patch applied successfully to { netfilter_file } " )
81143
82144
83145def main () -> None :
@@ -89,12 +151,13 @@ def main() -> None:
89151 ]
90152
91153 for file_path , patch_type in patch_files :
92- if not Path (file_path ).exists ():
154+ path = Path (file_path )
155+ if not path .exists ():
93156 print (f"Warning: { file_path } not found, skipping" , file = sys .stderr )
94157 continue
95158
96159 if check_already_patched (file_path , patch_type ):
97- print (f"Warning: { file_path } contains LXC" )
160+ print (f"Warning: { file_path } already contains LXC patches, skipping " )
98161 continue
99162
100163 if patch_type == "cgroup" :
0 commit comments