⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 printd.c

📁 unix环境高级编程第二版配套源代码 unix环境高级编程第二版配套源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Print server daemon. */#include "apue.h"#include "print.h"#include "ipp.h"#include <fcntl.h>#include <dirent.h>#include <ctype.h>#include <pwd.h>#include <pthread.h>#include <strings.h>#include <sys/select.h>#include <sys/uio.h>/* * These are for the HTTP response from the printer. */#define HTTP_INFO(x)	((x) >= 100 && (x) <= 199)#define HTTP_SUCCESS(x) ((x) >= 200 && (x) <= 299)/* * Describes a print job. */struct job {	struct job      *next;		/* next in list */	struct job      *prev;		/* previous in list */	long             jobid;		/* job ID */	struct printreq  req;		/* copy of print request */};/* * Describes a thread processing a client request. */struct worker_thread {	struct worker_thread  *next;	/* next in list */	struct worker_thread  *prev;	/* previous in list */	pthread_t              tid;		/* thread ID */	int                    sockfd;	/* socket */};/* * Needed for logging. */int					log_to_stderr = 0;/* * Printer-related stuff. */struct addrinfo		*printer;char					*printer_name;pthread_mutex_t		configlock = PTHREAD_MUTEX_INITIALIZER;int					reread;/* * Thread-related stuff. */struct worker_thread	*workers;pthread_mutex_t		workerlock = PTHREAD_MUTEX_INITIALIZER;sigset_t				mask;/* * Job-related stuff. */struct job				*jobhead, *jobtail;int					jobfd;long					nextjob;pthread_mutex_t		joblock = PTHREAD_MUTEX_INITIALIZER;pthread_cond_t			jobwait = PTHREAD_COND_INITIALIZER;/* * Function prototypes. */void		init_request(void);void		init_printer(void);void		update_jobno(void);long		get_newjobno(void);void		add_job(struct printreq *, long);void		replace_job(struct job *);void		remove_job(struct job *);void		build_qonstart(void);void		*client_thread(void *);void		*printer_thread(void *);void		*signal_thread(void *);ssize_t	readmore(int, char **, int, int *);int		printer_status(int, struct job *);void		add_worker(pthread_t, int);void		kill_workers(void);void		client_cleanup(void *);/* * Main print server thread.  Accepts connect requests from * clients and spawns additional threads to service requests. * * LOCKING: none. */intmain(int argc, char *argv[]){	pthread_t			tid;	struct addrinfo		*ailist, *aip;	int					sockfd, err, i, n, maxfd;	char				*host;	fd_set				rendezvous, rset;	struct sigaction	sa;	struct passwd		*pwdp;	if (argc != 1)		err_quit("usage: printd");	daemonize("printd");	sigemptyset(&sa.sa_mask);	sa.sa_flags = 0;	sa.sa_handler = SIG_IGN;	if (sigaction(SIGPIPE, &sa, NULL) < 0)		log_sys("sigaction failed");	sigemptyset(&mask);	sigaddset(&mask, SIGHUP);	sigaddset(&mask, SIGTERM);	if ((err = pthread_sigmask(SIG_BLOCK, &mask, NULL)) != 0)		log_sys("pthread_sigmask failed");	init_request();	init_printer();#ifdef _SC_HOST_NAME_MAX	n = sysconf(_SC_HOST_NAME_MAX);	if (n < 0)	/* best guess */#endif		n = HOST_NAME_MAX;	if ((host = malloc(n)) == NULL)		log_sys("malloc error");	if (gethostname(host, n) < 0)		log_sys("gethostname error");	if ((err = getaddrlist(host, "print", &ailist)) != 0) {		log_quit("getaddrinfo error: %s", gai_strerror(err));		exit(1);	}	FD_ZERO(&rendezvous);	maxfd = -1;	for (aip = ailist; aip != NULL; aip = aip->ai_next) {		if ((sockfd = initserver(SOCK_STREAM, aip->ai_addr,		  aip->ai_addrlen, QLEN)) >= 0) {			FD_SET(sockfd, &rendezvous);			if (sockfd > maxfd)				maxfd = sockfd;		}	}	if (maxfd == -1)		log_quit("service not enabled");	pwdp = getpwnam("lp");	if (pwdp == NULL)		log_sys("can't find user lp");	if (pwdp->pw_uid == 0)		log_quit("user lp is privileged");	if (setuid(pwdp->pw_uid) < 0)		log_sys("can't change IDs to user lp");	pthread_create(&tid, NULL, printer_thread, NULL);	pthread_create(&tid, NULL, signal_thread, NULL);	build_qonstart();	log_msg("daemon initialized");	for (;;) {		rset = rendezvous;		if (select(maxfd+1, &rset, NULL, NULL, NULL) < 0)			log_sys("select failed");		for (i = 0; i <= maxfd; i++) {			if (FD_ISSET(i, &rset)) {				/*				 * Accept the connection and handle				 * the request.				 */				sockfd = accept(i, NULL, NULL);				if (sockfd < 0)					log_ret("accept failed");				pthread_create(&tid, NULL, client_thread,				  (void *)sockfd);			}		}	}	exit(1);}/* * Initialize the job ID file.  Use a record lock to prevent * more than one printer daemon from running at a time. * * LOCKING: none, except for record-lock on job ID file. */voidinit_request(void){	int		n;	char	name[FILENMSZ];	sprintf(name, "%s/%s", SPOOLDIR, JOBFILE);	jobfd = open(name, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);	if (write_lock(jobfd, 0, SEEK_SET, 0) < 0)		log_quit("daemon already running");	/*	 * Reuse the name buffer for the job counter.	 */	if ((n = read(jobfd, name, FILENMSZ)) < 0)		log_sys("can't read job file");	if (n == 0)		nextjob = 1;	else		nextjob = atol(name);}/* * Initialize printer information. * * LOCKING: none. */voidinit_printer(void){	printer = get_printaddr();	if (printer == NULL) {		log_msg("no printer device registered");		exit(1);	}	printer_name = printer->ai_canonname;	if (printer_name == NULL)		printer_name = "printer";	log_msg("printer is %s", printer_name);}/* * Update the job ID file with the next job number. * * LOCKING: none. */voidupdate_jobno(void){	char	buf[32];	lseek(jobfd, 0, SEEK_SET);	sprintf(buf, "%ld", nextjob);	if (write(jobfd, buf, strlen(buf)) < 0)		log_sys("can't update job file");}/* * Get the next job number. * * LOCKING: acquires and releases joblock. */longget_newjobno(void){	long	jobid;	pthread_mutex_lock(&joblock);	jobid = nextjob++;	if (nextjob <= 0)		nextjob = 1;	pthread_mutex_unlock(&joblock);	return(jobid);}/* * Add a new job to the list of pending jobs.  Then signal * the printer thread that a job is pending. * * LOCKING: acquires and releases joblock. */voidadd_job(struct printreq *reqp, long jobid){	struct job	*jp;	if ((jp = malloc(sizeof(struct job))) == NULL)		log_sys("malloc failed");	memcpy(&jp->req, reqp, sizeof(struct printreq));	jp->jobid = jobid;	jp->next = NULL;	pthread_mutex_lock(&joblock);	jp->prev = jobtail;	if (jobtail == NULL)		jobhead = jp;	else		jobtail->next = jp;	jobtail = jp;	pthread_mutex_unlock(&joblock);	pthread_cond_signal(&jobwait);}/* * Replace a job back on the head of the list. * * LOCKING: acquires and releases joblock. */voidreplace_job(struct job *jp){	pthread_mutex_lock(&joblock);	jp->prev = NULL;	jp->next = jobhead;	if (jobhead == NULL)		jobtail = jp;	else		jobhead->prev = jp;	jobhead = jp;	pthread_mutex_unlock(&joblock);}/* * Remove a job from the list of pending jobs. * * LOCKING: caller must hold joblock. */voidremove_job(struct job *target){	if (target->next != NULL)		target->next->prev = target->prev;	else		jobtail = target->prev;	if (target->prev != NULL)		target->prev->next = target->next;	else		jobhead = target->next;}/* * Check the spool directory for pending jobs on start-up. * * LOCKING: none. */voidbuild_qonstart(void){	int				fd, err, nr;	long			jobid;	DIR				*dirp;	struct dirent	*entp;	struct printreq	req;	char			dname[FILENMSZ], fname[FILENMSZ];	sprintf(dname, "%s/%s", SPOOLDIR, REQDIR);	if ((dirp = opendir(dname)) == NULL)		return;	while ((entp = readdir(dirp)) != NULL) {		/*		 * Skip "." and ".."		 */		if (strcmp(entp->d_name, ".") == 0 ||		  strcmp(entp->d_name, "..") == 0)			continue;		/*		 * Read the request structure.		 */		sprintf(fname, "%s/%s/%s", SPOOLDIR, REQDIR, entp->d_name);		if ((fd = open(fname, O_RDONLY)) < 0)			continue;		nr = read(fd, &req, sizeof(struct printreq));		if (nr != sizeof(struct printreq)) {			if (nr < 0)				err = errno;			else				err = EIO;			close(fd);			log_msg("build_qonstart: can't read %s: %s",			  fname, strerror(err));			unlink(fname);			sprintf(fname, "%s/%s/%s", SPOOLDIR, DATADIR,			  entp->d_name);			unlink(fname);			continue;		}		jobid = atol(entp->d_name);		log_msg("adding job %ld to queue", jobid);		add_job(&req, jobid);	}	closedir(dirp);}/* * Accept a print job from a client. * * LOCKING: none. */void *client_thread(void *arg){	int					n, fd, sockfd, nr, nw, first;	long				jobid;	pthread_t			tid;	struct printreq		req;	struct printresp	res;	char				name[FILENMSZ];	char				buf[IOBUFSZ];	tid = pthread_self();	pthread_cleanup_push(client_cleanup, (void *)tid);	sockfd = (int)arg;	add_worker(tid, sockfd);	/*	 * Read the request header.	 */	if ((n = treadn(sockfd, &req, sizeof(struct printreq), 10)) !=	  sizeof(struct printreq)) {		res.jobid = 0;		if (n < 0)			res.retcode = htonl(errno);		else			res.retcode = htonl(EIO);		strncpy(res.msg, strerror(res.retcode), MSGLEN_MAX);		writen(sockfd, &res, sizeof(struct printresp));		pthread_exit((void *)1);	}	req.size = ntohl(req.size);	req.flags = ntohl(req.flags);	/*	 * Create the data file.	 */	jobid = get_newjobno();	sprintf(name, "%s/%s/%ld", SPOOLDIR, DATADIR, jobid);	if ((fd = creat(name, FILEPERM)) < 0) {		res.jobid = 0;		if (n < 0)			res.retcode = htonl(errno);		else			res.retcode = htonl(EIO);		log_msg("client_thread: can't create %s: %s", name,		  strerror(res.retcode));		strncpy(res.msg, strerror(res.retcode), MSGLEN_MAX);		writen(sockfd, &res, sizeof(struct printresp));		pthread_exit((void *)1);	}	/*	 * Read the file and store it in the spool directory.	 */	first = 1;	while ((nr = tread(sockfd, buf, IOBUFSZ, 20)) > 0) {		if (first) {			first = 0;			if (strncmp(buf, "%!PS", 4) != 0)				req.flags |= PR_TEXT;		}		nw = write(fd, buf, nr);		if (nw != nr) {			if (nw < 0)				res.retcode = htonl(errno);			else				res.retcode = htonl(EIO);			log_msg("client_thread: can't write %s: %s", name,			  strerror(res.retcode));			close(fd);			strncpy(res.msg, strerror(res.retcode), MSGLEN_MAX);			writen(sockfd, &res, sizeof(struct printresp));			unlink(name);			pthread_exit((void *)1);		}	}	close(fd);	/*	 * Create the control file.	 */	sprintf(name, "%s/%s/%ld", SPOOLDIR, REQDIR, jobid);	fd = creat(name, FILEPERM);	if (fd < 0) {		res.jobid = 0;		if (n < 0)			res.retcode = htonl(errno);		else			res.retcode = htonl(EIO);		log_msg("client_thread: can't create %s: %s", name,		  strerror(res.retcode));		strncpy(res.msg, strerror(res.retcode), MSGLEN_MAX);		writen(sockfd, &res, sizeof(struct printresp));		sprintf(name, "%s/%s/%ld", SPOOLDIR, DATADIR, jobid);		unlink(name);		pthread_exit((void *)1);	}	nw = write(fd, &req, sizeof(struct printreq));	if (nw != sizeof(struct printreq)) {		res.jobid = 0;		if (nw < 0)			res.retcode = htonl(errno);		else			res.retcode = htonl(EIO);		log_msg("client_thread: can't write %s: %s", name,		  strerror(res.retcode));		close(fd);		strncpy(res.msg, strerror(res.retcode), MSGLEN_MAX);		writen(sockfd, &res, sizeof(struct printresp));		unlink(name);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -