Hi !

On LKML Philippe Reynes posted an API update for ethtools API for
the pcnet32 care, basically to replace deprecated {get|set}_settings 
by the new API calls {get|set}_link_ksettings.
see: http://lkml.org/lkml/2016/11/6/2

So the scanner for this is simple:

<snip>
@find exists@
identifier oldapi,cmd,dev;
position p;
expression E;
@@

*static int oldapi@p(struct net_device *dev, struct ethtool_cmd *cmd)
{
<+...
*mii_ethtool_gset(&E, cmd);
...+>
}

@script:python@
p << find.p;
@@

msg = "old ethtool API in use."
coccilib.report.print_report(p[0], msg)
<snip>

 The problem was in the API update - as the get and set basically have the
same prototype so the find function seems to trigger in both - the
"solution" is a bit brute force regex in the "mod" rule - which I 
basicall think should not be needed.

<snip>
@initialize:python@
@@
import re
g = re.compile('get_')
s = re.compile('set_')

@find1 exists@
identifier get,cmd,dev;
expression E;
@@
static int get(struct net_device *dev, struct ethtool_cmd *cmd)
{
...
mii_ethtool_gset(&E, cmd);
...
}

@find2 exists@
identifier set,cmd,dev,ret;
expression E;
@@

static int set(struct net_device *dev, struct ethtool_cmd *cmd)            
{
<...
ret = mii_ethtool_sset(&E, cmd);
...>
}

@script:python mod@
oldg << find1.get;
olds << find2.set;
newg;
news;
@@

// the problem here is that the prototypes of get and set
// are identical so we only can keep them appart with regex 
if g.search(oldg) != None:
        coccinelle.newg = oldg.replace("get_settings","") + "get_link_ksettings"
else: 
        cocci.include_match(False)
if s.search(olds) != None:
        coccinelle.news = olds.replace("set_settings","") + "set_link_ksettings"
else:
        cocci.include_match(False)

@updateget@
identifier find1.get,find1.cmd,find1.dev,mod.newg;
expression E;
@@

-static int get(struct net_device *dev, struct ethtool_cmd *cmd)
+static int newg(struct net_device *dev, struct ethtool_link_ksettings *cmd)
{
<...
- mii_ethtool_gset(&E, cmd);
+ mii_ethtool_get_link_ksettings(&E, cmd);
...>
}

@updateset@
identifier find2.set,find2.cmd,find2.dev,mod.news;
identifier ret;
expression E;
@@

-static int set(struct net_device *dev, struct ethtool_cmd *cmd)
+static int news(struct net_device *dev, const struct ethtool_link_ksettings 
*cmd)
{
<...
(
  ret =
- mii_ethtool_sset(&E, cmd);
+ mii_ethtool_set_link_ksettings(&E, cmd);
|
- return mii_ethtool_sset(&E, cmd);
+ return mii_ethtool_set_link_ksettings(&E, cmd);
)
...>
}

@ksettings@
identifier ops;
identifier mod.newg;
identifier mod.news;
expression E1,E2,E3;
@@

struct ethtool_ops ops = {
...,
-.get_settings           = E1,
-.set_settings           = E2,
...,
 .get_link               = E3,
+.get_link_ksettings     = newg,
+.set_link_ksettings     = news,
...,
};
<snip>

Is there a more resonable solution to this ?
it seems to be working correctly but I did not see the need to
actually use regex if the get and set fuction should be differenciateable
by the calls in the body (mii_ethtool_gset vs. mii_ethtool_sset) but
I could not get it to work on that basis.

The original attempt that fails due to the position collision (atleat that
is what I assume that is happeining) is below - the two lines in the 
@updateset@ rule will trigger the problem if uncommented.
giving:

Fatal error: exception Failure("meta: semantic error: position cannot be 
inherited over modifications: p
 =File "eth.cocci", line 63, column 16,  charpos = 1123
    around = ';', whole content = position find2.p;
")

find1 and find2 with the respective update functions seem to be ok if they
are put in seperate files. So the spatch that causes this is:

<snip>
@find1 exists@
identifier get,cmd,dev;
position p;
expression E;
@@
static int get@p(struct net_device *dev, struct ethtool_cmd *cmd)
{
<+...
mii_ethtool_gset(&E, cmd);
...+>
}

@find2 exists@
identifier set,cmd,dev,ret;
position p;
expression E;
@@

static int set@p(struct net_device *dev, struct ethtool_cmd *cmd)            
{
<+...
(
ret = mii_ethtool_sset(&E, cmd);
|
return mii_ethtool_sset(&E, cmd);
)
...+>
}

@script:python mod@
oldg << find1.get;
olds << find2.set;
newg;
news;
@@

coccinelle.newg = oldg.replace("get_settings","") + "get_link_ksettings"
coccinelle.news = olds.replace("set_settings","") + "set_link_ksettings"

@updateget@
identifier find1.get,find1.cmd,find1.dev,mod.newg;
position find1.p;
expression E;
@@

-static int get@p(struct net_device *dev, struct ethtool_cmd *cmd)
+static int newg(struct net_device *dev, struct ethtool_link_ksettings *cmd)
{
<...
- mii_ethtool_gset(&E, cmd);
+ mii_ethtool_get_link_ksettings(&E, cmd);
...>
}

@updateset@
identifier find2.set,find2.cmd,find2.dev,mod.news;
identifier ret;
// the position causing the problem
//position find2.p;
expression E;
@@

//-static int set@p(struct net_device *dev, struct ethtool_cmd *cmd)
-static int set(struct net_device *dev, struct ethtool_cmd *cmd)
+static int news(struct net_device *dev, const struct ethtool_link_ksettings 
*cmd)
{
<...
(
  ret =
- mii_ethtool_sset(&E, cmd);
+ mii_ethtool_set_link_ksettings(&E, cmd);
|
- return mii_ethtool_sset(&E, cmd);
+ return mii_ethtool_set_link_ksettings(&E, cmd);
)
...>
}

@ksettings@
identifier ops;
identifier mod.newg;
identifier mod.news;
expression E1,E2,E3;
@@

struct ethtool_ops ops = {
...,
-.get_settings           = E1,
-.set_settings           = E2,
...,
 .get_link               = E3,
+.get_link_ksettings     = newg,
+.set_link_ksettings     = news,
...,
};
<snip>

thx!
hofrat
_______________________________________________
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci

Reply via email to