/* * slpr (ssh lpr) * * v1.0 2001-03-20 Fredrik Roubert * v1.1 2001-03-21 Fredrik Roubert * * $Id: slpr.c,v 1.1 2002/06/10 01:28:18 roubert Exp $ * */ #include #include #include #include #include #include #include #include #include #ifndef SSH_PATH #define SSH_PATH "/usr/local/bin/ssh" #endif #ifndef SSH_NAME #define SSH_NAME "ssh" #endif static const char ssh_path[] = SSH_PATH, ssh_name[] = SSH_NAME, lpr_name[] = "lpr", env_host[] = "SLPR_HOST", env_user[] = "SLPR_USER", env_printer[] = "SLPR_PRINTER", env_account[] = "SLPR_ACCOUNT"; #define ERROR(s) \ do { fprintf(stderr, __FILE__ ": line %i: %s(): %s\n", \ __LINE__, #s, strerror(errno)); exit(EXIT_FAILURE); } while (0) #define _ERROR(s) \ do { fprintf(stderr, __FILE__ ": line %i: %s(): %s\n", \ __LINE__, #s, strerror(errno)); _exit(EXIT_FAILURE); } while (0) #define BADARG(t, s) \ do { if (t) { fprintf(stderr, "%s: invalid option -- %s\n", \ argv[0], s); exit(EXIT_FAILURE); } } while (0) /* * this program never calls free() because allocated * memory will be freed by exec() and exit() anyway * */ static char * quote(const char *src) { char *dst; size_t len, i, j; len = strlen(src); if ((dst = malloc(1 + 2 * len)) == NULL) ERROR(malloc); for (i = 0, j = 0; i <= len; i ++) switch (src[i]) { case ' ': case '\'': case '\"': case '\\': dst[j ++] = '\\'; default: dst[j ++] = src[i]; } return dst; } int main(int argc, char *argv[]) { char *host, *user, *printer, *account, **opts, *lpr_args, **ssh_argv; int fp, op, status, fd, i; size_t lpr_arglen; pid_t pid; /* * get environment variables * */ host = getenv(env_host); user = getenv(env_user); if ((printer = getenv(env_printer)) != NULL) printer = quote(printer); if ((account = getenv(env_account)) != NULL) account = quote(account); /* * parse command line * */ opts = NULL; /* keep compiler happy */ if (argc > 1 && (opts = malloc((argc - 1) * sizeof (char *))) == NULL) ERROR(malloc); for (fp = 1, op = 0; fp < argc; fp ++) if (argv[fp][0] == '-') { /* remote host name */ if (argv[fp][1] == 'H') { BADARG(argv[fp][2] == '\0', argv[fp] + 1); host = argv[fp] + 2; } /* remote user name */ else if (argv[fp][1] == 'U') { BADARG(argv[fp][2] == '\0', argv[fp] + 1); user = argv[fp] + 2; } /* printer name */ else if (argv[fp][1] == 'P') { BADARG(argv[fp][2] == '\0', argv[fp] + 1); printer = quote(argv[fp] + 2); } /* account name */ else if (argv[fp][1] == 'R') { BADARG(argv[fp][2] == '\0', argv[fp] + 1); account = quote(argv[fp] + 2); } /* end of options */ else if (argv[fp][1] == '-' && argv[fp][2] == '\0') { BADARG(fp == argc - 1, argv[fp]); fp ++; break; } /* end of options, stdin filename */ else if (argv[fp][1] == '\0') break; /* pass option to lpr */ else opts[op ++] = quote(argv[fp]); } else break; /* take all input from stdin */ if (fp == argc - 1 && argv[fp][0] == '-' && argv[fp][1] == '\0') fp ++; /* * check arguments * */ if (host == NULL) { fprintf(stderr, "%s: Missing hostname\n" "usage: %s -Hhostname [options] [filenames ...]\n", argv[0], argv[0]); return EXIT_FAILURE; } /* * build argument string for lpr * */ lpr_arglen = sizeof lpr_name; if (printer != NULL) lpr_arglen += 3 + strlen(printer); if (account != NULL) lpr_arglen += 3 + strlen(account); for (i = 0; i < op; i ++) lpr_arglen += 1 + strlen(opts[i]); if ((lpr_args = malloc(lpr_arglen)) == NULL) ERROR(malloc); memcpy(lpr_args, lpr_name, sizeof lpr_name); if (printer != NULL) { strcat(lpr_args, " -P"); strcat(lpr_args, printer); } if (account != NULL) { strcat(lpr_args, " -R"); strcat(lpr_args, account); } for (i = 0; i < op; i ++) { strcat(lpr_args, " "); strcat(lpr_args, opts[i]); } /* * build argument vector for ssh * */ /* maximum 4 arguments, plus name and terminator */ if ((ssh_argv = malloc(6 * sizeof (char *))) == NULL) ERROR(malloc); i = 0; ssh_argv[i ++] = (char *)ssh_name; if (user != NULL) { ssh_argv[i ++] = "-l"; ssh_argv[i ++] = user; } ssh_argv[i ++] = host; ssh_argv[i ++] = lpr_args; ssh_argv[i ] = NULL; /* * execute ssh * */ if (fp == argc) /* take all input from stdin, easy */ { execv(ssh_path, ssh_argv); ERROR(execv); } for (i = fp; i < argc; i ++) { if (argv[i][0] == '-' && argv[i][1] == '\0') fd = STDIN_FILENO; else if ((fd = open(argv[i], O_RDONLY)) == -1) { fprintf(stderr, "%s: %s: %s\n", argv[0], argv[i], strerror(errno)); continue; } if ((pid = fork()) == -1) ERROR(fork); if (pid == 0) { if (fd != STDIN_FILENO) { if (close(STDIN_FILENO) == -1) _ERROR(close); if (dup(fd) == -1) _ERROR(dup); if (close(fd) == -1) _ERROR(close); } execv(ssh_path, ssh_argv); _ERROR(execv); } if (fd != STDIN_FILENO && close(fd) == -1) ERROR(close); if (waitpid(pid, &status, 0) == -1) ERROR(waitpid); if (WIFEXITED(status) == 0 || WEXITSTATUS(status) != 0) { fprintf(stderr, "%s: %s failed\n", argv[0], ssh_name); return EXIT_FAILURE; } } return EXIT_SUCCESS; }