#!/usr/bin/perl -w # # This script can be used to add, remove, rename and renumber system calls in # the kernel sources and resolve simple git conflicts when a branch carrying # new system calls is merged into another that also has new system calls with # conflicting numbers. # # Usage: # # ./scripts/syscall-manage.pl --add <name> [--compat] # # Add a new system call, giving it the specified name and allocating it # the next number, bumping __NR_syscalls. If --compat is specified, then # __SC_COMP() will be used in lieu of __SYSCALL() and the script will # attempt to emit appropriate compatibility lines into the tables. # # ./scripts/syscall-manage.pl --rm <name> # # Remove the system call with the specified name, decrementing # __NR_syscalls if it was the final one. # # ./scripts/syscall-manage.pl --rename <name> <new_name> # # Rename the system call with the specified name to the new name. # # ./scripts/syscall-manage.pl --renumber # # Renumber the system calls between 424 and __NR_syscalls to remove any # holes and update __NR_syscalls. # # ./scripts/syscall-manage.pl --resolve # # Resolve simple git conflicts across all system call table files # resulting from one branch being merged into another where both branches # add system calls with conflicting numbers. The new syscalls are # renumbered, __NR_syscalls is updated and the conflict markers and any # extra definition of __NR_syscalls are removed. # use strict; # # List of files that need to be altered and their insertion patterns # my $master = "include/uapi/asm-generic/unistd.h"; my $sys_ni = "kernel/sys_ni.c"; my @tables = ( { file => "arch/alpha/kernel/syscalls/syscall.tbl", pattern => "%NUM common %NAME sys_%NAME", num_offset => 110 }, { file => "arch/arm/tools/syscall.tbl", pattern => "%NUM common %NAME sys_%NAME" }, { file => "arch/ia64/kernel/syscalls/syscall.tbl", pattern => "%NUM common %NAME sys_%NAME" }, { file => "arch/m68k/kernel/syscalls/syscall.tbl", pattern => "%NUM common %NAME sys_%NAME" }, { file => "arch/microblaze/kernel/syscalls/syscall.tbl", pattern => "%NUM common %NAME sys_%NAME" }, { file => "arch/mips/kernel/syscalls/syscall_n32.tbl", pattern => "%NUM n32 %NAME sys_%NAME", compat => 0 }, { file => "arch/mips/kernel/syscalls/syscall_n32.tbl", pattern => "%NUM n32 %NAME compat_sys_%NAME", compat => 1 }, { file => "arch/mips/kernel/syscalls/syscall_n64.tbl", pattern => "%NUM n64 %NAME sys_%NAME" }, { file => "arch/mips/kernel/syscalls/syscall_o32.tbl", pattern => "%NUM o32 %NAME sys_%NAME", compat => 0 }, { file => "arch/mips/kernel/syscalls/syscall_o32.tbl", pattern => "%NUM o32 %NAME sys_%NAME compat_sys_%NAME", compat => 1 }, { file => "arch/parisc/kernel/syscalls/syscall.tbl", pattern => "%NUM common %NAME sys_%NAME", compat => 0 }, { file => "arch/parisc/kernel/syscalls/syscall.tbl", pattern => "%NUM common %NAME compat_sys_%NAME", compat => 1 }, { file => "arch/powerpc/kernel/syscalls/syscall.tbl", pattern => "%NUM common %NAME sys_%NAME", compat => 0 }, { file => "arch/powerpc/kernel/syscalls/syscall.tbl", pattern => "%NUM common %NAME sys_%NAME compat_sys_%NAME", compat => 1 }, { file => "arch/s390/kernel/syscalls/syscall.tbl", pattern => "%NUM common %NAME sys_%NAME sys_%NAME", widths => [ 8, 8, 24, 32, 32], compat => 0 }, { file => "arch/s390/kernel/syscalls/syscall.tbl", pattern => "%NUM common %NAME sys_%NAME compat_sys_%NAME", widths => [ 8, 8, 24, 32, 32], compat => 1 }, { file => "arch/sh/kernel/syscalls/syscall.tbl", pattern => "%NUM common %NAME sys_%NAME" }, { file => "arch/sparc/kernel/syscalls/syscall.tbl", pattern => "%NUM common %NAME sys_%NAME", compat => 0 }, { file => "arch/sparc/kernel/syscalls/syscall.tbl", pattern => "%NUM common %NAME sys_%NAME compat_sys_%NAME", compat => 1 }, { file => "arch/x86/entry/syscalls/syscall_32.tbl", pattern => "%NUM i386 %NAME sys_%NAME __ia32_sys_%NAME", widths => [ 8, 8, 24, 32, 32], compat => 0 }, { file => "arch/x86/entry/syscalls/syscall_32.tbl", pattern => "%NUM i386 %NAME sys_%NAME __ia32_compat_sys_%NAME", widths => [ 8, 8, 24, 32, 32], compat => 1 }, { file => "arch/x86/entry/syscalls/syscall_64.tbl", pattern => "%NUM common %NAME __x64_sys_%NAME", widths => [ 8, 8, 24, 32, 32] }, { file => "arch/xtensa/kernel/syscalls/syscall.tbl", pattern => "%NUM common %NAME sys_%NAME" }, #{ file => "tools/perf/arch/powerpc/entry/syscalls/syscall.tbl", # pattern => "%NUM common %NAME sys_%NAME" }, #{ file => "tools/perf/arch/s390/entry/syscalls/syscall.tbl", # pattern => "%NUM common %NAME sys_%NAME sys_%NAME" }, #{ file => "tools/perf/arch/x86/entry/syscalls/syscall_64.tbl", # pattern => "%NUM common %NAME __x64_sys_%NAME" }, ); my $common_base = 424; # # Helpers # sub read_file($) { my ($file) = @_; my @lines; open(FD, "<" . "$file") || die $file; while (<FD>) { chomp($_); push @lines, $_; } close(FD) || die $file; return \@lines; } sub write_file($$) { my ($file, $lines) = @_; print "Writing $file\n"; open(FD, ">" . "$file") || die $file; print FD $_, "\n" foreach(@{$lines}); close(FD) || die $file; } ############################################################################### # # Add a new syscall to the master list and return the syscall number allocated. # ############################################################################### sub add_to_master($$) { my ($name, $compat) = @_; my $f = $master; my $lines = read_file($f); my $num = -1; my $nr = -1; my $i; my $j = -1; for ($i = 0; $i <= $#{$lines}; $i++) { my $l = $lines->[$i]; if ($l =~ /^#define\s+__NR_syscalls\s+([0-9]+)/) { die "$f:$i: Multiple __NR_syscalls definitions\n" if ($nr != -1); $nr = $1; $j = $i; } if ($l =~ /^#define\s+__NR_([a-zA-Z0-9_]+)\s+([0-9]+)/) { if ($1 eq $name) { die "$f:$i: Syscall multiply defined (", $num, ")\n" if ($num != -1); print STDERR "$f:$i: Syscall already exists (", $2, ")\n"; $num = $2; } } } die "$f: error: Can't find __NR_syscalls\n" if ($nr == -1); if ($num == -1) { # Update the last syscall number $num = $nr; print "Allocating syscall number ", $num, "\n"; $lines->[$j] = "#define __NR_syscalls " . ($nr + 1); # Rewind to the last syscall number definition while ($j--, $j >= 0 && $lines->[$j] eq "") {} die "$f:$j: error: Expecting #undef __NR_syscalls\n" unless ($lines->[$j] =~ /^#undef\s+__NR_syscalls/); while ($j--, $j >= 0 && $lines->[$j] eq "") {} die "$f:%j: error: Expecting __SYSCALL or __SC_COMP\n" unless ($lines->[$j] =~ /^(__SYSCALL|__SC_COMP|__SC_3264|__SC_COMP_3264)/); if ($lines->[$j - 1] =~ /^#define __NR_([a-zA-Z0-9_]+) ([0-9]+)/) { die "$f:$j: error: Incorrect syscall number ($2 != $num)\n" if ($2 != $num - 1); } else { die "$f:$j: error: Expecting #define __NR_*\n"; } $j++; # Insert the new syscall number if ($compat == 0) { splice(@{$lines}, $j, 0, ( "#define __NR_$name $num", "__SYSCALL(__NR_$name, sys_$name)" )); } elsif ($compat == 1) { splice(@{$lines}, $j, 0, ( "#define __NR_$name $num", "__SC_COMP(__NR_$name, sys_$name, compat_sys_$name)" )); } else { die; } write_file($f, $lines); } return $num; } ############################################################################### # # Add tabs to a string to pad it out # ############################################################################### sub tab_to($$) { my ($s, $width) = @_; if ($width == 8) { return $s . "\t"; } elsif ($width == 16) { return $s . "\t" if (length($s) > 7); return $s . "\t\t"; } elsif ($width == 24) { return $s . "\t" if (length($s) > 15); return $s . "\t\t" if (length($s) > 7); return $s . "\t\t\t"; } elsif ($width == 32) { return $s . "\t" if (length($s) > 23); return $s . "\t\t" if (length($s) > 15); return $s . "\t\t\t" if (length($s) > 7); return $s . "\t\t\t\t"; } else { die "Width $width\n"; } } ############################################################################### # # Tabulate a table line appropriately. # ############################################################################### sub tabulate($$) { my ($l, $widths) = @_; my @bits = split(/\s+/, $l); my $rl = tab_to($bits[0], $widths->[0]); # Syscall number $rl .= tab_to($bits[1], $widths->[1]); # Syscall type $rl .= tab_to($bits[2], $widths->[2]); # Syscall name # Add the syscall handlers if ($#bits == 3) { $rl .= $bits[3]; } elsif ($#bits == 4) { $rl .= tab_to($bits[3], $widths->[3]); $rl .= $bits[4]; } elsif ($#bits == 5) { $rl .= tab_to($bits[3], $widths->[4]); $rl .= tab_to($bits[4], $widths->[5]); $rl .= $bits[5]; } else { die "Too many handlers\n"; } } ############################################################################### # # Add a new syscall to a syscall.tbl file. # ############################################################################### sub add_to_table($$$) { my ($name, $num, $table) = @_; my $f = $table->{file}; my $pattern = $table->{pattern}; my $widths = $table->{widths} ? $table->{widths} : [ 8, 8, 32, 32, 32 ]; my $lines = read_file($f); my $i; my $j = -1; $num += $table->{num_offset} if (exists $table->{num_offset}); for ($i = 0; $i <= $#{$lines}; $i++) { my $l = $lines->[$i]; my @bits = split(/\s+/, $l); next if ($#bits == -1); if ($bits[0] eq $num - 1) { die "$f:$i: Duplicate syscall ", $num - 1, "\n" if $j != -1; $j = $i; } if ($bits[0] eq $num) { if ($bits[2] eq $name) { print STDERR "$f:$i: Ignoring already-added syscall ", $num, "\n"; return; } die "$f:$i: Conflicting syscall ", $num, "\n"; } } die "$f: error: Can't find syscall ", $num - 1, "\n" if ($j == -1); $pattern =~ s/%NAME/$name/g; $pattern =~ s/%NUM/$num/g; $pattern = tabulate($pattern, $widths); # Insert the new syscall entry after the preceding one. splice(@{$lines}, $j + 1, 0, ( $pattern )); write_file($f, $lines); } ############################################################################### # # Remove a syscall from the master list. # ############################################################################### sub remove_from_master($) { my ($name) = @_; my $f = $master; my $lines = read_file($f); my $num = -1; my $nr = -1; my $i; my $i_nr = -1; my $i_num = -1; my $c = 1; for ($i = 0; $i <= $#{$lines}; $i++) { my $l = $lines->[$i]; if ($l =~ /^#define\s+__NR_syscalls\s+([0-9]+)/) { die "$f:$i: Multiple __NR_syscalls definitions\n" if ($nr != -1); $nr = $1; $i_nr = $i; } if ($l =~ /^#define\s+__NR_([a-zA-Z0-9_]+)\s+([0-9]+)/) { if ($1 eq $name) { if ($num != -1) { print STDERR "$f:$i: Syscall multiply defined (", $num, ")\n" } $num = $2; # Remove the last instance only $i_num = $i; } } } die "$f: error: Can't find __NR_syscalls\n" if ($i_nr == -1); if ($i_num == -1) { print "Syscall not found in unistd.h\n"; return; } # If the syscall number is the last one, deallocate it if ($nr == $num + 1) { print "Deallocating syscall number ", $num, "\n"; $lines->[$i_nr] = "#define __NR_syscalls " . ($nr - 1); } # Remove the __SYSCALL or __SC_COMP line also if ($lines->[$i_num + 1] =~ /^(__SYSCALL|__SC_COMP|__SC_3264|__SC_COMP_3264)[(]__NR_$name,/) { $c++; $c++ if ($lines->[$i_num + 1] =~ /\\$/); } splice(@{$lines}, $i_num, $c, ()); write_file($f, $lines); } ############################################################################### # # Remove a syscall from a syscall.tbl file. # ############################################################################### sub remove_from_table($$) { my ($name, $table) = @_; my $f = $table->{file}; my $lines = read_file($f); my $i; my $j = -1; for ($i = 0; $i <= $#{$lines}; $i++) { my $l = $lines->[$i]; my @bits = split(/\s+/, $l); my $num = $bits[0]; next if ($#bits < 2); if ($bits[2] eq $name) { print STDERR "$f:$i: Duplicate syscall ", $num, "\n" if ($j != -1); $j = $i; } } if ($j == -1) { print STDERR "$f: error: Can't find syscall ", $name, "\n"; return; } # Remove the syscall entry splice(@{$lines}, $j, 1, ()); write_file($f, $lines); } ############################################################################### # # Remove a syscall from kernel/sys_ni.c # ############################################################################### sub remove_from_sys_ni($) { my ($name) = @_; my $f = $sys_ni; my $lines = read_file($f); my $i; my $j = -1; for ($i = 0; $i <= $#{$lines}; $i++) { my $l = $lines->[$i]; if ($l =~ /COND_SYSCALL[_A-Z]*[(]$name[)]/) { if ($j == -1) { $j = $i; } else { print STDERR "$f:$i: Multiple COND_SYSCALLs\n"; } } } return if ($j == -1); # Remove the COND_SYSCALL entry splice(@{$lines}, $j, 1, ()); write_file($f, $lines); } ############################################################################### # # Rename a syscall in the master list. # ############################################################################### sub rename_in_master($$) { my ($name, $name2) = @_; my $f = $master; my $lines = read_file($f); my $num = -1; my $i; my $i_num = -1; for ($i = 0; $i <= $#{$lines}; $i++) { my $l = $lines->[$i]; if ($l =~ /^#define\s+__NR_([a-zA-Z0-9_]+)\s+([0-9]+)/) { if ($1 eq $name) { if ($num != -1) { print STDERR "$f:$i: Syscall multiply defined (", $num, ")\n" } $num = $2; # Rename the last instance only $i_num = $i; } } } if ($i_num == -1) { print "Syscall not found in unistd.h\n"; return; } # Rename the __SYSCALL or __SC_COMP line also $lines->[$i_num] =~ s/$name/$name2/g; if ($lines->[$i_num + 1] =~ /^(__SYSCALL|__SC_COMP|__SC_3264|__SC_COMP_3264)[(]__NR_$name,/) { $lines->[$i_num + 1] =~ s/$name/$name2/g; $lines->[$i_num + 2] =~ s/$name/$name2/g if ($lines->[$i_num + 1] =~ /\\$/); } write_file($f, $lines); } ############################################################################### # # Rename a syscall in a syscall.tbl file. # ############################################################################### sub rename_in_table($$$) { my ($name, $name2, $table) = @_; my $f = $table->{file}; my $pattern = $table->{pattern}; my $widths = $table->{widths} ? $table->{widths} : [ 8, 8, 32, 32, 32 ]; my $lines = read_file($f); my $i; my $j = -1; for ($i = 0; $i <= $#{$lines}; $i++) { my $l = $lines->[$i]; my @bits = split(/\s+/, $l); my $num = $bits[0]; next if ($#bits < 2); if ($bits[2] eq $name) { print STDERR "$f:$i: Duplicate syscall ", $num, "\n" if ($j != -1); $j = $i; } } if ($j == -1) { print STDERR "$f: error: Can't find syscall ", $name, "\n"; return; } # Rename the syscall entry my $l = $lines->[$j]; $l =~ s/$name/$name2/g; $lines->[$j] = $pattern = tabulate($l, $widths); write_file($f, $lines); } ############################################################################### # # Rename a syscall in kernel/sys_ni.c # ############################################################################### sub rename_in_sys_ni($$) { my ($name, $name2) = @_; my $f = $sys_ni; my $lines = read_file($f); my $changed = 0; my $i; for ($i = 0; $i <= $#{$lines}; $i++) { my $l = $lines->[$i]; if ($l =~ /COND_SYSCALL[_A-Z]*[(]$name[)]/) { $lines->[$i] =~ s/$name/$name2/; $changed = 1; } } write_file($f, $lines) if ($changed); } ############################################################################### # # Resolve git-conflicted syscalls in the master list. # ############################################################################### sub resolve_conflicts_in_master() { my $f = $master; my $lines = read_file($f); my $nr = -1; my $i; my $i_nr = -1; my $begin = -1; my $mid = -1; my $end = -1; my $in_section = 0; my $nr_in_section = 0; my %conflict_list = (); for ($i = 0; $i <= $#{$lines}; $i++) { my $l = $lines->[$i]; if ($l =~ /^#define\s+__NR_syscalls\s+([0-9]+)/) { if ($in_section == 0) { # Before '<<<<<<<' die "$f:$i: Multiple __NR_syscalls definitions\n[s=$in_section inr=$i_nr nis=$nr_in_section]\n" unless ($i_nr == -1); $nr = $1; $i_nr = $i; $nr_in_section = 4; } elsif ($in_section == 1 && $nr_in_section == 0) { # After '<<<<<<<' $nr = $1; $i_nr = $i; $nr_in_section = 1; } elsif ($in_section == 2 && $nr_in_section == 1) { # After '=======' $i_nr = $i; $nr_in_section = 2; } elsif ($in_section == 3 && $nr_in_section == 0) { # After '>>>>>>>' $nr = $1; $i_nr = $i; $nr_in_section = 3; } else { die "$f:$i: Multiple __NR_syscalls definitions\n[s=$in_section inr=$i_nr nis=$nr_in_section]\n"; } next; } next if ($in_section == 3); if ($l =~ /^<<<<<<</) { $begin = $i; $in_section = 1; next; } if ($l =~ /^=======/) { $mid = $i; $in_section = 2; next; } if ($l =~ /^>>>>>>>/) { $end = $i; $in_section = 3; next; } next if ($in_section == 0); } die "$f: error: Can't find __NR_syscalls\n" if ($i_nr == -1); # Analyse the pre-merge syscalls. my $top = -1; my $stop = ($begin == -1) ? $#{$lines} : $begin; for ($i = 0; $i < $stop; $i++) { my $l = $lines->[$i]; if ($l =~ /^#define\s+__NR_([a-zA-Z0-9_]+)\s+([0-9]+)/) { my $name = $1; my $num = $2; next if ($name eq "syscalls"); die "$f:$i: Redefinition of $name\n" if (exists($conflict_list{$name})); die "$f:$i: Number regression\n" if ($num < $top); $top = $num; $conflict_list{$name} = $num; #print "Keep __NR_", $name, " as ", $num, "\n"; } } if ($in_section == 0) { print "$f: Couldn't find section to be resolved\n"; return \%conflict_list; } # Analyse what we're merging into. for ($i = $begin + 1; $i < $mid; $i++) { my $l = $lines->[$i]; if ($l =~ /^#define\s+__NR_([a-zA-Z0-9_]+)\s+([0-9]+)/) { my $name = $1; my $num = $2; next if ($name eq "syscalls"); die "$f:$i: Redefinition of $name\n" if (exists($conflict_list{$name})); die "$f:$i: Number regression\n" if ($num < $top); $top = $num; $conflict_list{$name} = $num; print "Keep __NR_", $name, " as ", $num, "\n"; } } die "$f: Last number (", $top, ") different to limit-1 (", $nr - 1, ")\n" if ($top != -1 && $top != $nr - 1); # Renumber what we're merging in. for ($i = $mid + 1; $i < $end; $i++) { my $l = $lines->[$i]; if ($l =~ /^#define\s+__NR_([a-zA-Z0-9_]+)\s+([0-9]+)/) { my $name = $1; my $num = $2; next if ($name eq "syscalls"); if (exists($conflict_list{$name})) { warn "$f:$i: Definition of $name in both branches\n"; # Remove the duplicate splice(@{$lines}, $i, 2, ()); $end -= 2; $i--; next; } my $new = $nr; $conflict_list{$name} = $new; $l =~ s/(\s)$num/${1}$new/; print "Reassign __NR_", $name, " to ", $new, "\n"; $lines->[$i] = $l; $nr++; } } # Adjust __NR_syscalls if ($lines->[$i_nr] =~ /^#define\s+__NR_syscalls\s+([0-9]+)/) { my $num = $1; $lines->[$i_nr] =~ s/(\s)$num/${1}$nr/; print "__NR_syscalls set to $nr\n"; } # Delete various bits, starting with the highest index and working towards # the lowest so as not to displace the higher indices. splice(@{$lines}, $end, 1, ()); splice(@{$lines}, $mid, 1, ()); for ($i = $mid - 1; $i > $begin; $i--) { my $l = $lines->[$i]; splice(@{$lines}, $i, 1, ()) if ($l =~ /^#undef\s+__NR_syscalls\s*$/); splice(@{$lines}, $i, 1, ()) if ($l =~ /^#define\s+__NR_syscalls\s+([0-9]+)/); splice(@{$lines}, $i, 1, ()) if ($l =~ /^$/); } splice(@{$lines}, $begin, 1, ()); write_file($f, $lines); return \%conflict_list; } ############################################################################### # # Resolve git-conflicted syscalls in a syscall.tbl file. # ############################################################################### sub resolve_conflicts_in_table($$) { my ($conflict_list, $table) = @_; my $f = $table->{file}; my $lines = read_file($f); my $i; my $begin = -1; my $mid = -1; my $end = -1; my $in_section = 0; for ($i = 0; $i <= $#{$lines}; $i++) { my $l = $lines->[$i]; if ($l =~ /^<<<<<<</) { $begin = $i; $in_section = 1; next; } if ($l =~ /^=======/) { $mid = $i; $in_section = 2; next; } if ($l =~ /^>>>>>>>/) { $end = $i; $in_section = 3; last; } next if ($in_section == 0); } if ($in_section == 0) { print "$f: Couldn't find section to be resolved\n"; return; } my %used = (); for ($i = $begin + 1; $i < $mid; $i++) { my $l = $lines->[$i]; next unless ($l =~ /^[0-9]/); my @bits = split(/\s+/, $l); my $num = $bits[0]; my $name = $bits[2]; next if ($#bits < 2); die "$f:$i: Undefined (my) syscall '", $name, "'\n" unless (exists($conflict_list->{$name})); my $new = $conflict_list->{$name}; $new += $table->{num_offset} ? $table->{num_offset} : 0; die "$f:$i: Redefined (my) syscall '", $name, "'\n" if (exists($used{$name})); $used{$name} = 1; next if ($num == $new); } for ($i = $mid + 1; $i < $end; $i++) { my $l = $lines->[$i]; next unless ($l =~ /^[0-9]/); my @bits = split(/\s+/, $l); my $num = $bits[0]; next if ($#bits < 2); my $name = $bits[2]; die "$f:$i: Undefined (other) syscall '", $name, "'\n" unless (exists($conflict_list->{$name})); my $new = $conflict_list->{$name}; $new += $table->{num_offset} ? $table->{num_offset} : 0; if (exists($used{$name})) { warn "$f:$i: Redefined (other) syscall '", $name, "'\n"; splice(@{$lines}, $i, 1, ()); $i--; $end--; next; } $used{$name} = 1; next if ($num == $new); $lines->[$i] =~ s/^$num/$new/; } # Delete the git markers, starting with the highest index and working # towards the lowest so as not to displace the higher indices. splice(@{$lines}, $end, 1, ()); splice(@{$lines}, $mid, 1, ()); splice(@{$lines}, $begin, 1, ()); #print $_, "\n" foreach (@{$lines}); #exit(88); write_file($f, $lines); } ############################################################################### # # Renumber the syscall numbers in the master list that are between 424 and # __NR_syscalls and reduce __NR_syscalls. # ############################################################################### sub renumber_master() { my $f = $master; my $lines = read_file($f); my $nr = -1; my $next = $common_base; my $i; my $i_nr = -1; my %num_list = (); # Find the __NR_syscalls value. for ($i = 0; $i <= $#{$lines}; $i++) { my $l = $lines->[$i]; if ($l =~ /^#define\s+__NR_syscalls\s+([0-9]+)/) { die "$f:$i: Redefinition of __NR_syscalls\n" if ($i_nr != -1); $nr = $1; $i_nr = $i; } } die "$f: error: Can't find __NR_syscalls\n" if ($i_nr == -1); # Renumber the definitions. for ($i = 0; $i <= $#{$lines}; $i++) { my $l = $lines->[$i]; if ($l =~ /^#define\s+__NR_([a-zA-Z0-9_]+)\s+([0-9]+)/) { my $name = $1; my $num = $2; next if ($num < $common_base || $num >= $nr); if ($num != $next) { print "Renumber ", $name, " from ", $num, " to ", $next, "\n"; $lines->[$i] =~ s/(\s)$num/${1}$next/; $num_list{$name} = $next; } $next++; } } # Adjust __NR_syscalls $lines->[$i_nr] =~ s/(\s)$nr/${1}$next/; print "__NR_syscalls set to $next\n"; write_file($f, $lines); return \%num_list; } ############################################################################### # # Renumber the syscall numbers in a syscall.tbl file to match the master. # ############################################################################### sub renumber_table($$) { my ($num_list, $table) = @_; my $f = $table->{file}; my $lines = read_file($f); my $i; for ($i = 0; $i <= $#{$lines}; $i++) { my $l = $lines->[$i]; my @bits = split(/\s+/, $l); next if ($#bits < 2); my $num = $bits[0]; my $name = $bits[2]; next unless (exists($num_list->{$name})); my $new = $num_list->{$name}; $new += $table->{num_offset} ? $table->{num_offset} : 0; next if ($num eq $new); $lines->[$i] =~ s/^$num/$new/; } write_file($f, $lines); } ############################################################################### # # Change a syscall in a syscall.tbl file. # ############################################################################### sub change_in_table($$$) { my ($name, $to_id, $table) = @_; my $f = $table->{file}; my $pattern = $table->{pattern}; my $widths = $table->{widths} ? $table->{widths} : [ 8, 8, 32, 32, 32 ]; my $old_id = ""; my $lines = read_file($f); my $i; my $j = -1; for ($i = 0; $i <= $#{$lines}; $i++) { my $l = $lines->[$i]; my @bits = split(/\s+/, $l); next if ($#bits < 2); my $num = $bits[0]; if ($bits[2] eq $name) { print STDERR "$f:$i: Duplicate syscall ", $num, "\n" if ($j != -1); $j = $i; $old_id = $bits[0]; } } if ($j == -1) { print STDERR "$f: error: Can't find syscall ", $name, "\n"; return; } if ($old_id eq "") { print STDERR "$f: error: Can't find syscall number ", $name, "\n"; return; } # Rename the syscall entry my $l = $lines->[$j]; $l =~ s/^$old_id/$to_id/g; $lines->[$j] = $pattern = tabulate($l, $widths); write_file($f, $lines); } ############################################################################### # # Decide what to do based on the script parameters # ############################################################################### sub format_error() { print("Format: syscall-manage.pl --add <name> [--compat]\n"); print(" --change <name> <to-id>\n"); print(" --rm <name>\n"); print(" --rename <name>\n"); print(" --renumber\n"); print(" --resolve\n"); exit(2); } format_error() if ($#ARGV < 0); if ($ARGV[0] eq "--add") { format_error() if ($#ARGV < 1); my $name = $ARGV[1]; my $compat = 0; $compat = 1 if ($#ARGV == 2 && $ARGV[2] eq "--compat"); my $num = add_to_master($name, $compat); foreach my $table (@tables) { next if (exists($table->{compat}) && $compat != $table->{compat}); add_to_table($name, $num, $table); } } elsif ($ARGV[0] eq "--change") { format_error() if ($#ARGV < 2); my $name = $ARGV[1]; my $to_id = $ARGV[2]; foreach (@tables) { change_in_table($name, $to_id, $_); } } elsif ($ARGV[0] eq "--rm") { format_error() if ($#ARGV < 1); my $name = $ARGV[1]; remove_from_master($name); foreach (@tables) { remove_from_table($name, $_); } remove_from_sys_ni($name); } elsif ($ARGV[0] eq "--rename") { format_error() if ($#ARGV < 2); my $name = $ARGV[1]; my $name2 = $ARGV[2]; rename_in_master($name, $name2); foreach (@tables) { rename_in_table($name, $name2, $_); } rename_in_sys_ni($name, $name2); } elsif ($ARGV[0] eq "--resolve") { my $conflict_list = resolve_conflicts_in_master(); foreach (@tables) { resolve_conflicts_in_table($conflict_list, $_); } } elsif ($ARGV[0] eq "--renumber") { my $num_list = renumber_master(); foreach (@tables) { renumber_table($num_list, $_); } } else { format_error(); }