Sri Lanka captain Dimuth Karunaratne ensured his team would avoid an innings defeat but the tourists were in a precarious position at the end of the second day of the second and final Test against South Africa at the Wanderers Stadium on Monday.
The tourists were 150 for four at the close in Johannesburg, a lead of five runs with six wickets remaining.
Karunaratne, one of five left-handers in the Sri Lankan top six, made 91 not out off 116 balls with 17 fours.
But there was only one partnership of note, 85 for the second wicket with Lahiru Thirimanne, who scored 31. They came together after Kusal Perera had been bowled with only one run scored.
Fast bowler Lungi Ngidi took the first three wickets to finish the day with three for 26, having Thirimanne and Kusal Mendis caught down the leg side by wicketkeeper Quinton de Kock off successive deliveries. It was the third successive nought by Mendis.
Karunaratne's innings continued a fightback which started with the team's bowlers, who restricted South Africa's first innings lead to 145.
Vishwa Fernando took five for 101, his first five-wicket haul in Tests, as South Africa were bowled out for 302, losing their last nine wickets for 84 runs.
South Africa's collapse seemed unlikely when Dean Elgar (127) and Rassie van der Dussen (67) scored 68 runs off 14 overs in the first hour of the day.
Their second-wicket stand was worth 184 before the mid-morning drinks break brought a change in fortunes, with both batsmen dismissed in the first two overs after drinks.
Elgar, who made 95 in South Africa's innings win in the first Test at Centurion, completed his 13th Test century after starting the day on 92. He hit 22 fours in a 163-ball innings.
Perera, who made 64 and 60 in his previous two innings, was bowled for one by a ball from Ngidi which swung in from around the wicket. But Karunatne and Thirimanne both batted with assurance before Ngidi struck again.
Debutant Minod Bhanuka played a rash pull against the pace of Anrich Nortje and was out for one, with Keshav Maharaj taking a superb catch at midwicket, running several metres before diving full length.
Niroshan Dickwella made 18 not out to survive with Karunaratne until the close.