/* * 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 /* errno, ENOENT, etc. */ #include "tiny-lp-common.h" /* common tiny spooler definitions. */ #if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED) /* union semun is defined by including */ #else /* according to X/OPEN we have to define it ourselves */ union semun { int val; /* value for SETVAL */ struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */ unsigned short int *array; /* array for GETALL, SETALL */ struct seminfo *__buf; /* buffer for IPC_INFO */ }; #endif /* * function: get_sem_set. get an ID of the seaphore set, possibly creating * and initializing it, if it did not exist already. * input: - name of the caller process, for error message printing. * - flag determining whether or not to create the semaphore set * if it does not yet exist. * output: id of the semaphore set, or '-1' on error. */ int sem_set_get(char* caller, int create) { int sem_set_id; /* id of semaphore set, to return. */ union semun sem_val; /* semaphore value, for semctl(). */ int rc; /* return value of system calls. */ if (create) { /* create a semaphore set with ID 'SEM_ID', with two semaphores */ /* in it, with access to any user. */ sem_set_id = semget(SEM_ID, 2, IPC_CREAT | 0666); if (sem_set_id == -1) { fprintf(stderr, "%s: semget: ", caller); perror(""); exit(1); } /* intialize the 'mutex' semaphore in our set to '1'. */ sem_val.val = 1; rc = semctl(sem_set_id, SEM_MUTEX, SETVAL, sem_val); if (rc == -1) { fprintf(stderr, "%s: semctl: ", caller); perror(""); exit(1); } /* intialize the 'counter' semaphore in our set to '0'. */ sem_val.val = 0; rc = semctl(sem_set_id, SEM_COUNTER, SETVAL, sem_val); if (rc == -1) { fprintf(stderr, "%s: semctl: ", caller); perror(""); exit(1); } } else { /* get the semaphore set with ID 'SEM_ID'. */ sem_set_id = semget(SEM_ID, 2, 0666); if (sem_set_id == -1) { if (errno != ENOENT) { fprintf(stderr, "%s: semget: ", caller); perror(""); exit(1); } } } return sem_set_id; } /* * function: sem_signal_counter. signal the 'counter' semaphore in the given * set. * input: semaphore set ID. * output: none. */ void sem_signal_counter(int sem_set_id) { struct sembuf sem_op; /* structure for semaphore ops. */ /* increase the value of the semaphore by 1. */ sem_op.sem_num = SEM_COUNTER; sem_op.sem_op = 1; sem_op.sem_flg = 0; semop(sem_set_id, &sem_op, 1); } /* * function: sem_wait_counter. wait on the 'counter' semaphore in the given set. * input: semaphore set ID. * output: none. * notes: blocks the calling process if the counter becomes negative. */ void sem_wait_counter(int sem_set_id) { struct sembuf sem_op; /* structure for semaphore ops. */ /* block on the semaphore, unless it's value is non-negative. */ sem_op.sem_num = SEM_COUNTER; sem_op.sem_op = -1; sem_op.sem_flg = 0; semop(sem_set_id, &sem_op, 1); } /* * funciton: sem_signal_mutex. signal the 'mutex' semaphore in the given set. * input: semaphore set ID. * output: none. */ void sem_signal_mutex(int sem_set_id) { struct sembuf sem_op; /* structure for semaphore ops. */ /* increase the value of the semaphore by 1. */ sem_op.sem_num = SEM_MUTEX; sem_op.sem_op = 1; sem_op.sem_flg = 0; semop(sem_set_id, &sem_op, 1); } /* * function: sem_wait_mutex. wait on the 'mutex' semaphore in the given set. * input: semaphore set ID. * output: none. * notes: blocks the calling process if another process got the semaphore * locked already. */ void sem_wait_mutex(int sem_set_id) { struct sembuf sem_op; /* structure for semaphore ops. */ /* block on the semaphore, unless it's value is non-negative. */ sem_op.sem_num = SEM_MUTEX; sem_op.sem_op = -1; sem_op.sem_flg = 0; semop(sem_set_id, &sem_op, 1); }