Is there a way to know when a C program has been launched by cron?
Asked Answered
D

1

0

I have written a C utility that may be launched manually or on a regular basis, by a cron rule. Inside the C program I want to know if it was launched by a cron rule or not.

Reading the user name with getlogin_r renders the same username wether it is launched manually or by cron.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main() {
  char *username = malloc(80);
  getlogin_r(username, 80);
  printf("owner: %s\n", username);

  return 0;
}

Any idea?

Dorweiler answered 6/8, 2022 at 9:55 Comment(8)
if (strcmp(argv[1], "-cron") == 0) { /* started from cron job */ } and, of course, document the behaviour.Counterreply
@Counterreply if( argc > 1 && ... :-)Lavella
Of course I can pass a flag like this to my program. I mean, I wonder if there is a more "natural" way of distinguishing cron from a human user, in order to avoid the human error of neglecting the --cron flagDorweiler
Not any "natural" way. You could get the parent process id and check against the cron process, but it's much more work.Pilau
As a work-around without extending the code you could use a renamed hard or soft link to the executable to call by cron and check argv[0].Sarene
That's Interesting! ThanksDorweiler
isatty() on the stdin file descriptor might work. It won't specifically tell you it was run by cron, but at least whether it was run interactively.Marchelle
Good enough sj95126. Thanks!Dorweiler
D
1

Following user sj95126 suggestion, I found an indirect (but good enough) way of detecting if a program has been launched by cron or not.

When it comes to run a command-line present at the crontab, cron creates a non-interactive shell for it, i.e., one without standard input, standard output and standard error. This circumstance can be easily tested with the isatty() function from the unistd.h library.

This is a POC of the idea.

/* owner.c */
 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

/* return true if this process has been launched by cron */
/* cron is not directly identified but deduced from no having a tty */
int launched_bycron() {
  return (isatty(STDIN_FILENO) + isatty(STDOUT_FILENO) + isatty(STDERR_FILENO)) == 0;
}

int main() {
  /* print 1 if stdin, stdout or stderr exist */
  printf("stdin:    %d\n", isatty(STDIN_FILENO));  /* STDIN_FILENO = 0 */
  printf("stdout:   %d\n", isatty(STDOUT_FILENO)); /* STDIN_FILENO = 1 */
  printf("stderr:   %d\n", isatty(STDERR_FILENO)); /* STDIN_FILENO = 2 */

  /* get this process username */
  char *username = malloc(80);
  getlogin_r(username, 80);

  /* differentiate launching by cron from lauhcing by user */
  if (launched_bycron()) {
    printf("this was launched by cron\n");
  }
  else {
    printf("this was launched by %s\n", username);
  }

  return 0;
}

When launched manually the output is like this

$ ./owner
stdin:    1
stdout:   1
stderr:   1
this was launched by coterobarros

when launched by cron the output can still be captured piping the standard output to a file

crontab -l
* * * * * /usr/local/bin/owner > /tmp/owner.txt

and the content of the file is

$ cat /tmp/*.txt
stdin:    0
stdout:   0
stderr:   0
this was launched by cron

This link was very helpful too https://unix.stackexchange.com/questions/46789/check-if-script-is-started-by-cron-rather-than-invoked-manually

Dorweiler answered 6/8, 2022 at 17:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.