/* * tiny-lpr.c - a tiny printing command. Gets a file path, and copies that * file to the spool directory, from which it'll be later * fetched by a printer daemon. */ #include /* standard I/O routines. */ #include /* various type definitions. */ #include /* general SysV IPC structures */ #include /* semaphore functions and structs. */ #include /* access(), etc. */ #include /* malloc(), etc. */ #include /* strlen(), etc. */ #include /* atoi(), etc. */ #include /* options for open(). */ #include "tiny-lp-common.h" /* common tiny spooler definitions/functions. */ /* * function: make_filename. creates a unique file name for the spool directory. * input: none. * output: a unique file name. */ static char* make_filename() { int counter; /* contents of counter file, as integer. */ static char buf[200]; /* contents of counter file, as string. */ int f_counter; /* pointer to counter file. */ f_counter = open(SPOOL_COUNTER, O_RDWR | O_EXCL); if (f_counter < 0) { fprintf(stderr, "Cannot open file '%s': ", SPOOL_COUNTER); perror(""); exit(1); } read(f_counter, buf, 199); counter = atoi(buf); counter++; sprintf(buf, "%d", counter); lseek(f_counter, 0, SEEK_SET); write(f_counter, buf, strlen(buf)); close(f_counter); return buf; } /* * function: copyfile. copies a file from one place to a new directory, * under a new, unique file name. * input: path to the file to copy, and path to the directory to copy * it into. * output: name of the copy of the file. */ static char* copyfile(char* file_path, char* dir_path) { char* tmp_file; /* name for temporary file. */ FILE* f_in; /* pointer for source file. */ FILE* f_out; /* pointer for target file. */ char* out_file; /* full path to putput file. */ int c; /* character read/written. */ /* generate a unique file name. */ tmp_file = make_filename(); if (tmp_file == NULL) { perror("tmpnam: "); exit(1); } out_file = (char*)malloc(strlen(dir_path)+strlen("/")+strlen(tmp_file)+1); if (!out_file) { fprintf(stderr, "out of memory\n"); exit(1); } sprintf(out_file, "%s/%s", dir_path, tmp_file); /* open the input file for reading. open the temporary file for output. */ f_in = fopen(file_path, "r"); if (!f_in) { fprintf(stderr, "Cannot open file '%s' for reading: \n", file_path); perror(""); exit(1); } f_out = fopen(out_file, "w"); if (!f_out) { fprintf(stderr, "Cannot open file '%s' for output: \n", out_file); perror(""); exit(1); } /* perform the file copying operation. This is not very efficient, */ /* and should be done using large buffer copies instead. */ while ( (c=fgetc(f_in)) != EOF) fputc(c, f_out); fclose(f_in); fclose(f_out); return tmp_file; } /* * function: main. perform the whole operation. * intput: path to file to copy into spool directory. * output: messages regarding success or failure of the operation. */ void main(int argc, char* argv[]) { int sem_set_id; /* ID of the semaphore set. */ char* file_path; /* path to the file to print. */ char* tmp_file; /* name of copied file in spool area. */ int rc; /* return value of system calls. */ char tmp_file_path[MAX_PATH]; /* name of copied file in 'in' area. */ char tmp_file_out[MAX_PATH]; /* name of copied file in 'common' area. */ /* check command line arguments. */ if (argc != 2) { fprintf(stderr, "Usage: %s \n", argv[0]); exit(1); } file_path = argv[1]; /* check that the file exists, and that we can read it. */ if (access(file_path, F_OK) == -1) { fprintf(stderr, "%s: file '%s' does not exist.\n", argv[0], file_path); exit(1); } if (access(file_path, R_OK) == -1) { fprintf(stderr, "%s: file '%s': cannot access.\n", argv[0], file_path); exit(1); } /* copy the file to our 'in' spool directory. */ tmp_file = copyfile(file_path, SPOOL_DIR_IN); printf("%s: file copied to spool area\n", argv[0]); /* get the ID of the semaphore set. */ /* the '0' means we won't create the set if it was */ /* not creted by tiny-lpd first. */ sem_set_id = sem_set_get("lpr", 0); if (sem_set_id == -1) { fprintf(stderr, "%s: warning: tiny-lpd is not running.\n", argv[0]); exit(1); } /* lock the 'mutex' semaphore, to get exclusive access to */ /* the 'common' spool directory. */ sem_wait_mutex(sem_set_id); /* move copied file into 'common' spool directory. */ sprintf(tmp_file_path, "%s/%s", SPOOL_DIR_IN, tmp_file); sprintf(tmp_file_out, "%s/%s", SPOOL_DIR_COMMON, tmp_file); rc = rename(tmp_file_path, tmp_file_out); if (rc == -1) { fprintf(stderr, "%s: failed moving file '%s' to directory '%s': ", argv[0], tmp_file, SPOOL_DIR_COMMON); perror(""); /* remove the problematic file, to avoid cluttering the disk. */ unlink(tmp_file); } /* unlock the 'mutex' semaphore. */ sem_signal_mutex(sem_set_id); /* increment the 'counter' semaphore, to signal tiny-lpd that */ /* there is a new file to handle. */ sem_signal_counter(sem_set_id); }