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 DLIST_PROMOTE(print_db_head, last_entry); 59 60 for (p = print_db_head; p; p = p->next) { 61 if (p->ref_count) 62 continue; 63 if (p->tdb) { 64 if (tdb_close(print_db_head->tdb)) { 65 DEBUG(0,("get_print_db: Failed to close tdb for printer %s\n", 66 print_db_head->printer_name )); 67 return NULL; 68 } 69 } 70 p->tdb = NULL; 71 p->ref_count = 0; 72 memset(p->printer_name, '\0', sizeof(p->printer_name)); 73 break; 74 } 75 if (p) { 76 DLIST_PROMOTE(print_db_head, p); 77 p = print_db_head; 78 } 79 } 80 81 if (!p) { 82 /* Create one. */ 83 p = SMB_MALLOC_P(struct tdb_print_db); 84 if (!p) { 85 DEBUG(0,("get_print_db: malloc fail !\n")); 86 return NULL; 87 } 88 ZERO_STRUCTP(p); 89 DLIST_ADD(print_db_head, p); 90 } 91 92 pstrcpy(printdb_path, lock_path("printing/")); 93 pstrcat(printdb_path, printername); 94 pstrcat(printdb_path, ".tdb"); 95 96 if (geteuid() != 0) { 97 become_root(); 98 done_become_root = True; 99 } 100 101 p->tdb = tdb_open_log(printdb_path, 5000, TDB_DEFAULT, O_RDWR|O_CREAT, 102 0600); 103 104 if (done_become_root) 105 unbecome_root(); 106 107 if (!p->tdb) { 108 DEBUG(0,("get_print_db: Failed to open printer backend database %s.\n", 109 printdb_path )); 110 DLIST_REMOVE(print_db_head, p); 111 SAFE_FREE(p); 112 return NULL; 113 } 114 fstrcpy(p->printer_name, printername); 115 p->ref_count++; 116 return p; 117} 118 119/*************************************************************************** 120 Remove a reference count. 121****************************************************************************/ 122 123void release_print_db( struct tdb_print_db *pdb) 124{ 125 pdb->ref_count--; 126 SMB_ASSERT(pdb->ref_count >= 0); 127} 128 129/*************************************************************************** 130 Close all open print db entries. 131****************************************************************************/ 132 133void close_all_print_db(void) 134{ 135 struct tdb_print_db *p = NULL, *next_p = NULL; 136 137 for (p = print_db_head; p; p = next_p) { 138 next_p = p->next; 139 140 if (p->tdb) 141 tdb_close(p->tdb); 142 DLIST_REMOVE(print_db_head, p); 143 ZERO_STRUCTP(p); 144 SAFE_FREE(p); 145 } 146} 147 148 149/**************************************************************************** 150 Fetch and clean the pid_t record list for all pids interested in notify 151 messages. data needs freeing on exit. 152****************************************************************************/ 153 154TDB_DATA get_printer_notify_pid_list(TDB_CONTEXT *tdb, const char *printer_name, BOOL cleanlist) 155{ 156 TDB_DATA data; 157 size_t i; 158 159 ZERO_STRUCT(data); 160 161 data = tdb_fetch_bystring( tdb, NOTIFY_PID_LIST_KEY ); 162 163 if (!data.dptr) { 164 ZERO_STRUCT(data); 165 return data; 166 } 167 168 if (data.dsize % 8) { 169 DEBUG(0,("get_printer_notify_pid_list: Size of record for printer %s not a multiple of 8 !\n", printer_name )); 170 tdb_delete_bystring(tdb, NOTIFY_PID_LIST_KEY ); 171 SAFE_FREE(data.dptr); 172 ZERO_STRUCT(data); 173 return data; 174 } 175 176 if (!cleanlist) 177 return data; 178 179 /* 180 * Weed out all dead entries. 181 */ 182 183 for( i = 0; i < data.dsize; i += 8) { 184 pid_t pid = (pid_t)IVAL(data.dptr, i); 185 186 if (pid == sys_getpid()) 187 continue; 188 189 /* Entry is dead if process doesn't exist or refcount is zero. */ 190 191 while ((i < data.dsize) && ((IVAL(data.dptr, i + 4) == 0) || !process_exists(pid))) { 192 193 /* Refcount == zero is a logic error and should never happen. */ 194 if (IVAL(data.dptr, i + 4) == 0) { 195 DEBUG(0,("get_printer_notify_pid_list: Refcount == 0 for pid = %u printer %s !\n", 196 (unsigned int)pid, printer_name )); 197 } 198 199 if (data.dsize - i > 8) 200 memmove( &data.dptr[i], &data.dptr[i+8], data.dsize - i - 8); 201 data.dsize -= 8; 202 } 203 } 204 205 return data; 206} 207 208 209