Skip to content

Commit 3c405ae

Browse files
committed
pinky: promptly diagnose write errors
In some cases 'pinky' could run forever until interrupted: $ ln -s /dev/zero ~/.plan $ ln -s /dev/zero ~/.project $ timeout -v 5 pinky -l collin > /dev/full timeout: sending signal TERM to command ‘pinky’ After this change it will exit upon failing to write to standard output: $ timeout -v 5 ./src/pinky -l collin > /dev/full pinky: write error: No space left on device * src/pinky.c: Include fadvise.h, filenamecat.h, full-write.h, and ioblksize.h. (cat_file): New function. (print_entry): Check if standard output has it's error flag set after printing a user entry. (print_long_entry): Likewise. Use the new cat_file function. * NEWS: Mention the improvement.
1 parent 796b8d1 commit 3c405ae

File tree

2 files changed

+42
-44
lines changed

2 files changed

+42
-44
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ GNU coreutils NEWS -*- outline -*-
4848

4949
csplit, ls, and sort, now handle a more complete set of terminating signals.
5050

51+
'pinky' will now exit immediately upon receiving a write error, which is
52+
significant when reading large plan or project files.
53+
5154
'timeout' on Linux will always terminate the child in the case where the
5255
timeout process itself dies, like when it receives a KILL signal for example.
5356

src/pinky.c

Lines changed: 39 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,11 @@
2626
#include "system.h"
2727

2828
#include "canon-host.h"
29+
#include "fadvise.h"
30+
#include "filenamecat.h"
31+
#include "full-write.h"
2932
#include "hard-locale.h"
33+
#include "ioblksize.h"
3034
#include "readutmp.h"
3135

3236
/* The official name of this program (e.g., no 'g' prefix). */
@@ -309,6 +313,36 @@ print_entry (STRUCT_UTMP const *utmp_ent)
309313
#endif
310314

311315
putchar ('\n');
316+
317+
if (ferror (stdout))
318+
write_error ();
319+
}
320+
321+
/* If FILE exists in HOME, print it to standard output, preceded by HEADER. */
322+
323+
static void
324+
cat_file (char const *header, char const *home, char const *file)
325+
{
326+
char *full_name = file_name_concat (home, file, nullptr);
327+
int fd = open (full_name, O_RDONLY);
328+
329+
if (0 <= fd)
330+
{
331+
idx_t header_len = strlen (header);
332+
if (write (STDOUT_FILENO, header, header_len) != header_len)
333+
write_error ();
334+
335+
fdadvise (fd, 0, 0, FADVISE_SEQUENTIAL);
336+
337+
char buf[IO_BUFSIZE];
338+
for (ssize_t bytes_read; 0 < (bytes_read = read (fd, buf, sizeof buf));)
339+
if (full_write (STDOUT_FILENO, buf, bytes_read) != bytes_read)
340+
write_error ();
341+
342+
close (fd);
343+
}
344+
345+
free (full_name);
312346
}
313347

314348
/* Display a verbose line of information about UTMP_ENT. */
@@ -355,54 +389,15 @@ print_long_entry (const char name[])
355389
}
356390

357391
if (include_project)
358-
{
359-
FILE *stream;
360-
char buf[1024];
361-
char const *const baseproject = "/.project";
362-
char *const project =
363-
xmalloc (strlen (pw->pw_dir) + strlen (baseproject) + 1);
364-
stpcpy (stpcpy (project, pw->pw_dir), baseproject);
365-
366-
stream = fopen (project, "r");
367-
if (stream)
368-
{
369-
size_t bytes;
370-
371-
printf (_("Project: "));
372-
373-
while ((bytes = fread (buf, 1, sizeof (buf), stream)) > 0)
374-
fwrite (buf, 1, bytes, stdout);
375-
fclose (stream);
376-
}
377-
378-
free (project);
379-
}
392+
cat_file (_("Project: "), pw->pw_dir, ".project");
380393

381394
if (include_plan)
382-
{
383-
FILE *stream;
384-
char buf[1024];
385-
char const *const baseplan = "/.plan";
386-
char *const plan =
387-
xmalloc (strlen (pw->pw_dir) + strlen (baseplan) + 1);
388-
stpcpy (stpcpy (plan, pw->pw_dir), baseplan);
389-
390-
stream = fopen (plan, "r");
391-
if (stream)
392-
{
393-
size_t bytes;
394-
395-
printf (_("Plan:\n"));
396-
397-
while ((bytes = fread (buf, 1, sizeof (buf), stream)) > 0)
398-
fwrite (buf, 1, bytes, stdout);
399-
fclose (stream);
400-
}
401-
402-
free (plan);
403-
}
395+
cat_file (_("Plan:\n"), pw->pw_dir, ".plan");
404396

405397
putchar ('\n');
398+
399+
if (ferror (stdout))
400+
write_error ();
406401
}
407402

408403
/* Print the username of each valid entry and the number of valid entries

0 commit comments

Comments
 (0)