1/* 2 Unix SMB/Netbios implementation. 3 Version 3.0 4 printing backend routines 5 Copyright (C) Andrew Tridgell 1992-2000 6 Copyright (C) Jeremy Allison 2002 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 2 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21*/ 22 23#include "includes.h" 24#include "printing.h" 25 26static struct tdb_print_db *print_db_head; 27 28/**************************************************************************** 29 Function to find or create the printer specific job tdb given a printername. 30 Limits the number of tdb's open to MAX_PRINT_DBS_OPEN. 31****************************************************************************/ 32 33struct tdb_print_db *get_print_db_byname(const char *printername) 34{ 35 struct tdb_print_db *p = NULL, *last_entry = NULL; 36 int num_open = 0; 37 pstring printdb_path; 38 BOOL done_become_root = False; 39 40 SMB_ASSERT(printername != NULL); 41 42 for (p = print_db_head, last_entry = print_db_head; p; p = p->next) { 43 /* Ensure the list terminates... JRA. */ 44 SMB_ASSERT(p->next != print_db_head); 45 46 if (p->tdb && strequal(p->printer_name, printername)) { 47 DLIST_PROMOTE(print_db_head, p); 48 p->ref_count++; 49 return p; 50 } 51 num_open++; 52 last_entry = p; 53 } 54 55 /* Not found. */ 56 if (num_open >= MAX_PRINT_DBS_OPEN) { 57 /* Try and recycle the last entry. */ 58 if (print_db_head && last_entry) { 59 DLIST_PROMOTE(print_db_head, last_entry); 60 } 61 62 for (p = print_db_head; p; p = p->next) { 63 if (p->ref_count) 64 continue; 65 if (p->tdb) { 66 if (tdb_close(print_db_head->tdb)) { 67 DEBUG(0,("get_print_db: Failed to close tdb for printer %s\n", 68 print_db_head->printer_name )); 69 return NULL; 70 } 71 } 72 p->tdb = NULL; 73 p->ref_count = 0; 74 memset(p->printer_name, '\0', sizeof(p->printer_name)); 75 break; 76 } 77 if (p && print_db_head) { 78 DLIST_PROMOTE(print_db_head, p); 79 p = print_db_head; 80 } 81 } 82 83 if (!p) { 84 /* Create one. */ 85 p = SMB_MALLOC_P(struct tdb_print_db); 86 if (!p) { 87 DEBUG(0,("get_print_db: malloc fail !\n")); 88 return NULL; 89 } 90 ZERO_STRUCTP(p); 91 DLIST_ADD(print_db_head, p); 92 } 93 94 pstrcpy(printdb_path, lock_path("printing/")); 95 pstrcat(printdb_path, printername); 96 pstrcat(printdb_path, ".tdb"); 97 98 if (geteuid() != 0) { 99 become_root(); 100 done_become_root = True; 101 } 102 103 p->tdb = tdb_open_log(printdb_path, 5000, TDB_DEFAULT, O_RDWR|O_CREAT, 104 0600); 105 106 if (done_become_root) 107 unbecome_root(); 108 109 if (!p->tdb) { 110 DEBUG(0,("get_print_db: Failed to open printer backend database %s.\n", 111 printdb_path )); 112 DLIST_REMOVE(print_db_head, p); 113 SAFE_FREE(p); 114 return NULL; 115 } 116 fstrcpy(p->printer_name, printername); 117 p->ref_count++; 118 return p; 119} 120 121/*************************************************************************** 122 Remove a reference count. 123****************************************************************************/ 124 125void release_print_db( struct tdb_print_db *pdb) 126{ 127 pdb->ref_count--; 128 SMB_ASSERT(pdb->ref_count >= 0); 129} 130 131/*************************************************************************** 132 Close all open print db entries. 133****************************************************************************/ 134 135void close_all_print_db(void) 136{ 137 struct tdb_print_db *p = NULL, *next_p = NULL; 138 139 for (p = print_db_head; p; p = next_p) { 140 next_p = p->next; 141 142 if (p->tdb) 143 tdb_close(p->tdb); 144 DLIST_REMOVE(print_db_head, p); 145 ZERO_STRUCTP(p); 146 SAFE_FREE(p); 147 } 148} 149 150 151/**************************************************************************** 152 Fetch and clean the pid_t record list for all pids interested in notify 153 messages. data needs freeing on exit. 154****************************************************************************/ 155 156TDB_DATA get_printer_notify_pid_list(TDB_CONTEXT *tdb, const char *printer_name, BOOL cleanlist) 157{ 158 TDB_DATA data; 159 size_t i; 160 161 ZERO_STRUCT(data); 162 163 data = tdb_fetch_bystring( tdb, NOTIFY_PID_LIST_KEY ); 164 165 if (!data.dptr) { 166 ZERO_STRUCT(data); 167 return data; 168 } 169 170 if (data.dsize % 8) { 171 DEBUG(0,("get_printer_notify_pid_list: Size of record for printer %s not a multiple of 8 !\n", printer_name )); 172 tdb_delete_bystring(tdb, NOTIFY_PID_LIST_KEY ); 173 SAFE_FREE(data.dptr); 174 ZERO_STRUCT(data); 175 return data; 176 } 177 178 if (!cleanlist) 179 return data; 180 181 /* 182 * Weed out all dead entries. 183 */ 184 185 for( i = 0; i < data.dsize; i += 8) { 186 pid_t pid = (pid_t)IVAL(data.dptr, i); 187 188 if (pid == sys_getpid()) 189 continue; 190 191 /* Entry is dead if process doesn't exist or refcount is zero. */ 192 193 while ((i < data.dsize) && ((IVAL(data.dptr, i + 4) == 0) || !process_exists_by_pid(pid))) { 194 195 /* Refcount == zero is a logic error and should never happen. */ 196 if (IVAL(data.dptr, i + 4) == 0) { 197 DEBUG(0,("get_printer_notify_pid_list: Refcount == 0 for pid = %u printer %s !\n", 198 (unsigned int)pid, printer_name )); 199 } 200 201 if (data.dsize - i > 8) 202 memmove( &data.dptr[i], &data.dptr[i+8], data.dsize - i - 8); 203 data.dsize -= 8; 204 } 205 } 206 207 return data; 208} 209 210 211